Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #ifndef _JSEPCODECDESCRIPTION_H_
6 : #define _JSEPCODECDESCRIPTION_H_
7 :
8 : #include <string>
9 : #include "signaling/src/sdp/SdpMediaSection.h"
10 : #include "signaling/src/sdp/SdpHelper.h"
11 : #include "nsCRT.h"
12 : #include "mozilla/net/DataChannelProtocol.h"
13 :
14 : namespace mozilla {
15 :
16 : #define JSEP_CODEC_CLONE(T) \
17 : virtual JsepCodecDescription* Clone() const override \
18 : { \
19 : return new T(*this); \
20 : }
21 :
22 : // A single entry in our list of known codecs.
23 0 : class JsepCodecDescription {
24 : public:
25 0 : JsepCodecDescription(mozilla::SdpMediaSection::MediaType type,
26 : const std::string& defaultPt,
27 : const std::string& name,
28 : uint32_t clock,
29 : uint32_t channels,
30 : bool enabled)
31 0 : : mType(type),
32 : mDefaultPt(defaultPt),
33 : mName(name),
34 : mClock(clock),
35 : mChannels(channels),
36 : mEnabled(enabled),
37 : mStronglyPreferred(false),
38 0 : mDirection(sdp::kSend)
39 : {
40 0 : }
41 0 : virtual ~JsepCodecDescription() {}
42 :
43 : virtual JsepCodecDescription* Clone() const = 0;
44 :
45 : bool
46 0 : GetPtAsInt(uint16_t* ptOutparam) const
47 : {
48 0 : return SdpHelper::GetPtAsInt(mDefaultPt, ptOutparam);
49 : }
50 :
51 : virtual bool
52 0 : Matches(const std::string& fmt, const SdpMediaSection& remoteMsection) const
53 : {
54 : // note: fmt here is remote fmt (to go with remoteMsection)
55 0 : if (mType != remoteMsection.GetMediaType()) {
56 0 : return false;
57 : }
58 :
59 0 : const SdpRtpmapAttributeList::Rtpmap* entry(remoteMsection.FindRtpmap(fmt));
60 :
61 0 : if (entry) {
62 0 : if (!nsCRT::strcasecmp(mName.c_str(), entry->name.c_str())
63 0 : && (mClock == entry->clock)
64 0 : && (mChannels == entry->channels)) {
65 0 : return ParametersMatch(fmt, remoteMsection);
66 : }
67 0 : } else if (!fmt.compare("9") && mName == "G722") {
68 0 : return true;
69 0 : } else if (!fmt.compare("0") && mName == "PCMU") {
70 0 : return true;
71 0 : } else if (!fmt.compare("8") && mName == "PCMA") {
72 0 : return true;
73 : }
74 0 : return false;
75 : }
76 :
77 : virtual bool
78 0 : ParametersMatch(const std::string& fmt,
79 : const SdpMediaSection& remoteMsection) const
80 : {
81 0 : return true;
82 : }
83 :
84 : virtual bool
85 0 : Negotiate(const std::string& pt, const SdpMediaSection& remoteMsection)
86 : {
87 0 : mDefaultPt = pt;
88 0 : return true;
89 : }
90 :
91 : virtual void
92 0 : AddToMediaSection(SdpMediaSection& msection) const
93 : {
94 0 : if (mEnabled && msection.GetMediaType() == mType) {
95 : // Both send and recv codec will have the same pt, so don't add twice
96 0 : if (!msection.HasFormat(mDefaultPt)) {
97 0 : msection.AddCodec(mDefaultPt, mName, mClock, mChannels);
98 : }
99 :
100 0 : AddParametersToMSection(msection);
101 : }
102 0 : }
103 :
104 0 : virtual void AddParametersToMSection(SdpMediaSection& msection) const {}
105 :
106 : mozilla::SdpMediaSection::MediaType mType;
107 : std::string mDefaultPt;
108 : std::string mName;
109 : uint32_t mClock;
110 : uint32_t mChannels;
111 : bool mEnabled;
112 : bool mStronglyPreferred;
113 : sdp::Direction mDirection;
114 : // Will hold constraints from both fmtp and rid
115 : EncodingConstraints mConstraints;
116 : };
117 :
118 0 : class JsepAudioCodecDescription : public JsepCodecDescription {
119 : public:
120 0 : JsepAudioCodecDescription(const std::string& defaultPt,
121 : const std::string& name,
122 : uint32_t clock,
123 : uint32_t channels,
124 : uint32_t packetSize,
125 : uint32_t bitRate,
126 : bool enabled = true)
127 0 : : JsepCodecDescription(mozilla::SdpMediaSection::kAudio, defaultPt, name,
128 : clock, channels, enabled),
129 : mPacketSize(packetSize),
130 : mBitrate(bitRate),
131 : mMaxPlaybackRate(0),
132 : mForceMono(false),
133 : mFECEnabled(false),
134 0 : mDtmfEnabled(false)
135 : {
136 0 : }
137 :
138 0 : JSEP_CODEC_CLONE(JsepAudioCodecDescription)
139 :
140 : SdpFmtpAttributeList::OpusParameters
141 0 : GetOpusParameters(const std::string& pt,
142 : const SdpMediaSection& msection) const
143 : {
144 : // Will contain defaults if nothing else
145 0 : SdpFmtpAttributeList::OpusParameters result;
146 0 : auto* params = msection.FindFmtp(pt);
147 :
148 0 : if (params && params->codec_type == SdpRtpmapAttributeList::kOpus) {
149 : result =
150 0 : static_cast<const SdpFmtpAttributeList::OpusParameters&>(*params);
151 : }
152 :
153 0 : return result;
154 : }
155 :
156 : SdpFmtpAttributeList::TelephoneEventParameters
157 0 : GetTelephoneEventParameters(const std::string& pt,
158 : const SdpMediaSection& msection) const
159 : {
160 : // Will contain defaults if nothing else
161 0 : SdpFmtpAttributeList::TelephoneEventParameters result;
162 0 : auto* params = msection.FindFmtp(pt);
163 :
164 0 : if (params && params->codec_type == SdpRtpmapAttributeList::kTelephoneEvent) {
165 : result =
166 : static_cast<const SdpFmtpAttributeList::TelephoneEventParameters&>
167 0 : (*params);
168 : }
169 :
170 0 : return result;
171 : }
172 :
173 : void
174 0 : AddParametersToMSection(SdpMediaSection& msection) const override
175 : {
176 0 : if (mDirection == sdp::kSend) {
177 0 : return;
178 : }
179 :
180 0 : if (mName == "opus") {
181 : SdpFmtpAttributeList::OpusParameters opusParams(
182 0 : GetOpusParameters(mDefaultPt, msection));
183 0 : if (mMaxPlaybackRate) {
184 0 : opusParams.maxplaybackrate = mMaxPlaybackRate;
185 : }
186 0 : if (mChannels == 2 && !mForceMono) {
187 : // We prefer to receive stereo, if available.
188 0 : opusParams.stereo = 1;
189 : }
190 0 : opusParams.useInBandFec = mFECEnabled ? 1 : 0;
191 0 : msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, opusParams));
192 0 : } else if (mName == "telephone-event") {
193 : // add the default dtmf tones
194 : SdpFmtpAttributeList::TelephoneEventParameters teParams(
195 0 : GetTelephoneEventParameters(mDefaultPt, msection));
196 0 : msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, teParams));
197 : }
198 : }
199 :
200 : bool
201 0 : Negotiate(const std::string& pt,
202 : const SdpMediaSection& remoteMsection) override
203 : {
204 0 : JsepCodecDescription::Negotiate(pt, remoteMsection);
205 0 : if (mName == "opus" && mDirection == sdp::kSend) {
206 : SdpFmtpAttributeList::OpusParameters opusParams(
207 0 : GetOpusParameters(mDefaultPt, remoteMsection));
208 :
209 0 : mMaxPlaybackRate = opusParams.maxplaybackrate;
210 0 : mForceMono = !opusParams.stereo;
211 : // draft-ietf-rtcweb-fec-03.txt section 4.2 says support for FEC
212 : // at the received side is declarative and can be negotiated
213 : // separately for either media direction.
214 0 : mFECEnabled = opusParams.useInBandFec;
215 : }
216 :
217 0 : return true;
218 : }
219 :
220 : uint32_t mPacketSize;
221 : uint32_t mBitrate;
222 : uint32_t mMaxPlaybackRate;
223 : bool mForceMono;
224 : bool mFECEnabled;
225 : bool mDtmfEnabled;
226 : };
227 :
228 0 : class JsepVideoCodecDescription : public JsepCodecDescription {
229 : public:
230 0 : JsepVideoCodecDescription(const std::string& defaultPt,
231 : const std::string& name,
232 : uint32_t clock,
233 : bool enabled = true)
234 0 : : JsepCodecDescription(mozilla::SdpMediaSection::kVideo, defaultPt, name,
235 : clock, 0, enabled),
236 : mTmmbrEnabled(false),
237 : mRembEnabled(false),
238 : mFECEnabled(false),
239 0 : mPacketizationMode(0)
240 : {
241 : // Add supported rtcp-fb types
242 0 : mNackFbTypes.push_back("");
243 0 : mNackFbTypes.push_back(SdpRtcpFbAttributeList::pli);
244 0 : mCcmFbTypes.push_back(SdpRtcpFbAttributeList::fir);
245 0 : }
246 :
247 : virtual void
248 0 : EnableTmmbr() {
249 : // EnableTmmbr can be called multiple times due to multiple calls to
250 : // PeerConnectionImpl::ConfigureJsepSessionCodecs
251 0 : if (!mTmmbrEnabled) {
252 0 : mTmmbrEnabled = true;
253 0 : mCcmFbTypes.push_back(SdpRtcpFbAttributeList::tmmbr);
254 : }
255 0 : }
256 :
257 : virtual void
258 0 : EnableRemb() {
259 : // EnableRemb can be called multiple times due to multiple calls to
260 : // PeerConnectionImpl::ConfigureJsepSessionCodecs
261 0 : if (!mRembEnabled) {
262 0 : mRembEnabled = true;
263 0 : mOtherFbTypes.push_back({ "", SdpRtcpFbAttributeList::kRemb, "", ""});
264 : }
265 0 : }
266 :
267 : virtual void
268 0 : EnableFec(std::string redPayloadType, std::string ulpfecPayloadType) {
269 : // Enabling FEC for video works a little differently than enabling
270 : // REMB or TMMBR. Support for FEC is indicated by the presence of
271 : // particular codes (red and ulpfec) instead of using rtcpfb
272 : // attributes on a given codec. There is no rtcpfb to push for FEC
273 : // as can be seen above when REMB or TMMBR are enabled.
274 :
275 : // Ensure we have valid payload types. This returns zero on failure, which
276 : // is a valid payload type.
277 : uint16_t redPt, ulpfecPt;
278 0 : if (!SdpHelper::GetPtAsInt(redPayloadType, &redPt) ||
279 0 : !SdpHelper::GetPtAsInt(ulpfecPayloadType, &ulpfecPt)) {
280 0 : return;
281 : }
282 :
283 0 : mFECEnabled = true;
284 0 : mREDPayloadType = redPt;
285 0 : mULPFECPayloadType = ulpfecPt;
286 : }
287 :
288 : void
289 0 : AddParametersToMSection(SdpMediaSection& msection) const override
290 : {
291 0 : AddFmtpsToMSection(msection);
292 0 : AddRtcpFbsToMSection(msection);
293 0 : }
294 :
295 : void
296 0 : AddFmtpsToMSection(SdpMediaSection& msection) const
297 : {
298 0 : if (mName == "H264") {
299 : SdpFmtpAttributeList::H264Parameters h264Params(
300 0 : GetH264Parameters(mDefaultPt, msection));
301 :
302 0 : if (mDirection == sdp::kSend) {
303 0 : if (!h264Params.level_asymmetry_allowed) {
304 : // First time the fmtp has been set; set just in case this is for a
305 : // sendonly m-line, since even though we aren't receiving the level
306 : // negotiation still needs to happen (sigh).
307 0 : h264Params.profile_level_id = mProfileLevelId;
308 : }
309 : } else {
310 : // Parameters that only apply to what we receive
311 0 : h264Params.max_mbps = mConstraints.maxMbps;
312 0 : h264Params.max_fs = mConstraints.maxFs;
313 0 : h264Params.max_cpb = mConstraints.maxCpb;
314 0 : h264Params.max_dpb = mConstraints.maxDpb;
315 0 : h264Params.max_br = mConstraints.maxBr;
316 0 : strncpy(h264Params.sprop_parameter_sets,
317 : mSpropParameterSets.c_str(),
318 0 : sizeof(h264Params.sprop_parameter_sets) - 1);
319 0 : h264Params.profile_level_id = mProfileLevelId;
320 : }
321 :
322 : // Parameters that apply to both the send and recv directions
323 0 : h264Params.packetization_mode = mPacketizationMode;
324 : // Hard-coded, may need to change someday?
325 0 : h264Params.level_asymmetry_allowed = true;
326 :
327 0 : msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, h264Params));
328 0 : } else if (mName == "red" && mRedundantEncodings.size()) {
329 : SdpFmtpAttributeList::RedParameters redParams(
330 0 : GetRedParameters(mDefaultPt, msection));
331 0 : redParams.encodings = mRedundantEncodings;
332 0 : msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, redParams));
333 0 : } else if (mName == "VP8" || mName == "VP9") {
334 0 : if (mDirection == sdp::kRecv) {
335 : // VP8 and VP9 share the same SDP parameters thus far
336 : SdpFmtpAttributeList::VP8Parameters vp8Params(
337 0 : GetVP8Parameters(mDefaultPt, msection));
338 :
339 0 : vp8Params.max_fs = mConstraints.maxFs;
340 0 : vp8Params.max_fr = mConstraints.maxFps;
341 0 : msection.SetFmtp(SdpFmtpAttributeList::Fmtp(mDefaultPt, vp8Params));
342 : }
343 : }
344 0 : }
345 :
346 : void
347 0 : AddRtcpFbsToMSection(SdpMediaSection& msection) const
348 : {
349 0 : SdpRtcpFbAttributeList rtcpfbs(msection.GetRtcpFbs());
350 0 : for (const auto& rtcpfb : rtcpfbs.mFeedbacks) {
351 0 : if (rtcpfb.pt == mDefaultPt) {
352 : // Already set by the codec for the other direction.
353 0 : return;
354 : }
355 : }
356 :
357 0 : for (const std::string& type : mAckFbTypes) {
358 0 : rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kAck, type);
359 : }
360 0 : for (const std::string& type : mNackFbTypes) {
361 0 : rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kNack, type);
362 : }
363 0 : for (const std::string& type : mCcmFbTypes) {
364 0 : rtcpfbs.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kCcm, type);
365 : }
366 0 : for (const auto& fb : mOtherFbTypes) {
367 0 : rtcpfbs.PushEntry(mDefaultPt, fb.type, fb.parameter, fb.extra);
368 : }
369 :
370 0 : msection.SetRtcpFbs(rtcpfbs);
371 : }
372 :
373 : SdpFmtpAttributeList::H264Parameters
374 0 : GetH264Parameters(const std::string& pt,
375 : const SdpMediaSection& msection) const
376 : {
377 : // Will contain defaults if nothing else
378 0 : SdpFmtpAttributeList::H264Parameters result;
379 0 : auto* params = msection.FindFmtp(pt);
380 :
381 0 : if (params && params->codec_type == SdpRtpmapAttributeList::kH264) {
382 : result =
383 0 : static_cast<const SdpFmtpAttributeList::H264Parameters&>(*params);
384 : }
385 :
386 0 : return result;
387 : }
388 :
389 : SdpFmtpAttributeList::RedParameters
390 0 : GetRedParameters(const std::string& pt,
391 : const SdpMediaSection& msection) const
392 : {
393 0 : SdpFmtpAttributeList::RedParameters result;
394 0 : auto* params = msection.FindFmtp(pt);
395 :
396 0 : if (params && params->codec_type == SdpRtpmapAttributeList::kRed) {
397 : result =
398 0 : static_cast<const SdpFmtpAttributeList::RedParameters&>(*params);
399 : }
400 :
401 0 : return result;
402 : }
403 :
404 : SdpFmtpAttributeList::VP8Parameters
405 0 : GetVP8Parameters(const std::string& pt,
406 : const SdpMediaSection& msection) const
407 : {
408 : SdpRtpmapAttributeList::CodecType expectedType(
409 0 : mName == "VP8" ?
410 : SdpRtpmapAttributeList::kVP8 :
411 0 : SdpRtpmapAttributeList::kVP9);
412 :
413 : // Will contain defaults if nothing else
414 0 : SdpFmtpAttributeList::VP8Parameters result(expectedType);
415 0 : auto* params = msection.FindFmtp(pt);
416 :
417 0 : if (params && params->codec_type == expectedType) {
418 : result =
419 0 : static_cast<const SdpFmtpAttributeList::VP8Parameters&>(*params);
420 : }
421 :
422 0 : return result;
423 : }
424 :
425 : void
426 0 : NegotiateRtcpFb(const SdpMediaSection& remoteMsection,
427 : SdpRtcpFbAttributeList::Type type,
428 : std::vector<std::string>* supportedTypes)
429 : {
430 0 : std::vector<std::string> temp;
431 0 : for (auto& subType : *supportedTypes) {
432 0 : if (remoteMsection.HasRtcpFb(mDefaultPt, type, subType)) {
433 0 : temp.push_back(subType);
434 : }
435 : }
436 0 : *supportedTypes = temp;
437 0 : }
438 :
439 : void
440 0 : NegotiateRtcpFb(const SdpMediaSection& remoteMsection,
441 : std::vector<SdpRtcpFbAttributeList::Feedback>* supportedFbs) {
442 0 : std::vector<SdpRtcpFbAttributeList::Feedback> temp;
443 0 : for (auto& fb : *supportedFbs) {
444 0 : if (remoteMsection.HasRtcpFb(mDefaultPt, fb.type, fb.parameter)) {
445 0 : temp.push_back(fb);
446 : }
447 : }
448 0 : *supportedFbs = temp;
449 0 : }
450 :
451 : void
452 0 : NegotiateRtcpFb(const SdpMediaSection& remote)
453 : {
454 : // Removes rtcp-fb types that the other side doesn't support
455 0 : NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kAck, &mAckFbTypes);
456 0 : NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kNack, &mNackFbTypes);
457 0 : NegotiateRtcpFb(remote, SdpRtcpFbAttributeList::kCcm, &mCcmFbTypes);
458 0 : NegotiateRtcpFb(remote, &mOtherFbTypes);
459 0 : }
460 :
461 : virtual bool
462 0 : Negotiate(const std::string& pt,
463 : const SdpMediaSection& remoteMsection) override
464 : {
465 0 : JsepCodecDescription::Negotiate(pt, remoteMsection);
466 0 : if (mName == "H264") {
467 : SdpFmtpAttributeList::H264Parameters h264Params(
468 0 : GetH264Parameters(mDefaultPt, remoteMsection));
469 :
470 : // Level is negotiated symmetrically if level asymmetry is disallowed
471 0 : if (!h264Params.level_asymmetry_allowed) {
472 0 : SetSaneH264Level(std::min(GetSaneH264Level(h264Params.profile_level_id),
473 0 : GetSaneH264Level(mProfileLevelId)),
474 0 : &mProfileLevelId);
475 : }
476 :
477 0 : if (mDirection == sdp::kSend) {
478 : // Remote values of these apply only to the send codec.
479 0 : mConstraints.maxFs = h264Params.max_fs;
480 0 : mConstraints.maxMbps = h264Params.max_mbps;
481 0 : mConstraints.maxCpb = h264Params.max_cpb;
482 0 : mConstraints.maxDpb = h264Params.max_dpb;
483 0 : mConstraints.maxBr = h264Params.max_br;
484 0 : mSpropParameterSets = h264Params.sprop_parameter_sets;
485 : // Only do this if we didn't symmetrically negotiate above
486 0 : if (h264Params.level_asymmetry_allowed) {
487 0 : SetSaneH264Level(GetSaneH264Level(h264Params.profile_level_id),
488 0 : &mProfileLevelId);
489 : }
490 : } else {
491 : // TODO(bug 1143709): max-recv-level support
492 : }
493 0 : } else if (mName == "red") {
494 : SdpFmtpAttributeList::RedParameters redParams(
495 0 : GetRedParameters(mDefaultPt, remoteMsection));
496 0 : mRedundantEncodings = redParams.encodings;
497 0 : } else if (mName == "VP8" || mName == "VP9") {
498 0 : if (mDirection == sdp::kSend) {
499 : SdpFmtpAttributeList::VP8Parameters vp8Params(
500 0 : GetVP8Parameters(mDefaultPt, remoteMsection));
501 :
502 0 : mConstraints.maxFs = vp8Params.max_fs;
503 0 : mConstraints.maxFps = vp8Params.max_fr;
504 : }
505 : }
506 :
507 0 : NegotiateRtcpFb(remoteMsection);
508 0 : return true;
509 : }
510 :
511 : // Maps the not-so-sane encoding of H264 level into something that is
512 : // ordered in the way one would expect
513 : // 1b is 0xAB, everything else is the level left-shifted one half-byte
514 : // (eg; 1.0 is 0xA0, 1.1 is 0xB0, 3.1 is 0x1F0)
515 : static uint32_t
516 0 : GetSaneH264Level(uint32_t profileLevelId)
517 : {
518 0 : uint32_t profileIdc = (profileLevelId >> 16);
519 :
520 0 : if (profileIdc == 0x42 || profileIdc == 0x4D || profileIdc == 0x58) {
521 0 : if ((profileLevelId & 0x10FF) == 0x100B) {
522 : // Level 1b
523 0 : return 0xAB;
524 : }
525 : }
526 :
527 0 : uint32_t level = profileLevelId & 0xFF;
528 :
529 0 : if (level == 0x09) {
530 : // Another way to encode level 1b
531 0 : return 0xAB;
532 : }
533 :
534 0 : return level << 4;
535 : }
536 :
537 : static void
538 0 : SetSaneH264Level(uint32_t level, uint32_t* profileLevelId)
539 : {
540 0 : uint32_t profileIdc = (*profileLevelId >> 16);
541 0 : uint32_t levelMask = 0xFF;
542 :
543 0 : if (profileIdc == 0x42 || profileIdc == 0x4d || profileIdc == 0x58) {
544 0 : levelMask = 0x10FF;
545 0 : if (level == 0xAB) {
546 : // Level 1b
547 0 : level = 0x100B;
548 : } else {
549 : // Not 1b, just shift
550 0 : level = level >> 4;
551 : }
552 0 : } else if (level == 0xAB) {
553 : // Another way to encode 1b
554 0 : level = 0x09;
555 : } else {
556 : // Not 1b, just shift
557 0 : level = level >> 4;
558 : }
559 :
560 0 : *profileLevelId = (*profileLevelId & ~levelMask) | level;
561 0 : }
562 :
563 : enum Subprofile {
564 : kH264ConstrainedBaseline,
565 : kH264Baseline,
566 : kH264Main,
567 : kH264Extended,
568 : kH264High,
569 : kH264High10,
570 : kH264High42,
571 : kH264High44,
572 : kH264High10I,
573 : kH264High42I,
574 : kH264High44I,
575 : kH264CALVC44,
576 : kH264UnknownSubprofile
577 : };
578 :
579 : static Subprofile
580 0 : GetSubprofile(uint32_t profileLevelId)
581 : {
582 : // Based on Table 5 from RFC 6184:
583 : // Profile profile_idc profile-iop
584 : // (hexadecimal) (binary)
585 :
586 : // CB 42 (B) x1xx0000
587 : // same as: 4D (M) 1xxx0000
588 : // same as: 58 (E) 11xx0000
589 : // B 42 (B) x0xx0000
590 : // same as: 58 (E) 10xx0000
591 : // M 4D (M) 0x0x0000
592 : // E 58 00xx0000
593 : // H 64 00000000
594 : // H10 6E 00000000
595 : // H42 7A 00000000
596 : // H44 F4 00000000
597 : // H10I 6E 00010000
598 : // H42I 7A 00010000
599 : // H44I F4 00010000
600 : // C44I 2C 00010000
601 :
602 0 : if ((profileLevelId & 0xFF4F00) == 0x424000) {
603 : // 01001111 (mask, 0x4F)
604 : // x1xx0000 (from table)
605 : // 01000000 (expected value, 0x40)
606 0 : return kH264ConstrainedBaseline;
607 : }
608 :
609 0 : if ((profileLevelId & 0xFF8F00) == 0x4D8000) {
610 : // 10001111 (mask, 0x8F)
611 : // 1xxx0000 (from table)
612 : // 10000000 (expected value, 0x80)
613 0 : return kH264ConstrainedBaseline;
614 : }
615 :
616 0 : if ((profileLevelId & 0xFFCF00) == 0x58C000) {
617 : // 11001111 (mask, 0xCF)
618 : // 11xx0000 (from table)
619 : // 11000000 (expected value, 0xC0)
620 0 : return kH264ConstrainedBaseline;
621 : }
622 :
623 0 : if ((profileLevelId & 0xFF4F00) == 0x420000) {
624 : // 01001111 (mask, 0x4F)
625 : // x0xx0000 (from table)
626 : // 00000000 (expected value)
627 0 : return kH264Baseline;
628 : }
629 :
630 0 : if ((profileLevelId & 0xFFCF00) == 0x588000) {
631 : // 11001111 (mask, 0xCF)
632 : // 10xx0000 (from table)
633 : // 10000000 (expected value, 0x80)
634 0 : return kH264Baseline;
635 : }
636 :
637 0 : if ((profileLevelId & 0xFFAF00) == 0x4D0000) {
638 : // 10101111 (mask, 0xAF)
639 : // 0x0x0000 (from table)
640 : // 00000000 (expected value)
641 0 : return kH264Main;
642 : }
643 :
644 0 : if ((profileLevelId & 0xFF0000) == 0x580000) {
645 : // 11001111 (mask, 0xCF)
646 : // 00xx0000 (from table)
647 : // 00000000 (expected value)
648 0 : return kH264Extended;
649 : }
650 :
651 0 : if ((profileLevelId & 0xFFFF00) == 0x640000) {
652 0 : return kH264High;
653 : }
654 :
655 0 : if ((profileLevelId & 0xFFFF00) == 0x6E0000) {
656 0 : return kH264High10;
657 : }
658 :
659 0 : if ((profileLevelId & 0xFFFF00) == 0x7A0000) {
660 0 : return kH264High42;
661 : }
662 :
663 0 : if ((profileLevelId & 0xFFFF00) == 0xF40000) {
664 0 : return kH264High44;
665 : }
666 :
667 0 : if ((profileLevelId & 0xFFFF00) == 0x6E1000) {
668 0 : return kH264High10I;
669 : }
670 :
671 0 : if ((profileLevelId & 0xFFFF00) == 0x7A1000) {
672 0 : return kH264High42I;
673 : }
674 :
675 0 : if ((profileLevelId & 0xFFFF00) == 0xF41000) {
676 0 : return kH264High44I;
677 : }
678 :
679 0 : if ((profileLevelId & 0xFFFF00) == 0x2C1000) {
680 0 : return kH264CALVC44;
681 : }
682 :
683 0 : return kH264UnknownSubprofile;
684 : }
685 :
686 : virtual bool
687 0 : ParametersMatch(const std::string& fmt,
688 : const SdpMediaSection& remoteMsection) const override
689 : {
690 0 : if (mName == "H264") {
691 : SdpFmtpAttributeList::H264Parameters h264Params(
692 0 : GetH264Parameters(fmt, remoteMsection));
693 :
694 0 : if (h264Params.packetization_mode != mPacketizationMode) {
695 0 : return false;
696 : }
697 :
698 0 : if (GetSubprofile(h264Params.profile_level_id) !=
699 0 : GetSubprofile(mProfileLevelId)) {
700 0 : return false;
701 : }
702 : }
703 :
704 0 : return true;
705 : }
706 :
707 : virtual bool
708 0 : RtcpFbRembIsSet() const
709 : {
710 0 : for (const auto& fb : mOtherFbTypes) {
711 0 : if (fb.type == SdpRtcpFbAttributeList::kRemb) {
712 0 : return true;
713 : }
714 : }
715 0 : return false;
716 : }
717 :
718 : virtual void
719 0 : UpdateRedundantEncodings(std::vector<JsepCodecDescription*> codecs)
720 : {
721 0 : for (const auto codec : codecs) {
722 0 : if (codec->mType == SdpMediaSection::kVideo &&
723 0 : codec->mEnabled &&
724 0 : codec->mName != "red") {
725 : uint16_t pt;
726 0 : if (!SdpHelper::GetPtAsInt(codec->mDefaultPt, &pt)) {
727 0 : continue;
728 : }
729 0 : mRedundantEncodings.push_back(pt);
730 : }
731 : }
732 0 : }
733 :
734 0 : JSEP_CODEC_CLONE(JsepVideoCodecDescription)
735 :
736 : std::vector<std::string> mAckFbTypes;
737 : std::vector<std::string> mNackFbTypes;
738 : std::vector<std::string> mCcmFbTypes;
739 : std::vector<SdpRtcpFbAttributeList::Feedback> mOtherFbTypes;
740 : bool mTmmbrEnabled;
741 : bool mRembEnabled;
742 : bool mFECEnabled;
743 : uint8_t mREDPayloadType;
744 : uint8_t mULPFECPayloadType;
745 : std::vector<uint8_t> mRedundantEncodings;
746 :
747 : // H264-specific stuff
748 : uint32_t mProfileLevelId;
749 : uint32_t mPacketizationMode;
750 : std::string mSpropParameterSets;
751 : };
752 :
753 0 : class JsepApplicationCodecDescription : public JsepCodecDescription {
754 : // This is the new draft-21 implementation
755 : public:
756 0 : JsepApplicationCodecDescription(const std::string& name,
757 : uint16_t channels,
758 : uint16_t localPort,
759 : uint32_t localMaxMessageSize,
760 : bool enabled = true)
761 0 : : JsepCodecDescription(mozilla::SdpMediaSection::kApplication, "",
762 : name, 0, channels, enabled),
763 : mLocalPort(localPort),
764 : mLocalMaxMessageSize(localMaxMessageSize),
765 : mRemotePort(0),
766 0 : mRemoteMaxMessageSize(0)
767 : {
768 0 : }
769 :
770 0 : JSEP_CODEC_CLONE(JsepApplicationCodecDescription)
771 :
772 : // Override, uses sctpport or sctpmap instead of rtpmap
773 : virtual bool
774 0 : Matches(const std::string& fmt,
775 : const SdpMediaSection& remoteMsection) const override
776 : {
777 0 : if (mType != remoteMsection.GetMediaType()) {
778 0 : return false;
779 : }
780 :
781 0 : int sctp_port = remoteMsection.GetSctpPort();
782 0 : bool fmt_matches = nsCRT::strcasecmp(mName.c_str(),
783 0 : remoteMsection.GetFormats()[0].c_str()) == 0;
784 0 : if (sctp_port && fmt_matches) {
785 : // New sctp draft 21 format
786 0 : return true;
787 : }
788 :
789 : const SdpSctpmapAttributeList::Sctpmap* sctp_map(
790 0 : remoteMsection.GetSctpmap());
791 0 : if (sctp_map) {
792 : // Old sctp draft 05 format
793 0 : return nsCRT::strcasecmp(mName.c_str(), sctp_map->name.c_str()) == 0;
794 : }
795 :
796 0 : return false;
797 : }
798 :
799 : virtual void
800 0 : AddToMediaSection(SdpMediaSection& msection) const override
801 : {
802 0 : if (mEnabled && msection.GetMediaType() == mType) {
803 0 : if (msection.GetFormats().empty()) {
804 0 : msection.AddDataChannel(mName, mLocalPort, mChannels,
805 0 : mLocalMaxMessageSize);
806 : }
807 :
808 0 : AddParametersToMSection(msection);
809 : }
810 0 : }
811 :
812 : bool
813 0 : Negotiate(const std::string& pt, const SdpMediaSection& remoteMsection) override
814 : {
815 0 : JsepCodecDescription::Negotiate(pt, remoteMsection);
816 :
817 : uint32_t message_size;
818 0 : mRemoteMMSSet = remoteMsection.GetMaxMessageSize(&message_size);
819 0 : if (mRemoteMMSSet) {
820 0 : mRemoteMaxMessageSize = message_size;
821 : } else {
822 0 : mRemoteMaxMessageSize = WEBRTC_DATACHANELL_MAX_MESSAGE_SIZE_DEFAULT;
823 : }
824 :
825 0 : int sctp_port = remoteMsection.GetSctpPort();
826 0 : if (sctp_port) {
827 0 : mRemotePort = sctp_port;
828 0 : return true;
829 : }
830 :
831 : const SdpSctpmapAttributeList::Sctpmap* sctp_map(
832 0 : remoteMsection.GetSctpmap());
833 0 : if (sctp_map) {
834 0 : mRemotePort = std::stoi(sctp_map->pt);
835 0 : return true;
836 : }
837 :
838 0 : return false;
839 : }
840 :
841 :
842 : uint16_t mLocalPort;
843 : uint32_t mLocalMaxMessageSize;
844 : uint16_t mRemotePort;
845 : uint32_t mRemoteMaxMessageSize;
846 : bool mRemoteMMSSet;
847 : };
848 :
849 : } // namespace mozilla
850 :
851 : #endif
|