blob: ce0f2d17ee4e93573931abc1ad4987a7d8d7c59b [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:361/*
kjellanderb24317b2016-02-10 15:54:432 * Copyright 2012 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:363 *
kjellanderb24317b2016-02-10 15:54:434 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:369 */
10
Mirko Bonadei92ea95e2017-09-15 04:47:3111#include "pc/dtmfsender.h"
henrike@webrtc.org28e20752013-07-10 00:45:3612
kwibergd1fe2812016-04-27 13:47:2913#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:3614#include <set>
15#include <string>
16#include <vector>
17
Mirko Bonadei92ea95e2017-09-15 04:47:3118#include "rtc_base/fakeclock.h"
19#include "rtc_base/gunit.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3120#include "rtc_base/timeutils.h"
henrike@webrtc.org28e20752013-07-10 00:45:3621
henrike@webrtc.org28e20752013-07-10 00:45:3622using webrtc::DtmfProviderInterface;
23using webrtc::DtmfSender;
24using webrtc::DtmfSenderObserverInterface;
25
deadbeefe7fc7d52016-10-28 20:53:0826// TODO(deadbeef): Even though this test now uses a fake clock, it has a
27// generous 3-second timeout for every test case. The timeout could be tuned
28// to each test based on the tones sent, instead.
henrike@webrtc.org28e20752013-07-10 00:45:3629static const int kMaxWaitMs = 3000;
30
Magnus Jedvertfc950842015-10-12 14:10:4331class FakeDtmfObserver : public DtmfSenderObserverInterface {
henrike@webrtc.org28e20752013-07-10 00:45:3632 public:
33 FakeDtmfObserver() : completed_(false) {}
34
35 // Implements DtmfSenderObserverInterface.
kjellander@webrtc.org14665ff2015-03-04 12:58:3536 void OnToneChange(const std::string& tone) override {
Harald Alvestrandd7b79af2018-09-06 07:33:5637 tones_from_single_argument_callback_.push_back(tone);
38 if (tone.empty()) {
39 completed_ = true;
40 }
41 }
42 void OnToneChange(const std::string& tone,
43 const std::string& tone_buffer) override {
henrike@webrtc.org28e20752013-07-10 00:45:3644 tones_.push_back(tone);
Harald Alvestrandd7b79af2018-09-06 07:33:5645 tones_remaining_ = tone_buffer;
henrike@webrtc.org28e20752013-07-10 00:45:3646 if (tone.empty()) {
47 completed_ = true;
48 }
49 }
50
51 // getters
Yves Gerey665174f2018-06-19 13:03:0552 const std::vector<std::string>& tones() const { return tones_; }
Harald Alvestrandd7b79af2018-09-06 07:33:5653 const std::vector<std::string>& tones_from_single_argument_callback() const {
54 return tones_from_single_argument_callback_;
55 }
56 const std::string tones_remaining() { return tones_remaining_; }
Yves Gerey665174f2018-06-19 13:03:0557 bool completed() const { return completed_; }
henrike@webrtc.org28e20752013-07-10 00:45:3658
59 private:
60 std::vector<std::string> tones_;
Harald Alvestrandd7b79af2018-09-06 07:33:5661 std::vector<std::string> tones_from_single_argument_callback_;
62 std::string tones_remaining_;
henrike@webrtc.org28e20752013-07-10 00:45:3663 bool completed_;
64};
65
66class FakeDtmfProvider : public DtmfProviderInterface {
67 public:
68 struct DtmfInfo {
69 DtmfInfo(int code, int duration, int gap)
Yves Gerey665174f2018-06-19 13:03:0570 : code(code), duration(duration), gap(gap) {}
henrike@webrtc.org28e20752013-07-10 00:45:3671 int code;
72 int duration;
73 int gap;
74 };
75
76 FakeDtmfProvider() : last_insert_dtmf_call_(0) {}
77
Yves Gerey665174f2018-06-19 13:03:0578 ~FakeDtmfProvider() { SignalDestroyed(); }
henrike@webrtc.org28e20752013-07-10 00:45:3679
80 // Implements DtmfProviderInterface.
deadbeef20cb0c12017-02-02 04:27:0081 bool CanInsertDtmf() override { return can_insert_; }
henrike@webrtc.org28e20752013-07-10 00:45:3682
deadbeef20cb0c12017-02-02 04:27:0083 bool InsertDtmf(int code, int duration) override {
henrike@webrtc.org28e20752013-07-10 00:45:3684 int gap = 0;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:5285 // TODO(ronghuawu): Make the timer (basically the rtc::TimeNanos)
henrike@webrtc.org28e20752013-07-10 00:45:3686 // mockable and use a fake timer in the unit tests.
87 if (last_insert_dtmf_call_ > 0) {
Honghai Zhang82d78622016-05-06 18:29:1588 gap = static_cast<int>(rtc::TimeMillis() - last_insert_dtmf_call_);
henrike@webrtc.org28e20752013-07-10 00:45:3689 }
Honghai Zhang82d78622016-05-06 18:29:1590 last_insert_dtmf_call_ = rtc::TimeMillis();
henrike@webrtc.org28e20752013-07-10 00:45:3691
henrike@webrtc.org28e20752013-07-10 00:45:3692 dtmf_info_queue_.push_back(DtmfInfo(code, duration, gap));
93 return true;
94 }
95
nisseef8b61e2016-04-29 13:09:1596 sigslot::signal0<>* GetOnDestroyedSignal() override {
henrike@webrtc.org28e20752013-07-10 00:45:3697 return &SignalDestroyed;
98 }
99
100 // getter and setter
101 const std::vector<DtmfInfo>& dtmf_info_queue() const {
102 return dtmf_info_queue_;
103 }
104
105 // helper functions
deadbeef20cb0c12017-02-02 04:27:00106 void SetCanInsertDtmf(bool can_insert) { can_insert_ = can_insert; }
henrike@webrtc.org28e20752013-07-10 00:45:36107
108 private:
deadbeef20cb0c12017-02-02 04:27:00109 bool can_insert_ = false;
henrike@webrtc.org28e20752013-07-10 00:45:36110 std::vector<DtmfInfo> dtmf_info_queue_;
Peter Boström0c4e06b2015-10-07 10:23:21111 int64_t last_insert_dtmf_call_;
henrike@webrtc.org28e20752013-07-10 00:45:36112 sigslot::signal0<> SignalDestroyed;
113};
114
115class DtmfSenderTest : public testing::Test {
116 protected:
117 DtmfSenderTest()
Steve Antonb983bae2018-06-20 18:16:53118 : observer_(new rtc::RefCountedObject<FakeDtmfObserver>()),
henrike@webrtc.org28e20752013-07-10 00:45:36119 provider_(new FakeDtmfProvider()) {
deadbeef20cb0c12017-02-02 04:27:00120 provider_->SetCanInsertDtmf(true);
Steve Antonb983bae2018-06-20 18:16:53121 dtmf_ = DtmfSender::Create(rtc::Thread::Current(), provider_.get());
henrike@webrtc.org28e20752013-07-10 00:45:36122 dtmf_->RegisterObserver(observer_.get());
123 }
124
125 ~DtmfSenderTest() {
126 if (dtmf_.get()) {
127 dtmf_->UnregisterObserver();
128 }
129 }
130
131 // Constructs a list of DtmfInfo from |tones|, |duration| and
132 // |inter_tone_gap|.
Yves Gerey665174f2018-06-19 13:03:05133 void GetDtmfInfoFromString(const std::string& tones,
134 int duration,
henrike@webrtc.org28e20752013-07-10 00:45:36135 int inter_tone_gap,
136 std::vector<FakeDtmfProvider::DtmfInfo>* dtmfs) {
137 // Init extra_delay as -inter_tone_gap - duration to ensure the first
138 // DtmfInfo's gap field will be 0.
139 int extra_delay = -1 * (inter_tone_gap + duration);
140
141 std::string::const_iterator it = tones.begin();
142 for (; it != tones.end(); ++it) {
143 char tone = *it;
144 int code = 0;
145 webrtc::GetDtmfCode(tone, &code);
146 if (tone == ',') {
147 extra_delay = 2000; // 2 seconds
148 } else {
Yves Gerey665174f2018-06-19 13:03:05149 dtmfs->push_back(FakeDtmfProvider::DtmfInfo(
150 code, duration, duration + inter_tone_gap + extra_delay));
henrike@webrtc.org28e20752013-07-10 00:45:36151 extra_delay = 0;
152 }
153 }
154 }
155
Steve Antonb983bae2018-06-20 18:16:53156 void VerifyExpectedState(const std::string& tones,
Yves Gerey665174f2018-06-19 13:03:05157 int duration,
158 int inter_tone_gap) {
henrike@webrtc.org28e20752013-07-10 00:45:36159 EXPECT_EQ(tones, dtmf_->tones());
160 EXPECT_EQ(duration, dtmf_->duration());
161 EXPECT_EQ(inter_tone_gap, dtmf_->inter_tone_gap());
162 }
163
164 // Verify the provider got all the expected calls.
Yves Gerey665174f2018-06-19 13:03:05165 void VerifyOnProvider(const std::string& tones,
166 int duration,
henrike@webrtc.org28e20752013-07-10 00:45:36167 int inter_tone_gap) {
168 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
169 GetDtmfInfoFromString(tones, duration, inter_tone_gap, &dtmf_queue_ref);
170 VerifyOnProvider(dtmf_queue_ref);
171 }
172
173 void VerifyOnProvider(
174 const std::vector<FakeDtmfProvider::DtmfInfo>& dtmf_queue_ref) {
175 const std::vector<FakeDtmfProvider::DtmfInfo>& dtmf_queue =
176 provider_->dtmf_info_queue();
177 ASSERT_EQ(dtmf_queue_ref.size(), dtmf_queue.size());
178 std::vector<FakeDtmfProvider::DtmfInfo>::const_iterator it_ref =
179 dtmf_queue_ref.begin();
180 std::vector<FakeDtmfProvider::DtmfInfo>::const_iterator it =
181 dtmf_queue.begin();
182 while (it_ref != dtmf_queue_ref.end() && it != dtmf_queue.end()) {
183 EXPECT_EQ(it_ref->code, it->code);
184 EXPECT_EQ(it_ref->duration, it->duration);
deadbeefe7fc7d52016-10-28 20:53:08185 // Allow ~10ms error (can be small since we're using a fake clock).
186 EXPECT_GE(it_ref->gap, it->gap - 10);
187 EXPECT_LE(it_ref->gap, it->gap + 10);
henrike@webrtc.org28e20752013-07-10 00:45:36188 ++it_ref;
189 ++it;
190 }
191 }
192
193 // Verify the observer got all the expected callbacks.
194 void VerifyOnObserver(const std::string& tones_ref) {
195 const std::vector<std::string>& tones = observer_->tones();
196 // The observer will get an empty string at the end.
197 EXPECT_EQ(tones_ref.size() + 1, tones.size());
Harald Alvestrandd7b79af2018-09-06 07:33:56198 EXPECT_EQ(observer_->tones(),
199 observer_->tones_from_single_argument_callback());
henrike@webrtc.org28e20752013-07-10 00:45:36200 EXPECT_TRUE(tones.back().empty());
Harald Alvestrandd7b79af2018-09-06 07:33:56201 EXPECT_TRUE(observer_->tones_remaining().empty());
henrike@webrtc.org28e20752013-07-10 00:45:36202 std::string::const_iterator it_ref = tones_ref.begin();
203 std::vector<std::string>::const_iterator it = tones.begin();
204 while (it_ref != tones_ref.end() && it != tones.end()) {
205 EXPECT_EQ(*it_ref, it->at(0));
206 ++it_ref;
207 ++it;
208 }
209 }
210
kwibergd1fe2812016-04-27 13:47:29211 std::unique_ptr<FakeDtmfObserver> observer_;
212 std::unique_ptr<FakeDtmfProvider> provider_;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52213 rtc::scoped_refptr<DtmfSender> dtmf_;
deadbeefe7fc7d52016-10-28 20:53:08214 rtc::ScopedFakeClock fake_clock_;
henrike@webrtc.org28e20752013-07-10 00:45:36215};
216
217TEST_F(DtmfSenderTest, CanInsertDtmf) {
218 EXPECT_TRUE(dtmf_->CanInsertDtmf());
deadbeef20cb0c12017-02-02 04:27:00219 provider_->SetCanInsertDtmf(false);
henrike@webrtc.org28e20752013-07-10 00:45:36220 EXPECT_FALSE(dtmf_->CanInsertDtmf());
221}
222
223TEST_F(DtmfSenderTest, InsertDtmf) {
224 std::string tones = "@1%a&*$";
225 int duration = 100;
226 int inter_tone_gap = 50;
227 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
deadbeefe7fc7d52016-10-28 20:53:08228 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36229
230 // The unrecognized characters should be ignored.
231 std::string known_tones = "1a*";
232 VerifyOnProvider(known_tones, duration, inter_tone_gap);
233 VerifyOnObserver(known_tones);
234}
235
236TEST_F(DtmfSenderTest, InsertDtmfTwice) {
237 std::string tones1 = "12";
238 std::string tones2 = "ab";
239 int duration = 100;
240 int inter_tone_gap = 50;
241 EXPECT_TRUE(dtmf_->InsertDtmf(tones1, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 18:16:53242 VerifyExpectedState(tones1, duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36243 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08244 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
245 fake_clock_);
Steve Antonb983bae2018-06-20 18:16:53246 VerifyExpectedState("2", duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36247 // Insert with another tone buffer.
248 EXPECT_TRUE(dtmf_->InsertDtmf(tones2, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 18:16:53249 VerifyExpectedState(tones2, duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36250 // Wait until it's completed.
deadbeefe7fc7d52016-10-28 20:53:08251 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36252
253 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
254 GetDtmfInfoFromString("1", duration, inter_tone_gap, &dtmf_queue_ref);
255 GetDtmfInfoFromString("ab", duration, inter_tone_gap, &dtmf_queue_ref);
256 VerifyOnProvider(dtmf_queue_ref);
257 VerifyOnObserver("1ab");
258}
259
260TEST_F(DtmfSenderTest, InsertDtmfWhileProviderIsDeleted) {
261 std::string tones = "@1%a&*$";
262 int duration = 100;
263 int inter_tone_gap = 50;
264 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
265 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08266 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
267 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36268 // Delete provider.
269 provider_.reset();
270 // The queue should be discontinued so no more tone callbacks.
deadbeefe7fc7d52016-10-28 20:53:08271 SIMULATED_WAIT(false, 200, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36272 EXPECT_EQ(1U, observer_->tones().size());
273}
274
275TEST_F(DtmfSenderTest, InsertDtmfWhileSenderIsDeleted) {
276 std::string tones = "@1%a&*$";
277 int duration = 100;
278 int inter_tone_gap = 50;
279 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
280 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08281 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
282 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36283 // Delete the sender.
284 dtmf_ = NULL;
285 // The queue should be discontinued so no more tone callbacks.
deadbeefe7fc7d52016-10-28 20:53:08286 SIMULATED_WAIT(false, 200, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36287 EXPECT_EQ(1U, observer_->tones().size());
288}
289
290TEST_F(DtmfSenderTest, InsertEmptyTonesToCancelPreviousTask) {
291 std::string tones1 = "12";
292 std::string tones2 = "";
293 int duration = 100;
294 int inter_tone_gap = 50;
295 EXPECT_TRUE(dtmf_->InsertDtmf(tones1, duration, inter_tone_gap));
296 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08297 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
298 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36299 // Insert with another tone buffer.
300 EXPECT_TRUE(dtmf_->InsertDtmf(tones2, duration, inter_tone_gap));
301 // Wait until it's completed.
deadbeefe7fc7d52016-10-28 20:53:08302 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36303
304 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
305 GetDtmfInfoFromString("1", duration, inter_tone_gap, &dtmf_queue_ref);
306 VerifyOnProvider(dtmf_queue_ref);
307 VerifyOnObserver("1");
308}
309
deadbeefe7fc7d52016-10-28 20:53:08310TEST_F(DtmfSenderTest, InsertDtmfWithCommaAsDelay) {
henrike@webrtc.org28e20752013-07-10 00:45:36311 std::string tones = "3,4";
312 int duration = 100;
313 int inter_tone_gap = 50;
314 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
deadbeefe7fc7d52016-10-28 20:53:08315 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36316
317 VerifyOnProvider(tones, duration, inter_tone_gap);
318 VerifyOnObserver(tones);
319}
320
321TEST_F(DtmfSenderTest, TryInsertDtmfWhenItDoesNotWork) {
322 std::string tones = "3,4";
323 int duration = 100;
324 int inter_tone_gap = 50;
deadbeef20cb0c12017-02-02 04:27:00325 provider_->SetCanInsertDtmf(false);
henrike@webrtc.org28e20752013-07-10 00:45:36326 EXPECT_FALSE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
327}
328
329TEST_F(DtmfSenderTest, InsertDtmfWithInvalidDurationOrGap) {
330 std::string tones = "3,4";
dminor588101c2017-03-28 18:18:32331 int duration = 40;
henrike@webrtc.org28e20752013-07-10 00:45:36332 int inter_tone_gap = 50;
333
334 EXPECT_FALSE(dtmf_->InsertDtmf(tones, 6001, inter_tone_gap));
dminor588101c2017-03-28 18:18:32335 EXPECT_FALSE(dtmf_->InsertDtmf(tones, 39, inter_tone_gap));
Harald Alvestrand52e58522018-02-20 07:15:36336 EXPECT_FALSE(dtmf_->InsertDtmf(tones, duration, 29));
henrike@webrtc.org28e20752013-07-10 00:45:36337
338 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
339}
Harald Alvestrand1e0c8042018-03-06 09:51:27340
341TEST_F(DtmfSenderTest, InsertDtmfSendsAfterWait) {
342 std::string tones = "ABC";
343 int duration = 100;
344 int inter_tone_gap = 50;
345 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 18:16:53346 VerifyExpectedState("ABC", duration, inter_tone_gap);
Harald Alvestrand1e0c8042018-03-06 09:51:27347 // Wait until the first tone got sent.
348 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
349 fake_clock_);
Steve Antonb983bae2018-06-20 18:16:53350 VerifyExpectedState("BC", duration, inter_tone_gap);
Harald Alvestrand1e0c8042018-03-06 09:51:27351}