Coverage Report

Created: 2018-09-25 14:53

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