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