1 /*
2 * Copyright (c) 2016 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 "media/engine/payload_type_mapper.h"
12
13 #include <utility>
14
15 #include "absl/strings/ascii.h"
16 #include "api/audio_codecs/audio_format.h"
17 #include "media/base/media_constants.h"
18
19 namespace cricket {
20
AudioCodecToSdpAudioFormat(const AudioCodec & ac)21 webrtc::SdpAudioFormat AudioCodecToSdpAudioFormat(const AudioCodec& ac) {
22 return webrtc::SdpAudioFormat(ac.name, ac.clockrate, ac.channels, ac.params);
23 }
24
PayloadTypeMapper()25 PayloadTypeMapper::PayloadTypeMapper()
26 // RFC 3551 reserves payload type numbers in the range 96-127 exclusively
27 // for dynamic assignment. Once those are used up, it is recommended that
28 // payload types unassigned by the RFC are used for dynamic payload type
29 // mapping, before any static payload ids. At this point, we only support
30 // mapping within the exclusive range.
31 : next_unused_payload_type_(96),
32 max_payload_type_(127),
33 mappings_(
34 {// Static payload type assignments according to RFC 3551.
35 {{"PCMU", 8000, 1}, 0},
36 {{"GSM", 8000, 1}, 3},
37 {{"G723", 8000, 1}, 4},
38 {{"DVI4", 8000, 1}, 5},
39 {{"DVI4", 16000, 1}, 6},
40 {{"LPC", 8000, 1}, 7},
41 {{"PCMA", 8000, 1}, 8},
42 {{"G722", 8000, 1}, 9},
43 {{"L16", 44100, 2}, 10},
44 {{"L16", 44100, 1}, 11},
45 {{"QCELP", 8000, 1}, 12},
46 {{"CN", 8000, 1}, 13},
47 // RFC 4566 is a bit ambiguous on the contents of the "encoding
48 // parameters" field, which, for audio, encodes the number of
49 // channels. It is "optional and may be omitted if the number of
50 // channels is one". Does that necessarily imply that an omitted
51 // encoding parameter means one channel? Since RFC 3551 doesn't
52 // specify a value for this parameter for MPA, I've included both 0
53 // and 1 here, to increase the chances it will be correctly used if
54 // someone implements an MPEG audio encoder/decoder.
55 {{"MPA", 90000, 0}, 14},
56 {{"MPA", 90000, 1}, 14},
57 {{"G728", 8000, 1}, 15},
58 {{"DVI4", 11025, 1}, 16},
59 {{"DVI4", 22050, 1}, 17},
60 {{"G729", 8000, 1}, 18},
61
62 // Payload type assignments currently used by WebRTC.
63 // Includes data to reduce collisions (and thus reassignments)
64 {{kGoogleRtpDataCodecName, 0, 0}, kGoogleRtpDataCodecPlType},
65 {{kIlbcCodecName, 8000, 1}, 102},
66 {{kIsacCodecName, 16000, 1}, 103},
67 {{kIsacCodecName, 32000, 1}, 104},
68 {{kCnCodecName, 16000, 1}, 105},
69 {{kCnCodecName, 32000, 1}, 106},
70 {{kOpusCodecName,
71 48000,
72 2,
73 {{"minptime", "10"}, {"useinbandfec", "1"}}},
74 111},
75 // TODO(solenberg): Remove the hard coded 16k,32k,48k DTMF once we
76 // assign payload types dynamically for send side as well.
77 {{kDtmfCodecName, 48000, 1}, 110},
78 {{kDtmfCodecName, 32000, 1}, 112},
79 {{kDtmfCodecName, 16000, 1}, 113},
80 {{kDtmfCodecName, 8000, 1}, 126}}) {
81 // TODO(ossu): Try to keep this as change-proof as possible until we're able
82 // to remove the payload type constants from everywhere in the code.
83 for (const auto& mapping : mappings_) {
84 used_payload_types_.insert(mapping.second);
85 }
86 }
87
88 PayloadTypeMapper::~PayloadTypeMapper() = default;
89
GetMappingFor(const webrtc::SdpAudioFormat & format)90 absl::optional<int> PayloadTypeMapper::GetMappingFor(
91 const webrtc::SdpAudioFormat& format) {
92 auto iter = mappings_.find(format);
93 if (iter != mappings_.end())
94 return iter->second;
95
96 for (; next_unused_payload_type_ <= max_payload_type_;
97 ++next_unused_payload_type_) {
98 int payload_type = next_unused_payload_type_;
99 if (used_payload_types_.find(payload_type) == used_payload_types_.end()) {
100 used_payload_types_.insert(payload_type);
101 mappings_[format] = payload_type;
102 ++next_unused_payload_type_;
103 return payload_type;
104 }
105 }
106
107 return absl::nullopt;
108 }
109
FindMappingFor(const webrtc::SdpAudioFormat & format) const110 absl::optional<int> PayloadTypeMapper::FindMappingFor(
111 const webrtc::SdpAudioFormat& format) const {
112 auto iter = mappings_.find(format);
113 if (iter != mappings_.end())
114 return iter->second;
115
116 return absl::nullopt;
117 }
118
ToAudioCodec(const webrtc::SdpAudioFormat & format)119 absl::optional<AudioCodec> PayloadTypeMapper::ToAudioCodec(
120 const webrtc::SdpAudioFormat& format) {
121 // TODO(ossu): We can safely set bitrate to zero here, since that field is
122 // not presented in the SDP. It is used to ferry around some target bitrate
123 // values for certain codecs (ISAC and Opus) and in ways it really
124 // shouldn't. It should be removed once we no longer use CodecInsts in the
125 // ACM or NetEq.
126 auto opt_payload_type = GetMappingFor(format);
127 if (opt_payload_type) {
128 AudioCodec codec(*opt_payload_type, format.name, format.clockrate_hz, 0,
129 format.num_channels);
130 codec.params = format.parameters;
131 return std::move(codec);
132 }
133
134 return absl::nullopt;
135 }
136
operator ()(const webrtc::SdpAudioFormat & a,const webrtc::SdpAudioFormat & b) const137 bool PayloadTypeMapper::SdpAudioFormatOrdering::operator()(
138 const webrtc::SdpAudioFormat& a,
139 const webrtc::SdpAudioFormat& b) const {
140 if (a.clockrate_hz == b.clockrate_hz) {
141 if (a.num_channels == b.num_channels) {
142 int name_cmp =
143 absl::AsciiStrToLower(a.name).compare(absl::AsciiStrToLower(b.name));
144 if (name_cmp == 0)
145 return a.parameters < b.parameters;
146 return name_cmp < 0;
147 }
148 return a.num_channels < b.num_channels;
149 }
150 return a.clockrate_hz < b.clockrate_hz;
151 }
152
153 } // namespace cricket
154