blob: dc8cc115b8bed831e1e3fda7949a892327cc44ea [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2012 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellanderb24317b2016-02-10 07:54:43 -08004 * 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:36 +00009 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "pc/dtmfsender.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
kwibergd1fe2812016-04-27 06:47:29 -070013#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000014#include <set>
15#include <string>
16#include <vector>
17
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/fakeclock.h"
19#include "rtc_base/gunit.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/timeutils.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000021
henrike@webrtc.org28e20752013-07-10 00:45:36 +000022using webrtc::DtmfProviderInterface;
23using webrtc::DtmfSender;
24using webrtc::DtmfSenderObserverInterface;
25
deadbeefe7fc7d52016-10-28 13:53:08 -070026// 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:36 +000029static const int kMaxWaitMs = 3000;
30
Magnus Jedvertfc950842015-10-12 16:10:43 +020031class FakeDtmfObserver : public DtmfSenderObserverInterface {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032 public:
33 FakeDtmfObserver() : completed_(false) {}
34
35 // Implements DtmfSenderObserverInterface.
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000036 void OnToneChange(const std::string& tone) override {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000037 tones_.push_back(tone);
38 if (tone.empty()) {
39 completed_ = true;
40 }
41 }
42
43 // getters
Yves Gerey665174f2018-06-19 15:03:05 +020044 const std::vector<std::string>& tones() const { return tones_; }
45 bool completed() const { return completed_; }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000046
47 private:
48 std::vector<std::string> tones_;
49 bool completed_;
50};
51
52class FakeDtmfProvider : public DtmfProviderInterface {
53 public:
54 struct DtmfInfo {
55 DtmfInfo(int code, int duration, int gap)
Yves Gerey665174f2018-06-19 15:03:05 +020056 : code(code), duration(duration), gap(gap) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057 int code;
58 int duration;
59 int gap;
60 };
61
62 FakeDtmfProvider() : last_insert_dtmf_call_(0) {}
63
Yves Gerey665174f2018-06-19 15:03:05 +020064 ~FakeDtmfProvider() { SignalDestroyed(); }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065
66 // Implements DtmfProviderInterface.
deadbeef20cb0c12017-02-01 20:27:00 -080067 bool CanInsertDtmf() override { return can_insert_; }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000068
deadbeef20cb0c12017-02-01 20:27:00 -080069 bool InsertDtmf(int code, int duration) override {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070 int gap = 0;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000071 // TODO(ronghuawu): Make the timer (basically the rtc::TimeNanos)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072 // mockable and use a fake timer in the unit tests.
73 if (last_insert_dtmf_call_ > 0) {
Honghai Zhang82d78622016-05-06 11:29:15 -070074 gap = static_cast<int>(rtc::TimeMillis() - last_insert_dtmf_call_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075 }
Honghai Zhang82d78622016-05-06 11:29:15 -070076 last_insert_dtmf_call_ = rtc::TimeMillis();
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077
henrike@webrtc.org28e20752013-07-10 00:45:36 +000078 dtmf_info_queue_.push_back(DtmfInfo(code, duration, gap));
79 return true;
80 }
81
nisseef8b61e2016-04-29 06:09:15 -070082 sigslot::signal0<>* GetOnDestroyedSignal() override {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083 return &SignalDestroyed;
84 }
85
86 // getter and setter
87 const std::vector<DtmfInfo>& dtmf_info_queue() const {
88 return dtmf_info_queue_;
89 }
90
91 // helper functions
deadbeef20cb0c12017-02-01 20:27:00 -080092 void SetCanInsertDtmf(bool can_insert) { can_insert_ = can_insert; }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000093
94 private:
deadbeef20cb0c12017-02-01 20:27:00 -080095 bool can_insert_ = false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000096 std::vector<DtmfInfo> dtmf_info_queue_;
Peter Boström0c4e06b2015-10-07 12:23:21 +020097 int64_t last_insert_dtmf_call_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000098 sigslot::signal0<> SignalDestroyed;
99};
100
101class DtmfSenderTest : public testing::Test {
102 protected:
103 DtmfSenderTest()
Steve Antonb983bae2018-06-20 11:16:53 -0700104 : observer_(new rtc::RefCountedObject<FakeDtmfObserver>()),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105 provider_(new FakeDtmfProvider()) {
deadbeef20cb0c12017-02-01 20:27:00 -0800106 provider_->SetCanInsertDtmf(true);
Steve Antonb983bae2018-06-20 11:16:53 -0700107 dtmf_ = DtmfSender::Create(rtc::Thread::Current(), provider_.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108 dtmf_->RegisterObserver(observer_.get());
109 }
110
111 ~DtmfSenderTest() {
112 if (dtmf_.get()) {
113 dtmf_->UnregisterObserver();
114 }
115 }
116
117 // Constructs a list of DtmfInfo from |tones|, |duration| and
118 // |inter_tone_gap|.
Yves Gerey665174f2018-06-19 15:03:05 +0200119 void GetDtmfInfoFromString(const std::string& tones,
120 int duration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121 int inter_tone_gap,
122 std::vector<FakeDtmfProvider::DtmfInfo>* dtmfs) {
123 // Init extra_delay as -inter_tone_gap - duration to ensure the first
124 // DtmfInfo's gap field will be 0.
125 int extra_delay = -1 * (inter_tone_gap + duration);
126
127 std::string::const_iterator it = tones.begin();
128 for (; it != tones.end(); ++it) {
129 char tone = *it;
130 int code = 0;
131 webrtc::GetDtmfCode(tone, &code);
132 if (tone == ',') {
133 extra_delay = 2000; // 2 seconds
134 } else {
Yves Gerey665174f2018-06-19 15:03:05 +0200135 dtmfs->push_back(FakeDtmfProvider::DtmfInfo(
136 code, duration, duration + inter_tone_gap + extra_delay));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137 extra_delay = 0;
138 }
139 }
140 }
141
Steve Antonb983bae2018-06-20 11:16:53 -0700142 void VerifyExpectedState(const std::string& tones,
Yves Gerey665174f2018-06-19 15:03:05 +0200143 int duration,
144 int inter_tone_gap) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000145 EXPECT_EQ(tones, dtmf_->tones());
146 EXPECT_EQ(duration, dtmf_->duration());
147 EXPECT_EQ(inter_tone_gap, dtmf_->inter_tone_gap());
148 }
149
150 // Verify the provider got all the expected calls.
Yves Gerey665174f2018-06-19 15:03:05 +0200151 void VerifyOnProvider(const std::string& tones,
152 int duration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000153 int inter_tone_gap) {
154 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
155 GetDtmfInfoFromString(tones, duration, inter_tone_gap, &dtmf_queue_ref);
156 VerifyOnProvider(dtmf_queue_ref);
157 }
158
159 void VerifyOnProvider(
160 const std::vector<FakeDtmfProvider::DtmfInfo>& dtmf_queue_ref) {
161 const std::vector<FakeDtmfProvider::DtmfInfo>& dtmf_queue =
162 provider_->dtmf_info_queue();
163 ASSERT_EQ(dtmf_queue_ref.size(), dtmf_queue.size());
164 std::vector<FakeDtmfProvider::DtmfInfo>::const_iterator it_ref =
165 dtmf_queue_ref.begin();
166 std::vector<FakeDtmfProvider::DtmfInfo>::const_iterator it =
167 dtmf_queue.begin();
168 while (it_ref != dtmf_queue_ref.end() && it != dtmf_queue.end()) {
169 EXPECT_EQ(it_ref->code, it->code);
170 EXPECT_EQ(it_ref->duration, it->duration);
deadbeefe7fc7d52016-10-28 13:53:08 -0700171 // Allow ~10ms error (can be small since we're using a fake clock).
172 EXPECT_GE(it_ref->gap, it->gap - 10);
173 EXPECT_LE(it_ref->gap, it->gap + 10);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000174 ++it_ref;
175 ++it;
176 }
177 }
178
179 // Verify the observer got all the expected callbacks.
180 void VerifyOnObserver(const std::string& tones_ref) {
181 const std::vector<std::string>& tones = observer_->tones();
182 // The observer will get an empty string at the end.
183 EXPECT_EQ(tones_ref.size() + 1, tones.size());
184 EXPECT_TRUE(tones.back().empty());
185 std::string::const_iterator it_ref = tones_ref.begin();
186 std::vector<std::string>::const_iterator it = tones.begin();
187 while (it_ref != tones_ref.end() && it != tones.end()) {
188 EXPECT_EQ(*it_ref, it->at(0));
189 ++it_ref;
190 ++it;
191 }
192 }
193
kwibergd1fe2812016-04-27 06:47:29 -0700194 std::unique_ptr<FakeDtmfObserver> observer_;
195 std::unique_ptr<FakeDtmfProvider> provider_;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000196 rtc::scoped_refptr<DtmfSender> dtmf_;
deadbeefe7fc7d52016-10-28 13:53:08 -0700197 rtc::ScopedFakeClock fake_clock_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000198};
199
200TEST_F(DtmfSenderTest, CanInsertDtmf) {
201 EXPECT_TRUE(dtmf_->CanInsertDtmf());
deadbeef20cb0c12017-02-01 20:27:00 -0800202 provider_->SetCanInsertDtmf(false);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000203 EXPECT_FALSE(dtmf_->CanInsertDtmf());
204}
205
206TEST_F(DtmfSenderTest, InsertDtmf) {
207 std::string tones = "@1%a&*$";
208 int duration = 100;
209 int inter_tone_gap = 50;
210 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
deadbeefe7fc7d52016-10-28 13:53:08 -0700211 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212
213 // The unrecognized characters should be ignored.
214 std::string known_tones = "1a*";
215 VerifyOnProvider(known_tones, duration, inter_tone_gap);
216 VerifyOnObserver(known_tones);
217}
218
219TEST_F(DtmfSenderTest, InsertDtmfTwice) {
220 std::string tones1 = "12";
221 std::string tones2 = "ab";
222 int duration = 100;
223 int inter_tone_gap = 50;
224 EXPECT_TRUE(dtmf_->InsertDtmf(tones1, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 11:16:53 -0700225 VerifyExpectedState(tones1, duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000226 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 13:53:08 -0700227 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
228 fake_clock_);
Steve Antonb983bae2018-06-20 11:16:53 -0700229 VerifyExpectedState("2", duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000230 // Insert with another tone buffer.
231 EXPECT_TRUE(dtmf_->InsertDtmf(tones2, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 11:16:53 -0700232 VerifyExpectedState(tones2, duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000233 // Wait until it's completed.
deadbeefe7fc7d52016-10-28 13:53:08 -0700234 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000235
236 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
237 GetDtmfInfoFromString("1", duration, inter_tone_gap, &dtmf_queue_ref);
238 GetDtmfInfoFromString("ab", duration, inter_tone_gap, &dtmf_queue_ref);
239 VerifyOnProvider(dtmf_queue_ref);
240 VerifyOnObserver("1ab");
241}
242
243TEST_F(DtmfSenderTest, InsertDtmfWhileProviderIsDeleted) {
244 std::string tones = "@1%a&*$";
245 int duration = 100;
246 int inter_tone_gap = 50;
247 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
248 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 13:53:08 -0700249 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
250 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000251 // Delete provider.
252 provider_.reset();
253 // The queue should be discontinued so no more tone callbacks.
deadbeefe7fc7d52016-10-28 13:53:08 -0700254 SIMULATED_WAIT(false, 200, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000255 EXPECT_EQ(1U, observer_->tones().size());
256}
257
258TEST_F(DtmfSenderTest, InsertDtmfWhileSenderIsDeleted) {
259 std::string tones = "@1%a&*$";
260 int duration = 100;
261 int inter_tone_gap = 50;
262 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
263 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 13:53:08 -0700264 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
265 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000266 // Delete the sender.
267 dtmf_ = NULL;
268 // The queue should be discontinued so no more tone callbacks.
deadbeefe7fc7d52016-10-28 13:53:08 -0700269 SIMULATED_WAIT(false, 200, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000270 EXPECT_EQ(1U, observer_->tones().size());
271}
272
273TEST_F(DtmfSenderTest, InsertEmptyTonesToCancelPreviousTask) {
274 std::string tones1 = "12";
275 std::string tones2 = "";
276 int duration = 100;
277 int inter_tone_gap = 50;
278 EXPECT_TRUE(dtmf_->InsertDtmf(tones1, duration, inter_tone_gap));
279 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 13:53:08 -0700280 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
281 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000282 // Insert with another tone buffer.
283 EXPECT_TRUE(dtmf_->InsertDtmf(tones2, duration, inter_tone_gap));
284 // Wait until it's completed.
deadbeefe7fc7d52016-10-28 13:53:08 -0700285 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000286
287 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
288 GetDtmfInfoFromString("1", duration, inter_tone_gap, &dtmf_queue_ref);
289 VerifyOnProvider(dtmf_queue_ref);
290 VerifyOnObserver("1");
291}
292
deadbeefe7fc7d52016-10-28 13:53:08 -0700293TEST_F(DtmfSenderTest, InsertDtmfWithCommaAsDelay) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000294 std::string tones = "3,4";
295 int duration = 100;
296 int inter_tone_gap = 50;
297 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
deadbeefe7fc7d52016-10-28 13:53:08 -0700298 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000299
300 VerifyOnProvider(tones, duration, inter_tone_gap);
301 VerifyOnObserver(tones);
302}
303
304TEST_F(DtmfSenderTest, TryInsertDtmfWhenItDoesNotWork) {
305 std::string tones = "3,4";
306 int duration = 100;
307 int inter_tone_gap = 50;
deadbeef20cb0c12017-02-01 20:27:00 -0800308 provider_->SetCanInsertDtmf(false);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000309 EXPECT_FALSE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
310}
311
312TEST_F(DtmfSenderTest, InsertDtmfWithInvalidDurationOrGap) {
313 std::string tones = "3,4";
dminor588101c2017-03-28 11:18:32 -0700314 int duration = 40;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000315 int inter_tone_gap = 50;
316
317 EXPECT_FALSE(dtmf_->InsertDtmf(tones, 6001, inter_tone_gap));
dminor588101c2017-03-28 11:18:32 -0700318 EXPECT_FALSE(dtmf_->InsertDtmf(tones, 39, inter_tone_gap));
Harald Alvestrand52e58522018-02-20 08:15:36 +0100319 EXPECT_FALSE(dtmf_->InsertDtmf(tones, duration, 29));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000320
321 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
322}
Harald Alvestrand1e0c8042018-03-06 10:51:27 +0100323
324TEST_F(DtmfSenderTest, InsertDtmfSendsAfterWait) {
325 std::string tones = "ABC";
326 int duration = 100;
327 int inter_tone_gap = 50;
328 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 11:16:53 -0700329 VerifyExpectedState("ABC", duration, inter_tone_gap);
Harald Alvestrand1e0c8042018-03-06 10:51:27 +0100330 // Wait until the first tone got sent.
331 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
332 fake_clock_);
Steve Antonb983bae2018-06-20 11:16:53 -0700333 VerifyExpectedState("BC", duration, inter_tone_gap);
Harald Alvestrand1e0c8042018-03-06 10:51:27 +0100334}