mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 12:50:09 +00:00
Bug 1017888 - Part 1: Renegotiation support. r=mt, r=smaug
--HG-- extra : rebase_source : df1c2962ee88f75c6ad676b9cd79978a87dafb65 extra : amend_source : c938904331323ff3565624795ac76d82502f43fb
This commit is contained in:
parent
03913d3a48
commit
1f815978b4
@ -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:
|
||||
|
@ -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]
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -209,6 +209,7 @@ nsresult NrIceMediaStream::ParseAttributes(std::vector<std::string>&
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
has_parsed_attrs_ = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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, <rack));
|
||||
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
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user