Bug 1091242 - Part 2: New JSEP handling code. See https://github.com/unicorn-wg/gecko-dev/tree/multistream_rebase for more history. r=ehugg, r=jesup

This commit is contained in:
Byron Campen [:bwc] 2014-11-19 16:12:08 -08:00
parent b942d9f5bb
commit a49b1b7a20
8 changed files with 4187 additions and 0 deletions

View File

@ -0,0 +1,620 @@
/* 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 http://mozilla.org/MPL/2.0/. */
#ifndef _JSEPCODECDESCRIPTION_H_
#define _JSEPCODECDESCRIPTION_H_
#include <iostream>
#include <string>
#include "signaling/src/sdp/SdpMediaSection.h"
namespace mozilla {
#define JSEP_CODEC_CLONE(T) \
virtual JsepCodecDescription* Clone() const MOZ_OVERRIDE \
{ \
return new T(*this); \
}
// A single entry in our list of known codecs.
struct JsepCodecDescription {
JsepCodecDescription(mozilla::SdpMediaSection::MediaType type,
const std::string& defaultPt,
const std::string& name,
uint32_t clock,
uint32_t channels,
bool enabled)
: mType(type),
mDefaultPt(defaultPt),
mName(name),
mClock(clock),
mChannels(channels),
mEnabled(enabled)
{
}
virtual ~JsepCodecDescription() {}
virtual JsepCodecDescription* Clone() const = 0;
virtual void AddFmtps(SdpFmtpAttributeList& fmtp) const = 0;
virtual void AddRtcpFbs(SdpRtcpFbAttributeList& rtcpfb) const = 0;
virtual bool LoadFmtps(const SdpFmtpAttributeList::Parameters& params) = 0;
virtual bool LoadRtcpFbs(
const SdpRtcpFbAttributeList::Feedback& feedback) = 0;
static bool
GetPtAsInt(const std::string& ptString, uint16_t* ptOutparam)
{
char* end;
unsigned long pt = strtoul(ptString.c_str(), &end, 10);
size_t length = static_cast<size_t>(end - ptString.c_str());
if ((pt > UINT16_MAX) || (length != ptString.size())) {
return false;
}
*ptOutparam = pt;
return true;
}
bool
GetPtAsInt(uint16_t* ptOutparam) const
{
return GetPtAsInt(mDefaultPt, ptOutparam);
}
virtual bool
Matches(const std::string& fmt, const SdpMediaSection& remoteMsection) const
{
auto& attrs = remoteMsection.GetAttributeList();
if (!attrs.HasAttribute(SdpAttribute::kRtpmapAttribute)) {
return false;
}
const SdpRtpmapAttributeList& rtpmap = attrs.GetRtpmap();
if (!rtpmap.HasEntry(fmt)) {
return false;
}
const SdpRtpmapAttributeList::Rtpmap& entry = rtpmap.GetEntry(fmt);
if (mType == remoteMsection.GetMediaType()
&& (mName == entry.name)
&& (mClock == entry.clock)
&& (mChannels == entry.channels)) {
return ParametersMatch(FindParameters(entry.pt, remoteMsection));
}
return false;
}
virtual bool
ParametersMatch(const SdpFmtpAttributeList::Parameters* fmtp) const
{
return true;
}
static const SdpFmtpAttributeList::Parameters*
FindParameters(const std::string& pt,
const mozilla::SdpMediaSection& remoteMsection)
{
const SdpAttributeList& attrs = remoteMsection.GetAttributeList();
if (attrs.HasAttribute(SdpAttribute::kFmtpAttribute)) {
const SdpFmtpAttributeList& fmtps = attrs.GetFmtp();
for (auto i = fmtps.mFmtps.begin(); i != fmtps.mFmtps.end(); ++i) {
if (i->format == pt && i->parameters) {
return i->parameters.get();
}
}
}
return nullptr;
}
virtual JsepCodecDescription*
MakeNegotiatedCodec(const mozilla::SdpMediaSection& remoteMsection,
const std::string& pt,
bool sending) const
{
UniquePtr<JsepCodecDescription> negotiated(Clone());
negotiated->mDefaultPt = pt;
const SdpAttributeList& attrs = remoteMsection.GetAttributeList();
if (sending) {
auto* parameters = FindParameters(negotiated->mDefaultPt, remoteMsection);
if (parameters) {
if (!negotiated->LoadFmtps(*parameters)) {
// Remote parameters were invalid
return nullptr;
}
}
} else {
// If a receive track, we need to pay attention to remote end's rtcp-fb
if (attrs.HasAttribute(SdpAttribute::kRtcpFbAttribute)) {
auto& rtcpfbs = attrs.GetRtcpFb().mFeedbacks;
for (auto i = rtcpfbs.begin(); i != rtcpfbs.end(); ++i) {
if (i->pt == negotiated->mDefaultPt) {
if (!negotiated->LoadRtcpFbs(*i)) {
// Remote parameters were invalid
return nullptr;
}
}
}
}
}
return negotiated.release();
}
virtual void
AddToMediaSection(SdpMediaSection& msection) const
{
if (mEnabled && msection.GetMediaType() == mType) {
if (mType == SdpMediaSection::kApplication) {
// Hack: using mChannels for number of streams
msection.AddDataChannel(mDefaultPt, mName, mChannels);
} else {
msection.AddCodec(mDefaultPt, mName, mClock, mChannels);
}
AddFmtpsToMSection(msection);
AddRtcpFbsToMSection(msection);
}
}
virtual void
AddFmtpsToMSection(SdpMediaSection& msection) const
{
SdpAttributeList& attrs = msection.GetAttributeList();
UniquePtr<SdpFmtpAttributeList> fmtps;
if (attrs.HasAttribute(SdpAttribute::kFmtpAttribute)) {
fmtps.reset(new SdpFmtpAttributeList(attrs.GetFmtp()));
} else {
fmtps.reset(new SdpFmtpAttributeList);
}
AddFmtps(*fmtps);
if (!fmtps->mFmtps.empty()) {
attrs.SetAttribute(fmtps.release());
}
}
virtual void
AddRtcpFbsToMSection(SdpMediaSection& msection) const
{
SdpAttributeList& attrs = msection.GetAttributeList();
UniquePtr<SdpRtcpFbAttributeList> rtcpfbs;
if (attrs.HasAttribute(SdpAttribute::kRtcpFbAttribute)) {
rtcpfbs.reset(new SdpRtcpFbAttributeList(attrs.GetRtcpFb()));
} else {
rtcpfbs.reset(new SdpRtcpFbAttributeList);
}
AddRtcpFbs(*rtcpfbs);
if (!rtcpfbs->mFeedbacks.empty()) {
attrs.SetAttribute(rtcpfbs.release());
}
}
mozilla::SdpMediaSection::MediaType mType;
std::string mDefaultPt;
std::string mName;
uint32_t mClock;
uint32_t mChannels;
bool mEnabled;
};
struct JsepAudioCodecDescription : public JsepCodecDescription {
JsepAudioCodecDescription(const std::string& defaultPt,
const std::string& name,
uint32_t clock,
uint32_t channels,
uint32_t packetSize,
uint32_t bitRate,
bool enabled = true)
: JsepCodecDescription(mozilla::SdpMediaSection::kAudio, defaultPt, name,
clock, channels, enabled),
mPacketSize(packetSize),
mBitrate(bitRate)
{
}
virtual void
AddFmtps(SdpFmtpAttributeList& fmtp) const MOZ_OVERRIDE
{
// TODO
}
virtual void
AddRtcpFbs(SdpRtcpFbAttributeList& rtcpfb) const MOZ_OVERRIDE
{
// TODO: Do we want to add anything?
}
virtual bool
LoadFmtps(const SdpFmtpAttributeList::Parameters& params) MOZ_OVERRIDE
{
// TODO
return true;
}
virtual bool
LoadRtcpFbs(const SdpRtcpFbAttributeList::Feedback& feedback) MOZ_OVERRIDE
{
// Nothing to do
return true;
}
JSEP_CODEC_CLONE(JsepAudioCodecDescription)
uint32_t mPacketSize;
uint32_t mBitrate;
};
struct JsepVideoCodecDescription : public JsepCodecDescription {
JsepVideoCodecDescription(const std::string& defaultPt,
const std::string& name,
uint32_t clock,
bool enabled = true)
: JsepCodecDescription(mozilla::SdpMediaSection::kVideo, defaultPt, name,
clock, 0, enabled),
mMaxFs(0),
mMaxFr(0),
mPacketizationMode(0),
mMaxMbps(0),
mMaxCpb(0),
mMaxDpb(0),
mMaxBr(0)
{
}
virtual void
AddFmtps(SdpFmtpAttributeList& fmtp) const MOZ_OVERRIDE
{
if (mName == "H264") {
UniquePtr<SdpFmtpAttributeList::H264Parameters> params =
MakeUnique<SdpFmtpAttributeList::H264Parameters>();
params->packetization_mode = mPacketizationMode;
// Hard-coded, may need to change someday?
params->level_asymmetry_allowed = true;
params->profile_level_id = mProfileLevelId;
params->max_mbps = mMaxMbps;
params->max_fs = mMaxFs;
params->max_cpb = mMaxCpb;
params->max_dpb = mMaxDpb;
params->max_br = mMaxBr;
strncpy(params->sprop_parameter_sets,
mSpropParameterSets.c_str(),
sizeof(params->sprop_parameter_sets) - 1);
fmtp.PushEntry(mDefaultPt, "", mozilla::Move(params));
} else if (mName == "VP8") {
UniquePtr<SdpFmtpAttributeList::VP8Parameters> params =
MakeUnique<SdpFmtpAttributeList::VP8Parameters>();
params->max_fs = mMaxFs;
params->max_fr = mMaxFr;
fmtp.PushEntry(mDefaultPt, "", mozilla::Move(params));
}
}
virtual void
AddRtcpFbs(SdpRtcpFbAttributeList& rtcpfb) const MOZ_OVERRIDE
{
// Just hard code for now
rtcpfb.PushEntry(mDefaultPt, SdpRtcpFbAttributeList::kNack);
rtcpfb.PushEntry(
mDefaultPt, SdpRtcpFbAttributeList::kNack, SdpRtcpFbAttributeList::pli);
rtcpfb.PushEntry(
mDefaultPt, SdpRtcpFbAttributeList::kCcm, SdpRtcpFbAttributeList::fir);
}
virtual bool
LoadFmtps(const SdpFmtpAttributeList::Parameters& params) MOZ_OVERRIDE
{
switch (params.codec_type) {
case SdpRtpmapAttributeList::kH264:
LoadH264Parameters(params);
break;
case SdpRtpmapAttributeList::kVP8:
LoadVP8Parameters(params);
break;
case SdpRtpmapAttributeList::kVP9:
case SdpRtpmapAttributeList::kiLBC:
case SdpRtpmapAttributeList::kiSAC:
case SdpRtpmapAttributeList::kOpus:
case SdpRtpmapAttributeList::kG722:
case SdpRtpmapAttributeList::kPCMU:
case SdpRtpmapAttributeList::kPCMA:
case SdpRtpmapAttributeList::kOtherCodec:
MOZ_ASSERT(false, "Invalid codec type for video");
}
return true;
}
virtual bool
LoadRtcpFbs(const SdpRtcpFbAttributeList::Feedback& feedback) MOZ_OVERRIDE
{
switch (feedback.type) {
case SdpRtcpFbAttributeList::kAck:
mAckFbTypes.push_back(feedback.parameter);
break;
case SdpRtcpFbAttributeList::kCcm:
mCcmFbTypes.push_back(feedback.parameter);
break;
case SdpRtcpFbAttributeList::kNack:
mNackFbTypes.push_back(feedback.parameter);
break;
case SdpRtcpFbAttributeList::kApp:
case SdpRtcpFbAttributeList::kTrrInt:
// We don't support these, ignore.
{}
}
return true;
}
enum Subprofile {
kH264ConstrainedBaseline,
kH264Baseline,
kH264Main,
kH264Extended,
kH264High,
kH264High10,
kH264High42,
kH264High44,
kH264High10I,
kH264High42I,
kH264High44I,
kH264CALVC44,
kH264UnknownSubprofile
};
static Subprofile
GetSubprofile(uint32_t profileLevelId)
{
// Based on Table 5 from RFC 6184:
// Profile profile_idc profile-iop
// (hexadecimal) (binary)
// CB 42 (B) x1xx0000
// same as: 4D (M) 1xxx0000
// same as: 58 (E) 11xx0000
// B 42 (B) x0xx0000
// same as: 58 (E) 10xx0000
// M 4D (M) 0x0x0000
// E 58 00xx0000
// H 64 00000000
// H10 6E 00000000
// H42 7A 00000000
// H44 F4 00000000
// H10I 6E 00010000
// H42I 7A 00010000
// H44I F4 00010000
// C44I 2C 00010000
if ((profileLevelId & 0xFF4F00) == 0x424000) {
// 01001111 (mask, 0x4F)
// x1xx0000 (from table)
// 01000000 (expected value, 0x40)
return kH264ConstrainedBaseline;
}
if ((profileLevelId & 0xFF8F00) == 0x4D8000) {
// 10001111 (mask, 0x8F)
// 1xxx0000 (from table)
// 10000000 (expected value, 0x80)
return kH264ConstrainedBaseline;
}
if ((profileLevelId & 0xFFCF00) == 0x58C000) {
// 11001111 (mask, 0xCF)
// 11xx0000 (from table)
// 11000000 (expected value, 0xC0)
return kH264ConstrainedBaseline;
}
if ((profileLevelId & 0xFF4F00) == 0x420000) {
// 01001111 (mask, 0x4F)
// x0xx0000 (from table)
// 00000000 (expected value)
return kH264Baseline;
}
if ((profileLevelId & 0xFFCF00) == 0x588000) {
// 11001111 (mask, 0xCF)
// 10xx0000 (from table)
// 10000000 (expected value, 0x80)
return kH264Baseline;
}
if ((profileLevelId & 0xFFAF00) == 0x4D0000) {
// 10101111 (mask, 0xAF)
// 0x0x0000 (from table)
// 00000000 (expected value)
return kH264Main;
}
if ((profileLevelId & 0xFF0000) == 0x580000) {
// 11001111 (mask, 0xCF)
// 00xx0000 (from table)
// 00000000 (expected value)
return kH264Extended;
}
if ((profileLevelId & 0xFFFF00) == 0x640000) {
return kH264High;
}
if ((profileLevelId & 0xFFFF00) == 0x6E0000) {
return kH264High10;
}
if ((profileLevelId & 0xFFFF00) == 0x7A0000) {
return kH264High42;
}
if ((profileLevelId & 0xFFFF00) == 0xF40000) {
return kH264High44;
}
if ((profileLevelId & 0xFFFF00) == 0x6E1000) {
return kH264High10I;
}
if ((profileLevelId & 0xFFFF00) == 0x7A1000) {
return kH264High42I;
}
if ((profileLevelId & 0xFFFF00) == 0xF41000) {
return kH264High44I;
}
if ((profileLevelId & 0xFFFF00) == 0x2C1000) {
return kH264CALVC44;
}
return kH264UnknownSubprofile;
}
virtual bool
ParametersMatch(const SdpFmtpAttributeList::Parameters* fmtp) const
MOZ_OVERRIDE
{
if (mName == "H264") {
if (!fmtp) {
// No fmtp means that we cannot assume level asymmetry is allowed,
// and since we have no way of knowing the profile-level-id, we can't
// say that we match.
return false;
}
auto* h264Params =
static_cast<const SdpFmtpAttributeList::H264Parameters*>(fmtp);
if (!h264Params->level_asymmetry_allowed) {
if (GetSubprofile(h264Params->profile_level_id) !=
GetSubprofile(mProfileLevelId)) {
return false;
}
}
if (h264Params->packetization_mode != mPacketizationMode) {
return false;
}
}
return true;
}
void
LoadH264Parameters(const SdpFmtpAttributeList::Parameters& params)
{
const SdpFmtpAttributeList::H264Parameters& h264Params =
static_cast<const SdpFmtpAttributeList::H264Parameters&>(params);
mMaxFs = h264Params.max_fs;
mProfileLevelId = h264Params.profile_level_id;
mPacketizationMode = h264Params.packetization_mode;
mMaxMbps = h264Params.max_mbps;
mMaxCpb = h264Params.max_cpb;
mMaxDpb = h264Params.max_dpb;
mMaxBr = h264Params.max_br;
mSpropParameterSets = h264Params.sprop_parameter_sets;
}
void
LoadVP8Parameters(const SdpFmtpAttributeList::Parameters& params)
{
const SdpFmtpAttributeList::VP8Parameters& vp8Params =
static_cast<const SdpFmtpAttributeList::VP8Parameters&>(params);
mMaxFs = vp8Params.max_fs;
mMaxFr = vp8Params.max_fr;
}
JSEP_CODEC_CLONE(JsepVideoCodecDescription)
std::vector<std::string> mAckFbTypes;
std::vector<std::string> mNackFbTypes;
std::vector<std::string> mCcmFbTypes;
uint32_t mMaxFs;
// H264-specific stuff
uint32_t mProfileLevelId;
uint32_t mMaxFr;
uint32_t mPacketizationMode;
uint32_t mMaxMbps;
uint32_t mMaxCpb;
uint32_t mMaxDpb;
uint32_t mMaxBr;
std::string mSpropParameterSets;
};
struct JsepApplicationCodecDescription : public JsepCodecDescription {
JsepApplicationCodecDescription(const std::string& defaultPt,
const std::string& name,
uint16_t channels,
bool enabled = true)
: JsepCodecDescription(mozilla::SdpMediaSection::kApplication, defaultPt,
name, 0, channels, enabled)
{
}
virtual void
AddFmtps(SdpFmtpAttributeList& fmtp) const MOZ_OVERRIDE
{
// TODO: Is there anything to do here?
}
virtual void
AddRtcpFbs(SdpRtcpFbAttributeList& rtcpfb) const MOZ_OVERRIDE
{
// Nothing to do here.
}
virtual bool
LoadFmtps(const SdpFmtpAttributeList::Parameters& params) MOZ_OVERRIDE
{
// TODO: Is there anything to do here?
return true;
}
virtual bool
LoadRtcpFbs(const SdpRtcpFbAttributeList::Feedback& feedback) MOZ_OVERRIDE
{
// Nothing to do
return true;
}
JSEP_CODEC_CLONE(JsepApplicationCodecDescription)
// Override, uses sctpmap instead of rtpmap
virtual bool
Matches(const std::string& fmt,
const SdpMediaSection& remoteMsection) const MOZ_OVERRIDE
{
auto& attrs = remoteMsection.GetAttributeList();
if (!attrs.HasAttribute(SdpAttribute::kSctpmapAttribute)) {
return false;
}
const SdpSctpmapAttributeList& sctpmap = attrs.GetSctpmap();
if (!sctpmap.HasEntry(fmt)) {
return false;
}
const SdpSctpmapAttributeList::Sctpmap& entry = sctpmap.GetEntry(fmt);
if (mType == remoteMsection.GetMediaType() && (mName == entry.name)) {
return true;
}
return false;
}
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,164 @@
/* 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 http://mozilla.org/MPL/2.0/. */
#ifndef _JSEPSESSION_H_
#define _JSEPSESSION_H_
#include <string>
#include <vector>
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsError.h"
#include "signaling/src/jsep/JsepTransport.h"
#include "signaling/src/sdp/Sdp.h"
namespace mozilla {
// Forward declarations
struct JsepCodecDescription;
class JsepTrack;
struct JsepTrackPair;
enum JsepSignalingState {
kJsepStateStable,
kJsepStateHaveLocalOffer,
kJsepStateHaveRemoteOffer,
kJsepStateHaveLocalPranswer,
kJsepStateHaveRemotePranswer,
kJsepStateClosed
};
enum JsepSdpType {
kJsepSdpOffer,
kJsepSdpAnswer,
kJsepSdpPranswer,
};
struct JsepOAOptions {};
struct JsepOfferOptions : public JsepOAOptions {
Maybe<size_t> mOfferToReceiveAudio;
Maybe<size_t> mOfferToReceiveVideo;
Maybe<bool> mDontOfferDataChannel;
};
struct JsepAnswerOptions : public JsepOAOptions {};
class JsepSession
{
public:
explicit JsepSession(const std::string& name)
: mName(name), mState(kJsepStateStable)
{
}
virtual ~JsepSession() {}
virtual nsresult Init() = 0;
// Accessors for basic properties.
virtual const std::string&
GetName() const
{
return mName;
}
virtual JsepSignalingState
GetState() const
{
return mState;
}
// Set up the ICE And DTLS data.
virtual nsresult SetIceCredentials(const std::string& ufrag,
const std::string& pwd) = 0;
virtual bool RemoteIsIceLite() const = 0;
virtual std::vector<std::string> GetIceOptions() const = 0;
virtual nsresult AddDtlsFingerprint(const std::string& algorithm,
const std::vector<uint8_t>& value) = 0;
virtual nsresult AddAudioRtpExtension(const std::string& extensionName) = 0;
virtual nsresult AddVideoRtpExtension(const std::string& extensionName) = 0;
// Kinda gross to be locking down the data structure type like this, but
// returning by value is problematic due to the lack of stl move semantics in
// our build config, since we can't use UniquePtr in the container. The
// alternative is writing a raft of accessor functions that allow arbitrary
// manipulation (which will be unwieldy), or allowing functors to be injected
// that manipulate the data structure (still pretty unwieldy).
virtual std::vector<JsepCodecDescription*>& Codecs() = 0;
// Manage tracks. We take shared ownership of any track.
virtual nsresult AddTrack(const RefPtr<JsepTrack>& track) = 0;
virtual nsresult RemoveTrack(size_t track_index) = 0;
virtual nsresult ReplaceTrack(size_t track_index,
const RefPtr<JsepTrack>& track) = 0;
virtual size_t GetLocalTrackCount() const = 0;
virtual nsresult GetLocalTrack(size_t index,
RefPtr<JsepTrack>* track) const = 0;
virtual size_t GetRemoteTrackCount() const = 0;
virtual nsresult GetRemoteTrack(size_t index,
RefPtr<JsepTrack>* track) const = 0;
// Access the negotiated track pairs.
virtual size_t GetNegotiatedTrackPairCount() const = 0;
virtual nsresult GetNegotiatedTrackPair(size_t index,
const JsepTrackPair** pair) const = 0;
// Access transports.
virtual size_t GetTransportCount() const = 0;
virtual nsresult GetTransport(size_t index,
RefPtr<JsepTransport>* transport) const = 0;
// Basic JSEP operations.
virtual nsresult CreateOffer(const JsepOfferOptions& options,
std::string* offer) = 0;
virtual nsresult CreateAnswer(const JsepAnswerOptions& options,
std::string* answer) = 0;
virtual std::string GetLocalDescription() const = 0;
virtual std::string GetRemoteDescription() const = 0;
virtual nsresult SetLocalDescription(JsepSdpType type,
const std::string& sdp) = 0;
virtual nsresult SetRemoteDescription(JsepSdpType type,
const std::string& sdp) = 0;
virtual nsresult AddRemoteIceCandidate(const std::string& candidate,
const std::string& mid,
uint16_t level) = 0;
virtual nsresult AddLocalIceCandidate(const std::string& candidate,
const std::string& mid,
uint16_t level) = 0;
virtual nsresult EndOfLocalCandidates(const std::string& defaultCandidateAddr,
uint16_t defaultCandidatePort,
uint16_t level) = 0;
virtual nsresult Close() = 0;
// ICE controlling or controlled
virtual bool IsIceControlling() const = 0;
virtual const std::string
GetLastError() const
{
return "Error";
}
static const char*
GetStateStr(JsepSignalingState state)
{
static const char* states[] = { "stable", "have-local-offer",
"have-remote-offer", "have-local-pranswer",
"have-remote-pranswer", "closed" };
return states[state];
}
protected:
const std::string mName;
JsepSignalingState mState;
};
} // namespace mozilla
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,302 @@
/* 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 http://mozilla.org/MPL/2.0/. */
#ifndef _JSEPSESSIONIMPL_H_
#define _JSEPSESSIONIMPL_H_
#include <string>
#include <vector>
#include "signaling/src/jsep/JsepCodecDescription.h"
#include "signaling/src/jsep/JsepTrack.h"
#include "signaling/src/jsep/JsepSession.h"
#include "signaling/src/jsep/JsepTrack.h"
#include "signaling/src/jsep/JsepTrackImpl.h"
#include "signaling/src/sdp/SipccSdpParser.h"
namespace mozilla {
class JsepUuidGenerator
{
public:
virtual ~JsepUuidGenerator() {}
virtual bool Generate(std::string* id) = 0;
};
class JsepSessionImpl : public JsepSession
{
public:
JsepSessionImpl(const std::string& name, UniquePtr<JsepUuidGenerator> uuidgen)
: JsepSession(name),
mIsOfferer(false),
mIceControlling(false),
mRemoteIsIceLite(false),
mSessionId(0),
mSessionVersion(0),
mUuidGen(Move(uuidgen))
{
}
virtual ~JsepSessionImpl();
// Implement JsepSession methods.
virtual nsresult Init() MOZ_OVERRIDE;
virtual nsresult AddTrack(const RefPtr<JsepTrack>& track) MOZ_OVERRIDE;
virtual nsresult
RemoveTrack(size_t trackIndex) MOZ_OVERRIDE
{
mLastError.clear();
MOZ_CRASH(); // Stub
}
virtual nsresult SetIceCredentials(const std::string& ufrag,
const std::string& pwd) MOZ_OVERRIDE;
virtual bool
RemoteIsIceLite() const MOZ_OVERRIDE
{
return mRemoteIsIceLite;
}
virtual std::vector<std::string>
GetIceOptions() const MOZ_OVERRIDE
{
return mIceOptions;
}
virtual nsresult AddDtlsFingerprint(const std::string& algorithm,
const std::vector<uint8_t>& value) MOZ_OVERRIDE;
virtual nsresult AddAudioRtpExtension(
const std::string& extensionName) MOZ_OVERRIDE;
virtual nsresult AddVideoRtpExtension(
const std::string& extensionName) MOZ_OVERRIDE;
virtual std::vector<JsepCodecDescription*>&
Codecs() MOZ_OVERRIDE
{
return mCodecs;
}
virtual nsresult
ReplaceTrack(size_t trackIndex, const RefPtr<JsepTrack>& track) MOZ_OVERRIDE
{
mLastError.clear();
MOZ_CRASH(); // Stub
}
virtual size_t
GetLocalTrackCount() const MOZ_OVERRIDE
{
return mLocalTracks.size();
}
virtual nsresult GetLocalTrack(size_t index,
RefPtr<JsepTrack>* track) const MOZ_OVERRIDE;
virtual size_t
GetRemoteTrackCount() const MOZ_OVERRIDE
{
return mRemoteTracks.size();
}
virtual nsresult GetRemoteTrack(size_t index,
RefPtr<JsepTrack>* track) const MOZ_OVERRIDE;
virtual nsresult CreateOffer(const JsepOfferOptions& options,
std::string* offer) MOZ_OVERRIDE;
virtual nsresult CreateAnswer(const JsepAnswerOptions& options,
std::string* answer) MOZ_OVERRIDE;
virtual std::string GetLocalDescription() const MOZ_OVERRIDE;
virtual std::string GetRemoteDescription() const MOZ_OVERRIDE;
virtual nsresult SetLocalDescription(JsepSdpType type,
const std::string& sdp) MOZ_OVERRIDE;
virtual nsresult SetRemoteDescription(JsepSdpType type,
const std::string& sdp) MOZ_OVERRIDE;
virtual nsresult AddRemoteIceCandidate(const std::string& candidate,
const std::string& mid,
uint16_t level) MOZ_OVERRIDE;
virtual nsresult AddLocalIceCandidate(const std::string& candidate,
const std::string& mid,
uint16_t level) MOZ_OVERRIDE;
virtual nsresult EndOfLocalCandidates(const std::string& defaultCandidateAddr,
uint16_t defaultCandidatePort,
uint16_t level) MOZ_OVERRIDE;
virtual nsresult Close() MOZ_OVERRIDE;
virtual const std::string GetLastError() const MOZ_OVERRIDE;
virtual bool
IsIceControlling() const
{
return mIceControlling;
}
virtual bool
IsOfferer() const
{
return mIsOfferer;
}
// Access transports.
virtual size_t
GetTransportCount() const MOZ_OVERRIDE
{
return mTransports.size();
}
virtual nsresult
GetTransport(size_t index,
RefPtr<JsepTransport>* transport) const MOZ_OVERRIDE
{
if (index >= mTransports.size())
return NS_ERROR_INVALID_ARG;
*transport = mTransports[index];
return NS_OK;
}
// Access the negotiated track pairs.
virtual size_t
GetNegotiatedTrackPairCount() const MOZ_OVERRIDE
{
return mNegotiatedTrackPairs.size();
}
virtual nsresult
GetNegotiatedTrackPair(size_t index, const JsepTrackPair** pair) const
{
if (index >= mNegotiatedTrackPairs.size())
return NS_ERROR_INVALID_ARG;
*pair = &mNegotiatedTrackPairs[index];
return NS_OK;
}
private:
struct JsepDtlsFingerprint {
std::string mAlgorithm;
std::vector<uint8_t> mValue;
};
struct JsepSendingTrack {
RefPtr<JsepTrack> mTrack;
Maybe<size_t> mAssignedMLine;
};
struct JsepReceivingTrack {
RefPtr<JsepTrack> mTrack;
Maybe<size_t> mAssignedMLine;
};
// Non-const so it can set mLastError
nsresult CreateGenericSDP(UniquePtr<Sdp>* sdp);
void AddCodecs(SdpMediaSection* msection) const;
void AddExtmap(SdpMediaSection* msection) const;
JsepCodecDescription* FindMatchingCodec(
const std::string& pt,
const SdpMediaSection& msection) const;
const std::vector<SdpExtmapAttributeList::Extmap>* GetRtpExtensions(
SdpMediaSection::MediaType type) const;
void AddCommonCodecs(const SdpMediaSection& remoteMsection,
SdpMediaSection* msection);
void AddCommonExtmaps(const SdpMediaSection& remoteMsection,
SdpMediaSection* msection);
void SetupDefaultCodecs();
void SetupDefaultRtpExtensions();
void SetState(JsepSignalingState state);
// Non-const so it can set mLastError
nsresult ParseSdp(const std::string& sdp, UniquePtr<Sdp>* parsedp);
nsresult SetLocalDescriptionOffer(UniquePtr<Sdp> offer);
nsresult SetLocalDescriptionAnswer(JsepSdpType type, UniquePtr<Sdp> answer);
nsresult SetRemoteDescriptionOffer(UniquePtr<Sdp> offer);
nsresult SetRemoteDescriptionAnswer(JsepSdpType type, UniquePtr<Sdp> answer);
nsresult ValidateLocalDescription(const Sdp& description);
nsresult SetRemoteTracksFromDescription(const Sdp& remoteDescription);
// Non-const because we use our Uuid generator
nsresult CreateReceivingTrack(size_t mline, const SdpMediaSection& msection);
nsresult HandleNegotiatedSession(const UniquePtr<Sdp>& local,
const UniquePtr<Sdp>& remote);
nsresult DetermineSendingDirection(SdpDirectionAttribute::Direction offer,
SdpDirectionAttribute::Direction answer,
bool* sending, bool* receiving);
nsresult AddTransportAttributes(SdpMediaSection* msection,
SdpSetupAttribute::Role dtlsRole);
// Non-const so it can assign m-line index to tracks
nsresult AddOfferMSectionsByType(SdpMediaSection::MediaType type,
Maybe<size_t> offerToReceive,
Sdp* sdp);
nsresult CreateOfferMSection(SdpMediaSection::MediaType type,
SdpDirectionAttribute::Direction direction,
SdpMediaSection::Protocol proto,
Sdp* sdp);
nsresult CreateAnswerMSection(const JsepAnswerOptions& options,
size_t mlineIndex,
const SdpMediaSection& remoteMsection,
SdpMediaSection* msection,
Sdp* sdp);
nsresult DetermineAnswererSetupRole(const SdpMediaSection& remoteMsection,
SdpSetupAttribute::Role* rolep);
nsresult NegotiateTrack(const SdpMediaSection& remoteMsection,
const SdpMediaSection& localMsection,
JsepTrack::Direction,
RefPtr<JsepTrack>* track);
nsresult CreateTransport(const SdpMediaSection& msection,
RefPtr<JsepTransport>* transport);
nsresult SetupTransport(const SdpAttributeList& remote,
const SdpAttributeList& answer,
const RefPtr<JsepTransport>& transport);
nsresult AddCandidateToSdp(Sdp* sdp,
const std::string& candidate,
const std::string& mid,
uint16_t level);
std::vector<JsepSendingTrack> mLocalTracks;
std::vector<JsepReceivingTrack> mRemoteTracks;
std::vector<RefPtr<JsepTransport> > mTransports;
std::vector<JsepTrackPair> mNegotiatedTrackPairs;
bool mIsOfferer;
bool mIceControlling;
std::string mIceUfrag;
std::string mIcePwd;
bool mRemoteIsIceLite;
std::vector<std::string> mIceOptions;
std::vector<JsepDtlsFingerprint> mDtlsFingerprints;
uint64_t mSessionId;
uint64_t mSessionVersion;
std::vector<SdpExtmapAttributeList::Extmap> mAudioRtpExtensions;
std::vector<SdpExtmapAttributeList::Extmap> mVideoRtpExtensions;
UniquePtr<JsepUuidGenerator> mUuidGen;
std::string mDefaultRemoteStreamId;
UniquePtr<Sdp> mGeneratedLocalDescription; // Created but not set.
UniquePtr<Sdp> mCurrentLocalDescription;
UniquePtr<Sdp> mCurrentRemoteDescription;
UniquePtr<Sdp> mPendingLocalDescription;
UniquePtr<Sdp> mPendingRemoteDescription;
std::vector<JsepCodecDescription*> mCodecs;
std::string mLastError;
SipccSdpParser mParser;
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,120 @@
/* 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 http://mozilla.org/MPL/2.0/. */
#ifndef _JSEPTRACK_H_
#define _JSEPTRACK_H_
#include <string>
#include <mozilla/RefPtr.h>
#include <mozilla/UniquePtr.h>
#include <mozilla/Maybe.h>
#include "nsISupportsImpl.h"
#include "nsError.h"
#include "signaling/src/jsep/JsepTransport.h"
#include "signaling/src/sdp/Sdp.h"
#include "signaling/src/sdp/SdpMediaSection.h"
namespace mozilla {
// Forward reference.
struct JsepCodecDescription;
class JsepTrackNegotiatedDetails
{
public:
virtual ~JsepTrackNegotiatedDetails() {}
virtual mozilla::SdpMediaSection::Protocol GetProtocol() const = 0;
virtual Maybe<std::string> GetBandwidth(const std::string& type) const = 0;
virtual size_t GetCodecCount() const = 0;
virtual nsresult GetCodec(size_t index,
const JsepCodecDescription** config) const = 0;
virtual const SdpExtmapAttributeList::Extmap* GetExt(
const std::string& ext_name) const = 0;
};
class JsepTrack
{
public:
enum Direction { kJsepTrackSending, kJsepTrackReceiving };
JsepTrack(mozilla::SdpMediaSection::MediaType type,
const std::string& streamid,
const std::string& trackid,
Direction direction = kJsepTrackSending)
: mType(type),
mStreamId(streamid),
mTrackId(trackid),
mDirection(direction)
{
}
virtual mozilla::SdpMediaSection::MediaType
GetMediaType() const
{
return mType;
}
virtual const std::string&
GetStreamId() const
{
return mStreamId;
}
virtual const std::string&
GetTrackId() const
{
return mTrackId;
}
virtual Direction
GetDirection() const
{
return mDirection;
}
// This will be set when negotiation is carried out.
virtual const JsepTrackNegotiatedDetails*
GetNegotiatedDetails() const
{
if (mNegotiatedDetails) {
return mNegotiatedDetails.get();
}
return nullptr;
}
// This is for JsepSession's use.
virtual void
SetNegotiatedDetails(UniquePtr<JsepTrackNegotiatedDetails> details)
{
mNegotiatedDetails = Move(details);
}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(JsepTrack);
protected:
virtual ~JsepTrack() {}
private:
const mozilla::SdpMediaSection::MediaType mType;
const std::string mStreamId;
const std::string mTrackId;
const Direction mDirection;
UniquePtr<JsepTrackNegotiatedDetails> mNegotiatedDetails;
};
// Need a better name for this.
struct JsepTrackPair {
size_t mLevel;
RefPtr<JsepTrack> mSending;
RefPtr<JsepTrack> mReceiving;
RefPtr<JsepTransport> mRtpTransport;
RefPtr<JsepTransport> mRtcpTransport;
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,79 @@
/* 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 http://mozilla.org/MPL/2.0/. */
#ifndef _JSEPTRACKIMPL_H_
#define _JSEPTRACKIMPL_H_
#include <map>
#include <mozilla/RefPtr.h>
#include <mozilla/UniquePtr.h>
#include "signaling/src/jsep/JsepCodecDescription.h"
#include "signaling/src/jsep/JsepTrack.h"
#include "signaling/src/sdp/Sdp.h"
#include "signaling/src/sdp/SdpMediaSection.h"
namespace mozilla {
class JsepTrackNegotiatedDetailsImpl : public JsepTrackNegotiatedDetails
{
public:
virtual ~JsepTrackNegotiatedDetailsImpl()
{
for (auto c = mCodecs.begin(); c != mCodecs.end(); ++c) {
delete *c;
}
}
// Implement JsepTrackNegotiatedDetails.
virtual mozilla::SdpMediaSection::Protocol
GetProtocol() const MOZ_OVERRIDE
{
return mProtocol;
}
virtual Maybe<std::string>
GetBandwidth(const std::string& type) const MOZ_OVERRIDE
{
return mBandwidth;
}
virtual size_t
GetCodecCount() const MOZ_OVERRIDE
{
return mCodecs.size();
}
virtual nsresult
GetCodec(size_t index, const JsepCodecDescription** config) const MOZ_OVERRIDE
{
if (index >= mCodecs.size()) {
return NS_ERROR_INVALID_ARG;
}
*config = mCodecs[index];
return NS_OK;
}
virtual const SdpExtmapAttributeList::Extmap*
GetExt(const std::string& ext_name) const MOZ_OVERRIDE
{
auto it = mExtmap.find(ext_name);
if (it != mExtmap.end()) {
return &it->second;
}
return nullptr;
}
private:
// Make these friends to JsepSessionImpl to avoid having to
// write setters.
friend class JsepSessionImpl;
mozilla::SdpMediaSection::Protocol mProtocol;
Maybe<std::string> mBandwidth;
std::vector<JsepCodecDescription*> mCodecs;
std::map<std::string, SdpExtmapAttributeList::Extmap> mExtmap;
};
} // namespace mozilla
#endif

View File

@ -0,0 +1,117 @@
/* 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 http://mozilla.org/MPL/2.0/. */
#ifndef _JSEPTRANSPORT_H_
#define _JSEPTRANSPORT_H_
#include <string>
#include <vector>
#include <mozilla/RefPtr.h>
#include <mozilla/UniquePtr.h>
#include "nsISupportsImpl.h"
#include "signaling/src/sdp/SdpAttribute.h"
namespace mozilla {
class JsepDtlsTransport
{
public:
JsepDtlsTransport() : mRole(kJsepDtlsInvalidRole) {}
virtual ~JsepDtlsTransport() {}
enum Role {
kJsepDtlsClient,
kJsepDtlsServer,
kJsepDtlsInvalidRole
};
virtual const SdpFingerprintAttributeList&
GetFingerprints() const
{
return mFingerprints;
}
virtual Role
GetRole() const
{
return mRole;
}
private:
friend class JsepSessionImpl;
SdpFingerprintAttributeList mFingerprints;
Role mRole;
};
class JsepIceTransport
{
public:
JsepIceTransport() {}
virtual ~JsepIceTransport() {}
const std::string&
GetUfrag() const
{
return mUfrag;
}
const std::string&
GetPassword() const
{
return mPwd;
}
const std::vector<std::string>&
GetCandidates() const
{
return mCandidates;
}
private:
friend class JsepSessionImpl;
std::string mUfrag;
std::string mPwd;
std::vector<std::string> mCandidates;
};
class JsepTransport
{
public:
JsepTransport(const std::string& id, size_t components)
: mTransportId(id), mState(kJsepTransportOffered), mComponents(components)
{
}
enum State {
kJsepTransportOffered,
kJsepTransportAccepted,
kJsepTransportClosed
};
// Unique identifier for this transport within this call. Group?
std::string mTransportId;
// State.
State mState;
// ICE stuff.
UniquePtr<JsepIceTransport> mIce;
UniquePtr<JsepDtlsTransport> mDtls;
// Number of required components.
size_t mComponents;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(JsepTransport);
protected:
~JsepTransport() {}
};
} // namespace mozilla
#endif

File diff suppressed because it is too large Load Diff