1/*
2 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 *  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.
9 */
10
11#include "webrtc/modules/audio_coding/neteq/timestamp_scaler.h"
12
13#include "testing/gmock/include/gmock/gmock.h"
14#include "testing/gtest/include/gtest/gtest.h"
15#include "webrtc/modules/audio_coding/neteq/mock/mock_decoder_database.h"
16#include "webrtc/modules/audio_coding/neteq/packet.h"
17
18using ::testing::Return;
19using ::testing::ReturnNull;
20using ::testing::_;
21
22namespace webrtc {
23
24TEST(TimestampScaler, TestNoScaling) {
25  MockDecoderDatabase db;
26  DecoderDatabase::DecoderInfo info;
27  info.codec_type = kDecoderPCMu;  // Does not use scaled timestamps.
28  static const uint8_t kRtpPayloadType = 0;
29  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
30      .WillRepeatedly(Return(&info));
31
32  TimestampScaler scaler(db);
33  // Test both sides of the timestamp wrap-around.
34  for (uint32_t timestamp = 0xFFFFFFFF - 5; timestamp != 5; ++timestamp) {
35    // Scale to internal timestamp.
36    EXPECT_EQ(timestamp, scaler.ToInternal(timestamp, kRtpPayloadType));
37    // Scale back.
38    EXPECT_EQ(timestamp, scaler.ToExternal(timestamp));
39  }
40
41  EXPECT_CALL(db, Die());  // Called when database object is deleted.
42}
43
44TEST(TimestampScaler, TestNoScalingLargeStep) {
45  MockDecoderDatabase db;
46  DecoderDatabase::DecoderInfo info;
47  info.codec_type = kDecoderPCMu;  // Does not use scaled timestamps.
48  static const uint8_t kRtpPayloadType = 0;
49  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
50      .WillRepeatedly(Return(&info));
51
52  TimestampScaler scaler(db);
53  // Test both sides of the timestamp wrap-around.
54  static const uint32_t kStep = 160;
55  uint32_t start_timestamp = 0;
56  // |external_timestamp| will be a large positive value.
57  start_timestamp = start_timestamp - 5 * kStep;
58  for (uint32_t timestamp = start_timestamp; timestamp != 5 * kStep;
59      timestamp += kStep) {
60    // Scale to internal timestamp.
61    EXPECT_EQ(timestamp, scaler.ToInternal(timestamp, kRtpPayloadType));
62    // Scale back.
63    EXPECT_EQ(timestamp, scaler.ToExternal(timestamp));
64  }
65
66  EXPECT_CALL(db, Die());  // Called when database object is deleted.
67}
68
69TEST(TimestampScaler, TestG722) {
70  MockDecoderDatabase db;
71  DecoderDatabase::DecoderInfo info;
72  info.codec_type = kDecoderG722;  // Uses a factor 2 scaling.
73  static const uint8_t kRtpPayloadType = 17;
74  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
75      .WillRepeatedly(Return(&info));
76
77  TimestampScaler scaler(db);
78  // Test both sides of the timestamp wrap-around.
79  uint32_t external_timestamp = 0xFFFFFFFF - 5;
80  uint32_t internal_timestamp = external_timestamp;
81  for (; external_timestamp != 5; ++external_timestamp) {
82    // Scale to internal timestamp.
83    EXPECT_EQ(internal_timestamp,
84              scaler.ToInternal(external_timestamp, kRtpPayloadType));
85    // Scale back.
86    EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
87    internal_timestamp += 2;
88  }
89
90  EXPECT_CALL(db, Die());  // Called when database object is deleted.
91}
92
93TEST(TimestampScaler, TestG722LargeStep) {
94  MockDecoderDatabase db;
95  DecoderDatabase::DecoderInfo info;
96  info.codec_type = kDecoderG722;  // Uses a factor 2 scaling.
97  static const uint8_t kRtpPayloadType = 17;
98  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
99      .WillRepeatedly(Return(&info));
100
101  TimestampScaler scaler(db);
102  // Test both sides of the timestamp wrap-around.
103  static const uint32_t kStep = 320;
104  uint32_t external_timestamp = 0;
105  // |external_timestamp| will be a large positive value.
106  external_timestamp = external_timestamp - 5 * kStep;
107  uint32_t internal_timestamp = external_timestamp;
108  for (; external_timestamp != 5 * kStep; external_timestamp += kStep) {
109    // Scale to internal timestamp.
110    EXPECT_EQ(internal_timestamp,
111              scaler.ToInternal(external_timestamp, kRtpPayloadType));
112    // Scale back.
113    EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
114    // Internal timestamp should be incremented with twice the step.
115    internal_timestamp += 2 * kStep;
116  }
117
118  EXPECT_CALL(db, Die());  // Called when database object is deleted.
119}
120
121TEST(TimestampScaler, TestG722WithCng) {
122  MockDecoderDatabase db;
123  DecoderDatabase::DecoderInfo info_g722, info_cng;
124  info_g722.codec_type = kDecoderG722;  // Uses a factor 2 scaling.
125  info_cng.codec_type = kDecoderCNGwb;
126  static const uint8_t kRtpPayloadTypeG722 = 17;
127  static const uint8_t kRtpPayloadTypeCng = 13;
128  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadTypeG722))
129      .WillRepeatedly(Return(&info_g722));
130  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadTypeCng))
131      .WillRepeatedly(Return(&info_cng));
132
133  TimestampScaler scaler(db);
134  // Test both sides of the timestamp wrap-around.
135  uint32_t external_timestamp = 0xFFFFFFFF - 5;
136  uint32_t internal_timestamp = external_timestamp;
137  bool next_is_cng = false;
138  for (; external_timestamp != 5; ++external_timestamp) {
139    // Alternate between G.722 and CNG every other packet.
140    if (next_is_cng) {
141      // Scale to internal timestamp.
142      EXPECT_EQ(internal_timestamp,
143                scaler.ToInternal(external_timestamp, kRtpPayloadTypeCng));
144      next_is_cng = false;
145    } else {
146      // Scale to internal timestamp.
147      EXPECT_EQ(internal_timestamp,
148                scaler.ToInternal(external_timestamp, kRtpPayloadTypeG722));
149      next_is_cng = true;
150    }
151    // Scale back.
152    EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
153    internal_timestamp += 2;
154  }
155
156  EXPECT_CALL(db, Die());  // Called when database object is deleted.
157}
158
159// Make sure that the method ToInternal(Packet* packet) is wired up correctly.
160// Since it is simply calling the other ToInternal method, we are not doing
161// as many tests here.
162TEST(TimestampScaler, TestG722Packet) {
163  MockDecoderDatabase db;
164  DecoderDatabase::DecoderInfo info;
165  info.codec_type = kDecoderG722;  // Does uses a factor 2 scaling.
166  static const uint8_t kRtpPayloadType = 17;
167  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
168      .WillRepeatedly(Return(&info));
169
170  TimestampScaler scaler(db);
171  // Test both sides of the timestamp wrap-around.
172  uint32_t external_timestamp = 0xFFFFFFFF - 5;
173  uint32_t internal_timestamp = external_timestamp;
174  Packet packet;
175  packet.header.payloadType = kRtpPayloadType;
176  for (; external_timestamp != 5; ++external_timestamp) {
177    packet.header.timestamp = external_timestamp;
178    // Scale to internal timestamp.
179    scaler.ToInternal(&packet);
180    EXPECT_EQ(internal_timestamp, packet.header.timestamp);
181    internal_timestamp += 2;
182  }
183
184  EXPECT_CALL(db, Die());  // Called when database object is deleted.
185}
186
187// Make sure that the method ToInternal(PacketList* packet_list) is wired up
188// correctly. Since it is simply calling the ToInternal(Packet* packet) method,
189// we are not doing as many tests here.
190TEST(TimestampScaler, TestG722PacketList) {
191  MockDecoderDatabase db;
192  DecoderDatabase::DecoderInfo info;
193  info.codec_type = kDecoderG722;  // Uses a factor 2 scaling.
194  static const uint8_t kRtpPayloadType = 17;
195  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
196      .WillRepeatedly(Return(&info));
197
198  TimestampScaler scaler(db);
199  // Test both sides of the timestamp wrap-around.
200  uint32_t external_timestamp = 0xFFFFFFFF - 5;
201  uint32_t internal_timestamp = external_timestamp;
202  Packet packet1;
203  packet1.header.payloadType = kRtpPayloadType;
204  packet1.header.timestamp = external_timestamp;
205  Packet packet2;
206  packet2.header.payloadType = kRtpPayloadType;
207  packet2.header.timestamp = external_timestamp + 10;
208  PacketList packet_list;
209  packet_list.push_back(&packet1);
210  packet_list.push_back(&packet2);
211
212  scaler.ToInternal(&packet_list);
213  EXPECT_EQ(internal_timestamp, packet1.header.timestamp);
214  EXPECT_EQ(internal_timestamp + 20, packet2.header.timestamp);
215
216  EXPECT_CALL(db, Die());  // Called when database object is deleted.
217}
218
219TEST(TimestampScaler, TestG722Reset) {
220  MockDecoderDatabase db;
221  DecoderDatabase::DecoderInfo info;
222  info.codec_type = kDecoderG722;  // Uses a factor 2 scaling.
223  static const uint8_t kRtpPayloadType = 17;
224  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
225      .WillRepeatedly(Return(&info));
226
227  TimestampScaler scaler(db);
228  // Test both sides of the timestamp wrap-around.
229  uint32_t external_timestamp = 0xFFFFFFFF - 5;
230  uint32_t internal_timestamp = external_timestamp;
231  for (; external_timestamp != 5; ++external_timestamp) {
232    // Scale to internal timestamp.
233    EXPECT_EQ(internal_timestamp,
234              scaler.ToInternal(external_timestamp, kRtpPayloadType));
235    // Scale back.
236    EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
237    internal_timestamp += 2;
238  }
239  // Reset the scaler. After this, we expect the internal and external to start
240  // over at the same value again.
241  scaler.Reset();
242  internal_timestamp = external_timestamp;
243  for (; external_timestamp != 15; ++external_timestamp) {
244    // Scale to internal timestamp.
245    EXPECT_EQ(internal_timestamp,
246              scaler.ToInternal(external_timestamp, kRtpPayloadType));
247    // Scale back.
248    EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
249    internal_timestamp += 2;
250  }
251
252  EXPECT_CALL(db, Die());  // Called when database object is deleted.
253}
254
255// TODO(minyue): This test becomes trivial since Opus does not need a timestamp
256// scaler. Therefore, this test may be removed in future. There is no harm to
257// keep it, since it can be taken as a test case for the situation of a trivial
258// timestamp scaler.
259TEST(TimestampScaler, TestOpusLargeStep) {
260  MockDecoderDatabase db;
261  DecoderDatabase::DecoderInfo info;
262  info.codec_type = kDecoderOpus;
263  static const uint8_t kRtpPayloadType = 17;
264  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
265      .WillRepeatedly(Return(&info));
266
267  TimestampScaler scaler(db);
268  // Test both sides of the timestamp wrap-around.
269  static const uint32_t kStep = 960;
270  uint32_t external_timestamp = 0;
271  // |external_timestamp| will be a large positive value.
272  external_timestamp = external_timestamp - 5 * kStep;
273  uint32_t internal_timestamp = external_timestamp;
274  for (; external_timestamp != 5 * kStep; external_timestamp += kStep) {
275    // Scale to internal timestamp.
276    EXPECT_EQ(internal_timestamp,
277              scaler.ToInternal(external_timestamp, kRtpPayloadType));
278    // Scale back.
279    EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
280    internal_timestamp += kStep;
281  }
282
283  EXPECT_CALL(db, Die());  // Called when database object is deleted.
284}
285
286TEST(TimestampScaler, TestIsacFbLargeStep) {
287  MockDecoderDatabase db;
288  DecoderDatabase::DecoderInfo info;
289  info.codec_type = kDecoderISACfb;
290  static const uint8_t kRtpPayloadType = 17;
291  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
292      .WillRepeatedly(Return(&info));
293
294  TimestampScaler scaler(db);
295  // Test both sides of the timestamp wrap-around.
296  static const uint32_t kStep = 960;
297  uint32_t external_timestamp = 0;
298  // |external_timestamp| will be a large positive value.
299  external_timestamp = external_timestamp - 5 * kStep;
300  uint32_t internal_timestamp = external_timestamp;
301  for (; external_timestamp != 5 * kStep; external_timestamp += kStep) {
302    // Scale to internal timestamp.
303    EXPECT_EQ(internal_timestamp,
304              scaler.ToInternal(external_timestamp, kRtpPayloadType));
305    // Scale back.
306    EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
307    // Internal timestamp should be incremented with two-thirds the step.
308    internal_timestamp += 2 * kStep / 3;
309  }
310
311  EXPECT_CALL(db, Die());  // Called when database object is deleted.
312}
313
314TEST(TimestampScaler, Failures) {
315  static const uint8_t kRtpPayloadType = 17;
316  MockDecoderDatabase db;
317  EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
318      .WillOnce(ReturnNull());  // Return NULL to indicate unknown payload type.
319
320  TimestampScaler scaler(db);
321  uint32_t timestamp = 4711;  // Some number.
322  EXPECT_EQ(timestamp, scaler.ToInternal(timestamp, kRtpPayloadType));
323
324  Packet* packet = NULL;
325  scaler.ToInternal(packet);  // Should not crash. That's all we can test.
326
327  EXPECT_CALL(db, Die());  // Called when database object is deleted.
328}
329
330}  // namespace webrtc
331