Bug 1017888 - Part 1: Renegotiation support. r=mt, r=smaug

--HG--
extra : rebase_source : df1c2962ee88f75c6ad676b9cd79978a87dafb65
extra : amend_source : c938904331323ff3565624795ac76d82502f43fb
This commit is contained in:
Byron Campen [:bwc] 2014-12-10 15:53:54 -08:00
parent 03913d3a48
commit 1f815978b4
34 changed files with 2240 additions and 1147 deletions

View File

@ -805,9 +805,8 @@ RTCPeerConnection.prototype = {
},
removeTrack: function(sender) {
// Bug 844295: Not implementing this functionality.
throw new this._win.DOMException("removeTrack not yet implemented",
"NotSupportedError");
this._checkClosed();
this._impl.removeTrack(sender.track);
},
_replaceTrack: function(sender, withTrack) {
@ -1115,6 +1114,10 @@ PeerConnectionObserver.prototype = {
}
},
onNegotiationNeeded: function() {
this.dispatchEvent(new this._win.Event("negotiationneeded"));
},
// This method is primarily responsible for updating iceConnectionState.
// This state is defined in the WebRTC specification as follows:

View File

@ -150,8 +150,7 @@ skip-if = (toolkit == 'gonk' || (e10s && debug)) # b2g (Bug 1059867) or fd exhau
skip-if = (toolkit == 'gonk' || (e10s && debug)) # b2g (Bug 1059867) or fd exhaustion on e10s debug intermittent (Bug 1126078)
[test_peerConnection_twoVideoStreams.html]
skip-if = (toolkit == 'gonk' || (e10s && debug)) # b2g (Bug 1059867) or fd exhaustion on e10s debug intermittent (Bug 1126078)
# Renegotiation is not yet supported (bug 1017888)
#[test_peerConnection_addSecondAudioStream.html]
[test_peerConnection_addSecondAudioStream.html]
# Bug 950317: Hack for making a cleanup hook after finishing all WebRTC cases
[test_zmedia_cleanup.html]

View File

@ -23,6 +23,7 @@ interface PeerConnectionObserver
void onAddIceCandidateSuccess();
void onAddIceCandidateError(unsigned long name, DOMString message);
void onIceCandidate(unsigned short level, DOMString mid, DOMString candidate);
void onNegotiationNeeded();
/* Stats callbacks */
void onGetStatsSuccess(optional RTCStatsReportInternal report);
@ -40,7 +41,7 @@ interface PeerConnectionObserver
/* Changes to MediaStreamTracks */
void onAddStream(MediaStream stream);
void onRemoveStream();
void onRemoveStream(MediaStream stream);
void onAddTrack(MediaStreamTrack track);
void onRemoveTrack();
void onRemoveTrack(MediaStreamTrack track);
};

View File

@ -366,8 +366,10 @@ void NrIceCtx::trickle_cb(void *arg, nr_ice_ctx *ice_ctx,
NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
// Streams which do not exist shouldn't have candidates.
MOZ_ASSERT(s);
if (!s) {
// This stream has been removed because it is inactive
return;
}
// Format the candidate.
char candidate_str[NR_ICE_MAX_ATTRIBUTE_SIZE];
@ -668,32 +670,26 @@ abort:
nsresult NrIceCtx::StartGathering() {
ASSERT_ON_THREAD(sts_target_);
MOZ_ASSERT(connection_state_ == ICE_CTX_INIT);
if (connection_state_ != ICE_CTX_INIT) {
MOZ_MTLOG(ML_ERROR, "ICE ctx in the wrong state for gathering: '"
<< name_ << "' state: " << connection_state_);
// This might start gathering for the first time, or again after
// renegotiation, or might do nothing at all if gathering has already
// finished.
int r = nr_ice_gather(ctx_, &NrIceCtx::gather_cb, this);
if (r && (r != R_WOULDBLOCK)) {
MOZ_MTLOG(ML_ERROR, "Couldn't gather ICE candidates for '"
<< name_ << "', error=" << r);
SetConnectionState(ICE_CTX_FAILED);
return NS_ERROR_FAILURE;
}
int r = nr_ice_initialize(ctx_, &NrIceCtx::initialized_cb, this);
if (r && r != R_WOULDBLOCK) {
MOZ_MTLOG(ML_ERROR, "Couldn't gather ICE candidates for '"
<< name_ << "'");
SetConnectionState(ICE_CTX_FAILED);
return NS_ERROR_FAILURE;
}
SetGatheringState(ICE_CTX_GATHER_STARTED);
return NS_OK;
}
RefPtr<NrIceMediaStream> NrIceCtx::FindStream(
nr_ice_media_stream *stream) {
for (size_t i=0; i<streams_.size(); ++i) {
if (streams_[i]->stream() == stream) {
if (streams_[i] && (streams_[i]->stream() == stream)) {
return streams_[i];
}
}
@ -771,7 +767,7 @@ nsresult NrIceCtx::StartChecks() {
}
void NrIceCtx::initialized_cb(NR_SOCKET s, int h, void *arg) {
void NrIceCtx::gather_cb(NR_SOCKET s, int h, void *arg) {
NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
ctx->SetGatheringState(ICE_CTX_GATHER_COMPLETE);

View File

@ -225,7 +225,7 @@ class NrIceCtx {
// Create a media stream
RefPtr<NrIceMediaStream> CreateStream(const std::string& name,
int components);
int components);
RefPtr<NrIceMediaStream> GetStream(size_t index) {
if (index < streams_.size()) {
@ -234,6 +234,11 @@ class NrIceCtx {
return nullptr;
}
void RemoveStream(size_t index)
{
streams_[index] = nullptr;
}
// The name of the ctx
const std::string& name() const { return name_; }
@ -325,7 +330,7 @@ class NrIceCtx {
DISALLOW_COPY_ASSIGN(NrIceCtx);
// Callbacks for nICEr
static void initialized_cb(NR_SOCKET s, int h, void *arg); // ICE initialized
static void gather_cb(NR_SOCKET s, int h, void *arg); // ICE gather complete
// Handler implementation
static int select_pair(void *obj,nr_ice_media_stream *stream,

View File

@ -209,6 +209,7 @@ nsresult NrIceMediaStream::ParseAttributes(std::vector<std::string>&
return NS_ERROR_FAILURE;
}
has_parsed_attrs_ = true;
return NS_OK;
}

View File

@ -142,6 +142,7 @@ class NrIceMediaStream {
// Parse remote attributes
nsresult ParseAttributes(std::vector<std::string>& candidates);
bool HasParsedAttributes() const { return has_parsed_attrs_; }
// Parse trickle ICE candidate
nsresult ParseTrickleCandidate(const std::string& candidate);
@ -198,7 +199,8 @@ class NrIceMediaStream {
name_(name),
components_(components),
stream_(nullptr),
level_(0) {}
level_(0),
has_parsed_attrs_(false) {}
~NrIceMediaStream();
@ -210,6 +212,7 @@ class NrIceMediaStream {
const size_t components_;
nr_ice_media_stream *stream_;
uint16_t level_;
bool has_parsed_attrs_;
};

View File

@ -265,7 +265,7 @@ class IceTestPeer : public sigslot::has_slots<> {
PR_Sleep(1000);
}
void AddStream(int components) {
void AddStream_s(int components) {
char name[100];
snprintf(name, sizeof(name), "%s:stream%d", name_.c_str(),
(int)streams_.size());
@ -281,6 +281,14 @@ class IceTestPeer : public sigslot::has_slots<> {
stream->SignalPacketReceived.connect(this, &IceTestPeer::PacketReceived);
}
void AddStream(int components)
{
test_utils->sts_target()->Dispatch(WrapRunnable(this,
&IceTestPeer::AddStream_s,
components),
NS_DISPATCH_SYNC);
}
void SetStunServer(const std::string addr, uint16_t port) {
if (addr.empty()) {
// Happens when MOZ_DISABLE_NONLOCAL_CONNECTIONS is set
@ -410,9 +418,17 @@ class IceTestPeer : public sigslot::has_slots<> {
bool gathering_complete() { return gathering_complete_; }
int ready_ct() { return ready_ct_; }
bool is_ready(size_t stream) {
bool is_ready_s(size_t stream) {
return streams_[stream]->state() == NrIceMediaStream::ICE_OPEN;
}
bool is_ready(size_t stream)
{
bool result;
test_utils->sts_target()->Dispatch(
WrapRunnableRet(this, &IceTestPeer::is_ready_s, stream, &result),
NS_DISPATCH_SYNC);
return result;
}
bool ice_complete() { return ice_complete_; }
bool ice_reached_checking() { return ice_reached_checking_; }
size_t received() { return received_; }
@ -426,12 +442,16 @@ class IceTestPeer : public sigslot::has_slots<> {
remote_ = remote;
trickle_mode_ = trickle_mode;
ice_complete_ = false;
res = ice_ctx_->ParseGlobalAttributes(remote->GetGlobalAttributes());
ASSERT_TRUE(NS_SUCCEEDED(res));
if (trickle_mode == TRICKLE_NONE ||
trickle_mode == TRICKLE_REAL) {
for (size_t i=0; i<streams_.size(); ++i) {
if (streams_[i]->HasParsedAttributes()) {
continue;
}
std::vector<std::string> candidates =
remote->GetCandidates(i);
@ -444,7 +464,11 @@ class IceTestPeer : public sigslot::has_slots<> {
} else {
// Parse empty attributes and then trickle them out later
for (size_t i=0; i<streams_.size(); ++i) {
if (streams_[i]->HasParsedAttributes()) {
continue;
}
std::vector<std::string> empty_attrs;
std::cout << "Calling ParseAttributes on stream " << i << std::endl;
res = streams_[i]->ParseAttributes(empty_attrs);
ASSERT_TRUE(NS_SUCCEEDED(res));
}
@ -470,6 +494,8 @@ class IceTestPeer : public sigslot::has_slots<> {
// If we are in trickle deferred mode, now trickle in the candidates
// for |stream|
// The size of streams_ is not going to change out from under us, so should
// be safe here.
ASSERT_GT(remote_->streams_.size(), stream);
std::vector<SchedulableTrickleCandidate*>& candidates =
@ -602,6 +628,16 @@ class IceTestPeer : public sigslot::has_slots<> {
}
ice_ctx_ = nullptr;
if (remote_) {
remote_->UnsetRemote();
remote_ = nullptr;
}
}
void UnsetRemote()
{
remote_ = nullptr;
}
void StartChecks() {
@ -649,7 +685,7 @@ class IceTestPeer : public sigslot::has_slots<> {
// If we are connected, then try to trickle to the
// other side.
if (remote_ && remote_->remote_) {
if (remote_ && remote_->remote_ && (trickle_mode_ != TRICKLE_SIMULATE)) {
std::vector<mozilla::RefPtr<NrIceMediaStream> >::iterator it =
std::find(streams_.begin(), streams_.end(), stream);
ASSERT_NE(streams_.end(), it);
@ -663,8 +699,9 @@ class IceTestPeer : public sigslot::has_slots<> {
}
}
nsresult GetCandidatePairs(size_t stream_index,
std::vector<NrIceCandidatePair>* pairs) {
nsresult GetCandidatePairs_s(size_t stream_index,
std::vector<NrIceCandidatePair>* pairs)
{
MOZ_ASSERT(pairs);
if (stream_index >= streams_.size()) {
// Is there a better error for "no such index"?
@ -672,14 +709,20 @@ class IceTestPeer : public sigslot::has_slots<> {
return NS_ERROR_INVALID_ARG;
}
nsresult res;
return streams_[stream_index]->GetCandidatePairs(pairs);
}
nsresult GetCandidatePairs(size_t stream_index,
std::vector<NrIceCandidatePair>* pairs) {
nsresult v;
test_utils->sts_target()->Dispatch(
WrapRunnableRet(streams_[stream_index],
&NrIceMediaStream::GetCandidatePairs,
WrapRunnableRet(this,
&IceTestPeer::GetCandidatePairs_s,
stream_index,
pairs,
&res),
&v),
NS_DISPATCH_SYNC);
return res;
return v;
}
void DumpCandidatePair(const NrIceCandidatePair& pair) {
@ -693,7 +736,7 @@ class IceTestPeer : public sigslot::has_slots<> {
<< " codeword = " << pair.codeword << std::endl;
}
void DumpCandidatePairs(NrIceMediaStream *stream) {
void DumpCandidatePairs_s(NrIceMediaStream *stream) {
std::vector<NrIceCandidatePair> pairs;
nsresult res = stream->GetCandidatePairs(&pairs);
ASSERT_TRUE(NS_SUCCEEDED(res));
@ -707,10 +750,10 @@ class IceTestPeer : public sigslot::has_slots<> {
std::cerr << "]" << std::endl;
}
void DumpCandidatePairs() {
void DumpCandidatePairs_s() {
std::cerr << "Dumping candidate pairs for all streams [" << std::endl;
for (size_t s = 0; s < streams_.size(); ++s) {
DumpCandidatePairs(streams_[s]);
DumpCandidatePairs_s(streams_[s]);
}
std::cerr << "]" << std::endl;
}
@ -790,11 +833,11 @@ class IceTestPeer : public sigslot::has_slots<> {
void StreamReady(NrIceMediaStream *stream) {
++ready_ct_;
std::cerr << "Stream ready " << stream->name() << " ct=" << ready_ct_ << std::endl;
DumpCandidatePairs(stream);
DumpCandidatePairs_s(stream);
}
void StreamFailed(NrIceMediaStream *stream) {
std::cerr << "Stream failed " << stream->name() << " ct=" << ready_ct_ << std::endl;
DumpCandidatePairs(stream);
DumpCandidatePairs_s(stream);
}
void ConnectionStateChange(NrIceCtx* ctx,
@ -834,20 +877,40 @@ class IceTestPeer : public sigslot::has_slots<> {
candidate_filter_ = filter;
}
// Allow us to parse candidates directly on the current thread.
void ParseCandidate(size_t i, const std::string& candidate) {
void ParseCandidate_s(size_t i, const std::string& candidate) {
std::vector<std::string> attributes;
attributes.push_back(candidate);
streams_[i]->ParseAttributes(attributes);
}
void DisableComponent(size_t stream, int component_id) {
// Allow us to parse candidates directly on the current thread.
void ParseCandidate(size_t i, const std::string& candidate)
{
test_utils->sts_target()->Dispatch(
WrapRunnable(this,
&IceTestPeer::ParseCandidate_s,
i,
candidate),
NS_DISPATCH_SYNC);
}
void DisableComponent_s(size_t stream, int component_id) {
ASSERT_LT(stream, streams_.size());
nsresult res = streams_[stream]->DisableComponent(component_id);
ASSERT_TRUE(NS_SUCCEEDED(res));
}
void DisableComponent(size_t stream, int component_id)
{
test_utils->sts_target()->Dispatch(
WrapRunnable(this,
&IceTestPeer::DisableComponent_s,
stream,
component_id),
NS_DISPATCH_SYNC);
}
int trickled() { return trickled_; }
void SetControlling(NrIceCtx::Controlling controlling) {
@ -1612,6 +1675,64 @@ TEST_F(IceConnectTest, TestConnectTrickleTwoStreamsOneComponent) {
AssertCheckingReached();
}
void RealisticTrickleDelay(
std::vector<SchedulableTrickleCandidate*>& candidates) {
for (size_t i = 0; i < candidates.size(); ++i) {
SchedulableTrickleCandidate* cand = candidates[i];
if (cand->IsHost()) {
cand->Schedule(i*10);
} else if (cand->IsReflexive()) {
cand->Schedule(i*10 + 100);
} else if (cand->IsRelay()) {
cand->Schedule(i*10 + 200);
}
}
}
void DelayRelayCandidates(
std::vector<SchedulableTrickleCandidate*>& candidates,
unsigned int ms) {
for (auto i = candidates.begin(); i != candidates.end(); ++i) {
if ((*i)->IsRelay()) {
(*i)->Schedule(ms);
} else {
(*i)->Schedule(0);
}
}
}
TEST_F(IceConnectTest, TestConnectTrickleAddStreamDuringICE) {
AddStream("first", 1);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(0));
RealisticTrickleDelay(p2_->ControlTrickle(0));
AddStream("second", 1);
RealisticTrickleDelay(p1_->ControlTrickle(1));
RealisticTrickleDelay(p2_->ControlTrickle(1));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
AssertCheckingReached();
}
TEST_F(IceConnectTest, TestConnectTrickleAddStreamAfterICE) {
AddStream("first", 1);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(0));
RealisticTrickleDelay(p2_->ControlTrickle(0));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
AddStream("second", 1);
ASSERT_TRUE(Gather());
ConnectTrickle();
RealisticTrickleDelay(p1_->ControlTrickle(1));
RealisticTrickleDelay(p2_->ControlTrickle(1));
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
AssertCheckingReached();
}
TEST_F(IceConnectTest, TestConnectRealTrickleOneStreamOneComponent) {
AddStream("first", 1);
AddStream("second", 1);
@ -1657,32 +1778,6 @@ TEST_F(IceConnectTest, TestConnectTurnWithDelay) {
WaitForComplete();
}
void RealisticTrickleDelay(
std::vector<SchedulableTrickleCandidate*>& candidates) {
for (size_t i = 0; i < candidates.size(); ++i) {
SchedulableTrickleCandidate* cand = candidates[i];
if (cand->IsHost()) {
cand->Schedule(i*10);
} else if (cand->IsReflexive()) {
cand->Schedule(i*10 + 100);
} else if (cand->IsRelay()) {
cand->Schedule(i*10 + 200);
}
}
}
void DelayRelayCandidates(
std::vector<SchedulableTrickleCandidate*>& candidates,
unsigned int ms) {
for (auto i = candidates.begin(); i != candidates.end(); ++i) {
if ((*i)->IsRelay()) {
(*i)->Schedule(ms);
} else {
(*i)->Schedule(0);
}
}
}
TEST_F(IceConnectTest, TestConnectTurnWithNormalTrickleDelay) {
if (g_turn_server.empty())
return;

View File

@ -239,7 +239,7 @@ static int nr_ice_component_initialize_udp(struct nr_ice_ctx_ *ctx,nr_ice_compon
&ctx->turn_servers[j].turn_server,component->component_id,&cand))
ABORT(r);
cand->state=NR_ICE_CAND_STATE_INITIALIZING; /* Don't start */
cand->done_cb=nr_ice_initialize_finished_cb;
cand->done_cb=nr_ice_gather_finished_cb;
cand->cb_arg=cand;
TAILQ_INSERT_TAIL(&component->candidates,cand,entry_comp);
@ -393,6 +393,11 @@ int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *compon
Data pwd;
nr_ice_candidate *cand;
if (component->candidate_ct) {
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): component with id %d already has candidates, probably restarting gathering because of a new stream",ctx->label,component->component_id);
return(0);
}
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): initializing component with id %d",ctx->label,component->component_id);
if(addr_ct==0){
@ -435,7 +440,7 @@ int nr_ice_component_initialize(struct nr_ice_ctx_ *ctx,nr_ice_component *compon
cand=TAILQ_FIRST(&component->candidates);
while(cand){
if(cand->state!=NR_ICE_CAND_STATE_INITIALIZING){
if(r=nr_ice_candidate_initialize(cand,nr_ice_initialize_finished_cb,cand)){
if(r=nr_ice_candidate_initialize(cand,nr_ice_gather_finished_cb,cand)){
if(r!=R_WOULDBLOCK){
ctx->uninitialized_candidates--;
cand->state=NR_ICE_CAND_STATE_FAILED;

View File

@ -157,7 +157,7 @@ int nr_ice_ctx_set_turn_servers(nr_ice_ctx *ctx,nr_ice_turn_server *servers,int
return(_status);
}
int nr_ice_ctx_set_local_addrs(nr_ice_ctx *ctx,nr_local_addr *addrs,int ct)
static int nr_ice_ctx_set_local_addrs(nr_ice_ctx *ctx,nr_local_addr *addrs,int ct)
{
int _status,i,r;
@ -300,6 +300,7 @@ int nr_ice_fetch_turn_servers(int ct, nr_ice_turn_server **out)
}
#endif /* USE_TURN */
#define MAXADDRS 100 // Ridiculously high
int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp)
{
nr_ice_ctx *ctx=0;
@ -457,9 +458,9 @@ int nr_ice_ctx_destroy(nr_ice_ctx **ctxp)
return(0);
}
void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg)
void nr_ice_gather_finished_cb(NR_SOCKET s, int h, void *cb_arg)
{
int r,_status;
int r;
nr_ice_candidate *cand=cb_arg;
nr_ice_ctx *ctx;
@ -497,7 +498,6 @@ void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg)
if(ctx->uninitialized_candidates==0){
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): All candidates initialized",ctx->label);
ctx->state=NR_ICE_STATE_INITIALIZED;
if (ctx->done_cb) {
ctx->done_cb(0,0,ctx->cb_arg);
}
@ -532,47 +532,47 @@ static int nr_ice_ctx_pair_new_trickle_candidates(nr_ice_ctx *ctx, nr_ice_candid
}
#define MAXADDRS 100 // Ridiculously high
int nr_ice_initialize(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg)
int nr_ice_gather(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg)
{
int r,_status;
nr_ice_media_stream *stream;
nr_local_addr addrs[MAXADDRS];
int i,addr_ct;
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Initializing candidates",ctx->label);
ctx->state=NR_ICE_STATE_INITIALIZING;
ctx->done_cb=done_cb;
ctx->cb_arg=cb_arg;
if (!ctx->local_addrs) {
/* First, gather all the local addresses we have */
if(r=nr_stun_find_local_addresses(addrs,MAXADDRS,&addr_ct)) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to find local addresses",ctx->label);
ABORT(r);
}
/* Sort interfaces by preference */
if(ctx->interface_prioritizer) {
for(i=0;i<addr_ct;i++){
if(r=nr_interface_prioritizer_add_interface(ctx->interface_prioritizer,addrs+i)) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to add interface ",ctx->label);
ABORT(r);
}
}
if(r=nr_interface_prioritizer_sort_preference(ctx->interface_prioritizer)) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to sort interface by preference",ctx->label);
ABORT(r);
}
}
if (r=nr_ice_ctx_set_local_addrs(ctx,addrs,addr_ct)) {
ABORT(r);
}
}
if(STAILQ_EMPTY(&ctx->streams)) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s): Missing streams to initialize",ctx->label);
ABORT(R_BAD_ARGS);
}
/* First, gather all the local addresses we have */
if(r=nr_stun_find_local_addresses(addrs,MAXADDRS,&addr_ct)) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to find local addresses",ctx->label);
ABORT(r);
}
/* Sort interfaces by preference */
if(ctx->interface_prioritizer) {
for(i=0;i<addr_ct;i++){
if(r=nr_interface_prioritizer_add_interface(ctx->interface_prioritizer,addrs+i)) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to add interface ",ctx->label);
ABORT(r);
}
}
if(r=nr_interface_prioritizer_sort_preference(ctx->interface_prioritizer)) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s): unable to sort interface by preference",ctx->label);
ABORT(r);
}
}
if (r=nr_ice_ctx_set_local_addrs(ctx,addrs,addr_ct)) {
ABORT(r);
}
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Initializing candidates",ctx->label);
ctx->done_cb=done_cb;
ctx->cb_arg=cb_arg;
/* Initialize all the media stream/component pairs */
stream=STAILQ_FIRST(&ctx->streams);
@ -586,7 +586,6 @@ int nr_ice_initialize(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg)
if(ctx->uninitialized_candidates)
ABORT(R_WOULDBLOCK);
_status=0;
abort:
return(_status);

View File

@ -113,10 +113,6 @@ typedef STAILQ_HEAD(nr_ice_stun_id_head_,nr_ice_stun_id_) nr_ice_stun_id_head;
struct nr_ice_ctx_ {
UINT4 flags;
int state;
#define NR_ICE_STATE_CREATED 1
#define NR_ICE_STATE_INITIALIZING 2
#define NR_ICE_STATE_INITIALIZED 3
char *label;
char *ufrag;
@ -162,9 +158,9 @@ int nr_ice_ctx_create(char *label, UINT4 flags, nr_ice_ctx **ctxp);
#define NR_ICE_CTX_FLAGS_LITE (1<<3)
int nr_ice_ctx_destroy(nr_ice_ctx **ctxp);
int nr_ice_initialize(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg);
int nr_ice_gather(nr_ice_ctx *ctx, NR_async_cb done_cb, void *cb_arg);
int nr_ice_add_candidate(nr_ice_ctx *ctx, nr_ice_candidate *cand);
void nr_ice_initialize_finished_cb(NR_SOCKET s, int h, void *cb_arg);
void nr_ice_gather_finished_cb(NR_SOCKET s, int h, void *cb_arg);
int nr_ice_add_media_stream(nr_ice_ctx *ctx,char *label,int components, nr_ice_media_stream **streamp);
int nr_ice_get_global_attributes(nr_ice_ctx *ctx,char ***attrsp, int *attrctp);
int nr_ice_ctx_deliver_packet(nr_ice_ctx *ctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len);

View File

@ -627,7 +627,7 @@ int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_c
}
/* Now tell the peer_ctx that we're done */
if(r=nr_ice_peer_ctx_stream_done(stream->pctx,stream))
if(r=nr_ice_peer_ctx_check_if_done(stream->pctx))
ABORT(r);
done:
@ -668,7 +668,7 @@ int nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_comp
}
/* Now tell the peer_ctx that we're done */
if(r=nr_ice_peer_ctx_stream_done(stream->pctx,stream))
if(r=nr_ice_peer_ctx_check_if_done(stream->pctx))
ABORT(r);
_status=0;

View File

@ -348,6 +348,11 @@ static void nr_ice_peer_ctx_start_trickle_timer(nr_ice_peer_ctx *pctx)
{
UINT4 grace_period_timeout=0;
if(pctx->trickle_grace_period_timer) {
NR_async_timer_cancel(pctx->trickle_grace_period_timer);
pctx->trickle_grace_period_timer=0;
}
NR_reg_get_uint4(NR_ICE_REG_TRICKLE_GRACE_PERIOD,&grace_period_timeout);
if (grace_period_timeout) {
@ -506,27 +511,47 @@ int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first)
nr_ice_media_stream *stream;
int started = 0;
/* Might have added some streams */
pctx->reported_done = 0;
NR_async_timer_cancel(pctx->done_cb_timer);
pctx->done_cb_timer = 0;
pctx->checks_started = 0;
if((r=nr_ice_peer_ctx_check_if_done(pctx))) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) initial done check failed",pctx->ctx->label,pctx->label);
ABORT(r);
}
if (pctx->reported_done) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) in %s all streams were done",pctx->ctx->label,pctx->label,__FUNCTION__);
return (0);
}
stream=STAILQ_FIRST(&pctx->peer_streams);
if(!stream)
ABORT(R_FAILED);
while (stream) {
if(!TAILQ_EMPTY(&stream->check_list))
break;
assert(stream->ice_state != NR_ICE_MEDIA_STREAM_UNPAIRED);
if(!allow_non_first){
/* This test applies if:
if (stream->ice_state == NR_ICE_MEDIA_STREAM_CHECKS_FROZEN) {
if(!TAILQ_EMPTY(&stream->check_list))
break;
1. allow_non_first is 0 (i.e., non-trickle ICE)
2. the first stream has an empty check list.
if(!allow_non_first){
/* This test applies if:
But in the non-trickle ICE case, the other side should have provided
some candidates or ICE is pretty much not going to work and we're
just going to fail. Hence R_FAILED as opposed to R_NOT_FOUND and
immediate termination here.
*/
r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) first stream has empty check list",pctx->ctx->label,pctx->label);
ABORT(R_FAILED);
1. allow_non_first is 0 (i.e., non-trickle ICE)
2. the first stream has an empty check list.
But in the non-trickle ICE case, the other side should have provided
some candidates or ICE is pretty much not going to work and we're
just going to fail. Hence R_FAILED as opposed to R_NOT_FOUND and
immediate termination here.
*/
r_log(LOG_ICE,LOG_ERR,"ICE(%s): peer (%s) first stream has empty check list",pctx->ctx->label,pctx->label);
ABORT(R_FAILED);
}
}
stream=STAILQ_NEXT(stream, entry);
@ -620,9 +645,9 @@ static void nr_ice_peer_ctx_fire_done(NR_SOCKET s, int how, void *cb_arg)
}
}
/* OK, a stream just went ready. Examine all the streams to see if we're
/* Examine all the streams to see if we're
maybe miraculously done */
int nr_ice_peer_ctx_stream_done(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream)
int nr_ice_peer_ctx_check_if_done(nr_ice_peer_ctx *pctx)
{
int _status;
nr_ice_media_stream *str;

View File

@ -84,7 +84,7 @@ int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first);
void nr_ice_peer_ctx_stream_started_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream);
int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out);
int nr_ice_peer_ctx_log_state(nr_ice_peer_ctx *pctx);
int nr_ice_peer_ctx_stream_done(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream);
int nr_ice_peer_ctx_check_if_done(nr_ice_peer_ctx *pctx);
int nr_ice_peer_ctx_find_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component_id, nr_ice_component **compp);
int nr_ice_peer_ctx_deliver_packet_maybe(nr_ice_peer_ctx *pctx, nr_ice_component *comp, nr_transport_addr *source_addr, UCHAR *data, int len);
int nr_ice_peer_ctx_disable_component(nr_ice_peer_ctx *pctx, nr_ice_media_stream *lstream, int component_id);

View File

@ -91,27 +91,24 @@ public:
// 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 RemoveTrack(const std::string& streamId,
const std::string& trackId) = 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 std::vector<RefPtr<JsepTrack>> GetLocalTracks() const = 0;
virtual size_t GetRemoteTrackCount() const = 0;
virtual nsresult GetRemoteTrack(size_t index,
RefPtr<JsepTrack>* track) const = 0;
virtual std::vector<RefPtr<JsepTrack>> GetRemoteTracks() const = 0;
virtual std::vector<RefPtr<JsepTrack>> GetRemoteTracksAdded() const = 0;
virtual std::vector<RefPtr<JsepTrack>> GetRemoteTracksRemoved() const = 0;
// Access the negotiated track pairs.
virtual size_t GetNegotiatedTrackPairCount() const = 0;
virtual nsresult GetNegotiatedTrackPair(size_t index,
const JsepTrackPair** pair) const = 0;
virtual std::vector<JsepTrackPair> GetNegotiatedTrackPairs() const = 0;
// Access transports.
virtual size_t GetTransportCount() const = 0;
virtual nsresult GetTransport(size_t index,
RefPtr<JsepTransport>* transport) const = 0;
virtual std::vector<RefPtr<JsepTransport>> GetTransports() const = 0;
// Basic JSEP operations.
virtual nsresult CreateOffer(const JsepOfferOptions& options,
@ -129,7 +126,8 @@ public:
uint16_t level) = 0;
virtual nsresult AddLocalIceCandidate(const std::string& candidate,
const std::string& mid,
uint16_t level) = 0;
uint16_t level,
bool* skipped) = 0;
virtual nsresult EndOfLocalCandidates(const std::string& defaultCandidateAddr,
uint16_t defaultCandidatePort,
uint16_t level) = 0;
@ -154,6 +152,8 @@ public:
return states[state];
}
virtual bool AllLocalTracksAreAssigned() const = 0;
protected:
const std::string mName;
JsepSignalingState mState;

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,7 @@
#ifndef _JSEPSESSIONIMPL_H_
#define _JSEPSESSIONIMPL_H_
#include <set>
#include <string>
#include <vector>
@ -45,12 +46,8 @@ public:
virtual nsresult AddTrack(const RefPtr<JsepTrack>& track) MOZ_OVERRIDE;
virtual nsresult
RemoveTrack(size_t trackIndex) MOZ_OVERRIDE
{
mLastError.clear();
MOZ_CRASH(); // Stub
}
virtual nsresult RemoveTrack(const std::string& streamId,
const std::string& trackId) MOZ_OVERRIDE;
virtual nsresult SetIceCredentials(const std::string& ufrag,
const std::string& pwd) MOZ_OVERRIDE;
@ -89,23 +86,15 @@ public:
MOZ_CRASH(); // Stub
}
virtual size_t
GetLocalTrackCount() const MOZ_OVERRIDE
{
return mLocalTracks.size();
}
virtual std::vector<RefPtr<JsepTrack>> GetLocalTracks() const MOZ_OVERRIDE;
virtual nsresult GetLocalTrack(size_t index,
RefPtr<JsepTrack>* track) const MOZ_OVERRIDE;
virtual std::vector<RefPtr<JsepTrack>> GetRemoteTracks() const MOZ_OVERRIDE;
virtual size_t
GetRemoteTrackCount() const MOZ_OVERRIDE
{
return mRemoteTracks.size();
}
virtual std::vector<RefPtr<JsepTrack>>
GetRemoteTracksAdded() const MOZ_OVERRIDE;
virtual nsresult GetRemoteTrack(size_t index,
RefPtr<JsepTrack>* track) const MOZ_OVERRIDE;
virtual std::vector<RefPtr<JsepTrack>>
GetRemoteTracksRemoved() const MOZ_OVERRIDE;
virtual nsresult CreateOffer(const JsepOfferOptions& options,
std::string* offer) MOZ_OVERRIDE;
@ -129,7 +118,8 @@ public:
virtual nsresult AddLocalIceCandidate(const std::string& candidate,
const std::string& mid,
uint16_t level) MOZ_OVERRIDE;
uint16_t level,
bool* skipped) MOZ_OVERRIDE;
virtual nsresult EndOfLocalCandidates(const std::string& defaultCandidateAddr,
uint16_t defaultCandidatePort,
@ -152,41 +142,19 @@ public:
}
// Access transports.
virtual size_t
GetTransportCount() const MOZ_OVERRIDE
virtual std::vector<RefPtr<JsepTransport>>
GetTransports() const MOZ_OVERRIDE
{
return mTransports.size();
return mTransports;
}
virtual nsresult
GetTransport(size_t index,
RefPtr<JsepTransport>* transport) const MOZ_OVERRIDE
virtual std::vector<JsepTrackPair>
GetNegotiatedTrackPairs() const MOZ_OVERRIDE
{
if (index >= mTransports.size())
return NS_ERROR_INVALID_ARG;
*transport = mTransports[index];
return NS_OK;
return mNegotiatedTrackPairs;
}
// 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 MOZ_OVERRIDE
{
if (index >= mNegotiatedTrackPairs.size())
return NS_ERROR_INVALID_ARG;
*pair = &mNegotiatedTrackPairs[index];
return NS_OK;
}
virtual bool AllLocalTracksAreAssigned() const MOZ_OVERRIDE;
private:
struct JsepDtlsFingerprint {
@ -197,6 +165,7 @@ private:
struct JsepSendingTrack {
RefPtr<JsepTrack> mTrack;
Maybe<size_t> mAssignedMLine;
bool mSetInLocalDescription;
};
struct JsepReceivingTrack {
@ -230,34 +199,44 @@ private:
nsresult SetRemoteDescriptionOffer(UniquePtr<Sdp> offer);
nsresult SetRemoteDescriptionAnswer(JsepSdpType type, UniquePtr<Sdp> answer);
nsresult ValidateLocalDescription(const Sdp& description);
nsresult ValidateRemoteDescription(const Sdp& description);
nsresult SetRemoteTracksFromDescription(const Sdp& remoteDescription);
// Non-const because we use our Uuid generator
nsresult CreateReceivingTrack(size_t mline,
const Sdp& sdp,
const SdpMediaSection& msection);
const SdpMediaSection& msection,
RefPtr<JsepTrack>* track);
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 BindTrackToMsection(JsepSendingTrack* track,
SdpMediaSection* msection);
nsresult CreateReoffer(const Sdp& oldLocalSdp,
const Sdp& oldAnswer,
Sdp* newSdp);
void SetupBundle(Sdp* sdp) const;
void SetupMsidSemantic(const std::vector<std::string>& msids, Sdp* sdp) const;
nsresult GetIdsFromMsid(const Sdp& sdp,
const SdpMediaSection& msection,
std::string* streamId,
std::string* trackId);
nsresult GetRemoteIds(const Sdp& sdp,
const SdpMediaSection& msection,
std::string* streamId,
std::string* trackId);
nsresult GetMsids(const SdpMediaSection& msection,
std::vector<SdpMsidAttributeList::Msid>* msids);
nsresult CreateOfferMSection(SdpMediaSection::MediaType type,
SdpDirectionAttribute::Direction direction,
SdpMediaSection::Protocol proto,
Sdp* sdp);
nsresult GetFreeMsectionForSend(SdpMediaSection::MediaType type,
Sdp* sdp,
SdpMediaSection** msection);
nsresult CreateAnswerMSection(const JsepAnswerOptions& options,
size_t mlineIndex,
const SdpMediaSection& remoteMsection,
@ -282,20 +261,37 @@ private:
const std::string& mid,
uint16_t level);
SdpMediaSection* FindMsectionByMid(Sdp& sdp,
const std::string& mid) const;
const SdpMediaSection* FindMsectionByMid(const Sdp& sdp,
const std::string& mid) const;
const SdpGroupAttributeList::Group* FindBundleGroup(const Sdp& sdp) const;
void DisableMsection(Sdp& sdp, SdpMediaSection& msection) const;
nsresult GetNegotiatedBundleInfo(std::set<std::string>* bundleMids,
const SdpMediaSection** bundleMsection);
nsresult GetBundleInfo(const Sdp& sdp,
std::set<std::string>* bundleMids,
const SdpMediaSection** bundleMsection);
bool IsBundleSlave(const Sdp& localSdp, uint16_t level);
void DisableMsection(Sdp* sdp, SdpMediaSection* msection) const;
nsresult EnableMsection(SdpMediaSection* msection);
nsresult SetUniquePayloadTypes();
nsresult GetAllPayloadTypes(const JsepTrackNegotiatedDetails& trackDetails,
std::vector<uint8_t>* payloadTypesOut);
std::string GetCNAME(const SdpMediaSection& msection) const;
bool MsectionIsDisabled(const SdpMediaSection& msection) const;
std::vector<JsepSendingTrack> mLocalTracks;
std::vector<JsepReceivingTrack> mRemoteTracks;
// By the most recent SetRemoteDescription
std::vector<JsepReceivingTrack> mRemoteTracksAdded;
std::vector<JsepReceivingTrack> mRemoteTracksRemoved;
std::vector<RefPtr<JsepTransport> > mTransports;
std::vector<JsepTrackPair> mNegotiatedTrackPairs;
@ -312,6 +308,7 @@ private:
std::vector<SdpExtmapAttributeList::Extmap> mVideoRtpExtensions;
UniquePtr<JsepUuidGenerator> mUuidGen;
std::string mDefaultRemoteStreamId;
std::map<size_t, std::string> mDefaultRemoteTrackIdsByLevel;
std::string mCNAME;
UniquePtr<Sdp> mGeneratedLocalDescription; // Created but not set.
UniquePtr<Sdp> mCurrentLocalDescription;

View File

@ -78,6 +78,34 @@ nsresult MediaPipeline::Init_s() {
ASSERT_ON_THREAD(sts_thread_);
conduit_->AttachTransport(transport_);
return AttachTransport_s();
}
// Disconnect us from the transport so that we can cleanly destruct the
// pipeline on the main thread. ShutdownMedia_m() must have already been
// called
void MediaPipeline::ShutdownTransport_s() {
ASSERT_ON_THREAD(sts_thread_);
MOZ_ASSERT(!stream_); // verifies that ShutdownMedia_m() has run
DetachTransport_s();
}
void
MediaPipeline::DetachTransport_s()
{
ASSERT_ON_THREAD(sts_thread_);
disconnect_all();
transport_->Detach();
rtp_.transport_ = nullptr;
rtcp_.transport_ = nullptr;
}
nsresult
MediaPipeline::AttachTransport_s()
{
ASSERT_ON_THREAD(sts_thread_);
nsresult res;
MOZ_ASSERT(rtp_.transport_);
MOZ_ASSERT(rtcp_.transport_);
@ -92,22 +120,55 @@ nsresult MediaPipeline::Init_s() {
return res;
}
}
return NS_OK;
}
void
MediaPipeline::UpdateTransport_m(int level,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
nsAutoPtr<MediaPipelineFilter> filter)
{
RUN_ON_THREAD(sts_thread_,
WrapRunnable(
this,
&MediaPipeline::UpdateTransport_s,
level,
rtp_transport,
rtcp_transport,
filter),
NS_DISPATCH_NORMAL);
}
// Disconnect us from the transport so that we can cleanly destruct the
// pipeline on the main thread. ShutdownMedia_m() must have already been
// called
void MediaPipeline::ShutdownTransport_s() {
ASSERT_ON_THREAD(sts_thread_);
MOZ_ASSERT(!stream_); // verifies that ShutdownMedia_m() has run
void
MediaPipeline::UpdateTransport_s(int level,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
nsAutoPtr<MediaPipelineFilter> filter)
{
bool rtcp_mux = false;
if (!rtcp_transport) {
rtcp_transport = rtp_transport;
rtcp_mux = true;
}
disconnect_all();
transport_->Detach();
rtp_.transport_ = nullptr;
rtcp_.transport_ = nullptr;
if ((rtp_transport != rtp_.transport_) ||
(rtcp_transport != rtcp_.transport_)) {
DetachTransport_s();
rtp_ = TransportInfo(rtp_transport, rtcp_mux ? MUX : RTP);
rtcp_ = TransportInfo(rtcp_transport, rtcp_mux ? MUX : RTCP);
AttachTransport_s();
}
level_ = level;
if (filter_ && filter) {
// Use the new filter, but don't forget any remote SSRCs that we've learned
// by receiving traffic.
filter_->Update(*filter);
} else {
filter_ = filter;
}
}
void MediaPipeline::StateChange(TransportFlow *flow, TransportLayer::State state) {
@ -424,6 +485,7 @@ void MediaPipeline::RtpPacketReceived(TransportLayer *layer,
return;
}
MOZ_MTLOG(ML_DEBUG, description_ << " received RTP packet.");
increment_rtp_packets_received(out_len);
(void)conduit_->ReceivedRTPPacket(inner_data, out_len); // Ignore error codes
@ -484,6 +546,7 @@ void MediaPipeline::RtcpPacketReceived(TransportLayer *layer,
}
}
MOZ_MTLOG(ML_DEBUG, description_ << " received RTCP packet.");
increment_rtcp_packets_received();
MOZ_ASSERT(rtcp_.recv_srtp_); // This should never happen
@ -677,22 +740,6 @@ MediaPipeline::TransportInfo* MediaPipeline::GetTransportInfo_s(
return nullptr;
}
MediaPipelineFilter* MediaPipeline::UpdateFilterFromRemoteDescription_s(
nsAutoPtr<MediaPipelineFilter> filter) {
ASSERT_ON_THREAD(sts_thread_);
// This is only supposed to relax the filter. Relaxing a missing filter is
// not possible.
MOZ_ASSERT(filter_);
if (!filter) {
filter_ = nullptr;
} else {
filter_->IncorporateRemoteDescription(*filter);
}
return filter_.get();
}
nsresult MediaPipeline::PipelineTransport::SendRtpPacket(
const void *data, int len) {
@ -740,6 +787,7 @@ nsresult MediaPipeline::PipelineTransport::SendRtpPacket_s(
if (!NS_SUCCEEDED(res))
return res;
MOZ_MTLOG(ML_DEBUG, pipeline_->description_ << " sending RTP packet.");
pipeline_->increment_rtp_packets_sent(out_len);
return pipeline_->SendPacket(pipeline_->rtp_.transport_, inner_data,
out_len);
@ -793,6 +841,7 @@ nsresult MediaPipeline::PipelineTransport::SendRtcpPacket_s(
if (!NS_SUCCEEDED(res))
return res;
MOZ_MTLOG(ML_DEBUG, pipeline_->description_ << " sending RTCP packet.");
pipeline_->increment_rtcp_packets_sent();
return pipeline_->SendPacket(pipeline_->rtcp_.transport_, inner_data,
out_len);

View File

@ -126,8 +126,15 @@ class MediaPipeline : public sigslot::has_slots<> {
virtual nsresult Init();
MediaPipelineFilter* UpdateFilterFromRemoteDescription_s(
nsAutoPtr<MediaPipelineFilter> filter);
void UpdateTransport_m(int level,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
nsAutoPtr<MediaPipelineFilter> filter);
void UpdateTransport_s(int level,
RefPtr<TransportFlow> rtp_transport,
RefPtr<TransportFlow> rtcp_transport,
nsAutoPtr<MediaPipelineFilter> filter);
virtual Direction direction() const { return direction_; }
virtual const std::string& trackid() const { return track_id_; }
@ -160,6 +167,8 @@ class MediaPipeline : public sigslot::has_slots<> {
protected:
virtual ~MediaPipeline();
virtual void DetachMediaStream() {}
nsresult AttachTransport_s();
void DetachTransport_s();
// Separate class to allow ref counting
class PipelineTransport : public TransportInterface {
@ -236,7 +245,10 @@ class MediaPipeline : public sigslot::has_slots<> {
std::string track_id_; // The track on the stream.
// Written and used as with the stream_;
// Not used outside initialization in MediaPipelineTransmit
int level_; // The m-line index (starting at 0, to match convention)
// The m-line index (starting at 0, to match convention) Atomic because
// this value is updated from STS, but read on main, and we don't want to
// bother with dispatches just to get an int occasionally.
Atomic<int> level_;
RefPtr<MediaSessionConduit> conduit_; // Our conduit. Written on the main
// thread. Read on STS thread.

View File

@ -68,16 +68,17 @@ void MediaPipelineFilter::SetCorrelator(uint32_t correlator) {
correlator_ = correlator;
}
void MediaPipelineFilter::IncorporateRemoteDescription(
const MediaPipelineFilter& remote_filter) {
// Update SSRCs; we completely replace the remote SSRCs, since this could be
// renegotiation. We leave our SSRCs alone, though.
if (!remote_filter.remote_ssrc_set_.empty()) {
remote_ssrc_set_ = remote_filter.remote_ssrc_set_;
void MediaPipelineFilter::Update(const MediaPipelineFilter& filter_update) {
// We will not stomp the remote_ssrc_set_ if the update has no ssrcs,
// because we don't want to unlearn any remote ssrcs unless the other end
// has explicitly given us a new set.
if (!filter_update.remote_ssrc_set_.empty()) {
remote_ssrc_set_ = filter_update.remote_ssrc_set_;
}
// We do not mess with the payload types or correlator here, since the remote
// SDP doesn't tell us anything about what we will be receiving.
local_ssrc_set_ = filter_update.local_ssrc_set_;
payload_type_set_ = filter_update.payload_type_set_;
correlator_ = filter_update.correlator_;
}
MediaPipelineFilter::Result

View File

@ -69,7 +69,7 @@ class MediaPipelineFilter {
void AddUniquePT(uint8_t payload_type);
void SetCorrelator(uint32_t correlator);
void IncorporateRemoteDescription(const MediaPipelineFilter& remote_filter);
void Update(const MediaPipelineFilter& filter_update);
// Some payload types
static const uint8_t SENDER_REPORT_T = 200;

View File

@ -232,41 +232,138 @@ MediaPipelineFactory::CreateOrGetTransportFlow(
}
nsresult
MediaPipelineFactory::CreateMediaPipeline(const JsepTrackPair& aTrackPair,
const JsepTrack& aTrack)
MediaPipelineFactory::GetTransportParameters(
const JsepTrackPair& aTrackPair,
const JsepTrack& aTrack,
size_t* aLevelOut,
RefPtr<TransportFlow>* aRtpOut,
RefPtr<TransportFlow>* aRtcpOut,
nsAutoPtr<MediaPipelineFilter>* aFilterOut)
{
MOZ_MTLOG(ML_DEBUG,
"Creating media pipeline"
<< " m-line index=" << aTrackPair.mLevel
<< " type=" << aTrack.GetMediaType()
<< " direction=" << aTrack.GetDirection());
MOZ_ASSERT(aTrackPair.mRtpTransport);
*aLevelOut = aTrackPair.mLevel;
size_t transportLevel = aTrackPair.mBundleLevel.isSome() ?
*aTrackPair.mBundleLevel :
aTrackPair.mLevel;
// First make sure the transport flow exists.
RefPtr<TransportFlow> rtpFlow;
nsresult rv = CreateOrGetTransportFlow(
transportLevel, false, *aTrackPair.mRtpTransport, &rtpFlow);
if (NS_FAILED(rv))
transportLevel, false, *aTrackPair.mRtpTransport, aRtpOut);
if (NS_FAILED(rv)) {
return rv;
MOZ_ASSERT(rtpFlow);
}
MOZ_ASSERT(aRtpOut);
RefPtr<TransportFlow> rtcpFlow;
if (aTrackPair.mRtcpTransport) {
rv = CreateOrGetTransportFlow(
transportLevel, true, *aTrackPair.mRtcpTransport, &rtcpFlow);
if (NS_FAILED(rv))
transportLevel, true, *aTrackPair.mRtcpTransport, aRtcpOut);
if (NS_FAILED(rv)) {
return rv;
MOZ_ASSERT(rtcpFlow);
}
MOZ_ASSERT(aRtcpOut);
}
if (aTrackPair.mBundleLevel.isSome()) {
bool receiving =
aTrack.GetDirection() == JsepTrack::Direction::kJsepTrackReceiving;
*aFilterOut = new MediaPipelineFilter;
if (receiving) {
// Add remote SSRCs so we can distinguish which RTP packets actually
// belong to this pipeline (also RTCP sender reports).
for (auto i = aTrack.GetSsrcs().begin();
i != aTrack.GetSsrcs().end(); ++i) {
(*aFilterOut)->AddRemoteSSRC(*i);
}
// TODO(bug 1105005): Tell the filter about the mid for this track
// Add unique payload types as a last-ditch fallback
auto uniquePts = aTrack.GetNegotiatedDetails()->GetUniquePayloadTypes();
for (auto i = uniquePts.begin(); i != uniquePts.end(); ++i) {
(*aFilterOut)->AddUniquePT(*i);
}
} else {
// Add local SSRCs so we can distinguish which RTCP packets actually
// belong to this pipeline.
for (auto i = aTrack.GetSsrcs().begin();
i != aTrack.GetSsrcs().end(); ++i) {
(*aFilterOut)->AddLocalSSRC(*i);
}
}
}
return NS_OK;
}
nsresult
MediaPipelineFactory::CreateOrUpdateMediaPipeline(
const JsepTrackPair& aTrackPair,
const JsepTrack& aTrack)
{
MOZ_ASSERT(aTrackPair.mRtpTransport);
bool receiving =
aTrack.GetDirection() == JsepTrack::Direction::kJsepTrackReceiving;
size_t level;
RefPtr<TransportFlow> rtpFlow;
RefPtr<TransportFlow> rtcpFlow;
nsAutoPtr<MediaPipelineFilter> filter;
nsresult rv = GetTransportParameters(aTrackPair,
aTrack,
&level,
&rtpFlow,
&rtcpFlow,
&filter);
if (NS_FAILED(rv)) {
MOZ_MTLOG(ML_ERROR, "Failed to get transport parameters for pipeline, rv="
<< static_cast<unsigned>(rv));
return rv;
}
if (aTrack.GetMediaType() == SdpMediaSection::kApplication) {
// GetTransportParameters has already done everything we need for
// datachannel.
return NS_OK;
}
// Find the stream we need
SourceStreamInfo* stream;
if (receiving) {
stream = mPCMedia->GetRemoteStreamById(aTrack.GetStreamId());
} else {
stream = mPCMedia->GetLocalStreamById(aTrack.GetStreamId());
}
if (!stream) {
MOZ_MTLOG(ML_ERROR, "Negotiated " << (receiving ? "recv" : "send")
<< " stream id " << aTrack.GetStreamId() << " was never added");
MOZ_ASSERT(false);
return NS_ERROR_FAILURE;
}
if (!stream->HasTrack(aTrack.GetTrackId())) {
MOZ_MTLOG(ML_ERROR, "Negotiated " << (receiving ? "recv" : "send")
<< " track id " << aTrack.GetTrackId() << " was never added");
MOZ_ASSERT(false);
return NS_ERROR_FAILURE;
}
RefPtr<MediaPipeline> pipeline =
stream->GetPipelineByTrackId_m(aTrack.GetTrackId());
if (pipeline) {
pipeline->UpdateTransport_m(level, rtpFlow, rtcpFlow, filter);
return NS_OK;
}
MOZ_MTLOG(ML_DEBUG,
"Creating media pipeline"
<< " m-line index=" << aTrackPair.mLevel
<< " type=" << aTrack.GetMediaType()
<< " direction=" << aTrack.GetDirection());
RefPtr<MediaSessionConduit> conduit;
if (aTrack.GetMediaType() == SdpMediaSection::kAudio) {
rv = CreateAudioConduit(aTrackPair, aTrack, &conduit);
@ -282,13 +379,15 @@ MediaPipelineFactory::CreateMediaPipeline(const JsepTrackPair& aTrackPair,
}
if (receiving) {
rv = CreateMediaPipelineReceiving(rtpFlow, rtcpFlow,
aTrackPair, aTrack, conduit);
rv = CreateMediaPipelineReceiving(aTrackPair, aTrack,
level, rtpFlow, rtcpFlow, filter,
conduit);
if (NS_FAILED(rv))
return rv;
} else {
rv = CreateMediaPipelineSending(rtpFlow, rtcpFlow,
aTrackPair, aTrack, conduit);
rv = CreateMediaPipelineSending(aTrackPair, aTrack,
level, rtpFlow, rtcpFlow, filter,
conduit);
if (NS_FAILED(rv))
return rv;
}
@ -298,50 +397,25 @@ MediaPipelineFactory::CreateMediaPipeline(const JsepTrackPair& aTrackPair,
nsresult
MediaPipelineFactory::CreateMediaPipelineReceiving(
RefPtr<TransportFlow> aRtpFlow,
RefPtr<TransportFlow> aRtcpFlow,
const JsepTrackPair& aTrackPair,
const JsepTrack& aTrack,
size_t aLevel,
RefPtr<TransportFlow> aRtpFlow,
RefPtr<TransportFlow> aRtcpFlow,
nsAutoPtr<MediaPipelineFilter> aFilter,
const RefPtr<MediaSessionConduit>& aConduit)
{
// Find the stream we need
// We will error out earlier if this isn't here.
nsRefPtr<RemoteSourceStreamInfo> stream =
mPCMedia->GetRemoteStreamById(aTrack.GetStreamId());
MOZ_ASSERT(stream);
if (!stream) {
// This should never happen
MOZ_ASSERT(false);
MOZ_MTLOG(ML_ERROR, "Stream not found: " << aTrack.GetStreamId());
return NS_ERROR_FAILURE;
}
RefPtr<MediaPipelineReceive> pipeline;
nsAutoPtr<MediaPipelineFilter> filter;
TrackID numericTrackId = stream->GetNumericTrackId(aTrack.GetTrackId());
MOZ_ASSERT(numericTrackId != TRACK_INVALID);
if (aTrackPair.mBundleLevel.isSome()) {
filter = new MediaPipelineFilter;
// Add remote SSRCs so we can distinguish which RTP packets actually
// belong to this pipeline (also RTCP sender reports).
for (auto i = aTrack.GetSsrcs().begin();
i != aTrack.GetSsrcs().end(); ++i) {
filter->AddRemoteSSRC(*i);
}
// TODO(bug 1105005): Tell the filter about the mid for this track
// Add unique payload types as a last-ditch fallback
auto uniquePts = aTrack.GetNegotiatedDetails()->GetUniquePayloadTypes();
for (auto i = uniquePts.begin(); i != uniquePts.end(); ++i) {
filter->AddUniquePT(*i);
}
}
// We need to choose a numeric track id for MediaStreamGraph to use. Must be
// unique within the MediaStream, so level + 1 should be fine (cannot use 0).
TrackID numericTrackId = aTrackPair.mLevel + 1;
MOZ_MTLOG(ML_DEBUG, __FUNCTION__ << ": Creating pipeline for "
<< numericTrackId << " -> " << aTrack.GetTrackId());
if (aTrack.GetMediaType() == SdpMediaSection::kAudio) {
pipeline = new MediaPipelineReceiveAudio(
@ -351,12 +425,11 @@ MediaPipelineFactory::CreateMediaPipelineReceiving(
stream->GetMediaStream()->GetStream(),
aTrack.GetTrackId(),
numericTrackId,
aTrackPair.mLevel,
aLevel,
static_cast<AudioSessionConduit*>(aConduit.get()), // Ugly downcast.
aRtpFlow,
aRtcpFlow,
filter);
aFilter);
} else if (aTrack.GetMediaType() == SdpMediaSection::kVideo) {
pipeline = new MediaPipelineReceiveVideo(
mPC->GetHandle(),
@ -365,11 +438,11 @@ MediaPipelineFactory::CreateMediaPipelineReceiving(
stream->GetMediaStream()->GetStream(),
aTrack.GetTrackId(),
numericTrackId,
aTrackPair.mLevel,
aLevel,
static_cast<VideoSessionConduit*>(aConduit.get()), // Ugly downcast.
aRtpFlow,
aRtcpFlow,
filter);
aFilter);
} else {
MOZ_ASSERT(false);
MOZ_MTLOG(ML_ERROR, "Invalid media type in CreateMediaPipelineReceiving");
@ -396,35 +469,19 @@ MediaPipelineFactory::CreateMediaPipelineReceiving(
nsresult
MediaPipelineFactory::CreateMediaPipelineSending(
RefPtr<TransportFlow> aRtpFlow,
RefPtr<TransportFlow> aRtcpFlow,
const JsepTrackPair& aTrackPair,
const JsepTrack& aTrack,
size_t aLevel,
RefPtr<TransportFlow> aRtpFlow,
RefPtr<TransportFlow> aRtcpFlow,
nsAutoPtr<MediaPipelineFilter> aFilter,
const RefPtr<MediaSessionConduit>& aConduit)
{
nsresult rv;
// This is checked earlier
nsRefPtr<LocalSourceStreamInfo> stream =
mPCMedia->GetLocalStreamById(aTrack.GetStreamId());
MOZ_ASSERT(stream);
if (!stream) {
// This should never happen
MOZ_MTLOG(ML_ERROR, "Stream not found: " << aTrack.GetStreamId());
return NS_ERROR_FAILURE;
}
nsAutoPtr<MediaPipelineFilter> filter;
if (aTrackPair.mBundleLevel.isSome()) {
filter = new MediaPipelineFilter;
// Add local SSRCs so we can distinguish which RTCP packets actually
// belong to this pipeline.
for (auto i = aTrack.GetSsrcs().begin();
i != aTrack.GetSsrcs().end(); ++i) {
filter->AddLocalSSRC(*i);
}
}
// Now we have all the pieces, create the pipeline
RefPtr<MediaPipelineTransmit> pipeline = new MediaPipelineTransmit(
@ -433,12 +490,12 @@ MediaPipelineFactory::CreateMediaPipelineSending(
mPC->GetSTSThread(),
stream->GetMediaStream(),
aTrack.GetTrackId(),
aTrackPair.mLevel,
aLevel,
aTrack.GetMediaType() == SdpMediaSection::kVideo,
aConduit,
aRtpFlow,
aRtcpFlow,
filter);
aFilter);
#ifdef MOZILLA_INTERNAL_API
// implement checking for peerIdentity (where failure == black/silence)
@ -483,21 +540,18 @@ MediaPipelineFactory::CreateAudioConduit(const JsepTrackPair& aTrackPair,
bool receiving =
aTrack.GetDirection() == JsepTrack::Direction::kJsepTrackReceiving;
RefPtr<MediaSessionConduit> otherConduit =
mPCMedia->GetConduit(aTrackPair.mLevel, !receiving);
MOZ_ASSERT_IF(otherConduit,
otherConduit->type() == MediaSessionConduit::AUDIO);
// The two sides of a send/receive pair of conduits each keep a raw pointer
// to the other, and are responsible for cleanly shutting down.
RefPtr<AudioSessionConduit> conduit = AudioSessionConduit::Create(
static_cast<AudioSessionConduit*>(otherConduit.get()));
static_cast<AudioSessionConduit*>(nullptr));
if (!conduit) {
MOZ_MTLOG(ML_ERROR, "Could not create audio conduit");
return NS_ERROR_FAILURE;
}
mPCMedia->AddConduit(aTrackPair.mLevel, receiving, conduit);
mPCMedia->AddConduit(aTrack.GetStreamId(),
aTrack.GetTrackId(),
receiving,
conduit);
size_t numCodecs = aTrack.GetNegotiatedDetails()->GetCodecCount();
if (numCodecs == 0) {
@ -600,22 +654,18 @@ MediaPipelineFactory::CreateVideoConduit(const JsepTrackPair& aTrackPair,
bool receiving =
aTrack.GetDirection() == JsepTrack::Direction::kJsepTrackReceiving;
// Instantiate an appropriate conduit
RefPtr<MediaSessionConduit> peerConduit =
mPCMedia->GetConduit(aTrackPair.mLevel, !receiving);
MOZ_ASSERT_IF(peerConduit, peerConduit->type() == MediaSessionConduit::VIDEO);
// The two sides of a send/receive pair of conduits each keep a raw
// pointer to the other, and are responsible for cleanly shutting down.
RefPtr<VideoSessionConduit> conduit = VideoSessionConduit::Create(
static_cast<VideoSessionConduit*>(peerConduit.get()), receiving);
static_cast<VideoSessionConduit*>(nullptr), receiving);
if (!conduit) {
MOZ_MTLOG(ML_ERROR, "Could not create video conduit");
return NS_ERROR_FAILURE;
}
mPCMedia->AddConduit(aTrackPair.mLevel, receiving, conduit);
mPCMedia->AddConduit(aTrack.GetStreamId(),
aTrack.GetTrackId(),
receiving,
conduit);
size_t numCodecs = aTrack.GetNegotiatedDetails()->GetCodecCount();
if (numCodecs == 0) {

View File

@ -22,22 +22,26 @@ public:
{
}
nsresult CreateMediaPipeline(const JsepTrackPair& aTrackPair,
const JsepTrack& aTrack);
nsresult CreateOrUpdateMediaPipeline(const JsepTrackPair& aTrackPair,
const JsepTrack& aTrack);
private:
nsresult CreateMediaPipelineReceiving(
RefPtr<TransportFlow> aRtpFlow,
RefPtr<TransportFlow> aRtcpFlow,
const JsepTrackPair& aTrackPair,
const JsepTrack& aTrack,
size_t level,
RefPtr<TransportFlow> aRtpFlow,
RefPtr<TransportFlow> aRtcpFlow,
nsAutoPtr<MediaPipelineFilter> filter,
const RefPtr<MediaSessionConduit>& aConduit);
nsresult CreateMediaPipelineSending(
RefPtr<TransportFlow> aRtpFlow,
RefPtr<TransportFlow> aRtcpFlow,
const JsepTrackPair& aTrackPair,
const JsepTrack& aTrack,
size_t level,
RefPtr<TransportFlow> aRtpFlow,
RefPtr<TransportFlow> aRtcpFlow,
nsAutoPtr<MediaPipelineFilter> filter,
const RefPtr<MediaSessionConduit>& aConduit);
nsresult CreateAudioConduit(const JsepTrackPair& aTrackPair,
@ -56,6 +60,13 @@ private:
const JsepTransport& transport,
RefPtr<TransportFlow>* out);
nsresult GetTransportParameters(const JsepTrackPair& aTrackPair,
const JsepTrack& aTrack,
size_t* aLevelOut,
RefPtr<TransportFlow>* aRtpOut,
RefPtr<TransportFlow>* aRtcpOut,
nsAutoPtr<MediaPipelineFilter>* aFilterOut);
private:
// Not owned, and assumed to exist as long as the factory.
// The factory is a transient object, so this is fairly easy.

View File

@ -178,26 +178,27 @@ private:
class TracksAvailableCallback : public DOMMediaStream::OnTracksAvailableCallback
{
public:
TracksAvailableCallback(const std::list<std::string>& audioTrackIds,
const std::list<std::string>& videoTrackIds,
const std::set<std::string>& preexistingTrackIds,
TracksAvailableCallback(size_t numNewAudioTracks,
size_t numNewVideoTracks,
const std::string& pcHandle,
nsRefPtr<PeerConnectionObserver> aObserver)
: DOMMediaStream::OnTracksAvailableCallback(
// Once DOMMediaStream can handle more than one of each, this will change.
(audioTrackIds.empty() ? 0 : DOMMediaStream::HINT_CONTENTS_AUDIO) |
(videoTrackIds.empty() ? 0 : DOMMediaStream::HINT_CONTENTS_VIDEO))
(numNewAudioTracks ? DOMMediaStream::HINT_CONTENTS_AUDIO : 0) |
(numNewVideoTracks ? DOMMediaStream::HINT_CONTENTS_VIDEO : 0))
, mObserver(aObserver)
, mAudioTrackIds(audioTrackIds)
, mVideoTrackIds(videoTrackIds)
, mPreexistingTrackIds(preexistingTrackIds) {}
, mPcHandle(pcHandle)
{}
virtual void NotifyTracksAvailable(DOMMediaStream* aStream) MOZ_OVERRIDE
{
MOZ_ASSERT(NS_IsMainThread());
// Start currentTime from the point where this stream was successfully
// returned.
aStream->SetLogicalStreamStartTime(aStream->GetStream()->GetCurrentTime());
PeerConnectionWrapper wrapper(mPcHandle);
if (!wrapper.impl() || wrapper.impl()->IsClosed()) {
return;
}
CSFLogInfo(logTag, "Returning success for OnAddStream()");
// We are running on main thread here so we shouldn't have a race
@ -206,67 +207,67 @@ public:
nsTArray<nsRefPtr<MediaStreamTrack>> tracks;
aStream->GetTracks(tracks);
bool newStream = true;
for (size_t i = 0; i < tracks.Length(); i++) {
if (mPreexistingTrackIds.count(
PeerConnectionImpl::GetTrackId(*tracks[i]))) {
std::string trackId;
// This is the first chance we get to set the string track id on this
// track. It would be nice if we could specify this along with the numeric
// track id from the start, but we're stuck doing this fixup after the
// fact.
nsresult rv = wrapper.impl()->GetRemoteTrackId(aStream,
tracks[i]->GetTrackID(),
&trackId);
if (NS_FAILED(rv)) {
CSFLogError(logTag, "%s: Failed to get string track id for %u, rv = %u",
__FUNCTION__,
static_cast<unsigned>(tracks[i]->GetTrackID()),
static_cast<unsigned>(rv));
MOZ_ASSERT(false);
continue;
}
AssignNextIdToTrack(tracks[i]);
JSErrorResult rv;
mObserver->OnAddTrack(*tracks[i], rv);
std::string origTrackId = PeerConnectionImpl::GetTrackId(*tracks[i]);
if (origTrackId == trackId) {
// Pre-existing track
newStream = false;
continue;
}
tracks[i]->AssignId(NS_ConvertUTF8toUTF16(trackId.c_str()));
JSErrorResult jrv;
mObserver->OnAddTrack(*tracks[i], jrv);
CSFLogInfo(logTag, "Calling OnAddTrack(%s)",
PeerConnectionImpl::GetTrackId(*tracks[i]).c_str());
if (rv.Failed()) {
if (jrv.Failed()) {
CSFLogError(logTag, ": OnAddTrack(%u) failed! Error: %u",
static_cast<unsigned>(i),
static_cast<unsigned>(rv.ErrorCode()));
static_cast<unsigned>(jrv.ErrorCode()));
}
}
JSErrorResult rv;
CSFLogInfo(logTag, "Calling OnAddStream");
mObserver->OnAddStream(*aStream, rv);
if (rv.Failed()) {
CSFLogError(logTag, ": OnAddStream() failed! Error: %u",
static_cast<unsigned>(rv.ErrorCode()));
if (newStream) {
// Start currentTime from the point where this stream was successfully
// returned.
aStream->SetLogicalStreamStartTime(
aStream->GetStream()->GetCurrentTime());
JSErrorResult rv;
CSFLogInfo(logTag, "Calling OnAddStream");
mObserver->OnAddStream(*aStream, rv);
if (rv.Failed()) {
CSFLogError(logTag, ": OnAddStream() failed! Error: %u",
static_cast<unsigned>(rv.ErrorCode()));
}
}
if (!mAudioTrackIds.empty() || !mVideoTrackIds.empty()) {
CSFLogError(logTag, "Failed to assign %u audio and %u video tracks!",
static_cast<unsigned>(mAudioTrackIds.size()),
static_cast<unsigned>(mVideoTrackIds.size()));
}
}
void AssignNextIdToTrack(MediaStreamTrack* track)
{
std::list<std::string>* trackIds;
if (track->AsAudioStreamTrack()) {
trackIds = &mAudioTrackIds;
} else if (track->AsVideoStreamTrack()) {
trackIds = &mVideoTrackIds;
} else {
MOZ_ASSERT(false, "Track is neither an AudioStreamTrack nor "
"VideoStreamTrack");
return;
}
if (trackIds->empty()) {
MOZ_ASSERT(false, "Too many new MediaStreamTracks were created");
return;
}
track->AssignId(NS_ConvertUTF8toUTF16(trackIds->front().c_str()));
trackIds->pop_front();
}
private:
nsRefPtr<PeerConnectionObserver> mObserver;
std::list<std::string> mAudioTrackIds;
std::list<std::string> mVideoTrackIds;
const std::set<std::string> mPreexistingTrackIds;
const std::string mPcHandle;
};
#endif
@ -394,6 +395,7 @@ PeerConnectionImpl::PeerConnectionImpl(const GlobalObject* aGlobal)
, mHaveDataStream(false)
, mAddCandidateErrorCount(0)
, mTrickle(true) // TODO(ekr@rtfm.com): Use pref
, mShouldSuppressNegotiationNeeded(true)
{
#ifdef MOZILLA_INTERNAL_API
MOZ_ASSERT(NS_IsMainThread());
@ -1040,15 +1042,22 @@ PeerConnectionImpl::GetDatachannelParameters(
const mozilla::JsepApplicationCodecDescription** datachannelCodec,
uint16_t* level) const {
for (size_t j = 0; j < mJsepSession->GetNegotiatedTrackPairCount(); ++j) {
const JsepTrackPair* trackPair;
nsresult res = mJsepSession->GetNegotiatedTrackPair(j, &trackPair);
auto trackPairs = mJsepSession->GetNegotiatedTrackPairs();
for (auto j = trackPairs.begin(); j != trackPairs.end(); ++j) {
JsepTrackPair& trackPair = *j;
if (NS_SUCCEEDED(res) &&
trackPair->mSending && // Assumes we don't do recvonly datachannel
trackPair->mSending->GetMediaType() == SdpMediaSection::kApplication) {
bool sendDataChannel =
trackPair.mSending &&
trackPair.mSending->GetMediaType() == SdpMediaSection::kApplication;
bool recvDataChannel =
trackPair.mReceiving &&
trackPair.mReceiving->GetMediaType() == SdpMediaSection::kApplication;
(void)recvDataChannel;
MOZ_ASSERT(sendDataChannel == recvDataChannel);
if (!trackPair->mSending->GetNegotiatedDetails()->GetCodecCount()) {
if (sendDataChannel) {
if (!trackPair.mSending->GetNegotiatedDetails()->GetCodecCount()) {
CSFLogError(logTag, "%s: Negotiated m=application with no codec. "
"This is likely to be broken.",
__FUNCTION__);
@ -1056,10 +1065,11 @@ PeerConnectionImpl::GetDatachannelParameters(
}
for (size_t i = 0;
i < trackPair->mSending->GetNegotiatedDetails()->GetCodecCount();
i < trackPair.mSending->GetNegotiatedDetails()->GetCodecCount();
++i) {
const JsepCodecDescription* codec;
res = trackPair->mSending->GetNegotiatedDetails()->GetCodec(i, &codec);
nsresult res =
trackPair.mSending->GetNegotiatedDetails()->GetCodec(i, &codec);
if (NS_FAILED(res)) {
CSFLogError(logTag, "%s: Failed getting codec for m=application.",
@ -1086,10 +1096,10 @@ PeerConnectionImpl::GetDatachannelParameters(
*datachannelCodec =
static_cast<const JsepApplicationCodecDescription*>(codec);
if (trackPair->mBundleLevel.isSome()) {
*level = static_cast<uint16_t>(*trackPair->mBundleLevel);
if (trackPair.mBundleLevel.isSome()) {
*level = static_cast<uint16_t>(*trackPair.mBundleLevel);
} else {
*level = static_cast<uint16_t>(trackPair->mLevel);
*level = static_cast<uint16_t>(trackPair.mLevel);
}
return NS_OK;
}
@ -1235,6 +1245,7 @@ PeerConnectionImpl::CreateDataChannel(const nsAString& aLabel,
return rv;
}
mHaveDataStream = true;
OnNegotiationNeeded();
}
nsIDOMDataChannel *retval;
rv = NS_NewDOMDataChannel(dataChannel.forget(), mWindow, &retval);
@ -1306,6 +1317,8 @@ PeerConnectionImpl::NotifyDataChannel(already_AddRefed<DataChannel> aChannel)
mWindow, getter_AddRefs(domchannel));
NS_ENSURE_SUCCESS_VOID(rv);
mHaveDataStream = true;
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) {
return;
@ -1609,22 +1622,13 @@ PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
__FUNCTION__, mHandle.c_str(), errorString.c_str());
pco->OnSetRemoteDescriptionError(error, ObString(errorString.c_str()), jrv);
} else {
// Add the tracks. This code is pretty complicated because the tracks
// come in arbitrary orders and we want to group them by streamId.
size_t numTracks = mJsepSession->GetRemoteTrackCount();
std::vector<RefPtr<JsepTrack>> newTracks =
mJsepSession->GetRemoteTracksAdded();
// Group tracks by stream id
// Group new tracks by stream id
std::map<std::string, std::vector<RefPtr<JsepTrack>>> tracksByStreamId;
for (size_t i = 0; i < numTracks; ++i) {
RefPtr<JsepTrack> track;
nrv = mJsepSession->GetRemoteTrack(i, &track);
if (NS_FAILED(nrv)) {
pco->OnSetRemoteDescriptionError(kInternalError,
ObString("GetRemoteTrack failed"),
jrv);
return NS_OK;
}
for (auto i = newTracks.begin(); i != newTracks.end(); ++i) {
RefPtr<JsepTrack> track = *i;
if (track->GetMediaType() == mozilla::SdpMediaSection::kApplication) {
// Ignore datachannel
@ -1658,43 +1662,67 @@ PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
jrv);
return NS_OK;
}
CSFLogDebug(logTag, "Added remote stream %s", info->GetId().c_str());
}
// TODO(bug 1017888): Only get new tracks for renegotiation
std::list<std::string> newAudioTrackIds;
std::list<std::string> newVideoTrackIds;
// TODO(bug 1017888): Fill in for renegotiation
std::set<std::string> preexistingTrackIds;
size_t numNewAudioTracks = 0;
size_t numNewVideoTracks = 0;
size_t numPreexistingTrackIds = 0;
for (auto j = tracks.begin(); j != tracks.end(); ++j) {
RefPtr<JsepTrack> track = *j;
if (track->GetMediaType() == SdpMediaSection::kAudio) {
if (!info->HasTrack(track->GetTrackId())) {
if (track->GetMediaType() == SdpMediaSection::kAudio) {
++numNewAudioTracks;
} else if (track->GetMediaType() == SdpMediaSection::kVideo) {
++numNewVideoTracks;
} else {
MOZ_ASSERT(false);
continue;
}
info->AddTrack(track->GetTrackId());
newAudioTrackIds.push_back(track->GetTrackId());
} else if (track->GetMediaType() == SdpMediaSection::kVideo) {
info->AddTrack(track->GetTrackId());
newVideoTrackIds.push_back(track->GetTrackId());
CSFLogDebug(logTag, "Added remote track %s/%s",
info->GetId().c_str(), track->GetTrackId().c_str());
} else {
MOZ_ASSERT(false);
continue;
++numPreexistingTrackIds;
}
}
// Now that the streams are all set up, notify about track availability.
// TODO(bug 1017888): Suppress on renegotiation when no change.
#ifdef MOZILLA_INTERNAL_API
TracksAvailableCallback* tracksAvailableCallback =
new TracksAvailableCallback(newAudioTrackIds,
newVideoTrackIds,
preexistingTrackIds,
new TracksAvailableCallback(numNewAudioTracks,
numNewVideoTracks,
mHandle,
pco);
info->GetMediaStream()->OnTracksAvailable(tracksAvailableCallback);
#else
pco->OnAddStream(info->GetMediaStream(), jrv);
if (!numPreexistingTrackIds) {
pco->OnAddStream(*info->GetMediaStream(), jrv);
}
#endif
}
std::vector<RefPtr<JsepTrack>> removedTracks =
mJsepSession->GetRemoteTracksRemoved();
for (auto i = removedTracks.begin(); i != removedTracks.end(); ++i) {
nsRefPtr<RemoteSourceStreamInfo> info =
mMedia->GetRemoteStreamById((*i)->GetStreamId());
if (!info) {
MOZ_ASSERT(false, "A stream/track was removed that wasn't in PCMedia. "
"This is a bug.");
continue;
}
mMedia->RemoveRemoteTrack((*i)->GetStreamId(), (*i)->GetTrackId());
// We might be holding the last ref, but that's ok.
if (!info->GetTrackCount()) {
pco->OnRemoveStream(*info->GetMediaStream(), jrv);
}
}
pco->OnSetRemoteDescriptionSuccess(jrv);
#ifdef MOZILLA_INTERNAL_API
startCallTelem();
@ -1899,6 +1927,20 @@ PeerConnectionImpl::PrincipalChanged(DOMMediaStream* aMediaStream) {
}
#endif
#ifdef MOZILLA_INTERNAL_API
nsresult
PeerConnectionImpl::GetRemoteTrackId(DOMMediaStream* mediaStream,
TrackID numericTrackId,
std::string* trackId) const
{
if (IsClosed()) {
return NS_ERROR_UNEXPECTED;
}
return mMedia->GetRemoteTrackId(mediaStream, numericTrackId, trackId);
}
#endif
std::string
PeerConnectionImpl::GetTrackId(const MediaStreamTrack& aTrack)
{
@ -1942,8 +1984,8 @@ PeerConnectionImpl::AddTrack(MediaStreamTrack& aTrack,
return res;
}
CSFLogDebug(logTag, "Added track (%s) to stream %p",
trackId.c_str(), &aMediaStream);
CSFLogDebug(logTag, "Added track (%s) to stream %s",
trackId.c_str(), streamId.c_str());
if (num != mMedia->LocalStreamsLength()) {
aMediaStream.AddPrincipalChangeObserver(this);
@ -1986,12 +2028,46 @@ PeerConnectionImpl::AddTrack(MediaStreamTrack& aTrack,
}
mNumVideoStreams++;
}
OnNegotiationNeeded();
return NS_OK;
}
NS_IMETHODIMP
PeerConnectionImpl::RemoveTrack(MediaStreamTrack& aTrack) {
MOZ_CRASH(); // TODO(bug 1021647): Implement and expose RemoveTrack
PC_AUTO_ENTER_API_CALL(true);
DOMMediaStream* stream = aTrack.GetStream();
if (!stream) {
CSFLogError(logTag, "%s: Track has no stream", __FUNCTION__);
return NS_ERROR_INVALID_ARG;
}
nsRefPtr<LocalSourceStreamInfo> info =
media()->GetLocalStreamByDomStream(*stream);
if (!info) {
CSFLogError(logTag, "%s: Unknown stream", __FUNCTION__);
return NS_ERROR_INVALID_ARG;
}
std::string trackId(PeerConnectionImpl::GetTrackId(aTrack));
nsresult rv =
mJsepSession->RemoveTrack(info->GetId(), trackId);
if (NS_FAILED(rv)) {
CSFLogError(logTag, "%s: Unknown stream/track ids %s %s",
__FUNCTION__,
info->GetId().c_str(),
trackId.c_str());
return rv;
}
media()->RemoveLocalTrack(info->GetId(), trackId);
OnNegotiationNeeded();
return NS_OK;
}
@ -2331,10 +2407,24 @@ PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState)
mMedia->UpdateTransports(*mJsepSession);
}
bool fireNegotiationNeeded = false;
if (mSignalingState == PCImplSignalingState::SignalingStable) {
mMedia->UpdateMediaPipelines(*mJsepSession);
InitializeDataChannel();
mMedia->StartIceChecks(*mJsepSession);
mShouldSuppressNegotiationNeeded = false;
if (!mJsepSession->AllLocalTracksAreAssigned()) {
CSFLogInfo(logTag, "Not all local tracks were assigned to an "
"m-section, either because the offerer did not offer"
" to receive enough tracks, or because tracks were "
"added after CreateOffer/Answer, but before "
"offer/answer completed. This requires "
"renegotiation.");
fireNegotiationNeeded = true;
}
} else {
mShouldSuppressNegotiationNeeded = true;
}
if (mSignalingState == PCImplSignalingState::SignalingClosed) {
@ -2347,6 +2437,10 @@ PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState)
}
JSErrorResult rv;
pco->OnStateChange(PCObserverStateType::SignalingState, rv);
if (fireNegotiationNeeded) {
OnNegotiationNeeded();
}
}
void
@ -2461,7 +2555,11 @@ PeerConnectionImpl::CandidateReady(const std::string& candidate,
// outparam or something. Bug 1051052.
std::string mid;
nsresult res = mJsepSession->AddLocalIceCandidate(candidate, mid, level);
bool skipped = false;
nsresult res = mJsepSession->AddLocalIceCandidate(candidate,
mid,
level,
&skipped);
if (NS_FAILED(res)) {
std::string errorString = mJsepSession->GetLastError();
@ -2474,6 +2572,16 @@ PeerConnectionImpl::CandidateReady(const std::string& candidate,
errorString.c_str());
}
if (skipped) {
CSFLogDebug(logTag, "Skipped adding local candidate %s (level %u) to SDP, "
"this typically happens because the m-section is "
"bundled, which means it doesn't make sense for it to "
"have its own transport-related attributes.",
candidate.c_str(),
static_cast<unsigned>(level));
return;
}
CSFLogDebug(logTag, "Passing local candidate to content: %s",
candidate.c_str());
SendLocalIceCandidateToContent(level, mid, candidate);
@ -3125,6 +3233,24 @@ PeerConnectionImpl::RecordLongtermICEStatistics() {
#endif
}
void
PeerConnectionImpl::OnNegotiationNeeded()
{
if (mShouldSuppressNegotiationNeeded) {
return;
}
mShouldSuppressNegotiationNeeded = true;
nsRefPtr<PeerConnectionObserver> pco = do_QueryObjectReferent(mPCObserver);
if (!pco) {
return;
}
JSErrorResult rv;
pco->OnNegotiationNeeded(rv);
}
void
PeerConnectionImpl::IceStreamReady(NrIceMediaStream *aStream)
{

View File

@ -72,6 +72,7 @@ class MediaPipeline;
#ifdef USE_FAKE_MEDIA_STREAMS
typedef Fake_DOMMediaStream DOMMediaStream;
typedef Fake_MediaStreamTrack MediaStreamTrack;
#else
class DOMMediaStream;
#endif
@ -596,6 +597,10 @@ public:
// for monitoring changes in stream ownership
// PeerConnectionMedia can't do it because it doesn't know about principals
virtual void PrincipalChanged(DOMMediaStream* aMediaStream) MOZ_OVERRIDE;
nsresult GetRemoteTrackId(DOMMediaStream* mediaStream,
TrackID numericTrackId,
std::string* trackId) const;
#endif
static std::string GetTrackId(const dom::MediaStreamTrack& track);
@ -669,6 +674,8 @@ private:
// or other things.
void RecordLongtermICEStatistics();
void OnNegotiationNeeded();
// Timecard used to measure processing time. This should be the first class
// attribute so that we accurately measure the time required to instantiate
// any other attributes of this class.
@ -754,6 +761,8 @@ private:
bool mTrickle;
bool mShouldSuppressNegotiationNeeded;
public:
//these are temporary until the DataChannel Listen/Connect API is removed
unsigned short listenPort;

View File

@ -38,9 +38,9 @@
#endif
using namespace mozilla::dom;
namespace mozilla {
using namespace dom;
static const char* logTag = "PeerConnectionMedia";
@ -48,7 +48,7 @@ nsresult LocalSourceStreamInfo::ReplaceTrack(const std::string& oldTrackId,
DOMMediaStream* aNewStream,
const std::string& newTrackId)
{
mozilla::RefPtr<mozilla::MediaPipeline> pipeline = mPipelines[oldTrackId];
RefPtr<MediaPipeline> pipeline = mPipelines[oldTrackId];
if (!pipeline || !mTracks.count(oldTrackId)) {
CSFLogError(logTag, "Failed to find track id %s", oldTrackId.c_str());
@ -56,7 +56,7 @@ nsresult LocalSourceStreamInfo::ReplaceTrack(const std::string& oldTrackId,
}
nsresult rv =
static_cast<mozilla::MediaPipelineTransmit*>(pipeline.get())->ReplaceTrack(
static_cast<MediaPipelineTransmit*>(pipeline.get())->ReplaceTrack(
aNewStream, newTrackId);
NS_ENSURE_SUCCESS(rv, rv);
@ -66,6 +66,40 @@ nsresult LocalSourceStreamInfo::ReplaceTrack(const std::string& oldTrackId,
return NS_OK;
}
static void
PipelineReleaseRef_m(RefPtr<MediaPipeline> pipeline)
{}
static void
PipelineDetachTransport_s(RefPtr<MediaPipeline> pipeline,
nsCOMPtr<nsIThread> mainThread)
{
pipeline->ShutdownTransport_s();
mainThread->Dispatch(
// Make sure we let go of our reference before dispatching
// If the dispatch fails, well, we're hosed anyway.
WrapRunnableNM(PipelineReleaseRef_m, pipeline.forget()),
NS_DISPATCH_NORMAL);
}
void
SourceStreamInfo::RemoveTrack(const std::string& trackId)
{
mTracks.erase(trackId);
// Pipelines are already holding onto a ref to these.
mConduits.erase(trackId);
RefPtr<MediaPipeline> pipeline = GetPipelineByTrackId_m(trackId);
if (pipeline) {
mPipelines.erase(trackId);
pipeline->ShutdownMedia_m();
mParent->GetSTSThread()->Dispatch(
WrapRunnableNM(PipelineDetachTransport_s,
pipeline.forget(),
mParent->GetMainThread()),
NS_DISPATCH_NORMAL);
}
}
void SourceStreamInfo::DetachTransport_s()
{
ASSERT_ON_THREAD(mParent->GetSTSThread());
@ -160,7 +194,7 @@ PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
mParentName(parent->GetName()),
mAllowIceLoopback(false),
mIceCtx(nullptr),
mDNSResolver(new mozilla::NrIceResolver()),
mDNSResolver(new NrIceResolver()),
mUuidGen(MakeUnique<PCUuidGenerator>()),
mMainThread(mParent->GetMainThread()),
mSTSThread(mParent->GetSTSThread()),
@ -261,16 +295,11 @@ nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_serv
}
void
PeerConnectionMedia::UpdateTransports(const mozilla::JsepSession& session) {
PeerConnectionMedia::UpdateTransports(const JsepSession& session) {
size_t numTransports = session.GetTransportCount();
for (size_t i = 0; i < numTransports; ++i) {
RefPtr<JsepTransport> transport;
nsresult rv = session.GetTransport(i, &transport);
MOZ_ASSERT(NS_SUCCEEDED(rv));
if (NS_FAILED(rv))
break;
auto transports = session.GetTransports();
for (size_t i = 0; i < transports.size(); ++i) {
RefPtr<JsepTransport> transport = transports[i];
std::string ufrag;
std::string pwd;
@ -278,6 +307,8 @@ PeerConnectionMedia::UpdateTransports(const mozilla::JsepSession& session) {
bool hasAttrs = false;
if (transport->mIce) {
CSFLogDebug(logTag, "Transport %u is active",
static_cast<unsigned>(i));
hasAttrs = true;
ufrag = transport->mIce->GetUfrag();
pwd = transport->mIce->GetPassword();
@ -285,8 +316,6 @@ PeerConnectionMedia::UpdateTransports(const mozilla::JsepSession& session) {
}
// Update the transport.
// TODO(bug 1017888): don't repeat candidates on renegotiation. Perhaps
// suppress inside nICEr?
RUN_ON_THREAD(GetSTSThread(),
WrapRunnable(RefPtr<PeerConnectionMedia>(this),
&PeerConnectionMedia::UpdateIceMediaStream_s,
@ -300,37 +329,28 @@ PeerConnectionMedia::UpdateTransports(const mozilla::JsepSession& session) {
}
// TODO(bug 1017888): Need to deal properly with renegotatiation.
// For now just start gathering.
GatherIfReady();
}
nsresult PeerConnectionMedia::UpdateMediaPipelines(
const mozilla::JsepSession& session) {
size_t numPairs = session.GetNegotiatedTrackPairCount();
mozilla::MediaPipelineFactory factory(this);
const mozilla::JsepTrackPair* pair;
const JsepSession& session) {
auto trackPairs = session.GetNegotiatedTrackPairs();
MediaPipelineFactory factory(this);
nsresult rv;
for (size_t i = 0; i < numPairs; ++i) {
nsresult rv = session.GetNegotiatedTrackPair(i, &pair);
if (NS_FAILED(rv)) {
MOZ_ASSERT(false);
return rv;
}
for (auto i = trackPairs.begin(); i != trackPairs.end(); ++i) {
JsepTrackPair pair = *i;
if (pair->mReceiving) {
rv = factory.CreateMediaPipeline(*pair, *pair->mReceiving);
if (pair.mReceiving) {
rv = factory.CreateOrUpdateMediaPipeline(pair, *pair.mReceiving);
if (NS_FAILED(rv)) {
CSFLogError(logTag, "Failed to create receiving pipeline, rv=%u",
static_cast<unsigned>(rv));
return rv;
}
}
if (pair->mSending) {
rv = factory.CreateMediaPipeline(*pair, *pair->mSending);
if (pair.mSending) {
rv = factory.CreateOrUpdateMediaPipeline(pair, *pair.mSending);
if (NS_FAILED(rv)) {
CSFLogError(logTag, "Failed to create sending pipeline, rv=%u",
static_cast<unsigned>(rv));
return rv;
}
}
@ -340,26 +360,19 @@ nsresult PeerConnectionMedia::UpdateMediaPipelines(
}
void
PeerConnectionMedia::StartIceChecks(const mozilla::JsepSession& session) {
PeerConnectionMedia::StartIceChecks(const JsepSession& session) {
std::vector<size_t> numComponentsByLevel;
for (size_t i = 0; i < session.GetTransportCount(); ++i) {
RefPtr<JsepTransport> transport;
nsresult rv = session.GetTransport(i, &transport);
if (NS_FAILED(rv)) {
CSFLogError(logTag, "JsepSession::GetTransport() failed: %u",
static_cast<unsigned>(rv));
MOZ_ASSERT(false, "JsepSession::GetTransport() failed!");
break;
}
auto transports = session.GetTransports();
for (auto i = transports.begin(); i != transports.end(); ++i) {
RefPtr<JsepTransport> transport = *i;
if (transport->mState == JsepTransport::kJsepTransportClosed) {
CSFLogDebug(logTag, "Transport %u is disabled",
static_cast<unsigned>(i));
CSFLogDebug(logTag, "Transport %s is disabled",
transport->mTransportId.c_str());
numComponentsByLevel.push_back(0);
} else {
CSFLogDebug(logTag, "Transport %u has %u components",
static_cast<unsigned>(i),
CSFLogDebug(logTag, "Transport %s has %u components",
transport->mTransportId.c_str(),
static_cast<unsigned>(transport->mComponents));
numComponentsByLevel.push_back(transport->mComponents);
}
@ -411,8 +424,12 @@ PeerConnectionMedia::StartIceChecks_s(
for (size_t i = 0; i < aComponentCountByLevel.size(); ++i) {
RefPtr<NrIceMediaStream> stream(mIceCtx->GetStream(i));
if (!stream) {
MOZ_ASSERT(false, "JsepSession has more streams than the ICE ctx");
break;
continue;
}
if (!stream->HasParsedAttributes()) {
// Inactive stream. Remove.
mIceCtx->RemoveStream(i);
}
for (size_t c = aComponentCountByLevel[i]; c < stream->components(); ++c) {
@ -496,12 +513,10 @@ PeerConnectionMedia::GatherIfReady() {
void
PeerConnectionMedia::EnsureIceGathering_s() {
if (mIceCtx->gathering_state() == NrIceCtx::ICE_CTX_GATHER_INIT) {
if (mProxyServer) {
mIceCtx->SetProxyServer(*mProxyServer);
}
mIceCtx->StartGathering();
if (mProxyServer) {
mIceCtx->SetProxyServer(*mProxyServer);
}
mIceCtx->StartGathering();
}
void
@ -526,9 +541,14 @@ PeerConnectionMedia::UpdateIceMediaStream_s(size_t aMLine,
RefPtr<NrIceMediaStream> stream;
if (mIceStreams.size() == aMLine) {
mIceStreams.push_back(nullptr);
}
if (!mIceStreams[aMLine]) {
std::ostringstream os;
os << mParentName << " level=" << aMLine;
stream = mIceCtx->CreateStream(os.str().c_str(), aComponentCount);
stream = mIceCtx->CreateStream(os.str().c_str(),
aComponentCount);
if (!stream) {
CSFLogError(logTag, "Failed to create ICE stream.");
@ -540,12 +560,12 @@ PeerConnectionMedia::UpdateIceMediaStream_s(size_t aMLine,
stream->SignalCandidate.connect(this,
&PeerConnectionMedia::OnCandidateFound_s);
mIceStreams.push_back(stream);
mIceStreams[aMLine] = stream;
} else {
stream = mIceStreams[aMLine];
}
if (aHasAttrs) {
if (aHasAttrs && !stream->HasParsedAttributes()) {
std::vector<std::string> attrs;
for (auto i = aCandidateList.begin(); i != aCandidateList.end(); ++i) {
attrs.push_back("candidate:" + *i);
@ -595,17 +615,17 @@ PeerConnectionMedia::AddTrack(DOMMediaStream* aMediaStream,
}
nsresult
PeerConnectionMedia::RemoveTrack(DOMMediaStream* aMediaStream,
const std::string& trackId)
PeerConnectionMedia::RemoveLocalTrack(const std::string& streamId,
const std::string& trackId)
{
MOZ_ASSERT(aMediaStream);
ASSERT_ON_THREAD(mMainThread);
CSFLogDebug(logTag, "%s: MediaStream: %p", __FUNCTION__, aMediaStream);
CSFLogDebug(logTag, "%s: stream: %s track: %s", __FUNCTION__,
streamId.c_str(), trackId.c_str());
size_t i;
for (i = 0; i < mLocalSourceStreams.Length(); ++i) {
if (mLocalSourceStreams[i]->GetMediaStream() == aMediaStream) {
if (mLocalSourceStreams[i]->GetId() == streamId) {
break;
}
}
@ -621,6 +641,50 @@ PeerConnectionMedia::RemoveTrack(DOMMediaStream* aMediaStream,
return NS_OK;
}
nsresult
PeerConnectionMedia::RemoveRemoteTrack(const std::string& streamId,
const std::string& trackId)
{
ASSERT_ON_THREAD(mMainThread);
CSFLogDebug(logTag, "%s: stream: %s track: %s", __FUNCTION__,
streamId.c_str(), trackId.c_str());
size_t i;
for (i = 0; i < mRemoteSourceStreams.Length(); ++i) {
if (mRemoteSourceStreams[i]->GetId() == streamId) {
break;
}
}
if (i == mRemoteSourceStreams.Length()) {
return NS_ERROR_ILLEGAL_VALUE;
}
mRemoteSourceStreams[i]->RemoveTrack(trackId);
if (!(mRemoteSourceStreams[i]->GetTrackCount())) {
mRemoteSourceStreams.RemoveElementAt(i);
}
return NS_OK;
}
nsresult
PeerConnectionMedia::GetRemoteTrackId(DOMMediaStream* mediaStream,
TrackID numericTrackId,
std::string* trackId) const
{
auto* ncThis = const_cast<PeerConnectionMedia*>(this);
const RemoteSourceStreamInfo* info =
ncThis->GetRemoteStreamByDomStream(*mediaStream);
if (!info) {
CSFLogError(logTag, "%s: Could not find stream info", __FUNCTION__);
return NS_ERROR_NOT_AVAILABLE;
}
return info->GetTrackId(numericTrackId, trackId);
}
void
PeerConnectionMedia::SelfDestruct()
{
@ -732,7 +796,8 @@ PeerConnectionMedia::GetLocalStreamByDomStream(const DOMMediaStream& stream)
}
RemoteSourceStreamInfo*
PeerConnectionMedia::GetRemoteStreamByDomStream(const DOMMediaStream& stream)
PeerConnectionMedia::GetRemoteStreamByDomStream(
const DOMMediaStream& stream)
{
ASSERT_ON_THREAD(mMainThread);
for (size_t i = 0; i < mRemoteSourceStreams.Length(); ++i) {
@ -770,62 +835,6 @@ PeerConnectionMedia::GetRemoteStreamById(const std::string& id)
return nullptr;
}
static void
UpdateFilterFromRemoteDescription_s(
RefPtr<mozilla::MediaPipeline> receive,
RefPtr<mozilla::MediaPipeline> transmit,
nsAutoPtr<mozilla::MediaPipelineFilter> filter) {
// Update filter, and make a copy of the final version.
mozilla::MediaPipelineFilter *finalFilter(
receive->UpdateFilterFromRemoteDescription_s(filter));
if (finalFilter) {
filter = new mozilla::MediaPipelineFilter(*finalFilter);
}
// Set same filter on transmit pipeline too.
transmit->UpdateFilterFromRemoteDescription_s(filter);
}
bool
PeerConnectionMedia::UpdateFilterFromRemoteDescription_m(
const std::string& trackId,
nsAutoPtr<mozilla::MediaPipelineFilter> filter)
{
ASSERT_ON_THREAD(mMainThread);
RefPtr<mozilla::MediaPipeline> receive;
for (size_t i = 0; !receive && i < mRemoteSourceStreams.Length(); ++i) {
receive = mRemoteSourceStreams[i]->GetPipelineByTrackId_m(trackId);
}
RefPtr<mozilla::MediaPipeline> transmit;
for (size_t i = 0; !transmit && i < mLocalSourceStreams.Length(); ++i) {
transmit = mLocalSourceStreams[i]->GetPipelineByTrackId_m(trackId);
}
if (receive && transmit) {
// GetPipelineByLevel_m will return nullptr if shutdown is in progress;
// since shutdown is initiated in main, and involves a dispatch to STS
// before the pipelines are released, our dispatch to STS will complete
// before any release can happen due to a shutdown that hasn't started yet.
RUN_ON_THREAD(GetSTSThread(),
WrapRunnableNM(
&UpdateFilterFromRemoteDescription_s,
receive,
transmit,
filter
),
NS_DISPATCH_NORMAL);
return true;
} else {
CSFLogWarn(logTag, "Could not locate track %s to update filter",
trackId.c_str());
}
return false;
}
nsresult
PeerConnectionMedia::AddRemoteStream(nsRefPtr<RemoteSourceStreamInfo> aInfo)
{
@ -1112,21 +1121,35 @@ SourceStreamInfo::AnyCodecHasPluginID(uint64_t aPluginID)
nsresult
SourceStreamInfo::StorePipeline(
const std::string& trackId,
const mozilla::RefPtr<mozilla::MediaPipeline>& aPipeline)
const std::string& trackId,
const mozilla::RefPtr<mozilla::MediaPipeline>& aPipeline)
{
MOZ_ASSERT(mPipelines.find(trackId) == mPipelines.end());
if (mPipelines.find(trackId) != mPipelines.end()) {
CSFLogError(logTag, "%s: Storing duplicate track", __FUNCTION__);
return NS_ERROR_FAILURE;
}
mPipelines[trackId] = aPipeline;
return NS_OK;
}
nsresult
SourceStreamInfo::StoreConduit(const std::string& trackId,
RefPtr<MediaSessionConduit> aConduit)
{
MOZ_ASSERT(mConduits.find(trackId) == mConduits.end());
if (mConduits.find(trackId) != mConduits.end()) {
CSFLogError(logTag, "%s: Storing duplicate track", __FUNCTION__);
return NS_ERROR_FAILURE;
}
mConduits[trackId] = aConduit;
return NS_OK;
}
void
RemoteSourceStreamInfo::SyncPipeline(
mozilla::RefPtr<mozilla::MediaPipelineReceive> aPipeline)
RefPtr<MediaPipelineReceive> aPipeline)
{
// See if we have both audio and video here, and if so cross the streams and
// sync them
@ -1136,12 +1159,12 @@ RemoteSourceStreamInfo::SyncPipeline(
for (auto i = mPipelines.begin(); i != mPipelines.end(); ++i) {
if (i->second->IsVideo() != aPipeline->IsVideo()) {
// Ok, we have one video, one non-video - cross the streams!
mozilla::WebrtcAudioConduit *audio_conduit =
static_cast<mozilla::WebrtcAudioConduit*>(aPipeline->IsVideo() ?
WebrtcAudioConduit *audio_conduit =
static_cast<WebrtcAudioConduit*>(aPipeline->IsVideo() ?
i->second->Conduit() :
aPipeline->Conduit());
mozilla::WebrtcVideoConduit *video_conduit =
static_cast<mozilla::WebrtcVideoConduit*>(aPipeline->IsVideo() ?
WebrtcVideoConduit *video_conduit =
static_cast<WebrtcVideoConduit*>(aPipeline->IsVideo() ?
aPipeline->Conduit() :
i->second->Conduit());
video_conduit->SyncTo(audio_conduit);
@ -1170,4 +1193,22 @@ RefPtr<MediaPipeline> SourceStreamInfo::GetPipelineByTrackId_m(
return nullptr;
}
RefPtr<MediaSessionConduit> SourceStreamInfo::GetConduitByTrackId_m(
const std::string& trackId) {
ASSERT_ON_THREAD(mParent->GetMainThread());
// Refuse to hand out references if we're tearing down.
// (Since teardown involves a dispatch to and from STS before MediaConduits
// are released, it is safe to start other dispatches to and from STS with a
// RefPtr<MediaConduit>, since that reference won't be the last one
// standing)
if (mMediaStream) {
if (mConduits.count(trackId)) {
return mConduits[trackId];
}
}
return nullptr;
}
} // namespace mozilla

View File

@ -77,16 +77,20 @@ public:
MOZ_ASSERT(mMediaStream);
}
virtual ~SourceStreamInfo() {}
DOMMediaStream* GetMediaStream() const {
return mMediaStream;
}
nsresult StorePipeline(
const std::string& trackId,
const mozilla::RefPtr<mozilla::MediaPipeline>& aPipeline);
nsresult StorePipeline(const std::string& trackId,
const RefPtr<MediaPipeline>& aPipeline);
void AddTrack(const std::string& trackId) { mTracks.insert(trackId); }
void RemoveTrack(const std::string& trackId) { mTracks.erase(trackId); }
nsresult StoreConduit(const std::string& trackId,
RefPtr<MediaSessionConduit> aConduit);
virtual void AddTrack(const std::string& trackId) { mTracks.insert(trackId); }
void RemoveTrack(const std::string& trackId);
bool HasTrack(const std::string& trackId) const
{
return !!mTracks.count(trackId);
@ -95,10 +99,10 @@ public:
// This method exists for stats and the unittests.
// It allows visibility into the pipelines and flows.
const std::map<std::string, mozilla::RefPtr<mozilla::MediaPipeline>>&
const std::map<std::string, RefPtr<MediaPipeline>>&
GetPipelines() const { return mPipelines; }
mozilla::RefPtr<mozilla::MediaPipeline> GetPipelineByTrackId_m(
const std::string& trackId);
RefPtr<MediaPipeline> GetPipelineByTrackId_m(const std::string& trackId);
RefPtr<MediaSessionConduit> GetConduitByTrackId_m(const std::string& trackId);
const std::string& GetId() const { return mId; }
void DetachTransport_s();
@ -109,10 +113,10 @@ protected:
PeerConnectionMedia *mParent;
const std::string mId;
// These get set up before we generate our local description, the pipelines
// are set up once offer/answer completes.
// and conduits are set up once offer/answer completes.
std::set<std::string> mTracks;
// Indexed by track id, might contain pipelines for removed tracks
std::map<std::string, mozilla::RefPtr<mozilla::MediaPipeline>> mPipelines;
std::map<std::string, RefPtr<MediaPipeline>> mPipelines;
std::map<std::string, RefPtr<MediaSessionConduit>> mConduits;
};
// TODO(ekr@rtfm.com): Refactor {Local,Remote}SourceStreamInfo
@ -136,7 +140,7 @@ public:
#ifdef MOZILLA_INTERNAL_API
void UpdateSinkIdentity_m(nsIPrincipal* aPrincipal,
const mozilla::PeerIdentity* aSinkIdentity);
const PeerIdentity* aSinkIdentity);
#endif
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LocalSourceStreamInfo)
@ -159,6 +163,43 @@ class RemoteSourceStreamInfo : public SourceStreamInfo {
#endif
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RemoteSourceStreamInfo)
virtual void AddTrack(const std::string& track) MOZ_OVERRIDE
{
mTrackIdMap.push_back(track);
SourceStreamInfo::AddTrack(track);
}
TrackID GetNumericTrackId(const std::string& trackId) const
{
for (size_t i = 0; i < mTrackIdMap.size(); ++i) {
if (mTrackIdMap[i] == trackId) {
return static_cast<TrackID>(i + 1);
}
}
return TRACK_INVALID;
}
nsresult GetTrackId(TrackID numericTrackId, std::string* trackId) const
{
if (numericTrackId <= 0 ||
static_cast<size_t>(numericTrackId) > mTrackIdMap.size()) {
return NS_ERROR_INVALID_ARG;;
}
*trackId = mTrackIdMap[numericTrackId - 1];
return NS_OK;
}
private:
// For remote streams, the MediaStreamGraph API forces us to select a
// numeric track id before creation of the MediaStreamTrack, and does not
// allow us to specify a string-based id until later. We cannot simply use
// something based on mline index, since renegotiation can move tracks
// around. Hopefully someday we'll be able to specify the string id up-front,
// and have the numeric track id selected for us, in which case this variable
// and its dependencies can go away.
std::vector<std::string> mTrackIdMap;
};
class PeerConnectionMedia : public sigslot::has_slots<> {
@ -168,17 +209,17 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
explicit PeerConnectionMedia(PeerConnectionImpl *parent);
PeerConnectionImpl* GetPC() { return mParent; }
nsresult Init(const std::vector<mozilla::NrIceStunServer>& stun_servers,
const std::vector<mozilla::NrIceTurnServer>& turn_servers);
nsresult Init(const std::vector<NrIceStunServer>& stun_servers,
const std::vector<NrIceTurnServer>& turn_servers);
// WARNING: This destroys the object!
void SelfDestruct();
// Configure the ability to use localhost.
void SetAllowIceLoopback(bool val) { mAllowIceLoopback = val; }
mozilla::RefPtr<mozilla::NrIceCtx> ice_ctx() const { return mIceCtx; }
RefPtr<NrIceCtx> ice_ctx() const { return mIceCtx; }
mozilla::RefPtr<mozilla::NrIceMediaStream> ice_media_stream(size_t i) const {
RefPtr<NrIceMediaStream> ice_media_stream(size_t i) const {
// TODO(ekr@rtfm.com): If someone asks for a value that doesn't exist,
// make one.
if (i >= mIceStreams.size()) {
@ -192,17 +233,17 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
}
// Create and modify transports in response to negotiation events.
void UpdateTransports(const mozilla::JsepSession& session);
void UpdateTransports(const JsepSession& session);
// Start ICE checks.
void StartIceChecks(const mozilla::JsepSession& session);
void StartIceChecks(const JsepSession& session);
// Process a trickle ICE candidate.
void AddIceCandidate(const std::string& candidate, const std::string& mid,
uint32_t aMLine);
// Handle complete media pipelines.
nsresult UpdateMediaPipelines(const mozilla::JsepSession& session);
nsresult UpdateMediaPipelines(const JsepSession& session);
// Add a track (main thread only)
// TODO(bug 1089798): Once DOMMediaStream has an id field, use it instead of
@ -211,11 +252,14 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
std::string* streamId,
const std::string& trackId);
// Remove a track (main thread only)
// TODO(bug 1089798): Once DOMMediaStream has an id field, use it instead of
// passing |aMediaStream|
nsresult RemoveTrack(DOMMediaStream* aMediaStream,
const std::string& trackId);
nsresult RemoveLocalTrack(const std::string& streamId,
const std::string& trackId);
nsresult RemoveRemoteTrack(const std::string& streamId,
const std::string& trackId);
nsresult GetRemoteTrackId(DOMMediaStream* mediaStream,
TrackID numericTrackId,
std::string* trackId) const;
// Get a specific local stream
uint32_t LocalStreamsLength()
@ -238,11 +282,6 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
RemoteSourceStreamInfo* GetRemoteStreamByDomStream(
const DOMMediaStream& stream);
bool UpdateFilterFromRemoteDescription_m(
const std::string& trackId,
nsAutoPtr<mozilla::MediaPipelineFilter> filter);
// Add a remote stream.
nsresult AddRemoteStream(nsRefPtr<RemoteSourceStreamInfo> aInfo);
@ -251,7 +290,7 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// the stream, that would potentially affect others), so that it sends
// black/silence. Once the peer is identified, re-enable those streams.
void UpdateSinkIdentity_m(nsIPrincipal* aPrincipal,
const mozilla::PeerIdentity* aSinkIdentity);
const PeerIdentity* aSinkIdentity);
// this determines if any stream is peerIdentity constrained
bool AnyLocalStreamHasPeerIdentity() const;
// When we finally learn who is on the other end, we need to change the ownership
@ -266,7 +305,7 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// Get a transport flow either RTP/RTCP for a particular stream
// A stream can be of audio/video/datachannel/budled(?) types
mozilla::RefPtr<mozilla::TransportFlow> GetTransportFlow(int aStreamIndex,
RefPtr<TransportFlow> GetTransportFlow(int aStreamIndex,
bool aIsRtcp) {
int index_inner = aStreamIndex * 2 + (aIsRtcp ? 1 : 0);
@ -278,35 +317,55 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// Add a transport flow
void AddTransportFlow(int aIndex, bool aRtcp,
const mozilla::RefPtr<mozilla::TransportFlow> &aFlow);
void ConnectDtlsListener_s(const mozilla::RefPtr<mozilla::TransportFlow>& aFlow);
void DtlsConnected_s(mozilla::TransportLayer* aFlow,
mozilla::TransportLayer::State state);
const RefPtr<TransportFlow> &aFlow);
void ConnectDtlsListener_s(const RefPtr<TransportFlow>& aFlow);
void DtlsConnected_s(TransportLayer* aFlow,
TransportLayer::State state);
static void DtlsConnected_m(const std::string& aParentHandle,
bool aPrivacyRequested);
mozilla::RefPtr<mozilla::MediaSessionConduit> GetConduit(int aStreamIndex, bool aReceive) {
int index_inner = aStreamIndex * 2 + (aReceive ? 0 : 1);
RefPtr<MediaSessionConduit> GetConduit(const std::string& streamId,
const std::string& trackId,
bool aReceive) {
SourceStreamInfo* info;
if (aReceive) {
info = GetRemoteStreamById(streamId);
} else {
info = GetLocalStreamById(streamId);
}
if (mConduits.find(index_inner) == mConduits.end())
if (!info) {
MOZ_ASSERT(false);
return nullptr;
}
return mConduits[index_inner];
return info->GetConduitByTrackId_m(trackId);
}
// Add a conduit
void AddConduit(int aIndex, bool aReceive,
const mozilla::RefPtr<mozilla::MediaSessionConduit> &aConduit) {
int index_inner = aIndex * 2 + (aReceive ? 0 : 1);
void AddConduit(const std::string& streamId,
const std::string& trackId,
bool aReceive,
const RefPtr<MediaSessionConduit> &aConduit) {
SourceStreamInfo* info;
if (aReceive) {
info = GetRemoteStreamById(streamId);
} else {
info = GetLocalStreamById(streamId);
}
MOZ_ASSERT(!mConduits[index_inner]);
mConduits[index_inner] = aConduit;
if (!info) {
MOZ_ASSERT(false);
return;
}
info->StoreConduit(trackId, aConduit);
}
// ICE state signals
sigslot::signal2<mozilla::NrIceCtx*, mozilla::NrIceCtx::GatheringState>
sigslot::signal2<NrIceCtx*, NrIceCtx::GatheringState>
SignalIceGatheringStateChange;
sigslot::signal2<mozilla::NrIceCtx*, mozilla::NrIceCtx::ConnectionState>
sigslot::signal2<NrIceCtx*, NrIceCtx::ConnectionState>
SignalIceConnectionStateChange;
// This passes a candidate:... attribute and level
sigslot::signal2<const std::string&, uint16_t> SignalCandidate;
@ -359,21 +418,21 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
// ICE events
void IceGatheringStateChange_s(mozilla::NrIceCtx* ctx,
mozilla::NrIceCtx::GatheringState state);
void IceConnectionStateChange_s(mozilla::NrIceCtx* ctx,
mozilla::NrIceCtx::ConnectionState state);
void IceStreamReady_s(mozilla::NrIceMediaStream *aStream);
void OnCandidateFound_s(mozilla::NrIceMediaStream *aStream,
void IceGatheringStateChange_s(NrIceCtx* ctx,
NrIceCtx::GatheringState state);
void IceConnectionStateChange_s(NrIceCtx* ctx,
NrIceCtx::ConnectionState state);
void IceStreamReady_s(NrIceMediaStream *aStream);
void OnCandidateFound_s(NrIceMediaStream *aStream,
const std::string &candidate);
void EndOfLocalCandidates(const std::string& aDefaultAddr,
uint16_t aDefaultPort,
uint16_t aMLine);
void IceGatheringStateChange_m(mozilla::NrIceCtx* ctx,
mozilla::NrIceCtx::GatheringState state);
void IceConnectionStateChange_m(mozilla::NrIceCtx* ctx,
mozilla::NrIceCtx::ConnectionState state);
void IceGatheringStateChange_m(NrIceCtx* ctx,
NrIceCtx::GatheringState state);
void IceConnectionStateChange_m(NrIceCtx* ctx,
NrIceCtx::ConnectionState state);
void OnCandidateFound_m(const std::string &candidate, uint16_t aMLine);
void EndOfLocalCandidates_m(const std::string& aDefaultAddr,
uint16_t aDefaultPort,
@ -382,7 +441,6 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
return mProxyResolveCompleted;
}
// The parent PC
PeerConnectionImpl *mParent;
// and a loose handle on it for event driven stuff
@ -401,21 +459,17 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
bool mAllowIceLoopback;
// ICE objects
mozilla::RefPtr<mozilla::NrIceCtx> mIceCtx;
std::vector<mozilla::RefPtr<mozilla::NrIceMediaStream> > mIceStreams;
RefPtr<NrIceCtx> mIceCtx;
std::vector<RefPtr<NrIceMediaStream> > mIceStreams;
// DNS
nsRefPtr<mozilla::NrIceResolver> mDNSResolver;
nsRefPtr<NrIceResolver> mDNSResolver;
// Transport flows: even is RTP, odd is RTCP
std::map<int, mozilla::RefPtr<mozilla::TransportFlow> > mTransportFlows;
// Conduits: even is receive, odd is transmit (for easier correlation with
// flows)
std::map<int, mozilla::RefPtr<mozilla::MediaSessionConduit> > mConduits;
std::map<int, RefPtr<TransportFlow> > mTransportFlows;
// UUID Generator
mozilla::UniquePtr<PCUuidGenerator> mUuidGen;
UniquePtr<PCUuidGenerator> mUuidGen;
// The main thread.
nsCOMPtr<nsIThread> mMainThread;

View File

@ -90,6 +90,7 @@ public:
virtual void AddCodec(const std::string& pt, const std::string& name,
uint32_t clockrate, uint16_t channels) = 0;
virtual void ClearCodecs() = 0;
virtual void AddDataChannel(const std::string& pt, const std::string& name,
uint16_t streams) = 0;
@ -100,6 +101,53 @@ public:
return mLevel;
}
inline bool
IsReceiving() const
{
return GetDirectionAttribute().mValue & SdpDirectionAttribute::kRecvFlag;
}
inline bool
IsSending() const
{
return GetDirectionAttribute().mValue & SdpDirectionAttribute::kSendFlag;
}
inline void
SetReceiving(bool receiving)
{
auto direction = GetDirectionAttribute().mValue;
if (direction & SdpDirectionAttribute::kSendFlag) {
SetDirection(receiving ?
SdpDirectionAttribute::kSendrecv :
SdpDirectionAttribute::kSendonly);
} else {
SetDirection(receiving ?
SdpDirectionAttribute::kRecvonly :
SdpDirectionAttribute::kInactive);
}
}
inline void
SetSending(bool sending)
{
auto direction = GetDirectionAttribute().mValue;
if (direction & SdpDirectionAttribute::kRecvFlag) {
SetDirection(sending ?
SdpDirectionAttribute::kSendrecv :
SdpDirectionAttribute::kRecvonly);
} else {
SetDirection(sending ?
SdpDirectionAttribute::kSendonly :
SdpDirectionAttribute::kInactive);
}
}
inline void SetDirection(SdpDirectionAttribute::Direction direction)
{
GetAttributeList().SetAttribute(new SdpDirectionAttribute(direction));
}
private:
size_t mLevel;
};

View File

@ -290,6 +290,16 @@ SipccSdpMediaSection::AddCodec(const std::string& pt, const std::string& name,
mAttributeList.SetAttribute(rtpmap);
}
void
SipccSdpMediaSection::ClearCodecs()
{
mFormats.clear();
mAttributeList.RemoveAttribute(SdpAttribute::kRtpmapAttribute);
mAttributeList.RemoveAttribute(SdpAttribute::kFmtpAttribute);
mAttributeList.RemoveAttribute(SdpAttribute::kSctpmapAttribute);
mAttributeList.RemoveAttribute(SdpAttribute::kRtcpFbAttribute);
}
void
SipccSdpMediaSection::AddDataChannel(const std::string& pt,
const std::string& name, uint16_t streams)

View File

@ -59,6 +59,7 @@ public:
virtual void AddCodec(const std::string& pt, const std::string& name,
uint32_t clockrate, uint16_t channels) MOZ_OVERRIDE;
virtual void ClearCodecs() MOZ_OVERRIDE;
virtual void AddDataChannel(const std::string& pt, const std::string& name,
uint16_t streams) MOZ_OVERRIDE;

View File

@ -79,16 +79,17 @@ public:
virtual NS_IMETHODIMP NotifyDataChannel(nsIDOMDataChannel *channel, ER&) = 0;
virtual NS_IMETHODIMP OnStateChange(mozilla::dom::PCObserverStateType state_type, ER&,
void* = nullptr) = 0;
virtual NS_IMETHODIMP OnAddStream(mozilla::DOMMediaStream *stream, ER&) = 0;
virtual NS_IMETHODIMP OnRemoveStream(ER&) = 0;
virtual NS_IMETHODIMP OnAddTrack(ER&) = 0;
virtual NS_IMETHODIMP OnRemoveTrack(ER&) = 0;
virtual NS_IMETHODIMP OnAddStream(mozilla::DOMMediaStream &stream, ER&) = 0;
virtual NS_IMETHODIMP OnRemoveStream(mozilla::DOMMediaStream &stream, ER&) = 0;
virtual NS_IMETHODIMP OnAddTrack(mozilla::MediaStreamTrack &track, ER&) = 0;
virtual NS_IMETHODIMP OnRemoveTrack(mozilla::MediaStreamTrack &track, ER&) = 0;
virtual NS_IMETHODIMP OnReplaceTrackSuccess(ER&) = 0;
virtual NS_IMETHODIMP OnReplaceTrackError(uint32_t code, const char *msg, ER&) = 0;
virtual NS_IMETHODIMP OnAddIceCandidateSuccess(ER&) = 0;
virtual NS_IMETHODIMP OnAddIceCandidateError(uint32_t code, const char *msg, ER&) = 0;
virtual NS_IMETHODIMP OnIceCandidate(uint16_t level, const char *mid,
const char *candidate, ER&) = 0;
virtual NS_IMETHODIMP OnNegotiationNeeded(ER&) = 0;
protected:
mozilla::PeerConnectionImpl *pc;
std::vector<mozilla::DOMMediaStream *> streams;

View File

@ -245,17 +245,16 @@ protected:
if (checkFlags & CHECK_TRACKS) {
// Check that the transports exist.
ASSERT_EQ(types.size(), mSessionOff.GetTransportCount());
ASSERT_EQ(types.size(), mSessionOff.GetTransports().size());
auto tracks = mSessionOff.GetLocalTracks();
for (size_t i = 0; i < types.size(); ++i) {
RefPtr<JsepTrack> ltrack;
ASSERT_EQ(NS_OK, mSessionOff.GetLocalTrack(i, &ltrack));
ASSERT_NE("", ltrack->GetStreamId());
ASSERT_NE("", ltrack->GetTrackId());
if (ltrack->GetMediaType() != SdpMediaSection::kApplication) {
ASSERT_NE("", tracks[i]->GetStreamId());
ASSERT_NE("", tracks[i]->GetTrackId());
if (tracks[i]->GetMediaType() != SdpMediaSection::kApplication) {
std::string msidAttr("a=msid:");
msidAttr += ltrack->GetStreamId();
msidAttr += tracks[i]->GetStreamId();
msidAttr += " ";
msidAttr += ltrack->GetTrackId();
msidAttr += tracks[i]->GetTrackId();
ASSERT_NE(std::string::npos, offer.find(msidAttr))
<< "Did not find " << msidAttr << " in offer";
}
@ -273,19 +272,18 @@ protected:
}
if (checkFlags & CHECK_TRACKS) {
auto tracks = mSessionAns.GetRemoteTracks();
// Now verify that the right stuff is in the tracks.
ASSERT_EQ(types.size(), mSessionAns.GetRemoteTrackCount());
for (size_t i = 0; i < types.size(); ++i) {
RefPtr<JsepTrack> rtrack;
ASSERT_EQ(NS_OK, mSessionAns.GetRemoteTrack(i, &rtrack));
ASSERT_EQ(types[i], rtrack->GetMediaType());
ASSERT_NE("", rtrack->GetStreamId());
ASSERT_NE("", rtrack->GetTrackId());
if (rtrack->GetMediaType() != SdpMediaSection::kApplication) {
ASSERT_EQ(types.size(), tracks.size());
for (size_t i = 0; i < tracks.size(); ++i) {
ASSERT_EQ(types[i], tracks[i]->GetMediaType());
ASSERT_NE("", tracks[i]->GetStreamId());
ASSERT_NE("", tracks[i]->GetTrackId());
if (tracks[i]->GetMediaType() != SdpMediaSection::kApplication) {
std::string msidAttr("a=msid:");
msidAttr += rtrack->GetStreamId();
msidAttr += tracks[i]->GetStreamId();
msidAttr += " ";
msidAttr += rtrack->GetTrackId();
msidAttr += tracks[i]->GetTrackId();
ASSERT_NE(std::string::npos, offer.find(msidAttr))
<< "Did not find " << msidAttr << " in offer";
}
@ -303,26 +301,25 @@ protected:
if (checkFlags & CHECK_TRACKS) {
// Verify that the right stuff is in the tracks.
ASSERT_EQ(types.size(), mSessionAns.GetNegotiatedTrackPairCount());
auto pairs = mSessionAns.GetNegotiatedTrackPairs();
ASSERT_EQ(types.size(), pairs.size());
for (size_t i = 0; i < types.size(); ++i) {
const JsepTrackPair* pair;
ASSERT_EQ(NS_OK, mSessionAns.GetNegotiatedTrackPair(i, &pair));
ASSERT_TRUE(pair->mSending);
ASSERT_EQ(types[i], pair->mSending->GetMediaType());
ASSERT_TRUE(pair->mReceiving);
ASSERT_EQ(types[i], pair->mReceiving->GetMediaType());
ASSERT_NE("", pair->mSending->GetStreamId());
ASSERT_NE("", pair->mSending->GetTrackId());
ASSERT_TRUE(pairs[i].mSending);
ASSERT_EQ(types[i], pairs[i].mSending->GetMediaType());
ASSERT_TRUE(pairs[i].mReceiving);
ASSERT_EQ(types[i], pairs[i].mReceiving->GetMediaType());
ASSERT_NE("", pairs[i].mSending->GetStreamId());
ASSERT_NE("", pairs[i].mSending->GetTrackId());
// These might have been in the SDP, or might have been randomly
// chosen by JsepSessionImpl
ASSERT_NE("", pair->mReceiving->GetStreamId());
ASSERT_NE("", pair->mReceiving->GetTrackId());
ASSERT_NE("", pairs[i].mReceiving->GetStreamId());
ASSERT_NE("", pairs[i].mReceiving->GetTrackId());
if (pair->mReceiving->GetMediaType() != SdpMediaSection::kApplication) {
if (pairs[i].mReceiving->GetMediaType() != SdpMediaSection::kApplication) {
std::string msidAttr("a=msid:");
msidAttr += pair->mSending->GetStreamId();
msidAttr += pairs[i].mSending->GetStreamId();
msidAttr += " ";
msidAttr += pair->mSending->GetTrackId();
msidAttr += pairs[i].mSending->GetTrackId();
ASSERT_NE(std::string::npos, answer.find(msidAttr))
<< "Did not find " << msidAttr << " in offer";
}
@ -341,26 +338,25 @@ protected:
if (checkFlags & CHECK_TRACKS) {
// Verify that the right stuff is in the tracks.
ASSERT_EQ(types.size(), mSessionOff.GetNegotiatedTrackPairCount());
auto pairs = mSessionOff.GetNegotiatedTrackPairs();
ASSERT_EQ(types.size(), pairs.size());
for (size_t i = 0; i < types.size(); ++i) {
const JsepTrackPair* pair;
ASSERT_EQ(NS_OK, mSessionOff.GetNegotiatedTrackPair(i, &pair));
ASSERT_TRUE(pair->mSending);
ASSERT_EQ(types[i], pair->mSending->GetMediaType());
ASSERT_TRUE(pair->mReceiving);
ASSERT_EQ(types[i], pair->mReceiving->GetMediaType());
ASSERT_NE("", pair->mSending->GetStreamId());
ASSERT_NE("", pair->mSending->GetTrackId());
ASSERT_TRUE(pairs[i].mSending);
ASSERT_EQ(types[i], pairs[i].mSending->GetMediaType());
ASSERT_TRUE(pairs[i].mReceiving);
ASSERT_EQ(types[i], pairs[i].mReceiving->GetMediaType());
ASSERT_NE("", pairs[i].mSending->GetStreamId());
ASSERT_NE("", pairs[i].mSending->GetTrackId());
// These might have been in the SDP, or might have been randomly
// chosen by JsepSessionImpl
ASSERT_NE("", pair->mReceiving->GetStreamId());
ASSERT_NE("", pair->mReceiving->GetTrackId());
ASSERT_NE("", pairs[i].mReceiving->GetStreamId());
ASSERT_NE("", pairs[i].mReceiving->GetTrackId());
if (pair->mReceiving->GetMediaType() != SdpMediaSection::kApplication) {
if (pairs[i].mReceiving->GetMediaType() != SdpMediaSection::kApplication) {
std::string msidAttr("a=msid:");
msidAttr += pair->mReceiving->GetStreamId();
msidAttr += pairs[i].mReceiving->GetStreamId();
msidAttr += " ";
msidAttr += pair->mReceiving->GetTrackId();
msidAttr += pairs[i].mReceiving->GetTrackId();
ASSERT_NE(std::string::npos, answer.find(msidAttr))
<< "Did not find " << msidAttr << " in offer";
}
@ -372,14 +368,21 @@ protected:
void
GatherCandidates(JsepSession& session)
{
session.AddLocalIceCandidate(kAEqualsCandidate + kCandidates[0], "", 0);
session.AddLocalIceCandidate(kAEqualsCandidate + kCandidates[1], "", 0);
session.AddLocalIceCandidate(kAEqualsCandidate + kCandidates[2], "", 0);
bool skipped;
session.AddLocalIceCandidate(
kAEqualsCandidate + kCandidates[0], "", 0, &skipped);
session.AddLocalIceCandidate(
kAEqualsCandidate + kCandidates[1], "", 0, &skipped);
session.AddLocalIceCandidate(
kAEqualsCandidate + kCandidates[2], "", 0, &skipped);
session.EndOfLocalCandidates("192.168.0.2", 2002, 0);
session.AddLocalIceCandidate(kAEqualsCandidate + kCandidates[3], "", 1);
session.AddLocalIceCandidate(kAEqualsCandidate + kCandidates[4], "", 1);
session.AddLocalIceCandidate(kAEqualsCandidate + kCandidates[5], "", 1);
session.AddLocalIceCandidate(
kAEqualsCandidate + kCandidates[3], "", 1, &skipped);
session.AddLocalIceCandidate(
kAEqualsCandidate + kCandidates[4], "", 1, &skipped);
session.AddLocalIceCandidate(
kAEqualsCandidate + kCandidates[5], "", 1, &skipped);
session.EndOfLocalCandidates("192.168.1.2", 2012, 1);
std::cerr << "local SDP after candidates: "
@ -505,18 +508,16 @@ protected:
void
DumpTrackPairs(const JsepSessionImpl& session)
{
size_t count = mSessionAns.GetNegotiatedTrackPairCount();
for (size_t i = 0; i < count; ++i) {
std::cerr << "Track pair " << i << std::endl;
const JsepTrackPair* pair;
ASSERT_EQ(NS_OK, mSessionAns.GetNegotiatedTrackPair(i, &pair));
if (pair->mSending) {
auto pairs = mSessionAns.GetNegotiatedTrackPairs();
for (auto i = pairs.begin(); i != pairs.end(); ++i) {
std::cerr << "Track pair " << i->mLevel << std::endl;
if (i->mSending) {
std::cerr << "Sending-->" << std::endl;
DumpTrack(*pair->mSending);
DumpTrack(*i->mSending);
}
if (pair->mReceiving) {
if (i->mReceiving) {
std::cerr << "Receiving-->" << std::endl;
DumpTrack(*pair->mReceiving);
DumpTrack(*i->mReceiving);
}
}
}
@ -530,7 +531,7 @@ private:
ValidateTransport(TransportData& source, const std::string& sdp_str)
{
SipccSdpParser parser;
auto sdp = mozilla::Move(parser.Parse(sdp_str));
auto sdp = parser.Parse(sdp_str);
ASSERT_TRUE(!!sdp) << "Should have valid SDP" << std::endl
<< "Errors were: " << GetParseErrors(parser);
size_t num_m_sections = sdp->GetMediaSectionCount();
@ -672,7 +673,7 @@ TEST_F(JsepSessionTest, OfferAnswerRecvOnlyLines)
std::string offer = CreateOffer(Some(options));
SipccSdpParser parser;
auto outputSdp = mozilla::Move(parser.Parse(offer));
auto outputSdp = parser.Parse(offer);
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
<< "Errors were: " << GetParseErrors(parser);
@ -703,7 +704,7 @@ TEST_F(JsepSessionTest, OfferAnswerRecvOnlyLines)
SetRemoteOffer(offer, CHECK_SUCCESS);
std::string answer = CreateAnswer();
outputSdp = mozilla::Move(parser.Parse(answer));
outputSdp = parser.Parse(answer);
ASSERT_EQ(3U, outputSdp->GetMediaSectionCount());
ASSERT_EQ(SdpMediaSection::kAudio,
@ -731,7 +732,7 @@ TEST_F(JsepSessionTest, OfferAnswerSendOnlyLines)
std::string offer = CreateOffer(Some(options));
SipccSdpParser parser;
auto outputSdp = mozilla::Move(parser.Parse(offer));
auto outputSdp = parser.Parse(offer);
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
<< "Errors were: " << GetParseErrors(parser);
@ -762,7 +763,7 @@ TEST_F(JsepSessionTest, OfferAnswerSendOnlyLines)
SetRemoteOffer(offer, CHECK_SUCCESS);
std::string answer = CreateAnswer();
outputSdp = mozilla::Move(parser.Parse(answer));
outputSdp = parser.Parse(answer);
ASSERT_EQ(3U, outputSdp->GetMediaSectionCount());
ASSERT_EQ(SdpMediaSection::kAudio,
@ -792,7 +793,7 @@ TEST_F(JsepSessionTest, CreateOfferNoDatachannelDefault)
std::string offer = CreateOffer();
SipccSdpParser parser;
auto outputSdp = mozilla::Move(parser.Parse(offer));
auto outputSdp = parser.Parse(offer);
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
<< "Errors were: " << GetParseErrors(parser);
@ -818,7 +819,7 @@ TEST_F(JsepSessionTest, ValidateOfferedCodecParams)
std::string offer = CreateOffer();
SipccSdpParser parser;
auto outputSdp = mozilla::Move(parser.Parse(offer));
auto outputSdp = parser.Parse(offer);
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
<< "Errors were: " << GetParseErrors(parser);
@ -936,7 +937,7 @@ TEST_F(JsepSessionTest, ValidateAnsweredCodecParams)
std::string answer = CreateAnswer();
SipccSdpParser parser;
auto outputSdp = mozilla::Move(parser.Parse(answer));
auto outputSdp = parser.Parse(answer);
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
<< "Errors were: " << GetParseErrors(parser);
@ -991,47 +992,45 @@ TEST_F(JsepSessionTest, ValidateAnsweredCodecParams)
SetLocalAnswer(answer);
SetRemoteAnswer(answer);
ASSERT_EQ(2U, mSessionOff.GetNegotiatedTrackPairCount());
const JsepTrackPair* offerVideoPair;
ASSERT_EQ(NS_OK, mSessionOff.GetNegotiatedTrackPair(1, &offerVideoPair));
ASSERT_TRUE(offerVideoPair->mSending);
ASSERT_TRUE(offerVideoPair->mReceiving);
ASSERT_TRUE(offerVideoPair->mSending->GetNegotiatedDetails());
ASSERT_TRUE(offerVideoPair->mReceiving->GetNegotiatedDetails());
auto offerPairs = mSessionOff.GetNegotiatedTrackPairs();
ASSERT_EQ(2U, offerPairs.size());
ASSERT_TRUE(offerPairs[1].mSending);
ASSERT_TRUE(offerPairs[1].mReceiving);
ASSERT_TRUE(offerPairs[1].mSending->GetNegotiatedDetails());
ASSERT_TRUE(offerPairs[1].mReceiving->GetNegotiatedDetails());
ASSERT_EQ(1U,
offerVideoPair->mSending->GetNegotiatedDetails()->GetCodecCount());
offerPairs[1].mSending->GetNegotiatedDetails()->GetCodecCount());
ASSERT_EQ(1U,
offerVideoPair->mReceiving->GetNegotiatedDetails()->GetCodecCount());
offerPairs[1].mReceiving->GetNegotiatedDetails()->GetCodecCount());
const JsepCodecDescription* offerRecvCodec;
ASSERT_EQ(NS_OK,
offerVideoPair->mReceiving->GetNegotiatedDetails()->GetCodec(
offerPairs[1].mReceiving->GetNegotiatedDetails()->GetCodec(
0,
&offerRecvCodec));
const JsepCodecDescription* offerSendCodec;
ASSERT_EQ(NS_OK,
offerVideoPair->mSending->GetNegotiatedDetails()->GetCodec(
offerPairs[1].mSending->GetNegotiatedDetails()->GetCodec(
0,
&offerSendCodec));
ASSERT_EQ(2U, mSessionAns.GetNegotiatedTrackPairCount());
const JsepTrackPair* answerVideoPair;
ASSERT_EQ(NS_OK, mSessionAns.GetNegotiatedTrackPair(1, &answerVideoPair));
ASSERT_TRUE(answerVideoPair->mSending);
ASSERT_TRUE(answerVideoPair->mReceiving);
ASSERT_TRUE(answerVideoPair->mSending->GetNegotiatedDetails());
ASSERT_TRUE(answerVideoPair->mReceiving->GetNegotiatedDetails());
auto answerPairs = mSessionAns.GetNegotiatedTrackPairs();
ASSERT_EQ(2U, answerPairs.size());
ASSERT_TRUE(answerPairs[1].mSending);
ASSERT_TRUE(answerPairs[1].mReceiving);
ASSERT_TRUE(answerPairs[1].mSending->GetNegotiatedDetails());
ASSERT_TRUE(answerPairs[1].mReceiving->GetNegotiatedDetails());
ASSERT_EQ(1U,
answerVideoPair->mSending->GetNegotiatedDetails()->GetCodecCount());
answerPairs[1].mSending->GetNegotiatedDetails()->GetCodecCount());
ASSERT_EQ(1U,
answerVideoPair->mReceiving->GetNegotiatedDetails()->GetCodecCount());
answerPairs[1].mReceiving->GetNegotiatedDetails()->GetCodecCount());
const JsepCodecDescription* answerRecvCodec;
ASSERT_EQ(NS_OK,
answerVideoPair->mReceiving->GetNegotiatedDetails()->GetCodec(
answerPairs[1].mReceiving->GetNegotiatedDetails()->GetCodec(
0,
&answerRecvCodec));
const JsepCodecDescription* answerSendCodec;
ASSERT_EQ(NS_OK,
answerVideoPair->mSending->GetNegotiatedDetails()->GetCodec(
answerPairs[1].mSending->GetNegotiatedDetails()->GetCodec(
0,
&answerSendCodec));
@ -1093,7 +1092,7 @@ TEST_P(JsepSessionTest, TestRejectMline)
std::string answer = CreateAnswer();
SipccSdpParser parser;
auto outputSdp = mozilla::Move(parser.Parse(answer));
auto outputSdp = parser.Parse(answer);
ASSERT_TRUE(!!outputSdp) << "Should have valid SDP" << std::endl
<< "Errors were: " << GetParseErrors(parser);
@ -1114,16 +1113,16 @@ TEST_P(JsepSessionTest, TestRejectMline)
mSessionAns.SetLocalDescription(kJsepSdpAnswer, answer);
mSessionOff.SetRemoteDescription(kJsepSdpAnswer, answer);
ASSERT_EQ(types.size() - 1, mSessionOff.GetNegotiatedTrackPairCount());
ASSERT_EQ(types.size() - 1, mSessionAns.GetNegotiatedTrackPairCount());
ASSERT_EQ(types.size() - 1, mSessionOff.GetNegotiatedTrackPairs().size());
ASSERT_EQ(types.size() - 1, mSessionAns.GetNegotiatedTrackPairs().size());
ASSERT_EQ(types.size(), mSessionOff.GetTransportCount());
ASSERT_EQ(types.size(), mSessionOff.GetLocalTrackCount());
ASSERT_EQ(types.size() - 1, mSessionOff.GetRemoteTrackCount());
ASSERT_EQ(types.size(), mSessionOff.GetTransports().size());
ASSERT_EQ(types.size(), mSessionOff.GetLocalTracks().size());
ASSERT_EQ(types.size() - 1, mSessionOff.GetRemoteTracks().size());
ASSERT_EQ(types.size(), mSessionAns.GetTransportCount());
ASSERT_EQ(types.size(), mSessionAns.GetLocalTrackCount());
ASSERT_EQ(types.size(), mSessionAns.GetRemoteTrackCount());
ASSERT_EQ(types.size(), mSessionAns.GetTransports().size());
ASSERT_EQ(types.size(), mSessionAns.GetLocalTracks().size());
ASSERT_EQ(types.size(), mSessionAns.GetRemoteTracks().size());
}
TEST_F(JsepSessionTest, CreateOfferNoMlines)
@ -1239,9 +1238,8 @@ TEST_F(JsepSessionTest, TestRtcpFbStar)
SetLocalAnswer(answer, CHECK_SUCCESS);
SetRemoteAnswer(answer, CHECK_SUCCESS);
ASSERT_EQ(1U, mSessionAns.GetRemoteTrackCount());
RefPtr<JsepTrack> track;
ASSERT_EQ(NS_OK, mSessionAns.GetRemoteTrack(0, &track));
ASSERT_EQ(1U, mSessionAns.GetRemoteTracks().size());
RefPtr<JsepTrack> track = mSessionAns.GetRemoteTracks()[0];
ASSERT_TRUE(track->GetNegotiatedDetails());
auto* details = track->GetNegotiatedDetails();
for (size_t i = 0; i < details->GetCodecCount(); ++i) {
@ -1268,46 +1266,46 @@ TEST_F(JsepSessionTest, TestUniquePayloadTypes)
SetLocalAnswer(answer, CHECK_SUCCESS);
SetRemoteAnswer(answer, CHECK_SUCCESS);
ASSERT_EQ(3U, mSessionOff.GetNegotiatedTrackPairCount());
ASSERT_EQ(3U, mSessionAns.GetNegotiatedTrackPairCount());
auto offerPairs = mSessionOff.GetNegotiatedTrackPairs();
auto answerPairs = mSessionAns.GetNegotiatedTrackPairs();
ASSERT_EQ(3U, offerPairs.size());
ASSERT_EQ(3U, answerPairs.size());
const JsepTrackPair* pair;
ASSERT_EQ(NS_OK, mSessionOff.GetNegotiatedTrackPair(0, &pair));
ASSERT_TRUE(pair->mReceiving);
ASSERT_TRUE(pair->mReceiving->GetNegotiatedDetails());
ASSERT_TRUE(offerPairs[0].mReceiving);
ASSERT_TRUE(offerPairs[0].mReceiving->GetNegotiatedDetails());
ASSERT_EQ(0U,
pair->mReceiving->GetNegotiatedDetails()->GetUniquePayloadTypes().size());
offerPairs[0].mReceiving->GetNegotiatedDetails()->
GetUniquePayloadTypes().size());
ASSERT_EQ(NS_OK, mSessionOff.GetNegotiatedTrackPair(1, &pair));
ASSERT_TRUE(pair->mReceiving);
ASSERT_TRUE(pair->mReceiving->GetNegotiatedDetails());
ASSERT_TRUE(offerPairs[1].mReceiving);
ASSERT_TRUE(offerPairs[1].mReceiving->GetNegotiatedDetails());
ASSERT_EQ(0U,
pair->mReceiving->GetNegotiatedDetails()->GetUniquePayloadTypes().size());
offerPairs[1].mReceiving->GetNegotiatedDetails()->
GetUniquePayloadTypes().size());
ASSERT_EQ(NS_OK, mSessionOff.GetNegotiatedTrackPair(2, &pair));
ASSERT_TRUE(pair->mReceiving);
ASSERT_TRUE(pair->mReceiving->GetNegotiatedDetails());
ASSERT_TRUE(offerPairs[2].mReceiving);
ASSERT_TRUE(offerPairs[2].mReceiving->GetNegotiatedDetails());
ASSERT_NE(0U,
pair->mReceiving->GetNegotiatedDetails()->GetUniquePayloadTypes().size());
offerPairs[2].mReceiving->GetNegotiatedDetails()->
GetUniquePayloadTypes().size());
ASSERT_EQ(NS_OK, mSessionAns.GetNegotiatedTrackPair(0, &pair));
ASSERT_TRUE(pair->mReceiving);
ASSERT_TRUE(pair->mReceiving->GetNegotiatedDetails());
ASSERT_TRUE(answerPairs[0].mReceiving);
ASSERT_TRUE(answerPairs[0].mReceiving->GetNegotiatedDetails());
ASSERT_EQ(0U,
pair->mReceiving->GetNegotiatedDetails()->GetUniquePayloadTypes().size());
answerPairs[0].mReceiving->GetNegotiatedDetails()->
GetUniquePayloadTypes().size());
ASSERT_EQ(NS_OK, mSessionAns.GetNegotiatedTrackPair(1, &pair));
ASSERT_TRUE(pair->mReceiving);
ASSERT_TRUE(pair->mReceiving->GetNegotiatedDetails());
ASSERT_TRUE(answerPairs[1].mReceiving);
ASSERT_TRUE(answerPairs[1].mReceiving->GetNegotiatedDetails());
ASSERT_EQ(0U,
pair->mReceiving->GetNegotiatedDetails()->GetUniquePayloadTypes().size());
answerPairs[1].mReceiving->GetNegotiatedDetails()->
GetUniquePayloadTypes().size());
ASSERT_EQ(NS_OK, mSessionAns.GetNegotiatedTrackPair(2, &pair));
ASSERT_TRUE(pair->mReceiving);
ASSERT_TRUE(pair->mReceiving->GetNegotiatedDetails());
ASSERT_TRUE(answerPairs[2].mReceiving);
ASSERT_TRUE(answerPairs[2].mReceiving->GetNegotiatedDetails());
ASSERT_NE(0U,
pair->mReceiving->GetNegotiatedDetails()->GetUniquePayloadTypes().size());
answerPairs[2].mReceiving->GetNegotiatedDetails()->
GetUniquePayloadTypes().size());
}
} // namespace mozilla

View File

@ -333,9 +333,12 @@ class TestAgentReceive : public TestAgent {
bundle_filter_ = filter;
}
void UpdateFilterFromRemoteDescription_s(
void UpdateFilter_s(
nsAutoPtr<MediaPipelineFilter> filter) {
audio_pipeline_->UpdateFilterFromRemoteDescription_s(filter);
audio_pipeline_->UpdateTransport_s(1,
audio_rtp_transport_.flow_,
audio_rtcp_transport_.flow_,
filter);
}
private:
@ -417,7 +420,7 @@ class MediaPipelineTest : public ::testing::Test {
mozilla::SyncRunnable::DispatchToThread(
test_utils->sts_target(),
WrapRunnable(&p2_,
&TestAgentReceive::UpdateFilterFromRemoteDescription_s,
&TestAgentReceive::UpdateFilter_s,
refinedFilter));
}
@ -768,59 +771,6 @@ TEST_F(MediaPipelineFilterTest, TestPayloadTypeFilterSSRCUpdate) {
filter.FilterRTCP(rtcp_sr_s16, sizeof(rtcp_sr_s16)));
}
TEST_F(MediaPipelineFilterTest, TestAnswerAddsSSRCs) {
MediaPipelineFilter filter;
filter.SetCorrelator(7777);
ASSERT_TRUE(Filter(filter, 7777, 555, 110));
ASSERT_FALSE(Filter(filter, 7778, 556, 110));
// This should also have resulted in the SSRC 555 being added to the filter
ASSERT_TRUE(Filter(filter, 0, 555, 110));
ASSERT_FALSE(Filter(filter, 0, 556, 110));
// This sort of thing can happen when getting an answer with SSRC attrs
// The answer will not contain the correlator.
MediaPipelineFilter filter2;
filter2.AddRemoteSSRC(555);
filter2.AddRemoteSSRC(556);
filter2.AddRemoteSSRC(557);
filter.IncorporateRemoteDescription(filter2);
// Ensure that the old SSRC still works.
ASSERT_TRUE(Filter(filter, 0, 555, 110));
// Ensure that the new SSRCs work.
ASSERT_TRUE(Filter(filter, 0, 556, 110));
ASSERT_TRUE(Filter(filter, 0, 557, 110));
// Ensure that the correlator continues to work
ASSERT_TRUE(Filter(filter, 7777, 558, 110));
}
TEST_F(MediaPipelineFilterTest, TestSSRCMovedWithSDP) {
MediaPipelineFilter filter;
filter.SetCorrelator(7777);
filter.AddUniquePT(111);
ASSERT_TRUE(Filter(filter, 7777, 555, 110));
MediaPipelineFilter filter2;
filter2.AddRemoteSSRC(556);
filter.IncorporateRemoteDescription(filter2);
// Ensure that the old SSRC has been removed.
ASSERT_FALSE(Filter(filter, 0, 555, 110));
// Ensure that the new SSRC works.
ASSERT_TRUE(Filter(filter, 0, 556, 110));
// Ensure that the correlator continues to work
ASSERT_TRUE(Filter(filter, 7777, 558, 110));
// Ensure that the payload type mapping continues to work
ASSERT_TRUE(Filter(filter, 0, 559, 111));
}
TEST_F(MediaPipelineFilterTest, TestSSRCMovedWithCorrelator) {
MediaPipelineFilter filter;
filter.SetCorrelator(7777);
@ -841,10 +791,10 @@ TEST_F(MediaPipelineFilterTest, TestRemoteSDPNoSSRCs) {
MediaPipelineFilter filter2;
filter.IncorporateRemoteDescription(filter2);
filter.Update(filter2);
// Ensure that the old SSRC still works.
ASSERT_TRUE(Filter(filter, 7777, 555, 110));
ASSERT_TRUE(Filter(filter, 0, 555, 110));
}
TEST_F(MediaPipelineTest, TestAudioSendNoMux) {

View File

@ -280,15 +280,16 @@ public:
NS_IMETHOD OnSetRemoteDescriptionError(uint32_t code, const char *msg, ER&) MOZ_OVERRIDE;
NS_IMETHOD NotifyDataChannel(nsIDOMDataChannel *channel, ER&) MOZ_OVERRIDE;
NS_IMETHOD OnStateChange(PCObserverStateType state_type, ER&, void*) MOZ_OVERRIDE;
NS_IMETHOD OnAddStream(DOMMediaStream *stream, ER&) MOZ_OVERRIDE;
NS_IMETHOD OnRemoveStream(ER&) MOZ_OVERRIDE;
NS_IMETHOD OnAddTrack(ER&) MOZ_OVERRIDE;
NS_IMETHOD OnRemoveTrack(ER&) MOZ_OVERRIDE;
NS_IMETHOD OnAddStream(DOMMediaStream &stream, ER&) MOZ_OVERRIDE;
NS_IMETHOD OnRemoveStream(DOMMediaStream &stream, ER&) MOZ_OVERRIDE;
NS_IMETHOD OnAddTrack(MediaStreamTrack &track, ER&) MOZ_OVERRIDE;
NS_IMETHOD OnRemoveTrack(MediaStreamTrack &track, ER&) MOZ_OVERRIDE;
NS_IMETHOD OnReplaceTrackSuccess(ER&) MOZ_OVERRIDE;
NS_IMETHOD OnReplaceTrackError(uint32_t code, const char *msg, ER&) MOZ_OVERRIDE;
NS_IMETHOD OnAddIceCandidateSuccess(ER&) MOZ_OVERRIDE;
NS_IMETHOD OnAddIceCandidateError(uint32_t code, const char *msg, ER&) MOZ_OVERRIDE;
NS_IMETHOD OnIceCandidate(uint16_t level, const char *mid, const char *cand, ER&) MOZ_OVERRIDE;
NS_IMETHODIMP OnNegotiationNeeded(ER&);
// Hack because add_ice_candidates can happen asynchronously with respect
// to the API calls. The whole test suite needs a refactor.
@ -439,21 +440,19 @@ TestObserver::OnStateChange(PCObserverStateType state_type, ER&, void*)
NS_IMETHODIMP
TestObserver::OnAddStream(DOMMediaStream *stream, ER&)
TestObserver::OnAddStream(DOMMediaStream &stream, ER&)
{
PR_ASSERT(stream);
std::cout << name << ": OnAddStream called hints=" << stream->GetHintContents()
std::cout << name << ": OnAddStream called hints=" << stream.GetHintContents()
<< " thread=" << PR_GetCurrentThread() << std::endl ;
onAddStreamCalled = true;
streams.push_back(stream);
streams.push_back(&stream);
// We know that the media stream is secretly a Fake_SourceMediaStream,
// so now we can start it pulling from us
nsRefPtr<Fake_SourceMediaStream> fs =
static_cast<Fake_SourceMediaStream *>(stream->GetStream());
static_cast<Fake_SourceMediaStream *>(stream.GetStream());
test_utils->sts_target()->Dispatch(
WrapRunnable(fs, &Fake_SourceMediaStream::Start),
@ -463,21 +462,21 @@ TestObserver::OnAddStream(DOMMediaStream *stream, ER&)
}
NS_IMETHODIMP
TestObserver::OnRemoveStream(ER&)
TestObserver::OnRemoveStream(DOMMediaStream &stream, ER&)
{
state = stateSuccess;
return NS_OK;
}
NS_IMETHODIMP
TestObserver::OnAddTrack(ER&)
TestObserver::OnAddTrack(MediaStreamTrack &track, ER&)
{
state = stateSuccess;
return NS_OK;
}
NS_IMETHODIMP
TestObserver::OnRemoveTrack(ER&)
TestObserver::OnRemoveTrack(MediaStreamTrack &track, ER&)
{
state = stateSuccess;
return NS_OK;
@ -1657,6 +1656,12 @@ TestObserver::OnIceCandidate(uint16_t level,
return NS_OK;
}
NS_IMETHODIMP
TestObserver::OnNegotiationNeeded(ER&)
{
return NS_OK;
}
class SignalingEnvironment : public ::testing::Environment {
public:
void TearDown() {