/* * 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 #include "absl/strings/ascii.h" #include "api/audio_codecs/audio_format.h" #include "media/base/media_constants.h" namespace cricket { webrtc::SdpAudioFormat AudioCodecToSdpAudioFormat(const AudioCodec& ac) { return webrtc::SdpAudioFormat(ac.name, ac.clockrate, ac.channels, ac.params); } PayloadTypeMapper::PayloadTypeMapper() // RFC 3551 reserves payload type numbers in the range 96-127 exclusively // for dynamic assignment. Once those are used up, it is recommended that // payload types unassigned by the RFC are used for dynamic payload type // mapping, before any static payload ids. At this point, we only support // mapping within the exclusive range. : next_unused_payload_type_(96), max_payload_type_(127), mappings_( {// Static payload type assignments according to RFC 3551. {{kPcmuCodecName, 8000, 1}, 0}, {{"GSM", 8000, 1}, 3}, {{"G723", 8000, 1}, 4}, {{"DVI4", 8000, 1}, 5}, {{"DVI4", 16000, 1}, 6}, {{"LPC", 8000, 1}, 7}, {{kPcmaCodecName, 8000, 1}, 8}, {{kG722CodecName, 8000, 1}, 9}, {{kL16CodecName, 44100, 2}, 10}, {{kL16CodecName, 44100, 1}, 11}, {{"QCELP", 8000, 1}, 12}, {{kCnCodecName, 8000, 1}, 13}, // RFC 4566 is a bit ambiguous on the contents of the "encoding // parameters" field, which, for audio, encodes the number of // channels. It is "optional and may be omitted if the number of // channels is one". Does that necessarily imply that an omitted // encoding parameter means one channel? Since RFC 3551 doesn't // specify a value for this parameter for MPA, I've included both 0 // and 1 here, to increase the chances it will be correctly used if // someone implements an MPEG audio encoder/decoder. {{"MPA", 90000, 0}, 14}, {{"MPA", 90000, 1}, 14}, {{"G728", 8000, 1}, 15}, {{"DVI4", 11025, 1}, 16}, {{"DVI4", 22050, 1}, 17}, {{"G729", 8000, 1}, 18}, // Payload type assignments currently used by WebRTC. // Includes data to reduce collisions (and thus reassignments) {{kIlbcCodecName, 8000, 1}, 102}, {{kIsacCodecName, 16000, 1}, 103}, {{kIsacCodecName, 32000, 1}, 104}, {{kCnCodecName, 16000, 1}, 105}, {{kCnCodecName, 32000, 1}, 106}, {{kOpusCodecName, 48000, 2, {{kCodecParamMinPTime, "10"}, {kCodecParamUseInbandFec, kParamValueTrue}}}, 111}, // RED for opus is assigned in the lower range, starting at the top. // Note that the FMTP refers to the opus payload type. {{kRedCodecName, 48000, 2, {{kCodecParamNotInNameValueFormat, "111/111"}}}, 63}, // TODO(solenberg): Remove the hard coded 16k,32k,48k DTMF once we // assign payload types dynamically for send side as well. {{kDtmfCodecName, 48000, 1}, 110}, {{kDtmfCodecName, 32000, 1}, 112}, {{kDtmfCodecName, 16000, 1}, 113}, {{kDtmfCodecName, 8000, 1}, 126}}) { // TODO(ossu): Try to keep this as change-proof as possible until we're able // to remove the payload type constants from everywhere in the code. for (const auto& mapping : mappings_) { used_payload_types_.insert(mapping.second); } } PayloadTypeMapper::~PayloadTypeMapper() = default; absl::optional PayloadTypeMapper::GetMappingFor( const webrtc::SdpAudioFormat& format) { auto iter = mappings_.find(format); if (iter != mappings_.end()) return iter->second; for (; next_unused_payload_type_ <= max_payload_type_; ++next_unused_payload_type_) { int payload_type = next_unused_payload_type_; if (used_payload_types_.find(payload_type) == used_payload_types_.end()) { used_payload_types_.insert(payload_type); mappings_[format] = payload_type; ++next_unused_payload_type_; return payload_type; } } return absl::nullopt; } absl::optional PayloadTypeMapper::FindMappingFor( const webrtc::SdpAudioFormat& format) const { auto iter = mappings_.find(format); if (iter != mappings_.end()) return iter->second; return absl::nullopt; } absl::optional PayloadTypeMapper::ToAudioCodec( const webrtc::SdpAudioFormat& format) { // TODO(ossu): We can safely set bitrate to zero here, since that field is // not presented in the SDP. It is used to ferry around some target bitrate // values for certain codecs (ISAC and Opus) and in ways it really // shouldn't. It should be removed once we no longer use CodecInsts in the // ACM or NetEq. auto opt_payload_type = GetMappingFor(format); if (opt_payload_type) { AudioCodec codec(*opt_payload_type, format.name, format.clockrate_hz, 0, format.num_channels); codec.params = format.parameters; return std::move(codec); } return absl::nullopt; } bool PayloadTypeMapper::SdpAudioFormatOrdering::operator()( const webrtc::SdpAudioFormat& a, const webrtc::SdpAudioFormat& b) const { if (a.clockrate_hz == b.clockrate_hz) { if (a.num_channels == b.num_channels) { int name_cmp = absl::AsciiStrToLower(a.name).compare(absl::AsciiStrToLower(b.name)); if (name_cmp == 0) return a.parameters < b.parameters; return name_cmp < 0; } return a.num_channels < b.num_channels; } return a.clockrate_hz < b.clockrate_hz; } } // namespace cricket