blob: 069833a20668cf06f7971ebf7724c3e0647f2d2a [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>
kwibergd1fe2812016-04-27 13:47:2914#include <memory>
henrike@webrtc.org28e20752013-07-10 00:45:3615#include <string>
16#include <vector>
17
Steve Anton10542f22019-01-11 17:11:0018#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3119#include "rtc_base/gunit.h"
Steve Anton10542f22019-01-11 17:11:0020#include "rtc_base/ref_counted_object.h"
21#include "rtc_base/time_utils.h"
Yves Gerey3e707812018-11-28 15:47:4922#include "test/gtest.h"
henrike@webrtc.org28e20752013-07-10 00:45:3623
henrike@webrtc.org28e20752013-07-10 00:45:3624using webrtc::DtmfProviderInterface;
25using webrtc::DtmfSender;
26using webrtc::DtmfSenderObserverInterface;
27
deadbeefe7fc7d52016-10-28 20:53:0828// TODO(deadbeef): Even though this test now uses a fake clock, it has a
29// generous 3-second timeout for every test case. The timeout could be tuned
30// to each test based on the tones sent, instead.
henrike@webrtc.org28e20752013-07-10 00:45:3631static const int kMaxWaitMs = 3000;
32
Magnus Jedvertfc950842015-10-12 14:10:4333class FakeDtmfObserver : public DtmfSenderObserverInterface {
henrike@webrtc.org28e20752013-07-10 00:45:3634 public:
35 FakeDtmfObserver() : completed_(false) {}
36
37 // Implements DtmfSenderObserverInterface.
kjellander@webrtc.org14665ff2015-03-04 12:58:3538 void OnToneChange(const std::string& tone) override {
Harald Alvestrandd7b79af2018-09-06 07:33:5639 tones_from_single_argument_callback_.push_back(tone);
40 if (tone.empty()) {
41 completed_ = true;
42 }
43 }
44 void OnToneChange(const std::string& tone,
45 const std::string& tone_buffer) override {
henrike@webrtc.org28e20752013-07-10 00:45:3646 tones_.push_back(tone);
Harald Alvestrandd7b79af2018-09-06 07:33:5647 tones_remaining_ = tone_buffer;
henrike@webrtc.org28e20752013-07-10 00:45:3648 if (tone.empty()) {
49 completed_ = true;
50 }
51 }
52
53 // getters
Yves Gerey665174f2018-06-19 13:03:0554 const std::vector<std::string>& tones() const { return tones_; }
Harald Alvestrandd7b79af2018-09-06 07:33:5655 const std::vector<std::string>& tones_from_single_argument_callback() const {
56 return tones_from_single_argument_callback_;
57 }
58 const std::string tones_remaining() { return tones_remaining_; }
Yves Gerey665174f2018-06-19 13:03:0559 bool completed() const { return completed_; }
henrike@webrtc.org28e20752013-07-10 00:45:3660
61 private:
62 std::vector<std::string> tones_;
Harald Alvestrandd7b79af2018-09-06 07:33:5663 std::vector<std::string> tones_from_single_argument_callback_;
64 std::string tones_remaining_;
henrike@webrtc.org28e20752013-07-10 00:45:3665 bool completed_;
66};
67
68class FakeDtmfProvider : public DtmfProviderInterface {
69 public:
70 struct DtmfInfo {
71 DtmfInfo(int code, int duration, int gap)
Yves Gerey665174f2018-06-19 13:03:0572 : code(code), duration(duration), gap(gap) {}
henrike@webrtc.org28e20752013-07-10 00:45:3673 int code;
74 int duration;
75 int gap;
76 };
77
78 FakeDtmfProvider() : last_insert_dtmf_call_(0) {}
79
Yves Gerey665174f2018-06-19 13:03:0580 ~FakeDtmfProvider() { SignalDestroyed(); }
henrike@webrtc.org28e20752013-07-10 00:45:3681
82 // Implements DtmfProviderInterface.
deadbeef20cb0c12017-02-02 04:27:0083 bool CanInsertDtmf() override { return can_insert_; }
henrike@webrtc.org28e20752013-07-10 00:45:3684
deadbeef20cb0c12017-02-02 04:27:0085 bool InsertDtmf(int code, int duration) override {
henrike@webrtc.org28e20752013-07-10 00:45:3686 int gap = 0;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:5287 // TODO(ronghuawu): Make the timer (basically the rtc::TimeNanos)
henrike@webrtc.org28e20752013-07-10 00:45:3688 // mockable and use a fake timer in the unit tests.
89 if (last_insert_dtmf_call_ > 0) {
Honghai Zhang82d78622016-05-06 18:29:1590 gap = static_cast<int>(rtc::TimeMillis() - last_insert_dtmf_call_);
henrike@webrtc.org28e20752013-07-10 00:45:3691 }
Honghai Zhang82d78622016-05-06 18:29:1592 last_insert_dtmf_call_ = rtc::TimeMillis();
henrike@webrtc.org28e20752013-07-10 00:45:3693
henrike@webrtc.org28e20752013-07-10 00:45:3694 dtmf_info_queue_.push_back(DtmfInfo(code, duration, gap));
95 return true;
96 }
97
nisseef8b61e2016-04-29 13:09:1598 sigslot::signal0<>* GetOnDestroyedSignal() override {
henrike@webrtc.org28e20752013-07-10 00:45:3699 return &SignalDestroyed;
100 }
101
102 // getter and setter
103 const std::vector<DtmfInfo>& dtmf_info_queue() const {
104 return dtmf_info_queue_;
105 }
106
107 // helper functions
deadbeef20cb0c12017-02-02 04:27:00108 void SetCanInsertDtmf(bool can_insert) { can_insert_ = can_insert; }
henrike@webrtc.org28e20752013-07-10 00:45:36109
110 private:
deadbeef20cb0c12017-02-02 04:27:00111 bool can_insert_ = false;
henrike@webrtc.org28e20752013-07-10 00:45:36112 std::vector<DtmfInfo> dtmf_info_queue_;
Peter Boström0c4e06b2015-10-07 10:23:21113 int64_t last_insert_dtmf_call_;
henrike@webrtc.org28e20752013-07-10 00:45:36114 sigslot::signal0<> SignalDestroyed;
115};
116
Mirko Bonadei6a489f22019-04-09 13:11:12117class DtmfSenderTest : public ::testing::Test {
henrike@webrtc.org28e20752013-07-10 00:45:36118 protected:
119 DtmfSenderTest()
Steve Antonb983bae2018-06-20 18:16:53120 : observer_(new rtc::RefCountedObject<FakeDtmfObserver>()),
henrike@webrtc.org28e20752013-07-10 00:45:36121 provider_(new FakeDtmfProvider()) {
deadbeef20cb0c12017-02-02 04:27:00122 provider_->SetCanInsertDtmf(true);
Steve Antonb983bae2018-06-20 18:16:53123 dtmf_ = DtmfSender::Create(rtc::Thread::Current(), provider_.get());
henrike@webrtc.org28e20752013-07-10 00:45:36124 dtmf_->RegisterObserver(observer_.get());
125 }
126
127 ~DtmfSenderTest() {
128 if (dtmf_.get()) {
129 dtmf_->UnregisterObserver();
130 }
131 }
132
133 // Constructs a list of DtmfInfo from |tones|, |duration| and
134 // |inter_tone_gap|.
Yves Gerey665174f2018-06-19 13:03:05135 void GetDtmfInfoFromString(const std::string& tones,
136 int duration,
henrike@webrtc.org28e20752013-07-10 00:45:36137 int inter_tone_gap,
138 std::vector<FakeDtmfProvider::DtmfInfo>* dtmfs) {
139 // Init extra_delay as -inter_tone_gap - duration to ensure the first
140 // DtmfInfo's gap field will be 0.
141 int extra_delay = -1 * (inter_tone_gap + duration);
142
143 std::string::const_iterator it = tones.begin();
144 for (; it != tones.end(); ++it) {
145 char tone = *it;
146 int code = 0;
147 webrtc::GetDtmfCode(tone, &code);
148 if (tone == ',') {
149 extra_delay = 2000; // 2 seconds
150 } else {
Yves Gerey665174f2018-06-19 13:03:05151 dtmfs->push_back(FakeDtmfProvider::DtmfInfo(
152 code, duration, duration + inter_tone_gap + extra_delay));
henrike@webrtc.org28e20752013-07-10 00:45:36153 extra_delay = 0;
154 }
155 }
156 }
157
Steve Antonb983bae2018-06-20 18:16:53158 void VerifyExpectedState(const std::string& tones,
Yves Gerey665174f2018-06-19 13:03:05159 int duration,
160 int inter_tone_gap) {
henrike@webrtc.org28e20752013-07-10 00:45:36161 EXPECT_EQ(tones, dtmf_->tones());
162 EXPECT_EQ(duration, dtmf_->duration());
163 EXPECT_EQ(inter_tone_gap, dtmf_->inter_tone_gap());
164 }
165
166 // Verify the provider got all the expected calls.
Yves Gerey665174f2018-06-19 13:03:05167 void VerifyOnProvider(const std::string& tones,
168 int duration,
henrike@webrtc.org28e20752013-07-10 00:45:36169 int inter_tone_gap) {
170 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
171 GetDtmfInfoFromString(tones, duration, inter_tone_gap, &dtmf_queue_ref);
172 VerifyOnProvider(dtmf_queue_ref);
173 }
174
175 void VerifyOnProvider(
176 const std::vector<FakeDtmfProvider::DtmfInfo>& dtmf_queue_ref) {
177 const std::vector<FakeDtmfProvider::DtmfInfo>& dtmf_queue =
178 provider_->dtmf_info_queue();
179 ASSERT_EQ(dtmf_queue_ref.size(), dtmf_queue.size());
180 std::vector<FakeDtmfProvider::DtmfInfo>::const_iterator it_ref =
181 dtmf_queue_ref.begin();
182 std::vector<FakeDtmfProvider::DtmfInfo>::const_iterator it =
183 dtmf_queue.begin();
184 while (it_ref != dtmf_queue_ref.end() && it != dtmf_queue.end()) {
185 EXPECT_EQ(it_ref->code, it->code);
186 EXPECT_EQ(it_ref->duration, it->duration);
deadbeefe7fc7d52016-10-28 20:53:08187 // Allow ~10ms error (can be small since we're using a fake clock).
188 EXPECT_GE(it_ref->gap, it->gap - 10);
189 EXPECT_LE(it_ref->gap, it->gap + 10);
henrike@webrtc.org28e20752013-07-10 00:45:36190 ++it_ref;
191 ++it;
192 }
193 }
194
195 // Verify the observer got all the expected callbacks.
196 void VerifyOnObserver(const std::string& tones_ref) {
197 const std::vector<std::string>& tones = observer_->tones();
198 // The observer will get an empty string at the end.
199 EXPECT_EQ(tones_ref.size() + 1, tones.size());
Harald Alvestrandd7b79af2018-09-06 07:33:56200 EXPECT_EQ(observer_->tones(),
201 observer_->tones_from_single_argument_callback());
henrike@webrtc.org28e20752013-07-10 00:45:36202 EXPECT_TRUE(tones.back().empty());
Harald Alvestrandd7b79af2018-09-06 07:33:56203 EXPECT_TRUE(observer_->tones_remaining().empty());
henrike@webrtc.org28e20752013-07-10 00:45:36204 std::string::const_iterator it_ref = tones_ref.begin();
205 std::vector<std::string>::const_iterator it = tones.begin();
206 while (it_ref != tones_ref.end() && it != tones.end()) {
207 EXPECT_EQ(*it_ref, it->at(0));
208 ++it_ref;
209 ++it;
210 }
211 }
212
kwibergd1fe2812016-04-27 13:47:29213 std::unique_ptr<FakeDtmfObserver> observer_;
214 std::unique_ptr<FakeDtmfProvider> provider_;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52215 rtc::scoped_refptr<DtmfSender> dtmf_;
deadbeefe7fc7d52016-10-28 20:53:08216 rtc::ScopedFakeClock fake_clock_;
henrike@webrtc.org28e20752013-07-10 00:45:36217};
218
219TEST_F(DtmfSenderTest, CanInsertDtmf) {
220 EXPECT_TRUE(dtmf_->CanInsertDtmf());
deadbeef20cb0c12017-02-02 04:27:00221 provider_->SetCanInsertDtmf(false);
henrike@webrtc.org28e20752013-07-10 00:45:36222 EXPECT_FALSE(dtmf_->CanInsertDtmf());
223}
224
225TEST_F(DtmfSenderTest, InsertDtmf) {
226 std::string tones = "@1%a&*$";
227 int duration = 100;
228 int inter_tone_gap = 50;
229 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
deadbeefe7fc7d52016-10-28 20:53:08230 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36231
232 // The unrecognized characters should be ignored.
233 std::string known_tones = "1a*";
234 VerifyOnProvider(known_tones, duration, inter_tone_gap);
235 VerifyOnObserver(known_tones);
236}
237
238TEST_F(DtmfSenderTest, InsertDtmfTwice) {
239 std::string tones1 = "12";
240 std::string tones2 = "ab";
241 int duration = 100;
242 int inter_tone_gap = 50;
243 EXPECT_TRUE(dtmf_->InsertDtmf(tones1, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 18:16:53244 VerifyExpectedState(tones1, duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36245 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08246 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
247 fake_clock_);
Steve Antonb983bae2018-06-20 18:16:53248 VerifyExpectedState("2", duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36249 // Insert with another tone buffer.
250 EXPECT_TRUE(dtmf_->InsertDtmf(tones2, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 18:16:53251 VerifyExpectedState(tones2, duration, inter_tone_gap);
henrike@webrtc.org28e20752013-07-10 00:45:36252 // Wait until it's completed.
deadbeefe7fc7d52016-10-28 20:53:08253 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36254
255 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
256 GetDtmfInfoFromString("1", duration, inter_tone_gap, &dtmf_queue_ref);
257 GetDtmfInfoFromString("ab", duration, inter_tone_gap, &dtmf_queue_ref);
258 VerifyOnProvider(dtmf_queue_ref);
259 VerifyOnObserver("1ab");
260}
261
262TEST_F(DtmfSenderTest, InsertDtmfWhileProviderIsDeleted) {
263 std::string tones = "@1%a&*$";
264 int duration = 100;
265 int inter_tone_gap = 50;
266 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
267 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08268 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
269 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36270 // Delete provider.
271 provider_.reset();
272 // The queue should be discontinued so no more tone callbacks.
deadbeefe7fc7d52016-10-28 20:53:08273 SIMULATED_WAIT(false, 200, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36274 EXPECT_EQ(1U, observer_->tones().size());
275}
276
277TEST_F(DtmfSenderTest, InsertDtmfWhileSenderIsDeleted) {
278 std::string tones = "@1%a&*$";
279 int duration = 100;
280 int inter_tone_gap = 50;
281 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
282 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08283 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
284 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36285 // Delete the sender.
286 dtmf_ = NULL;
287 // The queue should be discontinued so no more tone callbacks.
deadbeefe7fc7d52016-10-28 20:53:08288 SIMULATED_WAIT(false, 200, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36289 EXPECT_EQ(1U, observer_->tones().size());
290}
291
292TEST_F(DtmfSenderTest, InsertEmptyTonesToCancelPreviousTask) {
293 std::string tones1 = "12";
294 std::string tones2 = "";
295 int duration = 100;
296 int inter_tone_gap = 50;
297 EXPECT_TRUE(dtmf_->InsertDtmf(tones1, duration, inter_tone_gap));
298 // Wait until the first tone got sent.
deadbeefe7fc7d52016-10-28 20:53:08299 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
300 fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36301 // Insert with another tone buffer.
302 EXPECT_TRUE(dtmf_->InsertDtmf(tones2, duration, inter_tone_gap));
303 // Wait until it's completed.
deadbeefe7fc7d52016-10-28 20:53:08304 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36305
306 std::vector<FakeDtmfProvider::DtmfInfo> dtmf_queue_ref;
307 GetDtmfInfoFromString("1", duration, inter_tone_gap, &dtmf_queue_ref);
308 VerifyOnProvider(dtmf_queue_ref);
309 VerifyOnObserver("1");
310}
311
deadbeefe7fc7d52016-10-28 20:53:08312TEST_F(DtmfSenderTest, InsertDtmfWithCommaAsDelay) {
henrike@webrtc.org28e20752013-07-10 00:45:36313 std::string tones = "3,4";
314 int duration = 100;
315 int inter_tone_gap = 50;
316 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
deadbeefe7fc7d52016-10-28 20:53:08317 EXPECT_TRUE_SIMULATED_WAIT(observer_->completed(), kMaxWaitMs, fake_clock_);
henrike@webrtc.org28e20752013-07-10 00:45:36318
319 VerifyOnProvider(tones, duration, inter_tone_gap);
320 VerifyOnObserver(tones);
321}
322
323TEST_F(DtmfSenderTest, TryInsertDtmfWhenItDoesNotWork) {
324 std::string tones = "3,4";
325 int duration = 100;
326 int inter_tone_gap = 50;
deadbeef20cb0c12017-02-02 04:27:00327 provider_->SetCanInsertDtmf(false);
henrike@webrtc.org28e20752013-07-10 00:45:36328 EXPECT_FALSE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
329}
330
331TEST_F(DtmfSenderTest, InsertDtmfWithInvalidDurationOrGap) {
332 std::string tones = "3,4";
dminor588101c2017-03-28 18:18:32333 int duration = 40;
henrike@webrtc.org28e20752013-07-10 00:45:36334 int inter_tone_gap = 50;
335
336 EXPECT_FALSE(dtmf_->InsertDtmf(tones, 6001, inter_tone_gap));
dminor588101c2017-03-28 18:18:32337 EXPECT_FALSE(dtmf_->InsertDtmf(tones, 39, inter_tone_gap));
Harald Alvestrand52e58522018-02-20 07:15:36338 EXPECT_FALSE(dtmf_->InsertDtmf(tones, duration, 29));
henrike@webrtc.org28e20752013-07-10 00:45:36339
340 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
341}
Harald Alvestrand1e0c8042018-03-06 09:51:27342
343TEST_F(DtmfSenderTest, InsertDtmfSendsAfterWait) {
344 std::string tones = "ABC";
345 int duration = 100;
346 int inter_tone_gap = 50;
347 EXPECT_TRUE(dtmf_->InsertDtmf(tones, duration, inter_tone_gap));
Steve Antonb983bae2018-06-20 18:16:53348 VerifyExpectedState("ABC", duration, inter_tone_gap);
Harald Alvestrand1e0c8042018-03-06 09:51:27349 // Wait until the first tone got sent.
350 EXPECT_TRUE_SIMULATED_WAIT(observer_->tones().size() == 1, kMaxWaitMs,
351 fake_clock_);
Steve Antonb983bae2018-06-20 18:16:53352 VerifyExpectedState("BC", duration, inter_tone_gap);
Harald Alvestrand1e0c8042018-03-06 09:51:27353}