Line data Source code
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 <algorithm>
14 :
15 : #include "webrtc/base/checks.h"
16 : #include "webrtc/base/logging.h"
17 : #include "webrtc/base/stringutils.h"
18 : #include "webrtc/common_types.h"
19 : #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
20 :
21 : namespace webrtc {
22 :
23 : namespace {
24 :
25 0 : bool PayloadIsCompatible(const RtpUtility::Payload& payload,
26 : const CodecInst& audio_codec) {
27 0 : if (!payload.audio)
28 0 : return false;
29 0 : if (_stricmp(payload.name, audio_codec.plname) != 0)
30 0 : return false;
31 0 : const AudioPayload& audio_payload = payload.typeSpecific.Audio;
32 0 : return audio_payload.frequency == static_cast<uint32_t>(audio_codec.plfreq) &&
33 0 : audio_payload.channels == audio_codec.channels;
34 : }
35 :
36 0 : bool PayloadIsCompatible(const RtpUtility::Payload& payload,
37 : const VideoCodec& video_codec) {
38 0 : if (payload.audio || _stricmp(payload.name, video_codec.plName) != 0)
39 0 : return false;
40 : // For H264, profiles must match as well.
41 0 : if (video_codec.codecType == kVideoCodecH264) {
42 0 : return video_codec.H264().profile ==
43 0 : payload.typeSpecific.Video.h264_profile;
44 : }
45 0 : return true;
46 : }
47 :
48 0 : RtpUtility::Payload CreatePayloadType(const CodecInst& audio_codec) {
49 : RtpUtility::Payload payload;
50 0 : payload.name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
51 0 : strncpy(payload.name, audio_codec.plname, RTP_PAYLOAD_NAME_SIZE - 1);
52 0 : RTC_DCHECK_GE(audio_codec.plfreq, 1000);
53 0 : payload.typeSpecific.Audio.frequency = audio_codec.plfreq;
54 0 : payload.typeSpecific.Audio.channels = audio_codec.channels;
55 0 : payload.typeSpecific.Audio.rate = 0;
56 0 : payload.audio = true;
57 0 : return payload;
58 : }
59 :
60 0 : RtpVideoCodecTypes ConvertToRtpVideoCodecType(VideoCodecType type) {
61 0 : switch (type) {
62 : case kVideoCodecVP8:
63 0 : return kRtpVideoVp8;
64 : case kVideoCodecVP9:
65 0 : return kRtpVideoVp9;
66 : case kVideoCodecH264:
67 0 : return kRtpVideoH264;
68 : case kVideoCodecRED:
69 : case kVideoCodecULPFEC:
70 0 : return kRtpVideoNone;
71 : default:
72 0 : return kRtpVideoGeneric;
73 : }
74 : }
75 :
76 0 : RtpUtility::Payload CreatePayloadType(const VideoCodec& video_codec) {
77 : RtpUtility::Payload payload;
78 0 : payload.name[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
79 0 : strncpy(payload.name, video_codec.plName, RTP_PAYLOAD_NAME_SIZE - 1);
80 0 : payload.typeSpecific.Video.videoCodecType =
81 0 : ConvertToRtpVideoCodecType(video_codec.codecType);
82 0 : if (video_codec.codecType == kVideoCodecH264)
83 0 : payload.typeSpecific.Video.h264_profile = video_codec.H264().profile;
84 0 : payload.audio = false;
85 0 : return payload;
86 : }
87 :
88 0 : bool IsPayloadTypeValid(int8_t payload_type) {
89 0 : assert(payload_type >= 0);
90 :
91 : // Sanity check.
92 0 : switch (payload_type) {
93 : // Reserved payload types to avoid RTCP conflicts when marker bit is set.
94 : case 64: // 192 Full INTRA-frame request.
95 : case 72: // 200 Sender report.
96 : case 73: // 201 Receiver report.
97 : case 74: // 202 Source description.
98 : case 75: // 203 Goodbye.
99 : case 76: // 204 Application-defined.
100 : case 77: // 205 Transport layer FB message.
101 : case 78: // 206 Payload-specific FB message.
102 : case 79: // 207 Extended report.
103 0 : LOG(LS_ERROR) << "Can't register invalid receiver payload type: "
104 0 : << payload_type;
105 0 : return false;
106 : default:
107 0 : return true;
108 : }
109 : }
110 :
111 : } // namespace
112 :
113 0 : RTPPayloadRegistry::RTPPayloadRegistry()
114 : : incoming_payload_type_(-1),
115 : last_received_payload_type_(-1),
116 : last_received_media_payload_type_(-1),
117 : rtx_(false),
118 0 : ssrc_rtx_(0) {}
119 :
120 : RTPPayloadRegistry::~RTPPayloadRegistry() = default;
121 :
122 0 : int32_t RTPPayloadRegistry::RegisterReceivePayload(const CodecInst& audio_codec,
123 : bool* created_new_payload) {
124 0 : *created_new_payload = false;
125 0 : if (!IsPayloadTypeValid(audio_codec.pltype))
126 0 : return -1;
127 :
128 0 : rtc::CritScope cs(&crit_sect_);
129 :
130 0 : auto it = payload_type_map_.find(audio_codec.pltype);
131 0 : if (it != payload_type_map_.end()) {
132 : // We already use this payload type. Check if it's the same as we already
133 : // have. If same, ignore sending an error.
134 0 : if (PayloadIsCompatible(it->second, audio_codec)) {
135 0 : it->second.typeSpecific.Audio.rate = 0;
136 0 : return 0;
137 : }
138 0 : LOG(LS_ERROR) << "Payload type already registered: " << audio_codec.pltype;
139 0 : return -1;
140 : }
141 :
142 : // Audio codecs must be unique.
143 0 : DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(audio_codec);
144 :
145 0 : payload_type_map_[audio_codec.pltype] = CreatePayloadType(audio_codec);
146 0 : *created_new_payload = true;
147 :
148 : // Successful set of payload type, clear the value of last received payload
149 : // type since it might mean something else.
150 0 : last_received_payload_type_ = -1;
151 0 : last_received_media_payload_type_ = -1;
152 0 : return 0;
153 : }
154 :
155 0 : int32_t RTPPayloadRegistry::RegisterReceivePayload(
156 : const VideoCodec& video_codec) {
157 0 : if (!IsPayloadTypeValid(video_codec.plType))
158 0 : return -1;
159 :
160 0 : rtc::CritScope cs(&crit_sect_);
161 :
162 0 : auto it = payload_type_map_.find(video_codec.plType);
163 0 : if (it != payload_type_map_.end()) {
164 : // We already use this payload type. Check if it's the same as we already
165 : // have. If same, ignore sending an error.
166 0 : if (PayloadIsCompatible(it->second, video_codec))
167 0 : return 0;
168 0 : LOG(LS_ERROR) << "Payload type already registered: "
169 0 : << static_cast<int>(video_codec.plType);
170 0 : return -1;
171 : }
172 :
173 0 : payload_type_map_[video_codec.plType] = CreatePayloadType(video_codec);
174 :
175 : // Successful set of payload type, clear the value of last received payload
176 : // type since it might mean something else.
177 0 : last_received_payload_type_ = -1;
178 0 : last_received_media_payload_type_ = -1;
179 0 : return 0;
180 : }
181 :
182 0 : int32_t RTPPayloadRegistry::DeRegisterReceivePayload(
183 : const int8_t payload_type) {
184 0 : rtc::CritScope cs(&crit_sect_);
185 0 : payload_type_map_.erase(payload_type);
186 0 : return 0;
187 : }
188 :
189 : // There can't be several codecs with the same rate, frequency and channels
190 : // for audio codecs, but there can for video.
191 : // Always called from within a critical section.
192 0 : void RTPPayloadRegistry::DeregisterAudioCodecOrRedTypeRegardlessOfPayloadType(
193 : const CodecInst& audio_codec) {
194 0 : for (auto iterator = payload_type_map_.begin();
195 0 : iterator != payload_type_map_.end(); ++iterator) {
196 0 : if (PayloadIsCompatible(iterator->second, audio_codec)) {
197 : // Remove old setting.
198 0 : payload_type_map_.erase(iterator);
199 0 : break;
200 : }
201 : }
202 0 : }
203 :
204 0 : int32_t RTPPayloadRegistry::ReceivePayloadType(const CodecInst& audio_codec,
205 : int8_t* payload_type) const {
206 0 : assert(payload_type);
207 0 : rtc::CritScope cs(&crit_sect_);
208 :
209 0 : for (const auto& it : payload_type_map_) {
210 0 : if (PayloadIsCompatible(it.second, audio_codec)) {
211 0 : *payload_type = it.first;
212 0 : return 0;
213 : }
214 : }
215 0 : return -1;
216 : }
217 :
218 0 : int32_t RTPPayloadRegistry::ReceivePayloadType(const VideoCodec& video_codec,
219 : int8_t* payload_type) const {
220 0 : assert(payload_type);
221 0 : rtc::CritScope cs(&crit_sect_);
222 :
223 0 : for (const auto& it : payload_type_map_) {
224 0 : if (PayloadIsCompatible(it.second, video_codec)) {
225 0 : *payload_type = it.first;
226 0 : return 0;
227 : }
228 : }
229 0 : return -1;
230 : }
231 :
232 0 : bool RTPPayloadRegistry::RtxEnabled() const {
233 0 : rtc::CritScope cs(&crit_sect_);
234 0 : return rtx_;
235 : }
236 :
237 0 : bool RTPPayloadRegistry::IsRtx(const RTPHeader& header) const {
238 0 : rtc::CritScope cs(&crit_sect_);
239 0 : return IsRtxInternal(header);
240 : }
241 :
242 0 : bool RTPPayloadRegistry::IsRtxInternal(const RTPHeader& header) const {
243 0 : return rtx_ && ssrc_rtx_ == header.ssrc;
244 : }
245 :
246 0 : bool RTPPayloadRegistry::RestoreOriginalPacket(uint8_t* restored_packet,
247 : const uint8_t* packet,
248 : size_t* packet_length,
249 : uint32_t original_ssrc,
250 : const RTPHeader& header) {
251 0 : if (kRtxHeaderSize + header.headerLength + header.paddingLength >
252 0 : *packet_length) {
253 0 : return false;
254 : }
255 0 : const uint8_t* rtx_header = packet + header.headerLength;
256 0 : uint16_t original_sequence_number = (rtx_header[0] << 8) + rtx_header[1];
257 :
258 : // Copy the packet into the restored packet, except for the RTX header.
259 0 : memcpy(restored_packet, packet, header.headerLength);
260 0 : memcpy(restored_packet + header.headerLength,
261 0 : packet + header.headerLength + kRtxHeaderSize,
262 0 : *packet_length - header.headerLength - kRtxHeaderSize);
263 0 : *packet_length -= kRtxHeaderSize;
264 :
265 : // Replace the SSRC and the sequence number with the originals.
266 0 : ByteWriter<uint16_t>::WriteBigEndian(restored_packet + 2,
267 0 : original_sequence_number);
268 0 : ByteWriter<uint32_t>::WriteBigEndian(restored_packet + 8, original_ssrc);
269 :
270 0 : rtc::CritScope cs(&crit_sect_);
271 0 : if (!rtx_)
272 0 : return true;
273 :
274 0 : auto apt_mapping = rtx_payload_type_map_.find(header.payloadType);
275 0 : if (apt_mapping == rtx_payload_type_map_.end()) {
276 : // No associated payload type found. Warn, unless we have already done so.
277 0 : if (payload_types_with_suppressed_warnings_.find(header.payloadType) ==
278 0 : payload_types_with_suppressed_warnings_.end()) {
279 0 : LOG(LS_WARNING)
280 : << "No RTX associated payload type mapping was available; "
281 : "not able to restore original packet from RTX packet "
282 0 : "with payload type: "
283 0 : << static_cast<int>(header.payloadType) << ". "
284 0 : << "Suppressing further warnings for this payload type.";
285 0 : payload_types_with_suppressed_warnings_.insert(header.payloadType);
286 : }
287 0 : return false;
288 : }
289 0 : restored_packet[1] = static_cast<uint8_t>(apt_mapping->second);
290 0 : if (header.markerBit) {
291 0 : restored_packet[1] |= kRtpMarkerBitMask; // Marker bit is set.
292 : }
293 0 : return true;
294 : }
295 :
296 0 : void RTPPayloadRegistry::SetRtxSsrc(uint32_t ssrc) {
297 0 : rtc::CritScope cs(&crit_sect_);
298 0 : ssrc_rtx_ = ssrc;
299 0 : rtx_ = true;
300 0 : }
301 :
302 0 : bool RTPPayloadRegistry::GetRtxSsrc(uint32_t* ssrc) const {
303 0 : rtc::CritScope cs(&crit_sect_);
304 0 : *ssrc = ssrc_rtx_;
305 0 : return rtx_;
306 : }
307 :
308 0 : void RTPPayloadRegistry::SetRtxPayloadType(int payload_type,
309 : int associated_payload_type) {
310 0 : rtc::CritScope cs(&crit_sect_);
311 0 : if (payload_type < 0) {
312 0 : LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type;
313 0 : return;
314 : }
315 :
316 0 : rtx_payload_type_map_[payload_type] = associated_payload_type;
317 0 : rtx_ = true;
318 : }
319 :
320 0 : bool RTPPayloadRegistry::IsRed(const RTPHeader& header) const {
321 0 : rtc::CritScope cs(&crit_sect_);
322 0 : auto it = payload_type_map_.find(header.payloadType);
323 0 : return it != payload_type_map_.end() && _stricmp(it->second.name, "red") == 0;
324 : }
325 :
326 0 : bool RTPPayloadRegistry::IsEncapsulated(const RTPHeader& header) const {
327 0 : return IsRed(header) || IsRtx(header);
328 : }
329 :
330 0 : bool RTPPayloadRegistry::GetPayloadSpecifics(uint8_t payload_type,
331 : PayloadUnion* payload) const {
332 0 : rtc::CritScope cs(&crit_sect_);
333 0 : auto it = payload_type_map_.find(payload_type);
334 :
335 : // Check that this is a registered payload type.
336 0 : if (it == payload_type_map_.end()) {
337 0 : return false;
338 : }
339 0 : *payload = it->second.typeSpecific;
340 0 : return true;
341 : }
342 :
343 0 : int RTPPayloadRegistry::GetPayloadTypeFrequency(
344 : uint8_t payload_type) const {
345 0 : const RtpUtility::Payload* payload = PayloadTypeToPayload(payload_type);
346 0 : if (!payload) {
347 0 : return -1;
348 : }
349 0 : rtc::CritScope cs(&crit_sect_);
350 0 : return payload->audio ? payload->typeSpecific.Audio.frequency
351 0 : : kVideoPayloadTypeFrequency;
352 : }
353 :
354 0 : const RtpUtility::Payload* RTPPayloadRegistry::PayloadTypeToPayload(
355 : uint8_t payload_type) const {
356 0 : rtc::CritScope cs(&crit_sect_);
357 :
358 0 : auto it = payload_type_map_.find(payload_type);
359 :
360 : // Check that this is a registered payload type.
361 0 : if (it == payload_type_map_.end()) {
362 0 : return nullptr;
363 : }
364 :
365 0 : return &it->second;
366 : }
367 :
368 0 : void RTPPayloadRegistry::SetIncomingPayloadType(const RTPHeader& header) {
369 0 : rtc::CritScope cs(&crit_sect_);
370 0 : if (!IsRtxInternal(header))
371 0 : incoming_payload_type_ = header.payloadType;
372 0 : }
373 :
374 0 : bool RTPPayloadRegistry::ReportMediaPayloadType(uint8_t media_payload_type) {
375 0 : rtc::CritScope cs(&crit_sect_);
376 0 : if (last_received_media_payload_type_ == media_payload_type) {
377 : // Media type unchanged.
378 0 : return true;
379 : }
380 0 : last_received_media_payload_type_ = media_payload_type;
381 0 : return false;
382 : }
383 :
384 : // Returns -1 if a payload with name |payload_name| is not registered.
385 0 : int8_t RTPPayloadRegistry::GetPayloadTypeWithName(
386 : const char* payload_name) const {
387 0 : rtc::CritScope cs(&crit_sect_);
388 0 : for (const auto& it : payload_type_map_) {
389 0 : if (_stricmp(it.second.name, payload_name) == 0)
390 0 : return it.first;
391 : }
392 0 : return -1;
393 : }
394 :
395 : } // namespace webrtc
|