1/* 2 * Copyright (c) 2013 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/rtp_rtcp/include/rtp_payload_registry.h" 12 13#include "testing/gmock/include/gmock/gmock.h" 14#include "testing/gtest/include/gtest/gtest.h" 15#include "webrtc/base/scoped_ptr.h" 16#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h" 17#include "webrtc/modules/rtp_rtcp/source/byte_io.h" 18#include "webrtc/modules/rtp_rtcp/source/mock/mock_rtp_payload_strategy.h" 19#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" 20 21namespace webrtc { 22 23using ::testing::Eq; 24using ::testing::Return; 25using ::testing::_; 26 27static const char* kTypicalPayloadName = "name"; 28static const size_t kTypicalChannels = 1; 29static const int kTypicalFrequency = 44000; 30static const int kTypicalRate = 32 * 1024; 31 32class RtpPayloadRegistryTest : public ::testing::Test { 33 public: 34 void SetUp() { 35 // Note: the payload registry takes ownership of the strategy. 36 mock_payload_strategy_ = new testing::NiceMock<MockRTPPayloadStrategy>(); 37 rtp_payload_registry_.reset(new RTPPayloadRegistry(mock_payload_strategy_)); 38 } 39 40 protected: 41 RtpUtility::Payload* ExpectReturnOfTypicalAudioPayload(uint8_t payload_type, 42 uint32_t rate) { 43 bool audio = true; 44 RtpUtility::Payload returned_payload = { 45 "name", 46 audio, 47 {// Initialize the audio struct in this case. 48 {kTypicalFrequency, kTypicalChannels, rate}}}; 49 50 // Note: we return a new payload since the payload registry takes ownership 51 // of the created object. 52 RtpUtility::Payload* returned_payload_on_heap = 53 new RtpUtility::Payload(returned_payload); 54 EXPECT_CALL(*mock_payload_strategy_, 55 CreatePayloadType(kTypicalPayloadName, payload_type, 56 kTypicalFrequency, kTypicalChannels, rate)) 57 .WillOnce(Return(returned_payload_on_heap)); 58 return returned_payload_on_heap; 59 } 60 61 rtc::scoped_ptr<RTPPayloadRegistry> rtp_payload_registry_; 62 testing::NiceMock<MockRTPPayloadStrategy>* mock_payload_strategy_; 63}; 64 65TEST_F(RtpPayloadRegistryTest, RegistersAndRemembersPayloadsUntilDeregistered) { 66 uint8_t payload_type = 97; 67 RtpUtility::Payload* returned_payload_on_heap = 68 ExpectReturnOfTypicalAudioPayload(payload_type, kTypicalRate); 69 70 bool new_payload_created = false; 71 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 72 kTypicalPayloadName, payload_type, kTypicalFrequency, 73 kTypicalChannels, kTypicalRate, &new_payload_created)); 74 75 EXPECT_TRUE(new_payload_created) << "A new payload WAS created."; 76 77 const RtpUtility::Payload* retrieved_payload = 78 rtp_payload_registry_->PayloadTypeToPayload(payload_type); 79 EXPECT_TRUE(retrieved_payload); 80 81 // We should get back the exact pointer to the payload returned by the 82 // payload strategy. 83 EXPECT_EQ(returned_payload_on_heap, retrieved_payload); 84 85 // Now forget about it and verify it's gone. 86 EXPECT_EQ(0, rtp_payload_registry_->DeRegisterReceivePayload(payload_type)); 87 EXPECT_FALSE(rtp_payload_registry_->PayloadTypeToPayload(payload_type)); 88} 89 90TEST_F(RtpPayloadRegistryTest, AudioRedWorkProperly) { 91 const uint8_t kRedPayloadType = 127; 92 const int kRedSampleRate = 8000; 93 const size_t kRedChannels = 1; 94 const int kRedBitRate = 0; 95 96 // This creates an audio RTP payload strategy. 97 rtp_payload_registry_.reset( 98 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))); 99 100 bool new_payload_created = false; 101 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 102 "red", kRedPayloadType, kRedSampleRate, kRedChannels, 103 kRedBitRate, &new_payload_created)); 104 EXPECT_TRUE(new_payload_created); 105 106 EXPECT_EQ(kRedPayloadType, rtp_payload_registry_->red_payload_type()); 107 108 const RtpUtility::Payload* retrieved_payload = 109 rtp_payload_registry_->PayloadTypeToPayload(kRedPayloadType); 110 EXPECT_TRUE(retrieved_payload); 111 EXPECT_TRUE(retrieved_payload->audio); 112 EXPECT_STRCASEEQ("red", retrieved_payload->name); 113 114 // Sample rate is correctly registered. 115 EXPECT_EQ(kRedSampleRate, 116 rtp_payload_registry_->GetPayloadTypeFrequency(kRedPayloadType)); 117} 118 119TEST_F(RtpPayloadRegistryTest, 120 DoesNotAcceptSamePayloadTypeTwiceExceptIfPayloadIsCompatible) { 121 uint8_t payload_type = 97; 122 123 bool ignored = false; 124 RtpUtility::Payload* first_payload_on_heap = 125 ExpectReturnOfTypicalAudioPayload(payload_type, kTypicalRate); 126 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 127 kTypicalPayloadName, payload_type, kTypicalFrequency, 128 kTypicalChannels, kTypicalRate, &ignored)); 129 130 EXPECT_EQ(-1, rtp_payload_registry_->RegisterReceivePayload( 131 kTypicalPayloadName, payload_type, kTypicalFrequency, 132 kTypicalChannels, kTypicalRate, &ignored)) 133 << "Adding same codec twice = bad."; 134 135 RtpUtility::Payload* second_payload_on_heap = 136 ExpectReturnOfTypicalAudioPayload(payload_type - 1, kTypicalRate); 137 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 138 kTypicalPayloadName, payload_type - 1, kTypicalFrequency, 139 kTypicalChannels, kTypicalRate, &ignored)) 140 << "With a different payload type is fine though."; 141 142 // Ensure both payloads are preserved. 143 const RtpUtility::Payload* retrieved_payload = 144 rtp_payload_registry_->PayloadTypeToPayload(payload_type); 145 EXPECT_TRUE(retrieved_payload); 146 EXPECT_EQ(first_payload_on_heap, retrieved_payload); 147 retrieved_payload = 148 rtp_payload_registry_->PayloadTypeToPayload(payload_type - 1); 149 EXPECT_TRUE(retrieved_payload); 150 EXPECT_EQ(second_payload_on_heap, retrieved_payload); 151 152 // Ok, update the rate for one of the codecs. If either the incoming rate or 153 // the stored rate is zero it's not really an error to register the same 154 // codec twice, and in that case roughly the following happens. 155 ON_CALL(*mock_payload_strategy_, PayloadIsCompatible(_, _, _, _)) 156 .WillByDefault(Return(true)); 157 EXPECT_CALL(*mock_payload_strategy_, 158 UpdatePayloadRate(first_payload_on_heap, kTypicalRate)); 159 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 160 kTypicalPayloadName, payload_type, kTypicalFrequency, 161 kTypicalChannels, kTypicalRate, &ignored)); 162} 163 164TEST_F(RtpPayloadRegistryTest, 165 RemovesCompatibleCodecsOnRegistryIfCodecsMustBeUnique) { 166 ON_CALL(*mock_payload_strategy_, PayloadIsCompatible(_, _, _, _)) 167 .WillByDefault(Return(true)); 168 ON_CALL(*mock_payload_strategy_, CodecsMustBeUnique()) 169 .WillByDefault(Return(true)); 170 171 uint8_t payload_type = 97; 172 173 bool ignored = false; 174 ExpectReturnOfTypicalAudioPayload(payload_type, kTypicalRate); 175 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 176 kTypicalPayloadName, payload_type, kTypicalFrequency, 177 kTypicalChannels, kTypicalRate, &ignored)); 178 ExpectReturnOfTypicalAudioPayload(payload_type - 1, kTypicalRate); 179 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 180 kTypicalPayloadName, payload_type - 1, kTypicalFrequency, 181 kTypicalChannels, kTypicalRate, &ignored)); 182 183 EXPECT_FALSE(rtp_payload_registry_->PayloadTypeToPayload(payload_type)) 184 << "The first payload should be " 185 "deregistered because the only thing that differs is payload type."; 186 EXPECT_TRUE(rtp_payload_registry_->PayloadTypeToPayload(payload_type - 1)) 187 << "The second payload should still be registered though."; 188 189 // Now ensure non-compatible codecs aren't removed. 190 ON_CALL(*mock_payload_strategy_, PayloadIsCompatible(_, _, _, _)) 191 .WillByDefault(Return(false)); 192 ExpectReturnOfTypicalAudioPayload(payload_type + 1, kTypicalRate); 193 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 194 kTypicalPayloadName, payload_type + 1, kTypicalFrequency, 195 kTypicalChannels, kTypicalRate, &ignored)); 196 197 EXPECT_TRUE(rtp_payload_registry_->PayloadTypeToPayload(payload_type - 1)) 198 << "Not compatible; both payloads should be kept."; 199 EXPECT_TRUE(rtp_payload_registry_->PayloadTypeToPayload(payload_type + 1)) 200 << "Not compatible; both payloads should be kept."; 201} 202 203TEST_F(RtpPayloadRegistryTest, 204 LastReceivedCodecTypesAreResetWhenRegisteringNewPayloadTypes) { 205 rtp_payload_registry_->set_last_received_payload_type(17); 206 EXPECT_EQ(17, rtp_payload_registry_->last_received_payload_type()); 207 208 bool media_type_unchanged = rtp_payload_registry_->ReportMediaPayloadType(18); 209 EXPECT_FALSE(media_type_unchanged); 210 media_type_unchanged = rtp_payload_registry_->ReportMediaPayloadType(18); 211 EXPECT_TRUE(media_type_unchanged); 212 213 bool ignored; 214 ExpectReturnOfTypicalAudioPayload(34, kTypicalRate); 215 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 216 kTypicalPayloadName, 34, kTypicalFrequency, kTypicalChannels, 217 kTypicalRate, &ignored)); 218 219 EXPECT_EQ(-1, rtp_payload_registry_->last_received_payload_type()); 220 media_type_unchanged = rtp_payload_registry_->ReportMediaPayloadType(18); 221 EXPECT_FALSE(media_type_unchanged); 222} 223 224class ParameterizedRtpPayloadRegistryTest 225 : public RtpPayloadRegistryTest, 226 public ::testing::WithParamInterface<int> {}; 227 228TEST_P(ParameterizedRtpPayloadRegistryTest, 229 FailsToRegisterKnownPayloadsWeAreNotInterestedIn) { 230 int payload_type = GetParam(); 231 232 bool ignored; 233 EXPECT_EQ(-1, rtp_payload_registry_->RegisterReceivePayload( 234 "whatever", static_cast<uint8_t>(payload_type), 19, 1, 17, 235 &ignored)); 236} 237 238INSTANTIATE_TEST_CASE_P(TestKnownBadPayloadTypes, 239 ParameterizedRtpPayloadRegistryTest, 240 testing::Values(64, 72, 73, 74, 75, 76, 77, 78, 79)); 241 242class RtpPayloadRegistryGenericTest 243 : public RtpPayloadRegistryTest, 244 public ::testing::WithParamInterface<int> {}; 245 246TEST_P(RtpPayloadRegistryGenericTest, RegisterGenericReceivePayloadType) { 247 int payload_type = GetParam(); 248 249 bool ignored; 250 251 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 252 "generic-codec", static_cast<int8_t>(payload_type), 19, 1, 253 17, &ignored)); // dummy values, except for payload_type 254} 255 256// Generates an RTX packet for the given length and original sequence number. 257// The RTX sequence number and ssrc will use the default value of 9999. The 258// caller takes ownership of the returned buffer. 259const uint8_t* GenerateRtxPacket(size_t header_length, 260 size_t payload_length, 261 uint16_t original_sequence_number) { 262 uint8_t* packet = 263 new uint8_t[kRtxHeaderSize + header_length + payload_length](); 264 // Write the RTP version to the first byte, so the resulting header can be 265 // parsed. 266 static const int kRtpExpectedVersion = 2; 267 packet[0] = static_cast<uint8_t>(kRtpExpectedVersion << 6); 268 // Write a junk sequence number. It should be thrown away when the packet is 269 // restored. 270 ByteWriter<uint16_t>::WriteBigEndian(packet + 2, 9999); 271 // Write a junk ssrc. It should also be thrown away when the packet is 272 // restored. 273 ByteWriter<uint32_t>::WriteBigEndian(packet + 8, 9999); 274 275 // Now write the RTX header. It occurs at the start of the payload block, and 276 // contains just the sequence number. 277 ByteWriter<uint16_t>::WriteBigEndian(packet + header_length, 278 original_sequence_number); 279 return packet; 280} 281 282void TestRtxPacket(RTPPayloadRegistry* rtp_payload_registry, 283 int rtx_payload_type, 284 int expected_payload_type, 285 bool should_succeed) { 286 size_t header_length = 100; 287 size_t payload_length = 200; 288 size_t original_length = header_length + payload_length + kRtxHeaderSize; 289 290 RTPHeader header; 291 header.ssrc = 1000; 292 header.sequenceNumber = 100; 293 header.payloadType = rtx_payload_type; 294 header.headerLength = header_length; 295 296 uint16_t original_sequence_number = 1234; 297 uint32_t original_ssrc = 500; 298 299 rtc::scoped_ptr<const uint8_t[]> packet(GenerateRtxPacket( 300 header_length, payload_length, original_sequence_number)); 301 rtc::scoped_ptr<uint8_t[]> restored_packet( 302 new uint8_t[header_length + payload_length]); 303 size_t length = original_length; 304 bool success = rtp_payload_registry->RestoreOriginalPacket( 305 restored_packet.get(), packet.get(), &length, original_ssrc, header); 306 ASSERT_EQ(should_succeed, success) 307 << "Test success should match should_succeed."; 308 if (!success) { 309 return; 310 } 311 312 EXPECT_EQ(original_length - kRtxHeaderSize, length) 313 << "The restored packet should be exactly kRtxHeaderSize smaller."; 314 315 rtc::scoped_ptr<RtpHeaderParser> header_parser(RtpHeaderParser::Create()); 316 RTPHeader restored_header; 317 ASSERT_TRUE( 318 header_parser->Parse(restored_packet.get(), length, &restored_header)); 319 EXPECT_EQ(original_sequence_number, restored_header.sequenceNumber) 320 << "The restored packet should have the original sequence number " 321 << "in the correct location in the RTP header."; 322 EXPECT_EQ(expected_payload_type, restored_header.payloadType) 323 << "The restored packet should have the correct payload type."; 324 EXPECT_EQ(original_ssrc, restored_header.ssrc) 325 << "The restored packet should have the correct ssrc."; 326} 327 328TEST_F(RtpPayloadRegistryTest, MultipleRtxPayloadTypes) { 329 // Set the incoming payload type to 90. 330 RTPHeader header; 331 header.payloadType = 90; 332 header.ssrc = 1; 333 rtp_payload_registry_->SetIncomingPayloadType(header); 334 rtp_payload_registry_->SetRtxSsrc(100); 335 // Map two RTX payload types. 336 rtp_payload_registry_->SetRtxPayloadType(105, 95); 337 rtp_payload_registry_->SetRtxPayloadType(106, 96); 338 rtp_payload_registry_->set_use_rtx_payload_mapping_on_restore(true); 339 340 TestRtxPacket(rtp_payload_registry_.get(), 105, 95, true); 341 TestRtxPacket(rtp_payload_registry_.get(), 106, 96, true); 342 343 // If the option is off, the map will be ignored. 344 rtp_payload_registry_->set_use_rtx_payload_mapping_on_restore(false); 345 TestRtxPacket(rtp_payload_registry_.get(), 105, 90, true); 346 TestRtxPacket(rtp_payload_registry_.get(), 106, 90, true); 347} 348 349// TODO(holmer): Ignored by default for compatibility with misconfigured RTX 350// streams in Chrome. When that is fixed, remove this. 351TEST_F(RtpPayloadRegistryTest, IgnoresRtxPayloadTypeMappingByDefault) { 352 // Set the incoming payload type to 90. 353 RTPHeader header; 354 header.payloadType = 90; 355 header.ssrc = 1; 356 rtp_payload_registry_->SetIncomingPayloadType(header); 357 rtp_payload_registry_->SetRtxSsrc(100); 358 // Map two RTX payload types. 359 rtp_payload_registry_->SetRtxPayloadType(105, 95); 360 rtp_payload_registry_->SetRtxPayloadType(106, 96); 361 362 TestRtxPacket(rtp_payload_registry_.get(), 105, 90, true); 363 TestRtxPacket(rtp_payload_registry_.get(), 106, 90, true); 364} 365 366TEST_F(RtpPayloadRegistryTest, InferLastReceivedPacketIfPayloadTypeUnknown) { 367 rtp_payload_registry_->SetRtxSsrc(100); 368 // Set the incoming payload type to 90. 369 RTPHeader header; 370 header.payloadType = 90; 371 header.ssrc = 1; 372 rtp_payload_registry_->SetIncomingPayloadType(header); 373 rtp_payload_registry_->SetRtxPayloadType(105, 95); 374 rtp_payload_registry_->set_use_rtx_payload_mapping_on_restore(true); 375 // Mapping respected for known type. 376 TestRtxPacket(rtp_payload_registry_.get(), 105, 95, true); 377 // Mapping ignored for unknown type, even though the option is on. 378 TestRtxPacket(rtp_payload_registry_.get(), 106, 90, true); 379} 380 381TEST_F(RtpPayloadRegistryTest, InvalidRtxConfiguration) { 382 rtp_payload_registry_->SetRtxSsrc(100); 383 // Fails because no mappings exist and the incoming payload type isn't known. 384 TestRtxPacket(rtp_payload_registry_.get(), 105, 0, false); 385 // Succeeds when the mapping is used, but fails for the implicit fallback. 386 rtp_payload_registry_->SetRtxPayloadType(105, 95); 387 rtp_payload_registry_->set_use_rtx_payload_mapping_on_restore(true); 388 TestRtxPacket(rtp_payload_registry_.get(), 105, 95, true); 389 TestRtxPacket(rtp_payload_registry_.get(), 106, 0, false); 390} 391 392INSTANTIATE_TEST_CASE_P(TestDynamicRange, 393 RtpPayloadRegistryGenericTest, 394 testing::Range(96, 127 + 1)); 395 396} // namespace webrtc 397