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/interface/rtp_payload_registry.h" 12 13 #include "testing/gmock/include/gmock/gmock.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 #include "webrtc/modules/rtp_rtcp/source/mock/mock_rtp_payload_strategy.h" 16 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" 17 #include "webrtc/system_wrappers/interface/scoped_ptr.h" 18 19 namespace webrtc { 20 21 using ::testing::Eq; 22 using ::testing::Return; 23 using ::testing::_; 24 25 static const char* kTypicalPayloadName = "name"; 26 static const uint8_t kTypicalChannels = 1; 27 static const int kTypicalFrequency = 44000; 28 static const int kTypicalRate = 32 * 1024; 29 30 class RtpPayloadRegistryTest : public ::testing::Test { 31 public: 32 void SetUp() { 33 // Note: the payload registry takes ownership of the strategy. 34 mock_payload_strategy_ = new testing::NiceMock<MockRTPPayloadStrategy>(); 35 rtp_payload_registry_.reset(new RTPPayloadRegistry(mock_payload_strategy_)); 36 } 37 38 protected: 39 ModuleRTPUtility::Payload* ExpectReturnOfTypicalAudioPayload( 40 uint8_t payload_type, uint32_t rate) { 41 bool audio = true; 42 ModuleRTPUtility::Payload returned_payload = { "name", audio, { 43 // Initialize the audio struct in this case. 44 { kTypicalFrequency, kTypicalChannels, rate } 45 }}; 46 47 // Note: we return a new payload since the payload registry takes ownership 48 // of the created object. 49 ModuleRTPUtility::Payload* returned_payload_on_heap = 50 new ModuleRTPUtility::Payload(returned_payload); 51 EXPECT_CALL(*mock_payload_strategy_, 52 CreatePayloadType(kTypicalPayloadName, payload_type, 53 kTypicalFrequency, 54 kTypicalChannels, 55 rate)).WillOnce(Return(returned_payload_on_heap)); 56 return returned_payload_on_heap; 57 } 58 59 scoped_ptr<RTPPayloadRegistry> rtp_payload_registry_; 60 testing::NiceMock<MockRTPPayloadStrategy>* mock_payload_strategy_; 61 }; 62 63 TEST_F(RtpPayloadRegistryTest, RegistersAndRemembersPayloadsUntilDeregistered) { 64 uint8_t payload_type = 97; 65 ModuleRTPUtility::Payload* returned_payload_on_heap = 66 ExpectReturnOfTypicalAudioPayload(payload_type, kTypicalRate); 67 68 bool new_payload_created = false; 69 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 70 kTypicalPayloadName, payload_type, kTypicalFrequency, kTypicalChannels, 71 kTypicalRate, &new_payload_created)); 72 73 EXPECT_TRUE(new_payload_created) << "A new payload WAS created."; 74 75 ModuleRTPUtility::Payload* retrieved_payload = NULL; 76 EXPECT_TRUE(rtp_payload_registry_->PayloadTypeToPayload(payload_type, 77 retrieved_payload)); 78 79 // We should get back the exact pointer to the payload returned by the 80 // payload strategy. 81 EXPECT_EQ(returned_payload_on_heap, retrieved_payload); 82 83 // Now forget about it and verify it's gone. 84 EXPECT_EQ(0, rtp_payload_registry_->DeRegisterReceivePayload(payload_type)); 85 EXPECT_FALSE(rtp_payload_registry_->PayloadTypeToPayload( 86 payload_type, retrieved_payload)); 87 } 88 89 TEST_F(RtpPayloadRegistryTest, DoesNotCreateNewPayloadTypeIfRed) { 90 EXPECT_CALL(*mock_payload_strategy_, 91 CreatePayloadType(_, _, _, _, _)).Times(0); 92 93 bool new_payload_created = false; 94 uint8_t red_type_of_the_day = 104; 95 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 96 "red", red_type_of_the_day, kTypicalFrequency, kTypicalChannels, 97 kTypicalRate, &new_payload_created)); 98 ASSERT_FALSE(new_payload_created); 99 100 ASSERT_EQ(red_type_of_the_day, rtp_payload_registry_->red_payload_type()); 101 102 ModuleRTPUtility::Payload* retrieved_payload = NULL; 103 EXPECT_TRUE(rtp_payload_registry_->PayloadTypeToPayload(red_type_of_the_day, 104 retrieved_payload)); 105 EXPECT_FALSE(retrieved_payload->audio); 106 EXPECT_STRCASEEQ("red", retrieved_payload->name); 107 } 108 109 TEST_F(RtpPayloadRegistryTest, 110 DoesNotAcceptSamePayloadTypeTwiceExceptIfPayloadIsCompatible) { 111 uint8_t payload_type = 97; 112 113 bool ignored = false; 114 ModuleRTPUtility::Payload* first_payload_on_heap = 115 ExpectReturnOfTypicalAudioPayload(payload_type, kTypicalRate); 116 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 117 kTypicalPayloadName, payload_type, kTypicalFrequency, kTypicalChannels, 118 kTypicalRate, &ignored)); 119 120 EXPECT_EQ(-1, rtp_payload_registry_->RegisterReceivePayload( 121 kTypicalPayloadName, payload_type, kTypicalFrequency, kTypicalChannels, 122 kTypicalRate, &ignored)) << "Adding same codec twice = bad."; 123 124 ModuleRTPUtility::Payload* second_payload_on_heap = 125 ExpectReturnOfTypicalAudioPayload(payload_type - 1, kTypicalRate); 126 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 127 kTypicalPayloadName, payload_type - 1, kTypicalFrequency, 128 kTypicalChannels, kTypicalRate, &ignored)) << 129 "With a different payload type is fine though."; 130 131 // Ensure both payloads are preserved. 132 ModuleRTPUtility::Payload* retrieved_payload = NULL; 133 EXPECT_TRUE(rtp_payload_registry_->PayloadTypeToPayload(payload_type, 134 retrieved_payload)); 135 EXPECT_EQ(first_payload_on_heap, retrieved_payload); 136 EXPECT_TRUE(rtp_payload_registry_->PayloadTypeToPayload(payload_type - 1, 137 retrieved_payload)); 138 EXPECT_EQ(second_payload_on_heap, retrieved_payload); 139 140 // Ok, update the rate for one of the codecs. If either the incoming rate or 141 // the stored rate is zero it's not really an error to register the same 142 // codec twice, and in that case roughly the following happens. 143 ON_CALL(*mock_payload_strategy_, PayloadIsCompatible(_, _, _, _)) 144 .WillByDefault(Return(true)); 145 EXPECT_CALL(*mock_payload_strategy_, 146 UpdatePayloadRate(first_payload_on_heap, kTypicalRate)); 147 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 148 kTypicalPayloadName, payload_type, kTypicalFrequency, kTypicalChannels, 149 kTypicalRate, &ignored)); 150 } 151 152 TEST_F(RtpPayloadRegistryTest, 153 RemovesCompatibleCodecsOnRegistryIfCodecsMustBeUnique) { 154 ON_CALL(*mock_payload_strategy_, PayloadIsCompatible(_, _, _, _)) 155 .WillByDefault(Return(true)); 156 ON_CALL(*mock_payload_strategy_, CodecsMustBeUnique()) 157 .WillByDefault(Return(true)); 158 159 uint8_t payload_type = 97; 160 161 bool ignored = false; 162 ExpectReturnOfTypicalAudioPayload(payload_type, kTypicalRate); 163 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 164 kTypicalPayloadName, payload_type, kTypicalFrequency, kTypicalChannels, 165 kTypicalRate, &ignored)); 166 ExpectReturnOfTypicalAudioPayload(payload_type - 1, kTypicalRate); 167 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 168 kTypicalPayloadName, payload_type - 1, kTypicalFrequency, 169 kTypicalChannels, kTypicalRate, &ignored)); 170 171 ModuleRTPUtility::Payload* retrieved_payload = NULL; 172 EXPECT_FALSE(rtp_payload_registry_->PayloadTypeToPayload( 173 payload_type, retrieved_payload)) << "The first payload should be " 174 "deregistered because the only thing that differs is payload type."; 175 EXPECT_TRUE(rtp_payload_registry_->PayloadTypeToPayload( 176 payload_type - 1, retrieved_payload)) << 177 "The second payload should still be registered though."; 178 179 // Now ensure non-compatible codecs aren't removed. 180 ON_CALL(*mock_payload_strategy_, PayloadIsCompatible(_, _, _, _)) 181 .WillByDefault(Return(false)); 182 ExpectReturnOfTypicalAudioPayload(payload_type + 1, kTypicalRate); 183 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 184 kTypicalPayloadName, payload_type + 1, kTypicalFrequency, 185 kTypicalChannels, kTypicalRate, &ignored)); 186 187 EXPECT_TRUE(rtp_payload_registry_->PayloadTypeToPayload( 188 payload_type - 1, retrieved_payload)) << 189 "Not compatible; both payloads should be kept."; 190 EXPECT_TRUE(rtp_payload_registry_->PayloadTypeToPayload( 191 payload_type + 1, retrieved_payload)) << 192 "Not compatible; both payloads should be kept."; 193 } 194 195 TEST_F(RtpPayloadRegistryTest, 196 LastReceivedCodecTypesAreResetWhenRegisteringNewPayloadTypes) { 197 rtp_payload_registry_->set_last_received_payload_type(17); 198 EXPECT_EQ(17, rtp_payload_registry_->last_received_payload_type()); 199 200 bool media_type_unchanged = rtp_payload_registry_->ReportMediaPayloadType(18); 201 EXPECT_FALSE(media_type_unchanged); 202 media_type_unchanged = rtp_payload_registry_->ReportMediaPayloadType(18); 203 EXPECT_TRUE(media_type_unchanged); 204 205 bool ignored; 206 ExpectReturnOfTypicalAudioPayload(34, kTypicalRate); 207 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload( 208 kTypicalPayloadName, 34, kTypicalFrequency, kTypicalChannels, 209 kTypicalRate, &ignored)); 210 211 EXPECT_EQ(-1, rtp_payload_registry_->last_received_payload_type()); 212 media_type_unchanged = rtp_payload_registry_->ReportMediaPayloadType(18); 213 EXPECT_FALSE(media_type_unchanged); 214 } 215 216 class ParameterizedRtpPayloadRegistryTest : 217 public RtpPayloadRegistryTest, 218 public ::testing::WithParamInterface<int> { 219 }; 220 221 TEST_P(ParameterizedRtpPayloadRegistryTest, 222 FailsToRegisterKnownPayloadsWeAreNotInterestedIn) { 223 int payload_type = GetParam(); 224 225 bool ignored; 226 EXPECT_EQ(-1, rtp_payload_registry_->RegisterReceivePayload( 227 "whatever", static_cast<uint8_t>(payload_type), 19, 1, 17, 228 &ignored)); 229 } 230 231 INSTANTIATE_TEST_CASE_P(TestKnownBadPayloadTypes, 232 ParameterizedRtpPayloadRegistryTest, 233 testing::Values(64, 72, 73, 74, 75, 76, 77, 78, 79)); 234 235 class RtpPayloadRegistryGenericTest : 236 public RtpPayloadRegistryTest, 237 public ::testing::WithParamInterface<int> { 238 }; 239 240 TEST_P(RtpPayloadRegistryGenericTest, RegisterGenericReceivePayloadType) { 241 int payload_type = GetParam(); 242 243 bool ignored; 244 245 EXPECT_EQ(0, rtp_payload_registry_->RegisterReceivePayload("generic-codec", 246 static_cast<int8_t>(payload_type), 247 19, 1, 17, &ignored)); // dummy values, except for payload_type 248 } 249 250 INSTANTIATE_TEST_CASE_P(TestDynamicRange, RtpPayloadRegistryGenericTest, 251 testing::Range(96, 127+1)); 252 253 } // namespace webrtc 254