text: /*
   *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
   *
   *  Use of this source code is governed by a BSD-style license
   *  that can be found in the LICENSE file in the root of the source
   *  tree. An additional intellectual property rights grant can be found
   *  in the file PATENTS.  All contributing project authors may
   *  be found in the AUTHORS file in the root of the source tree.
   */
  
  #include "media/engine/payload_type_mapper.h"
  
  #include <set>
  #include <string>
  
  #include "absl/strings/string_view.h"
  #include "media/base/media_constants.h"
  #include "test/gtest.h"
  
  namespace cricket {
  
  class PayloadTypeMapperTest : public ::testing::Test {
   protected:
    PayloadTypeMapper mapper_;
  };
  
  TEST_F(PayloadTypeMapperTest, StaticPayloadTypes) {
    EXPECT_EQ(0, mapper_.FindMappingFor({"pcmu", 8000, 1}));
    EXPECT_EQ(3, mapper_.FindMappingFor({"gsm", 8000, 1}));
    EXPECT_EQ(4, mapper_.FindMappingFor({"g723", 8000, 1}));
    EXPECT_EQ(5, mapper_.FindMappingFor({"dvi4", 8000, 1}));
    EXPECT_EQ(6, mapper_.FindMappingFor({"dvi4", 16000, 1}));
    EXPECT_EQ(7, mapper_.FindMappingFor({"lpc", 8000, 1}));
    EXPECT_EQ(8, mapper_.FindMappingFor({"pcma", 8000, 1}));
    EXPECT_EQ(9, mapper_.FindMappingFor({"g722", 8000, 1}));
    EXPECT_EQ(10, mapper_.FindMappingFor({"l16", 44100, 2}));
    EXPECT_EQ(11, mapper_.FindMappingFor({"l16", 44100, 1}));
    EXPECT_EQ(12, mapper_.FindMappingFor({"qcelp", 8000, 1}));
    EXPECT_EQ(13, mapper_.FindMappingFor({"cn", 8000, 1}));
    EXPECT_EQ(14, mapper_.FindMappingFor({"mpa", 90000, 0}));
    EXPECT_EQ(14, mapper_.FindMappingFor({"mpa", 90000, 1}));
    EXPECT_EQ(15, mapper_.FindMappingFor({"g728", 8000, 1}));
    EXPECT_EQ(16, mapper_.FindMappingFor({"dvi4", 11025, 1}));
    EXPECT_EQ(17, mapper_.FindMappingFor({"dvi4", 22050, 1}));
    EXPECT_EQ(18, mapper_.FindMappingFor({"g729", 8000, 1}));
  }
  
  TEST_F(PayloadTypeMapperTest, WebRTCPayloadTypes) {
    // Tests that the payload mapper knows about the audio formats we've
    // been using in WebRTC, with their hard coded values.
    EXPECT_EQ(102, mapper_.FindMappingFor({kIlbcCodecName, 8000, 1}));
    EXPECT_EQ(103, mapper_.FindMappingFor({kIsacCodecName, 16000, 1}));
    EXPECT_EQ(104, mapper_.FindMappingFor({kIsacCodecName, 32000, 1}));
    EXPECT_EQ(105, mapper_.FindMappingFor({kCnCodecName, 16000, 1}));
    EXPECT_EQ(106, mapper_.FindMappingFor({kCnCodecName, 32000, 1}));
    EXPECT_EQ(111, mapper_.FindMappingFor(
                       {kOpusCodecName,
                        48000,
                        2,
                        {{"minptime", "10"}, {"useinbandfec", "1"}}}));
    EXPECT_EQ(
        63, mapper_.FindMappingFor({kRedCodecName, 48000, 2, {{"", "111/111"}}}));
    // TODO(solenberg): Remove 16k, 32k, 48k DTMF checks once these payload types
    // are dynamically assigned.
    EXPECT_EQ(110, mapper_.FindMappingFor({kDtmfCodecName, 48000, 1}));
    EXPECT_EQ(112, mapper_.FindMappingFor({kDtmfCodecName, 32000, 1}));
    EXPECT_EQ(113, mapper_.FindMappingFor({kDtmfCodecName, 16000, 1}));
    EXPECT_EQ(126, mapper_.FindMappingFor({kDtmfCodecName, 8000, 1}));
  }
  
  TEST_F(PayloadTypeMapperTest, ValidDynamicPayloadTypes) {
    // RFC 3551 says:
    // "This profile reserves payload type numbers in the range 96-127
    // exclusively for dynamic assignment.  Applications SHOULD first use
    // values in this range for dynamic payload types.  Those applications
    // which need to define more than 32 dynamic payload types MAY bind
    // codes below 96, in which case it is RECOMMENDED that unassigned
    // payload type numbers be used first.  However, the statically assigned
    // payload types are default bindings and MAY be dynamically bound to
    // new encodings if needed."
  
    // Tests that the payload mapper uses values in the dynamic payload type range
    // (96 - 127) before any others and that the values returned are all valid.
    bool has_been_below_96 = false;
    std::set<int> used_payload_types;
    for (int i = 0; i != 256; ++i) {
      std::string format_name = "unknown_format_" + std::to_string(i);
      webrtc::SdpAudioFormat format(format_name.c_str(), i * 100, (i % 2) + 1);
      auto opt_payload_type = mapper_.GetMappingFor(format);
      bool mapper_is_full = false;
  
      // There's a limited number of slots for payload types. We're fine with not
      // being able to map them all.
      if (opt_payload_type) {
        int payload_type = *opt_payload_type;
        EXPECT_FALSE(mapper_is_full) << "Mapping should not fail sporadically";
        EXPECT_EQ(used_payload_types.find(payload_type), used_payload_types.end())
            << "Payload types must not be reused";
        used_payload_types.insert(payload_type);
        EXPECT_GE(payload_type, 0) << "Negative payload types are invalid";
        EXPECT_LE(payload_type, 127) << "Payload types above 127 are invalid";
        EXPECT_FALSE(payload_type >= 96 && has_been_below_96);
        if (payload_type < 96)
          has_been_below_96 = true;
  
        EXPECT_EQ(payload_type, mapper_.FindMappingFor(format))
            << "Mapping must be permanent after successful call to "
               "GetMappingFor";
        EXPECT_EQ(payload_type, mapper_.GetMappingFor(format))
            << "Subsequent calls to GetMappingFor must return the same value";
      } else {
        mapper_is_full = true;
      }
    }
  
    // Also, we must've been able to map at least one dynamic payload type.
    EXPECT_FALSE(used_payload_types.empty())
        << "Mapper must support at least one user-defined payload type";
  }
  
  TEST_F(PayloadTypeMapperTest, ToAudioCodec) {
    webrtc::SdpAudioFormat format("unknown_format", 4711, 17);
    auto opt_payload_type = mapper_.GetMappingFor(format);
    EXPECT_TRUE(opt_payload_type);
    auto opt_audio_codec = mapper_.ToAudioCodec(format);
    EXPECT_TRUE(opt_audio_codec);
  
    if (opt_payload_type && opt_audio_codec) {
      int payload_type = *opt_payload_type;
      const AudioCodec& codec = *opt_audio_codec;
  
      EXPECT_EQ(codec.id, payload_type);
      EXPECT_EQ(codec.name, format.name);
      EXPECT_EQ(codec.clockrate, format.clockrate_hz);
      EXPECT_EQ(codec.channels, format.num_channels);
      EXPECT_EQ(codec.params, format.parameters);
    }
  }
  
  }  // namespace cricket
  