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