Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at */
#ifndef _JSEPTRACK_H_
#define _JSEPTRACK_H_
#include <functional>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <mozilla/UniquePtr.h>
#include "mozilla/Preferences.h"
#include "nsError.h"
#include "jsep/JsepTrackEncoding.h"
#include "jsep/SsrcGenerator.h"
#include "sdp/Sdp.h"
#include "sdp/SdpAttribute.h"
#include "sdp/SdpMediaSection.h"
#include "libwebrtcglue/RtpRtcpConfig.h"
namespace mozilla {
class JsepTrackNegotiatedDetails {
: mTias(0), mRtpRtcpConf(webrtc::RtcpMode::kCompound) {}
JsepTrackNegotiatedDetails(const JsepTrackNegotiatedDetails& orig)
: mExtmap(orig.mExtmap),
mRtpRtcpConf(orig.mRtpRtcpConf) {
for (const auto& encoding : orig.mEncodings) {
mEncodings.emplace_back(new JsepTrackEncoding(*encoding));
size_t GetEncodingCount() const { return mEncodings.size(); }
const JsepTrackEncoding& GetEncoding(size_t index) const {
MOZ_RELEASE_ASSERT(index < mEncodings.size());
return *mEncodings[index];
void TruncateEncodings(size_t aSize) {
if (mEncodings.size() < aSize) {
const SdpExtmapAttributeList::Extmap* GetExt(
const std::string& ext_name) const {
auto it = mExtmap.find(ext_name);
if (it != mExtmap.end()) {
return &it->second;
return nullptr;
void ForEachRTPHeaderExtension(
const std::function<void(const SdpExtmapAttributeList::Extmap& extmap)>&
fn) const {
for (auto entry : mExtmap) {
std::vector<uint8_t> GetUniqueReceivePayloadTypes() const {
return mUniqueReceivePayloadTypes;
uint32_t GetTias() const { return mTias; }
RtpRtcpConfig GetRtpRtcpConfig() const { return mRtpRtcpConf; }
friend class JsepTrack;
std::map<std::string, SdpExtmapAttributeList::Extmap> mExtmap;
std::vector<uint8_t> mUniqueReceivePayloadTypes;
std::vector<UniquePtr<JsepTrackEncoding>> mEncodings;
uint32_t mTias; // bits per second
RtpRtcpConfig mRtpRtcpConf;
class JsepTrack {
JsepTrack(mozilla::SdpMediaSection::MediaType type, sdp::Direction direction)
: mType(type),
mRemoteSetSendBit(false) {}
virtual ~JsepTrack() {}
void UpdateStreamIds(const std::vector<std::string>& streamIds) {
mStreamIds = streamIds;
void SetTrackId(const std::string& aTrackId) { mTrackId = aTrackId; }
void ClearStreamIds() { mStreamIds.clear(); }
void RecvTrackSetRemote(const Sdp& aSdp, const SdpMediaSection& aMsection);
void RecvTrackSetLocal(const SdpMediaSection& aMsection);
// This is called whenever a remote description is set; we do not wait for
// offer/answer to complete, since there's nothing to actually negotiate here.
void SendTrackSetRemote(SsrcGenerator& aSsrcGenerator,
const SdpMediaSection& aRemoteMsection);
JsepTrack(const JsepTrack& orig) { *this = orig; }
JsepTrack(JsepTrack&& orig) = default;
JsepTrack& operator=(JsepTrack&& rhs) = default;
JsepTrack& operator=(const JsepTrack& rhs) {
if (this != &rhs) {
mType = rhs.mType;
mStreamIds = rhs.mStreamIds;
mTrackId = rhs.mTrackId;
mCNAME = rhs.mCNAME;
mDirection = rhs.mDirection;
mRids = rhs.mRids;
mSsrcs = rhs.mSsrcs;
mSsrcToRtxSsrc = rhs.mSsrcToRtxSsrc;
mActive = rhs.mActive;
mRemoteSetSendBit = rhs.mRemoteSetSendBit;
mReceptive = rhs.mReceptive;
mMaxEncodings = rhs.mMaxEncodings;
mInHaveRemote = rhs.mInHaveRemote;
mRtxIsAllowed = rhs.mRtxIsAllowed;
mFecCodec = rhs.mFecCodec;
mAudioPreferredCodec = rhs.mAudioPreferredCodec;
mVideoPreferredCodec = rhs.mVideoPreferredCodec;
for (const auto& codec : rhs.mPrototypeCodecs) {
if (rhs.mNegotiatedDetails) {
new JsepTrackNegotiatedDetails(*rhs.mNegotiatedDetails));
return *this;
virtual mozilla::SdpMediaSection::MediaType GetMediaType() const {
return mType;
virtual const std::vector<std::string>& GetStreamIds() const {
return mStreamIds;
virtual const std::string& GetCNAME() const { return mCNAME; }
virtual void SetCNAME(const std::string& cname) { mCNAME = cname; }
virtual sdp::Direction GetDirection() const { return mDirection; }
virtual const std::vector<uint32_t>& GetSsrcs() const { return mSsrcs; }
virtual std::vector<uint32_t> GetRtxSsrcs() const {
std::vector<uint32_t> result;
if (mRtxIsAllowed &&
Preferences::GetBool("", false) &&
!mSsrcToRtxSsrc.empty()) {
MOZ_ASSERT(mSsrcToRtxSsrc.size() == mSsrcs.size());
for (const auto ssrc : mSsrcs) {
auto it = mSsrcToRtxSsrc.find(ssrc);
MOZ_ASSERT(it != mSsrcToRtxSsrc.end());
return result;
virtual void EnsureSsrcs(SsrcGenerator& ssrcGenerator, size_t aNumber);
bool GetActive() const { return mActive; }
void SetActive(bool active) { mActive = active; }
bool GetRemoteSetSendBit() const { return mRemoteSetSendBit; }
bool GetReceptive() const { return mReceptive; }
virtual void PopulateCodecs(
const std::vector<UniquePtr<JsepCodecDescription>>& prototype);
template <class UnaryFunction>
void ForEachCodec(UnaryFunction func) {
std::for_each(mPrototypeCodecs.begin(), mPrototypeCodecs.end(), func);
template <class BinaryPredicate>
void SortCodecs(BinaryPredicate sorter) {
std::stable_sort(mPrototypeCodecs.begin(), mPrototypeCodecs.end(), sorter);
// These two are non-const because this is where ssrcs are chosen.
virtual void AddToOffer(SsrcGenerator& ssrcGenerator, SdpMediaSection* offer);
virtual void AddToAnswer(const SdpMediaSection& offer,
SsrcGenerator& ssrcGenerator,
SdpMediaSection* answer);
virtual nsresult Negotiate(const SdpMediaSection& answer,
const SdpMediaSection& remote,
const SdpMediaSection& local);
static void SetUniqueReceivePayloadTypes(std::vector<JsepTrack*>& tracks);
virtual void GetNegotiatedPayloadTypes(
std::vector<uint16_t>* payloadTypes) const;
// This will be set when negotiation is carried out.
virtual const JsepTrackNegotiatedDetails* GetNegotiatedDetails() const {
if (mNegotiatedDetails) {
return mNegotiatedDetails.get();
return nullptr;
virtual JsepTrackNegotiatedDetails* GetNegotiatedDetails() {
if (mNegotiatedDetails) {
return mNegotiatedDetails.get();
return nullptr;
virtual void ClearNegotiatedDetails() { mNegotiatedDetails.reset(); }
void SetRids(const std::vector<std::string>& aRids);
void ClearRids() { mRids.clear(); }
const std::vector<std::string>& GetRids() const { return mRids; }
void AddToMsection(const std::vector<std::string>& aRids,
sdp::Direction direction, SsrcGenerator& ssrcGenerator,
bool rtxEnabled, SdpMediaSection* msection);
// See Bug 1642419, this can be removed when all sites are working with RTX.
void SetRtxIsAllowed(bool aRtxIsAllowed) { mRtxIsAllowed = aRtxIsAllowed; }
void SetMaxEncodings(size_t aMax);
bool IsInHaveRemote() const { return mInHaveRemote; }
const std::string& GetFecCodecName() { return mFecCodec; }
const std::string& GetAudioPreferredCodec() { return mAudioPreferredCodec; }
const std::string& GetVideoPreferredCodec() { return mVideoPreferredCodec; }
std::vector<UniquePtr<JsepCodecDescription>> GetCodecClones() const;
static void EnsureNoDuplicatePayloadTypes(
std::vector<UniquePtr<JsepCodecDescription>>* codecs);
static void GetPayloadTypes(
const std::vector<UniquePtr<JsepCodecDescription>>& codecs,
std::vector<uint16_t>* pts);
void AddToMsection(const std::vector<UniquePtr<JsepCodecDescription>>& codecs,
SdpMediaSection* msection) const;
void GetRids(const SdpMediaSection& msection, sdp::Direction direction,
std::vector<SdpRidAttributeList::Rid>* rids) const;
void CreateEncodings(
const SdpMediaSection& remote,
const std::vector<UniquePtr<JsepCodecDescription>>& negotiatedCodecs,
JsepTrackNegotiatedDetails* details);
// Identifies codecs we want to store for logging purposes.
void MaybeStoreCodecToLog(const std::string& codec,
SdpMediaSection::MediaType type);
virtual std::vector<UniquePtr<JsepCodecDescription>> NegotiateCodecs(
const SdpMediaSection& remote, bool remoteIsOffer,
Maybe<const SdpMediaSection&> local);
void UpdateSsrcs(SsrcGenerator& ssrcGenerator, size_t encodings);
void PruneSsrcs(size_t aNumSsrcs);
bool IsRtxEnabled(
const std::vector<UniquePtr<JsepCodecDescription>>& codecs) const;
mozilla::SdpMediaSection::MediaType mType;
// These are the ids that everyone outside of JsepSession care about
std::vector<std::string> mStreamIds;
std::string mTrackId;
std::string mCNAME;
sdp::Direction mDirection;
std::vector<UniquePtr<JsepCodecDescription>> mPrototypeCodecs;
// List of rids. May be initially populated from JS, or from a remote SDP.
// Can be updated by remote SDP. If no negotiation has taken place at all,
// this will be empty. If negotiation has taken place, but no simulcast
// attr was negotiated, this will contain the empty string as a single
// element. If a simulcast attribute was negotiated, this will contain the
// negotiated rids.
std::vector<std::string> mRids;
UniquePtr<JsepTrackNegotiatedDetails> mNegotiatedDetails;
std::vector<uint32_t> mSsrcs;
std::map<uint32_t, uint32_t> mSsrcToRtxSsrc;
bool mActive;
bool mRemoteSetSendBit;
// This is used to drive RTCRtpTransceiver.[[Receptive]]. Basically, this
// denotes whether we are prepared to receive RTP. When we apply a local
// description with the recv bit set, this is set to true, even if we have
// not seen the remote description yet. If we apply either a local or remote
// description without the recv bit set (from our perspective), this is set
// to false.
bool mReceptive = false;
size_t mMaxEncodings = 3;
bool mInHaveRemote = false;
// See Bug 1642419, this can be removed when all sites are working with RTX.
bool mRtxIsAllowed = true;
// Codec names for logging
std::string mFecCodec;
std::string mAudioPreferredCodec;
std::string mVideoPreferredCodec;
} // namespace mozilla