blob: 3f59af0e2312882339614fa055722fe2dcb47aa4 [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
Steve Anton10542f22019-01-11 17:11:0011#include "pc/dtmf_sender.h"
henrike@webrtc.org28e20752013-07-10 00:45:3612
Yves Gerey3e707812018-11-28 15:47:4913#include <stddef.h>
Jonas Olssona4d87372019-07-05 17:08:3314
kwibergd1fe2812016-04-27 13:47:2915#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:3616#include <string>
17#include <vector>
18
Steve Anton10542f22019-01-11 17:11:0019#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3120#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 17:11:0021#include "rtc_base/ref_counted_object.h"
22#include "rtc_base/time_utils.h"
Yves Gerey3e707812018-11-28 15:47:4923#include "test/gtest.h"
henrike@webrtc.org28e20752013-07-10 00:45:3624
henrike@webrtc.org28e20752013-07-10 00:45:3625using webrtc::DtmfProviderInterface;
26using webrtc::DtmfSender;
27using webrtc::DtmfSenderObserverInterface;
28
deadbeefe7fc7d52016-10-28 20:53:0829// TODO(deadbeef): Even though this test now uses a fake clock, it has a
30// generous 3-second timeout for every test case. The timeout could be tuned
31// to each test based on the tones sent, instead.
henrike@webrtc.org28e20752013-07-10 00:45:3632static const int kMaxWaitMs = 3000;
33
Magnus Jedvertfc950842015-10-12 14:10:4334class FakeDtmfObserver : public DtmfSenderObserverInterface {
henrike@webrtc.org28e20752013-07-10 00:45:3635 public:
36 FakeDtmfObserver() : completed_(false) {}
37
38 // Implements DtmfSenderObserverInterface.
kjellander@webrtc.org14665ff2015-03-04 12:58:3539 void OnToneChange(const std::string& tone) override {
Harald Alvestrandd7b79af2018-09-06 07:33:5640 tones_from_single_argument_callback_.push_back(tone);
41 if (tone.empty()) {
42 completed_ = true;
43 }
44 }
45 void OnToneChange(const std::string& tone,
46 const std::string& tone_buffer) override {
henrike@webrtc.org28e20752013-07-10 00:45:3647 tones_.push_back(tone);
Harald Alvestrandd7b79af2018-09-06 07:33:5648 tones_remaining_ = tone_buffer;
henrike@webrtc.org28e20752013-07-10 00:45:3649 if (tone.empty()) {
50 completed_ = true;
51 }
52 }
53
54 // getters
Yves Gerey665174f2018-06-19 13:03:0555 const std::vector<std::string>& tones() const { return tones_; }
Harald Alvestrandd7b79af2018-09-06 07:33:5656 const std::vector<std::string>& tones_from_single_argument_callback() const {
57 return tones_from_single_argument_callback_;
58 }
59 const std::string tones_remaining() { return tones_remaining_; }
Yves Gerey665174f2018-06-19 13:03:0560 bool completed() const { return completed_; }
henrike@webrtc.org28e20752013-07-10 00:45:3661
62 private:
63 std::vector<std::string> tones_;
Harald Alvestrandd7b79af2018-09-06 07:33:5664 std::vector<std::string> tones_from_single_argument_callback_;
65 std::string tones_remaining_;
henrike@webrtc.org28e20752013-07-10 00:45:3666 bool completed_;
67};
68
69class FakeDtmfProvider : public DtmfProviderInterface {
70 public:
71 struct DtmfInfo {
72 DtmfInfo(int code, int duration, int gap)
Yves Gerey665174f2018-06-19 13:03:0573 : code(code), duration(duration), gap(gap) {}
henrike@webrtc.org28e20752013-07-10 00:45:3674 int code;
75 int duration;
76 int gap;
77 };
78
79 FakeDtmfProvider() : last_insert_dtmf_call_(0) {}
80
Yves Gerey665174f2018-06-19 13:03:0581 ~FakeDtmfProvider() { SignalDestroyed(); }
henrike@webrtc.org28e20752013-07-10 00:45:3682
83 // Implements DtmfProviderInterface.
deadbeef20cb0c12017-02-02 04:27:0084 bool CanInsertDtmf() override { return can_insert_; }
henrike@webrtc.org28e20752013-07-10 00:45:3685
deadbeef20cb0c12017-02-02 04:27:0086 bool InsertDtmf(int code, int duration) override {
henrike@webrtc.org28e20752013-07-10 00:45:3687 int gap = 0;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:5288 // TODO(ronghuawu): Make the timer (basically the rtc::TimeNanos)
henrike@webrtc.org28e20752013-07-10 00:45:3689 // mockable and use a fake timer in the unit tests.
90 if (last_insert_dtmf_call_ > 0) {
Honghai Zhang82d78622016-05-06 18:29:1591 gap = static_cast<int>(rtc::TimeMillis() - last_insert_dtmf_call_);
henrike@webrtc.org28e20752013-07-10 00:45:3692 }
Honghai Zhang82d78622016-05-06 18:29:1593 last_insert_dtmf_call_ = rtc::TimeMillis();
henrike@webrtc.org28e20752013-07-10 00:45:3694
henrike@webrtc.org28e20752013-07-10 00:45:3695 dtmf_info_queue_.push_back(DtmfInfo(code, duration, gap));
96 return true;
97 }
98
nisseef8b61e2016-04-29 13:09:1599 sigslot::signal0<>* GetOnDestroyedSignal() override {
henrike@webrtc.org28e20752013-07-10 00:45:36100 return &SignalDestroyed;
101 }
102
103 // getter and setter
104 const std::vector<DtmfInfo>& dtmf_info_queue() const {
105 return dtmf_info_queue_;
106 }
107
108 // helper functions
deadbeef20cb0c12017-02-02 04:27:00109 void SetCanInsertDtmf(bool can_insert) { can_insert_ = can_insert; }
henrike@webrtc.org28e20752013-07-10 00:45:36110
111 private:
deadbeef20cb0c12017-02-02 04:27:00112 bool can_insert_ = false;
henrike@webrtc.org28e20752013-07-10 00:45:36113 std::vector<DtmfInfo> dtmf_info_queue_;
Peter Boström0c4e06b2015-10-07 10:23:21114 int64_t last_insert_dtmf_call_;
henrike@webrtc.org28e20752013-07-10 00:45:36115 sigslot::signal0<> SignalDestroyed;
116};
117
Mirko Bonadei6a489f22019-04-09 13:11:12118class DtmfSenderTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36119 protected:
120 DtmfSenderTest()
Steve Antonb983bae2018-06-20 18:16:53121 : observer_(new rtc::RefCountedObject<FakeDtmfObserver>()),
henrike@webrtc.org28e20752013-07-10 00:45:36122 provider_(new FakeDtmfProvider()) {
deadbeef20cb0c12017-02-02 04:27:00123 provider_->SetCanInsertDtmf(true);
Steve Antonb983bae2018-06-20 18:16:53124 dtmf_ = DtmfSender::Create(rtc::Thread::Current(), provider_.get());
henrike@webrtc.org28e20752013-07-10 00:45:36125 dtmf_->RegisterObserver(observer_.get());
126 }
127
128 ~DtmfSenderTest() {
129 if (dtmf_.get()) {
130 dtmf_->UnregisterObserver();
131 }
132 }
133
134 // Constructs a list of DtmfInfo from |tones|, |duration| and
135 // |inter_tone_gap|.
Yves Gerey665174f2018-06-19 13:03:05136 void GetDtmfInfoFromString(const std::string& tones,
137 int duration,
henrike@webrtc.org28e20752013-07-10 00:45:36138 int inter_tone_gap,
139 std::vector<FakeDtmfProvider::DtmfInfo>* dtmfs) {
140 // Init extra_delay as -inter_tone_gap - duration to ensure the first
141 // DtmfInfo's gap field will be 0.
142 int extra_delay = -1 * (inter_tone_gap + duration);
143
144 std::string::const_iterator it = tones.begin();
145 for (; it != tones.end(); ++it) {
146 char tone = *it;
147 int code = 0;
148 webrtc::GetDtmfCode(tone, &code);
149 if (tone == ',') {
150 extra_delay = 2000; // 2 seconds
151 } else {
Yves Gerey665174f2018-06-19 13:03:05152 dtmfs->push_back(FakeDtmfProvider::DtmfInfo(
153 code, duration, duration + inter_tone_gap + extra_delay));
henrike@webrtc.org28e20752013-07-10 00:45:36154 extra_delay = 0;
155 }
156 }
157 }
158
Steve Antonb983bae2018-06-20 18:16:53159 void VerifyExpectedState(const std::string& tones,
Yves Gerey665174f2018-06-19 13:03:05160 int duration,
161 int inter_tone_gap) {
henrike@webrtc.org28e20752013-07-10 00:45:36162 EXPECT_EQ(tones, dtmf_->tones());
163 EXPECT_EQ(duration, dtmf_->duration());
164 EXPECT_EQ(inter_tone_gap, dtmf_->inter_tone_gap());
165 }
166
167 // Verify the provider got all the expected calls.
Yves Gerey665174f2018-06-19 13:03:05168 void VerifyOnProvider(const std::string& tones,
169 int duration,
henrike@webrtc.org28e20752013-07-10 00:45:36170 int inter_tone_gap) {
171 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
172 GetDtmfInfoFromString(tones, duration, inter_tone_gap, &dtmf_queue_ref);
173 VerifyOnProvider(dtmf_queue_ref);
174 }
175
176 void VerifyOnProvider(
177 const std::vector<FakeDtmfProvider::DtmfInfo>& dtmf_queue_ref) {
178 const std::vector<FakeDtmfProvider::DtmfInfo>& dtmf_queue =
179 provider_->dtmf_info_queue();
180 ASSERT_EQ(dtmf_queue_ref.size(), dtmf_queue.size());
181 std::vector<FakeDtmfProvider::DtmfInfo>::const_iterator it_ref =
182 dtmf_queue_ref.begin();
183 std::vector<FakeDtmfProvider::DtmfInfo>::const_iterator it =
184 dtmf_queue.begin();
185 while (it_ref != dtmf_queue_ref.end() && it != dtmf_queue.end()) {
186 EXPECT_EQ(it_ref->code, it->code);
187 EXPECT_EQ(it_ref->duration, it->duration);
deadbeefe7fc7d52016-10-28 20:53:08188 // Allow ~10ms error (can be small since we're using a fake clock).
189 EXPECT_GE(it_ref->gap, it->gap - 10);
190 EXPECT_LE(it_ref->gap, it->gap + 10);
henrike@webrtc.org28e20752013-07-10 00:45:36191 ++it_ref;
192 ++it;
193 }
194 }
195
196 // Verify the observer got all the expected callbacks.
197 void VerifyOnObserver(const std::string& tones_ref) {
198 const std::vector<std::string>& tones = observer_->tones();
199 // The observer will get an empty string at the end.
200 EXPECT_EQ(tones_ref.size() + 1, tones.size());
Harald Alvestrandd7b79af2018-09-06 07:33:56201 EXPECT_EQ(observer_->tones(),
202 observer_->tones_from_single_argument_callback());
henrike@webrtc.org28e20752013-07-10 00:45:36203 EXPECT_TRUE(tones.back().empty());
Harald Alvestrandd7b79af2018-09-06 07:33:56204 EXPECT_TRUE(observer_->tones_remaining().empty());
henrike@webrtc.org28e20752013-07-10 00:45:36205 std::string::const_iterator it_ref = tones_ref.begin();
206 std::vector<std::string>::const_iterator it = tones.begin();
207 while (it_ref != tones_ref.end() && it != tones.end()) {
208 EXPECT_EQ(*it_ref, it->at(0));
209 ++it_ref;
210 ++it;
211 }
212 }
213
kwibergd1fe2812016-04-27 13:47:29214 std::unique_ptr<FakeDtmfObserver> observer_;
215 std::unique_ptr<FakeDtmfProvider> provider_;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52216 rtc::scoped_refptr<DtmfSender> dtmf_;
deadbeefe7fc7d52016-10-28 20:53:08217 rtc::ScopedFakeClock fake_clock_;
henrike@webrtc.org28e20752013-07-10 00:45:36218};
219
220TEST_F(DtmfSenderTest, CanInsertDtmf) {
221 EXPECT_TRUE(dtmf_->CanInsertDtmf());
deadbeef20cb0c12017-02-02 04:27:00222 provider_->SetCanInsertDtmf(false);
henrike@webrtc.org28e20752013-07-10 00:45:36223 EXPECT_FALSE(dtmf_->CanInsertDtmf());
224}
225
226TEST_F(DtmfSenderTest, InsertDtmf) {
227 std::string tones = "@1%a&*$";
228 int duration = 100;
229 int inter_tone_gap = 50;
230 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
deadbeefe7fc7d52016-10-28 20:53:08231 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36232
233 // The unrecognized characters should be ignored.
234 std::string known_tones = "1a*";
235 VerifyOnProvider(known_tones, duration, inter_tone_gap);
236 VerifyOnObserver(known_tones);
237}
238
239TEST_F(DtmfSenderTest, InsertDtmfTwice) {
240 std::string tones1 = "12";
241 std::string tones2 = "ab";
242 int duration = 100;
243 int inter_tone_gap = 50;
244 EXPECT_TRUE(dtmf_->InsertDtmf(tones1, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 18:16:53245 VerifyExpectedState(tones1, duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36246 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08247 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
248 fake_clock_);
Steve Antonb983bae2018-06-20 18:16:53249 VerifyExpectedState("2", duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36250 // Insert with another tone buffer.
251 EXPECT_TRUE(dtmf_->InsertDtmf(tones2, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 18:16:53252 VerifyExpectedState(tones2, duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36253 // Wait until it's completed.
deadbeefe7fc7d52016-10-28 20:53:08254 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36255
256 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
257 GetDtmfInfoFromString("1", duration, inter_tone_gap, &dtmf_queue_ref);
258 GetDtmfInfoFromString("ab", duration, inter_tone_gap, &dtmf_queue_ref);
259 VerifyOnProvider(dtmf_queue_ref);
260 VerifyOnObserver("1ab");
261}
262
263TEST_F(DtmfSenderTest, InsertDtmfWhileProviderIsDeleted) {
264 std::string tones = "@1%a&*$";
265 int duration = 100;
266 int inter_tone_gap = 50;
267 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
268 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08269 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
270 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36271 // Delete provider.
272 provider_.reset();
273 // The queue should be discontinued so no more tone callbacks.
deadbeefe7fc7d52016-10-28 20:53:08274 SIMULATED_WAIT(false, 200, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36275 EXPECT_EQ(1U, observer_->tones().size());
276}
277
278TEST_F(DtmfSenderTest, InsertDtmfWhileSenderIsDeleted) {
279 std::string tones = "@1%a&*$";
280 int duration = 100;
281 int inter_tone_gap = 50;
282 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
283 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08284 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
285 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36286 // Delete the sender.
287 dtmf_ = NULL;
288 // The queue should be discontinued so no more tone callbacks.
deadbeefe7fc7d52016-10-28 20:53:08289 SIMULATED_WAIT(false, 200, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36290 EXPECT_EQ(1U, observer_->tones().size());
291}
292
293TEST_F(DtmfSenderTest, InsertEmptyTonesToCancelPreviousTask) {
294 std::string tones1 = "12";
295 std::string tones2 = "";
296 int duration = 100;
297 int inter_tone_gap = 50;
298 EXPECT_TRUE(dtmf_->InsertDtmf(tones1, duration, inter_tone_gap));
299 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08300 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
301 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36302 // Insert with another tone buffer.
303 EXPECT_TRUE(dtmf_->InsertDtmf(tones2, duration, inter_tone_gap));
304 // Wait until it's completed.
deadbeefe7fc7d52016-10-28 20:53:08305 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36306
307 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
308 GetDtmfInfoFromString("1", duration, inter_tone_gap, &dtmf_queue_ref);
309 VerifyOnProvider(dtmf_queue_ref);
310 VerifyOnObserver("1");
311}
312
deadbeefe7fc7d52016-10-28 20:53:08313TEST_F(DtmfSenderTest, InsertDtmfWithCommaAsDelay) {
henrike@webrtc.org28e20752013-07-10 00:45:36314 std::string tones = "3,4";
315 int duration = 100;
316 int inter_tone_gap = 50;
317 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
deadbeefe7fc7d52016-10-28 20:53:08318 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36319
320 VerifyOnProvider(tones, duration, inter_tone_gap);
321 VerifyOnObserver(tones);
322}
323
324TEST_F(DtmfSenderTest, TryInsertDtmfWhenItDoesNotWork) {
325 std::string tones = "3,4";
326 int duration = 100;
327 int inter_tone_gap = 50;
deadbeef20cb0c12017-02-02 04:27:00328 provider_->SetCanInsertDtmf(false);
henrike@webrtc.org28e20752013-07-10 00:45:36329 EXPECT_FALSE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
330}
331
332TEST_F(DtmfSenderTest, InsertDtmfWithInvalidDurationOrGap) {
333 std::string tones = "3,4";
dminor588101c2017-03-28 18:18:32334 int duration = 40;
henrike@webrtc.org28e20752013-07-10 00:45:36335 int inter_tone_gap = 50;
336
337 EXPECT_FALSE(dtmf_->InsertDtmf(tones, 6001, inter_tone_gap));
dminor588101c2017-03-28 18:18:32338 EXPECT_FALSE(dtmf_->InsertDtmf(tones, 39, inter_tone_gap));
Harald Alvestrand52e58522018-02-20 07:15:36339 EXPECT_FALSE(dtmf_->InsertDtmf(tones, duration, 29));
henrike@webrtc.org28e20752013-07-10 00:45:36340
341 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
342}
Harald Alvestrand1e0c8042018-03-06 09:51:27343
344TEST_F(DtmfSenderTest, InsertDtmfSendsAfterWait) {
345 std::string tones = "ABC";
346 int duration = 100;
347 int inter_tone_gap = 50;
348 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 18:16:53349 VerifyExpectedState("ABC", duration, inter_tone_gap);
Harald Alvestrand1e0c8042018-03-06 09:51:27350 // Wait until the first tone got sent.
351 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
352 fake_clock_);
Steve Antonb983bae2018-06-20 18:16:53353 VerifyExpectedState("BC", duration, inter_tone_gap);
Harald Alvestrand1e0c8042018-03-06 09:51:27354}