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 "api/audio_codecs/audio_format.h"
16 #include "common_types.h"  // NOLINT(build/include)
17 #include "media/base/mediaconstants.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           {{kGoogleSctpDataCodecName, 0, 0}, kGoogleSctpDataCodecPlType},
71           {{kOpusCodecName,   48000, 2,
72               {{"minptime", "10"}, {"useinbandfec", "1"}}}, 111},
73           // TODO(solenberg): Remove the hard coded 16k,32k,48k DTMF once we
74           // assign payload types dynamically for send side as well.
75           {{kDtmfCodecName,   48000, 1}, 110},
76           {{kDtmfCodecName,   32000, 1}, 112},
77           {{kDtmfCodecName,   16000, 1}, 113},
78           {{kDtmfCodecName,    8000, 1}, 126}}) {
79   // TODO(ossu): Try to keep this as change-proof as possible until we're able
80   // to remove the payload type constants from everywhere in the code.
81   for (const auto& mapping : mappings_) {
82     used_payload_types_.insert(mapping.second);
83   }
84 }
85 
86 PayloadTypeMapper::~PayloadTypeMapper() = default;
87 
GetMappingFor(const webrtc::SdpAudioFormat & format)88 rtc::Optional<int> PayloadTypeMapper::GetMappingFor(
89     const webrtc::SdpAudioFormat& format) {
90   auto iter = mappings_.find(format);
91   if (iter != mappings_.end())
92     return iter->second;
93 
94   for (; next_unused_payload_type_ <= max_payload_type_;
95        ++next_unused_payload_type_) {
96     int payload_type = next_unused_payload_type_;
97     if (used_payload_types_.find(payload_type) == used_payload_types_.end()) {
98       used_payload_types_.insert(payload_type);
99       mappings_[format] = payload_type;
100       ++next_unused_payload_type_;
101       return payload_type;
102     }
103   }
104 
105   return rtc::nullopt;
106 }
107 
FindMappingFor(const webrtc::SdpAudioFormat & format) const108 rtc::Optional<int> PayloadTypeMapper::FindMappingFor(
109     const webrtc::SdpAudioFormat& format) const {
110   auto iter = mappings_.find(format);
111   if (iter != mappings_.end())
112     return iter->second;
113 
114   return rtc::nullopt;
115 }
116 
ToAudioCodec(const webrtc::SdpAudioFormat & format)117 rtc::Optional<AudioCodec> PayloadTypeMapper::ToAudioCodec(
118     const webrtc::SdpAudioFormat& format) {
119   // TODO(ossu): We can safely set bitrate to zero here, since that field is
120   // not presented in the SDP. It is used to ferry around some target bitrate
121   // values for certain codecs (ISAC and Opus) and in ways it really
122   // shouldn't. It should be removed once we no longer use CodecInsts in the
123   // ACM or NetEq.
124   auto opt_payload_type = GetMappingFor(format);
125   if (opt_payload_type) {
126     AudioCodec codec(*opt_payload_type, format.name, format.clockrate_hz, 0,
127                      format.num_channels);
128     codec.params = format.parameters;
129     return std::move(codec);
130   }
131 
132   return rtc::nullopt;
133 }
134 
operator ()(const webrtc::SdpAudioFormat & a,const webrtc::SdpAudioFormat & b) const135 bool PayloadTypeMapper::SdpAudioFormatOrdering::operator()(
136     const webrtc::SdpAudioFormat& a,
137     const webrtc::SdpAudioFormat& b) const {
138   if (a.clockrate_hz == b.clockrate_hz) {
139     if (a.num_channels == b.num_channels) {
140       int name_cmp = STR_CASE_CMP(a.name.c_str(), b.name.c_str());
141       if (name_cmp == 0)
142         return a.parameters < b.parameters;
143       return name_cmp < 0;
144     }
145     return a.num_channels < b.num_channels;
146   }
147   return a.clockrate_hz < b.clockrate_hz;
148 }
149 
150 }  // namespace cricket
151