Bug 1318180: turn network offline events into ice disconnected event. r=bwc,jib

MozReview-Commit-ID: Kqbicl2goL2

--HG--
extra : rebase_source : 4ed7d1364af8bd1575e2ced1bd8512405e0dd669
This commit is contained in:
Nils Ohlmeier [:drno] 2016-11-17 23:16:33 -08:00
Родитель c7690fb4ef
Коммит 2ca25c39f6
16 изменённых файлов: 337 добавлений и 70 удалений

Просмотреть файл

@ -182,19 +182,11 @@ GlobalPCList.prototype = {
} }
} else if (topic == "profile-change-net-teardown" || } else if (topic == "profile-change-net-teardown" ||
topic == "network:offline-about-to-go-offline") { topic == "network:offline-about-to-go-offline") {
// Delete all peerconnections on shutdown - mostly synchronously (we // As Necko doesn't prevent us from accessing the network we still need to
// need them to be done deleting transports and streams before we // monitor the network offline/online state here. See bug 1326483
// return)! All socket operations must be queued to STS thread
// before we return to here.
// Also kill them if "Work Offline" is selected - more can be created
// while offline, but attempts to connect them should fail.
for (let winId in this._list) {
cleanupWinId(this._list, winId);
}
this._networkdown = true; this._networkdown = true;
} else if (topic == "network:offline-status-changed") { } else if (topic == "network:offline-status-changed") {
if (data == "offline") { if (data == "offline") {
// this._list shold be empty here
this._networkdown = true; this._networkdown = true;
} else if (data == "online") { } else if (data == "online") {
this._networkdown = false; this._networkdown = false;
@ -1211,9 +1203,11 @@ RTCPeerConnection.prototype = {
}, },
changeIceConnectionState: function(state) { changeIceConnectionState: function(state) {
this._iceConnectionState = state; if (state != this._iceConnectionState) {
_globalPCList.notifyLifecycleObservers(this, "iceconnectionstatechange"); this._iceConnectionState = state;
this.dispatchEvent(new this._win.Event("iceconnectionstatechange")); _globalPCList.notifyLifecycleObservers(this, "iceconnectionstatechange");
this.dispatchEvent(new this._win.Event("iceconnectionstatechange"));
}
}, },
getStats: function(selector, onSucc, onErr) { getStats: function(selector, onSucc, onErr) {
@ -1370,35 +1364,25 @@ PeerConnectionObserver.prototype = {
// //
// iceConnectionState: // iceConnectionState:
// ------------------- // -------------------
// new The ICE Agent is gathering addresses and/or waiting for // new Any of the RTCIceTransports are in the new state and none
// remote candidates to be supplied. // of them are in the checking, failed or disconnected state.
// //
// checking The ICE Agent has received remote candidates on at least // checking Any of the RTCIceTransports are in the checking state and
// one component, and is checking candidate pairs but has not // none of them are in the failed or disconnected state.
// yet found a connection. In addition to checking, it may
// also still be gathering.
// //
// connected The ICE Agent has found a usable connection for all // connected All RTCIceTransports are in the connected, completed or
// components but is still checking other candidate pairs to // closed state and at least one of them is in the connected
// see if there is a better connection. It may also still be
// gathering.
//
// completed The ICE Agent has finished gathering and checking and found
// a connection for all components. Open issue: it is not
// clear how the non controlling ICE side knows it is in the
// state. // state.
// //
// failed The ICE Agent is finished checking all candidate pairs and // completed All RTCIceTransports are in the completed or closed state
// failed to find a connection for at least one component. // and at least one of them is in the completed state.
// Connections may have been found for some components.
// //
// disconnected Liveness checks have failed for one or more components. // failed Any of the RTCIceTransports are in the failed state.
// This is more aggressive than failed, and may trigger
// intermittently (and resolve itself without action) on a
// flaky network.
// //
// closed The ICE Agent has shut down and is no longer responding to // disconnected Any of the RTCIceTransports are in the disconnected state
// STUN requests. // and none of them are in the failed state.
//
// closed All of the RTCIceTransports are in the closed state.
handleIceConnectionStateChange: function(iceConnectionState) { handleIceConnectionStateChange: function(iceConnectionState) {
let pc = this._dompc; let pc = this._dompc;

Просмотреть файл

@ -971,6 +971,16 @@ nsresult NrIceCtx::Finalize() {
return NS_OK; return NS_OK;
} }
void NrIceCtx::UpdateNetworkState(bool online) {
MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): updating network state to " <<
(online ? "online" : "offline"));
if (online) {
nr_ice_peer_ctx_refresh_consent_all_streams(peer_);
} else {
nr_ice_peer_ctx_disconnect_all_streams(peer_);
}
}
void NrIceCtx::SetConnectionState(ConnectionState state) { void NrIceCtx::SetConnectionState(ConnectionState state) {
if (state == connection_state_) if (state == connection_state_)
return; return;

Просмотреть файл

@ -314,6 +314,9 @@ class NrIceCtx {
// Start checking // Start checking
nsresult StartChecks(); nsresult StartChecks();
// Notify that the network has gone online/offline
void UpdateNetworkState(bool online);
// Finalize the ICE negotiation. I.e., there will be no // Finalize the ICE negotiation. I.e., there will be no
// more forking. // more forking.
nsresult Finalize(); nsresult Finalize();

Просмотреть файл

@ -1366,6 +1366,26 @@ class IceTestPeer : public sigslot::has_slots<> {
NS_DISPATCH_SYNC); NS_DISPATCH_SYNC);
} }
void ChangeNetworkState_s(bool online) {
ice_ctx_->ctx()->UpdateNetworkState(online);
}
void ChangeNetworkStateToOffline() {
test_utils_->sts_target()->Dispatch(
WrapRunnable(this,
&IceTestPeer::ChangeNetworkState_s,
false),
NS_DISPATCH_SYNC);
}
void ChangeNetworkStateToOnline() {
test_utils_->sts_target()->Dispatch(
WrapRunnable(this,
&IceTestPeer::ChangeNetworkState_s,
true),
NS_DISPATCH_SYNC);
}
int trickled() { return trickled_; } int trickled() { return trickled_; }
void SetControlling(NrIceCtx::Controlling controlling) { void SetControlling(NrIceCtx::Controlling controlling) {
@ -3350,6 +3370,49 @@ TEST_F(WebRtcIceConnectTest, TestConsentDelayed) {
SendReceive(); SendReceive();
} }
TEST_F(WebRtcIceConnectTest, TestNetworkForcedOfflineAndRecovery) {
AddStream(1);
SetupAndCheckConsent();
p1_->ChangeNetworkStateToOffline();
ASSERT_TRUE_WAIT(p1_->ice_connected() == 0, kDefaultTimeout);
// Next round of consent check should switch it back to online
ASSERT_TRUE_WAIT(p1_->ice_connected(), kDefaultTimeout);
}
TEST_F(WebRtcIceConnectTest, TestNetworkForcedOfflineTwice) {
AddStream(1);
SetupAndCheckConsent();
p2_->ChangeNetworkStateToOffline();
ASSERT_TRUE_WAIT(p2_->ice_connected() == 0, kDefaultTimeout);
p2_->ChangeNetworkStateToOffline();
ASSERT_TRUE_WAIT(p2_->ice_connected() == 0, kDefaultTimeout);
}
TEST_F(WebRtcIceConnectTest, TestNetworkOnlineDoesntChangeState) {
AddStream(1);
SetupAndCheckConsent();
p2_->ChangeNetworkStateToOnline();
ASSERT_TRUE(p2_->ice_connected());
PR_Sleep(1500);
p2_->ChangeNetworkStateToOnline();
ASSERT_TRUE(p2_->ice_connected());
}
TEST_F(WebRtcIceConnectTest, TestNetworkOnlineTriggersConsent) {
// Let's emulate audio + video w/o rtcp-mux
AddStream(2);
AddStream(2);
SetupAndCheckConsent();
p1_->ChangeNetworkStateToOffline();
p1_->SetBlockStun(true);
ASSERT_TRUE_WAIT(p1_->ice_connected() == 0, kDefaultTimeout);
PR_Sleep(1500);
ASSERT_TRUE(p1_->ice_connected() == 0);
p1_->SetBlockStun(false);
p1_->ChangeNetworkStateToOnline();
ASSERT_TRUE_WAIT(p1_->ice_connected(), 500);
}
TEST_F(WebRtcIceConnectTest, TestConnectTurn) { TEST_F(WebRtcIceConnectTest, TestConnectTurn) {
if (turn_server_.empty()) if (turn_server_.empty())
return; return;

Просмотреть файл

@ -1242,13 +1242,22 @@ static void nr_ice_component_consent_timeout_cb(NR_SOCKET s, int how, void *cb_a
} }
static void nr_ice_component_consent_request_timed_out(nr_ice_component *comp) void nr_ice_component_disconnected(nr_ice_component *comp)
{ {
if (!comp->can_send) { if (!comp->can_send) {
return; return;
} }
nr_ice_peer_ctx_disconnected(comp->stream->pctx); if (comp->disconnected) {
return;
}
r_log(LOG_ICE,LOG_WARNING,"ICE(%s)/STREAM(%s)/COMP(%d): component disconnected",
comp->ctx->label, comp->stream->label, comp->component_id);
comp->disconnected = 1;
/* a single disconnected component disconnects the stream */
nr_ice_media_stream_set_disconnected(comp->stream, NR_ICE_MEDIA_STREAM_DISCONNECTED);
} }
static void nr_ice_component_consent_refreshed(nr_ice_component *comp) static void nr_ice_component_consent_refreshed(nr_ice_component *comp)
@ -1264,7 +1273,9 @@ static void nr_ice_component_consent_refreshed(nr_ice_component *comp)
comp->ctx->label, comp->stream->label, comp->component_id, comp->ctx->label, comp->stream->label, comp->component_id,
comp->consent_last_seen.tv_sec); comp->consent_last_seen.tv_sec);
nr_ice_peer_ctx_connected(comp->stream->pctx); comp->disconnected = 0;
nr_ice_media_stream_check_if_connected(comp->stream);
if (comp->consent_timeout) if (comp->consent_timeout)
NR_async_timer_cancel(comp->consent_timeout); NR_async_timer_cancel(comp->consent_timeout);
@ -1297,7 +1308,7 @@ static void nr_ice_component_refresh_consent_cb(NR_SOCKET s, int how, void *cb_a
case NR_STUN_CLIENT_STATE_TIMED_OUT: case NR_STUN_CLIENT_STATE_TIMED_OUT:
r_log(LOG_ICE, LOG_INFO, "ICE(%s)/STREAM(%s)/COMP(%d): A single consent refresh request timed out", r_log(LOG_ICE, LOG_INFO, "ICE(%s)/STREAM(%s)/COMP(%d): A single consent refresh request timed out",
comp->ctx->label, comp->stream->label, comp->component_id); comp->ctx->label, comp->stream->label, comp->component_id);
nr_ice_component_consent_request_timed_out(comp); nr_ice_component_disconnected(comp);
break; break;
default: default:
break; break;
@ -1340,6 +1351,9 @@ static void nr_ice_component_consent_timer_cb(NR_SOCKET s, int how, void *cb_arg
nr_ice_component *comp=cb_arg; nr_ice_component *comp=cb_arg;
int r; int r;
if (comp->consent_timer) {
NR_async_timer_cancel(comp->consent_timer);
}
comp->consent_timer = 0; comp->consent_timer = 0;
comp->consent_ctx->params.ice_binding_request.username = comp->consent_ctx->params.ice_binding_request.username =
@ -1361,12 +1375,6 @@ static void nr_ice_component_consent_timer_cb(NR_SOCKET s, int how, void *cb_arg
comp)) { comp)) {
r_log(LOG_ICE,LOG_ERR,"ICE(%s)/STREAM(%s)/COMP(%d): Refresh consent failed with %d", r_log(LOG_ICE,LOG_ERR,"ICE(%s)/STREAM(%s)/COMP(%d): Refresh consent failed with %d",
comp->ctx->label, comp->stream->label, comp->component_id, r); comp->ctx->label, comp->stream->label, comp->component_id, r);
/* In case our attempt to send the refresh binding request reports an
* error we don't have to wait for timeouts, but declare this connection
* dead right away. */
if (r != R_WOULDBLOCK) {
nr_ice_component_consent_failed(comp);
}
} }
nr_ice_component_consent_schedule_consent_timer(comp); nr_ice_component_consent_schedule_consent_timer(comp);
@ -1384,6 +1392,11 @@ void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp)
&comp->consent_timer); &comp->consent_timer);
} }
void nr_ice_component_refresh_consent_now(nr_ice_component *comp)
{
nr_ice_component_consent_timer_cb(0, 0, comp);
}
void nr_ice_component_consent_destroy(nr_ice_component *comp) void nr_ice_component_consent_destroy(nr_ice_component *comp)
{ {
if (comp->consent_timer) { if (comp->consent_timer) {
@ -1401,6 +1414,7 @@ void nr_ice_component_consent_destroy(nr_ice_component *comp)
} }
if (comp->consent_ctx) { if (comp->consent_ctx) {
nr_stun_client_ctx_destroy(&comp->consent_ctx); nr_stun_client_ctx_destroy(&comp->consent_ctx);
comp->consent_ctx = 0;
} }
} }
@ -1411,6 +1425,8 @@ int nr_ice_component_setup_consent(nr_ice_component *comp)
r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): Setting up refresh consent", r_log(LOG_ICE,LOG_DEBUG,"ICE(%s)/STREAM(%s)/COMP(%d): Setting up refresh consent",
comp->ctx->label, comp->stream->label, comp->component_id); comp->ctx->label, comp->stream->label, comp->component_id);
nr_ice_component_consent_destroy(comp);
if (r=nr_stun_client_ctx_create("consent", comp->active->local->osock, if (r=nr_stun_client_ctx_create("consent", comp->active->local->osock,
&comp->active->remote->addr, 0, &comp->active->remote->addr, 0,
&comp->consent_ctx)) &comp->consent_ctx))
@ -1423,6 +1439,7 @@ int nr_ice_component_setup_consent(nr_ice_component *comp)
ABORT(r); ABORT(r);
comp->can_send = 1; comp->can_send = 1;
comp->disconnected = 0;
nr_ice_component_consent_refreshed(comp); nr_ice_component_consent_refreshed(comp);
nr_ice_component_consent_calc_consent_timer(comp); nr_ice_component_consent_calc_consent_timer(comp);

Просмотреть файл

@ -75,6 +75,7 @@ struct nr_ice_component_ {
void *consent_timeout; void *consent_timeout;
void *consent_handle; void *consent_handle;
int can_send; int can_send;
int disconnected;
struct timeval consent_last_seen; struct timeval consent_last_seen;
STAILQ_ENTRY(nr_ice_component_)entry; STAILQ_ENTRY(nr_ice_component_)entry;
@ -97,6 +98,8 @@ int nr_ice_component_set_failed(nr_ice_component *comp);
int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp); int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp);
int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair); int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair);
int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version); int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version);
void nr_ice_component_refresh_consent_now(nr_ice_component *comp);
void nr_ice_component_disconnected(nr_ice_component *comp);
#ifdef __cplusplus #ifdef __cplusplus
} }

Просмотреть файл

@ -43,7 +43,7 @@ static char *RCSSTRING __UNUSED__="$Id: ice_media_stream.c,v 1.2 2008/04/28 17:5
#include "ice_ctx.h" #include "ice_ctx.h"
static char *nr_ice_media_stream_states[]={"INVALID", static char *nr_ice_media_stream_states[]={"INVALID",
"UNPAIRED","FROZEN","ACTIVE","COMPLETED","FAILED" "UNPAIRED","FROZEN","ACTIVE","CONNECTED","FAILED"
}; };
int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state); int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state);
@ -74,6 +74,7 @@ int nr_ice_media_stream_create(nr_ice_ctx *ctx,char *label,int components, nr_ic
TAILQ_INIT(&stream->check_list); TAILQ_INIT(&stream->check_list);
TAILQ_INIT(&stream->trigger_check_queue); TAILQ_INIT(&stream->trigger_check_queue);
stream->disconnected = 0;
stream->component_ct=components; stream->component_ct=components;
stream->ice_state = NR_ICE_MEDIA_STREAM_UNPAIRED; stream->ice_state = NR_ICE_MEDIA_STREAM_UNPAIRED;
*streamp=stream; *streamp=stream;
@ -339,7 +340,7 @@ static void nr_ice_media_stream_check_timer_cb(NR_SOCKET s, int h, void *cb_arg)
pair=TAILQ_NEXT(pair,triggered_check_queue_entry); pair=TAILQ_NEXT(pair,triggered_check_queue_entry);
} }
if (stream->ice_state != NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED) { if (stream->ice_state != NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED) {
if(!pair){ if(!pair){
/* Find the highest priority WAITING check and move it to RUNNING */ /* Find the highest priority WAITING check and move it to RUNNING */
pair=TAILQ_FIRST(&stream->check_list); pair=TAILQ_FIRST(&stream->check_list);
@ -392,7 +393,7 @@ int nr_ice_media_stream_start_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream
/* Even if the stream is completed already remote can still create a new /* Even if the stream is completed already remote can still create a new
* triggered check request which needs to fire, but not change our stream * triggered check request which needs to fire, but not change our stream
* state. */ * state. */
if (stream->ice_state != NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED) { if (stream->ice_state != NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED) {
if(r=nr_ice_media_stream_set_state(stream,NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE)) { if(r=nr_ice_media_stream_set_state(stream,NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE)) {
ABORT(r); ABORT(r);
} }
@ -584,6 +585,80 @@ int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state)
return(0); return(0);
} }
void nr_ice_media_stream_refresh_consent_all(nr_ice_media_stream *stream)
{
nr_ice_component *comp;
comp=STAILQ_FIRST(&stream->components);
while(comp){
if((comp->state != NR_ICE_COMPONENT_DISABLED) &&
(comp->local_component->state != NR_ICE_COMPONENT_DISABLED) &&
comp->disconnected) {
nr_ice_component_refresh_consent_now(comp);
}
comp=STAILQ_NEXT(comp,entry);
}
}
void nr_ice_media_stream_disconnect_all_components(nr_ice_media_stream *stream)
{
nr_ice_component *comp;
comp=STAILQ_FIRST(&stream->components);
while(comp){
if((comp->state != NR_ICE_COMPONENT_DISABLED) &&
(comp->local_component->state != NR_ICE_COMPONENT_DISABLED)) {
comp->disconnected = 1;
}
comp=STAILQ_NEXT(comp,entry);
}
}
void nr_ice_media_stream_set_disconnected(nr_ice_media_stream *stream, int disconnected)
{
if (stream->disconnected == disconnected) {
return;
}
if (stream->ice_state != NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED) {
return;
}
stream->disconnected = disconnected;
if (disconnected == NR_ICE_MEDIA_STREAM_DISCONNECTED) {
nr_ice_peer_ctx_disconnected(stream->pctx);
} else {
nr_ice_peer_ctx_check_if_connected(stream->pctx);
}
}
int nr_ice_media_stream_check_if_connected(nr_ice_media_stream *stream)
{
nr_ice_component *comp;
comp=STAILQ_FIRST(&stream->components);
while(comp){
if((comp->state != NR_ICE_COMPONENT_DISABLED) &&
(comp->local_component->state != NR_ICE_COMPONENT_DISABLED) &&
comp->disconnected)
break;
comp=STAILQ_NEXT(comp,entry);
}
/* At least one disconnected component */
if(comp)
goto done;
nr_ice_media_stream_set_disconnected(stream, NR_ICE_MEDIA_STREAM_CONNECTED);
done:
return(0);
}
/* S OK, this component has a nominated. If every component has a nominated, /* S OK, this component has a nominated. If every component has a nominated,
the stream is ready */ the stream is ready */
int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component) int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component)
@ -607,7 +682,7 @@ int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_c
/* All done... */ /* All done... */
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/ICE-STREAM(%s): all active components have nominated candidate pairs",stream->pctx->label,stream->label); r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/ICE-STREAM(%s): all active components have nominated candidate pairs",stream->pctx->label,stream->label);
nr_ice_media_stream_set_state(stream,NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED); nr_ice_media_stream_set_state(stream,NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED);
/* Cancel our timer */ /* Cancel our timer */
if(stream->timer){ if(stream->timer){
@ -747,8 +822,12 @@ int nr_ice_media_stream_send(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, in
2. Use the address on the remote side 2. Use the address on the remote side
*/ */
if(r=nr_socket_sendto(comp->active->local->osock,data,len,0, if(r=nr_socket_sendto(comp->active->local->osock,data,len,0,
&comp->active->remote->addr)) &comp->active->remote->addr)) {
if ((r==R_IO_ERROR) || (r==R_EOD)) {
nr_ice_component_disconnected(comp);
}
ABORT(r); ABORT(r);
}
_status=0; _status=0;
abort: abort:

Просмотреть файл

@ -59,9 +59,14 @@ struct nr_ice_media_stream_ {
#define NR_ICE_MEDIA_STREAM_UNPAIRED 1 #define NR_ICE_MEDIA_STREAM_UNPAIRED 1
#define NR_ICE_MEDIA_STREAM_CHECKS_FROZEN 2 #define NR_ICE_MEDIA_STREAM_CHECKS_FROZEN 2
#define NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE 3 #define NR_ICE_MEDIA_STREAM_CHECKS_ACTIVE 3
#define NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED 4 #define NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED 4
#define NR_ICE_MEDIA_STREAM_CHECKS_FAILED 5 #define NR_ICE_MEDIA_STREAM_CHECKS_FAILED 5
int disconnected;
#define NR_ICE_MEDIA_STREAM_CONNECTED 0
#define NR_ICE_MEDIA_STREAM_DISCONNECTED 1
nr_ice_cand_pair_head check_list; nr_ice_cand_pair_head check_list;
nr_ice_cand_pair_head trigger_check_queue; nr_ice_cand_pair_head trigger_check_queue;
void *timer; /* Check list periodic timer */ void *timer; /* Check list periodic timer */
@ -87,6 +92,10 @@ int nr_ice_media_stream_unfreeze_pairs_foundation(nr_ice_media_stream *stream, c
int nr_ice_media_stream_dump_state(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream,FILE *out); int nr_ice_media_stream_dump_state(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream,FILE *out);
int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component); int nr_ice_media_stream_component_nominated(nr_ice_media_stream *stream,nr_ice_component *component);
int nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_component *component); int nr_ice_media_stream_component_failed(nr_ice_media_stream *stream,nr_ice_component *component);
void nr_ice_media_stream_refresh_consent_all(nr_ice_media_stream *stream);
void nr_ice_media_stream_disconnect_all_components(nr_ice_media_stream *stream);
void nr_ice_media_stream_set_disconnected(nr_ice_media_stream *stream, int disconnected);
int nr_ice_media_stream_check_if_connected(nr_ice_media_stream *stream);
int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state); int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state);
int nr_ice_media_stream_get_best_candidate(nr_ice_media_stream *str, int component, nr_ice_candidate **candp); int nr_ice_media_stream_get_best_candidate(nr_ice_media_stream *str, int component, nr_ice_candidate **candp);
int nr_ice_media_stream_send(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component, UCHAR *data, int len); int nr_ice_media_stream_send(nr_ice_peer_ctx *pctx, nr_ice_media_stream *str, int component, UCHAR *data, int len);

Просмотреть файл

@ -648,12 +648,45 @@ int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out)
} }
#endif #endif
void nr_ice_peer_ctx_refresh_consent_all_streams(nr_ice_peer_ctx *pctx)
{
nr_ice_media_stream *str;
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): refreshing consent on all streams",pctx->label);
str=STAILQ_FIRST(&pctx->peer_streams);
while(str) {
nr_ice_media_stream_refresh_consent_all(str);
str=STAILQ_NEXT(str,entry);
}
}
void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx) void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx)
{ {
if (pctx->reported_connected && if (pctx->reported_connected &&
pctx->handler && pctx->handler &&
pctx->handler->vtbl->ice_disconnected) { pctx->handler->vtbl->ice_disconnected) {
pctx->handler->vtbl->ice_disconnected(pctx->handler->obj, pctx); pctx->handler->vtbl->ice_disconnected(pctx->handler->obj, pctx);
pctx->reported_connected = 0;
}
}
void nr_ice_peer_ctx_disconnect_all_streams(nr_ice_peer_ctx *pctx)
{
nr_ice_media_stream *str;
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s): disconnecting all streams",pctx->label);
str=STAILQ_FIRST(&pctx->peer_streams);
while(str) {
nr_ice_media_stream_disconnect_all_components(str);
/* The first stream to be disconnected will cause the peer ctx to signal
the disconnect up. */
nr_ice_media_stream_set_disconnected(str, NR_ICE_MEDIA_STREAM_DISCONNECTED);
str=STAILQ_NEXT(str,entry);
} }
} }
@ -687,7 +720,7 @@ int nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx *pctx)
str=STAILQ_FIRST(&pctx->peer_streams); str=STAILQ_FIRST(&pctx->peer_streams);
while(str){ while(str){
if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED){ if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED){
succeeded++; succeeded++;
} }
else if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FAILED){ else if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_FAILED){
@ -716,7 +749,6 @@ int nr_ice_peer_ctx_check_if_connected(nr_ice_peer_ctx *pctx)
done: done:
_status=0; _status=0;
// abort:
return(_status); return(_status);
} }

Просмотреть файл

@ -83,6 +83,8 @@ int nr_ice_peer_ctx_parse_global_attributes(nr_ice_peer_ctx *pctx, char **attrs,
int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx); int nr_ice_peer_ctx_start_checks(nr_ice_peer_ctx *pctx);
int nr_ice_peer_ctx_start_checks2(nr_ice_peer_ctx *pctx, int allow_non_first); 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); void nr_ice_peer_ctx_stream_started_checks(nr_ice_peer_ctx *pctx, nr_ice_media_stream *stream);
void nr_ice_peer_ctx_refresh_consent_all_streams(nr_ice_peer_ctx *pctx);
void nr_ice_peer_ctx_disconnect_all_streams(nr_ice_peer_ctx *pctx);
void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx); void nr_ice_peer_ctx_disconnected(nr_ice_peer_ctx *pctx);
void nr_ice_peer_ctx_connected(nr_ice_peer_ctx *pctx); void nr_ice_peer_ctx_connected(nr_ice_peer_ctx *pctx);
int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out); int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out);

Просмотреть файл

@ -22,9 +22,12 @@
#include "nsServiceManagerUtils.h" // do_GetService #include "nsServiceManagerUtils.h" // do_GetService
#include "nsIObserverService.h" #include "nsIObserverService.h"
#include "nsIObserver.h" #include "nsIObserver.h"
#include "nsIIOService.h" // NS_IOSERVICE_*
#include "mozilla/Services.h" #include "mozilla/Services.h"
#include "mozilla/StaticPtr.h" #include "mozilla/StaticPtr.h"
#include "nsCRTGlue.h"
#include "gmp-video-decode.h" // GMP_API_VIDEO_DECODER #include "gmp-video-decode.h" // GMP_API_VIDEO_DECODER
#include "gmp-video-encode.h" // GMP_API_VIDEO_ENCODER #include "gmp-video-encode.h" // GMP_API_VIDEO_ENCODER
@ -34,12 +37,12 @@ namespace mozilla {
using namespace dom; using namespace dom;
class PeerConnectionCtxShutdown : public nsIObserver class PeerConnectionCtxObserver : public nsIObserver
{ {
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
PeerConnectionCtxShutdown() {} PeerConnectionCtxObserver() {}
void Init() void Init()
{ {
@ -55,6 +58,10 @@ public:
NS_XPCOM_SHUTDOWN_OBSERVER_ID, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
false); false);
MOZ_ALWAYS_SUCCEEDS(rv); MOZ_ALWAYS_SUCCEEDS(rv);
rv = observerService->AddObserver(this,
NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
false);
MOZ_ALWAYS_SUCCEEDS(rv);
#endif #endif
(void) rv; (void) rv;
} }
@ -71,34 +78,52 @@ public:
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
nsresult rv = observerService->RemoveObserver(this, nsresult rv = observerService->RemoveObserver(this,
NS_XPCOM_SHUTDOWN_OBSERVER_ID); NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
MOZ_ALWAYS_SUCCEEDS(rv);
rv = observerService->RemoveObserver(this,
NS_XPCOM_SHUTDOWN_OBSERVER_ID);
MOZ_ALWAYS_SUCCEEDS(rv); MOZ_ALWAYS_SUCCEEDS(rv);
// Make sure we're not deleted while still inside ::Observe() // Make sure we're not deleted while still inside ::Observe()
RefPtr<PeerConnectionCtxShutdown> kungFuDeathGrip(this); RefPtr<PeerConnectionCtxObserver> kungFuDeathGrip(this);
PeerConnectionCtx::gPeerConnectionCtxShutdown = nullptr; PeerConnectionCtx::gPeerConnectionCtxObserver = nullptr;
}
if (strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC) == 0) {
const nsLiteralString onlineString(u"" NS_IOSERVICE_ONLINE);
const nsLiteralString offlineString(u"" NS_IOSERVICE_OFFLINE);
if (NS_strcmp(aData, offlineString.get()) == 0) {
CSFLogDebug(logTag, "Updating network state to offline");
PeerConnectionCtx::UpdateNetworkState(false);
} else if(NS_strcmp(aData, onlineString.get()) == 0) {
CSFLogDebug(logTag, "Updating network state to online");
PeerConnectionCtx::UpdateNetworkState(true);
} else {
CSFLogDebug(logTag, "Received unsupported network state event");
MOZ_CRASH();
}
} }
return NS_OK; return NS_OK;
} }
private: private:
virtual ~PeerConnectionCtxShutdown() virtual ~PeerConnectionCtxObserver()
{ {
nsCOMPtr<nsIObserverService> observerService = nsCOMPtr<nsIObserverService> observerService =
services::GetObserverService(); services::GetObserverService();
if (observerService) if (observerService)
observerService->RemoveObserver(this, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
} }
}; };
NS_IMPL_ISUPPORTS(PeerConnectionCtxShutdown, nsIObserver); NS_IMPL_ISUPPORTS(PeerConnectionCtxObserver, nsIObserver);
} }
namespace mozilla { namespace mozilla {
PeerConnectionCtx* PeerConnectionCtx::gInstance; PeerConnectionCtx* PeerConnectionCtx::gInstance;
nsIThread* PeerConnectionCtx::gMainThread; nsIThread* PeerConnectionCtx::gMainThread;
StaticRefPtr<PeerConnectionCtxShutdown> PeerConnectionCtx::gPeerConnectionCtxShutdown; StaticRefPtr<PeerConnectionCtxObserver> PeerConnectionCtx::gPeerConnectionCtxObserver;
const std::map<const std::string, PeerConnectionImpl *>& const std::map<const std::string, PeerConnectionImpl *>&
PeerConnectionCtx::mGetPeerConnections() PeerConnectionCtx::mGetPeerConnections()
@ -129,9 +154,9 @@ nsresult PeerConnectionCtx::InitializeGlobal(nsIThread *mainThread,
gInstance = ctx; gInstance = ctx;
if (!PeerConnectionCtx::gPeerConnectionCtxShutdown) { if (!PeerConnectionCtx::gPeerConnectionCtxObserver) {
PeerConnectionCtx::gPeerConnectionCtxShutdown = new PeerConnectionCtxShutdown(); PeerConnectionCtx::gPeerConnectionCtxObserver = new PeerConnectionCtxObserver();
PeerConnectionCtx::gPeerConnectionCtxShutdown->Init(); PeerConnectionCtx::gPeerConnectionCtxObserver->Init();
} }
} }
@ -334,6 +359,17 @@ PeerConnectionCtx::EverySecondTelemetryCallback_m(nsITimer* timer, void *closure
} }
#endif #endif
void
PeerConnectionCtx::UpdateNetworkState(bool online) {
auto ctx = GetInstance();
if (ctx->mPeerConnections.empty()) {
return;
}
for (auto pc : ctx->mPeerConnections) {
pc.second->UpdateNetworkState(online);
}
}
nsresult PeerConnectionCtx::Initialize() { nsresult PeerConnectionCtx::Initialize() {
initGMP(); initGMP();

Просмотреть файл

@ -18,7 +18,7 @@
#include "nsIRunnable.h" #include "nsIRunnable.h"
namespace mozilla { namespace mozilla {
class PeerConnectionCtxShutdown; class PeerConnectionCtxObserver;
namespace dom { namespace dom {
class WebrtcGlobalInformation; class WebrtcGlobalInformation;
@ -48,6 +48,8 @@ class PeerConnectionCtx {
bool gmpHasH264(); bool gmpHasH264();
static void UpdateNetworkState(bool online);
// Make these classes friend so that they can access mPeerconnections. // Make these classes friend so that they can access mPeerconnections.
friend class PeerConnectionImpl; friend class PeerConnectionImpl;
friend class PeerConnectionWrapper; friend class PeerConnectionWrapper;
@ -101,7 +103,7 @@ private:
static PeerConnectionCtx *gInstance; static PeerConnectionCtx *gInstance;
public: public:
static nsIThread *gMainThread; static nsIThread *gMainThread;
static mozilla::StaticRefPtr<mozilla::PeerConnectionCtxShutdown> gPeerConnectionCtxShutdown; static mozilla::StaticRefPtr<mozilla::PeerConnectionCtxObserver> gPeerConnectionCtxObserver;
}; };
} // namespace mozilla } // namespace mozilla

Просмотреть файл

@ -2297,10 +2297,17 @@ PeerConnectionImpl::AddIceCandidate(const char* aCandidate, const char* aMid, un
pco->OnAddIceCandidateError(error, ObString(errorString.c_str()), rv); pco->OnAddIceCandidateError(error, ObString(errorString.c_str()), rv);
} }
UpdateSignalingState();
return NS_OK; return NS_OK;
} }
void
PeerConnectionImpl::UpdateNetworkState(bool online) {
if (!mMedia) {
return;
}
mMedia->UpdateNetworkState(online);
}
NS_IMETHODIMP NS_IMETHODIMP
PeerConnectionImpl::CloseStreams() { PeerConnectionImpl::CloseStreams() {
PC_AUTO_ENTER_API_CALL(false); PC_AUTO_ENTER_API_CALL(false);
@ -3364,8 +3371,6 @@ PeerConnectionImpl::CandidateReady(const std::string& candidate,
CSFLogDebug(logTag, "Passing local candidate to content: %s", CSFLogDebug(logTag, "Passing local candidate to content: %s",
candidate.c_str()); candidate.c_str());
SendLocalIceCandidateToContent(level, mid, candidate); SendLocalIceCandidateToContent(level, mid, candidate);
UpdateSignalingState();
} }
static void static void

Просмотреть файл

@ -414,6 +414,8 @@ public:
NS_ConvertUTF16toUTF8(aMid).get(), aLevel); NS_ConvertUTF16toUTF8(aMid).get(), aLevel);
} }
void UpdateNetworkState(bool online);
NS_IMETHODIMP CloseStreams(); NS_IMETHODIMP CloseStreams();
void CloseStreams(ErrorResult &rv) void CloseStreams(ErrorResult &rv)

Просмотреть файл

@ -858,6 +858,7 @@ PeerConnectionMedia::AddIceCandidate(const std::string& candidate,
aMLine), aMLine),
NS_DISPATCH_NORMAL); NS_DISPATCH_NORMAL);
} }
void void
PeerConnectionMedia::AddIceCandidate_s(const std::string& aCandidate, PeerConnectionMedia::AddIceCandidate_s(const std::string& aCandidate,
const std::string& aMid, const std::string& aMid,
@ -877,6 +878,21 @@ PeerConnectionMedia::AddIceCandidate_s(const std::string& aCandidate,
} }
} }
void
PeerConnectionMedia::UpdateNetworkState(bool online) {
RUN_ON_THREAD(GetSTSThread(),
WrapRunnable(
RefPtr<PeerConnectionMedia>(this),
&PeerConnectionMedia::UpdateNetworkState_s,
online),
NS_DISPATCH_NORMAL);
}
void
PeerConnectionMedia::UpdateNetworkState_s(bool online) {
mIceCtxHdlr->ctx()->UpdateNetworkState(online);
}
void void
PeerConnectionMedia::FlushIceCtxOperationQueueIfReady() PeerConnectionMedia::FlushIceCtxOperationQueueIfReady()
{ {

Просмотреть файл

@ -292,6 +292,9 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
void AddIceCandidate(const std::string& candidate, const std::string& mid, void AddIceCandidate(const std::string& candidate, const std::string& mid,
uint32_t aMLine); uint32_t aMLine);
// Handle notifications of network online/offline events.
void UpdateNetworkState(bool online);
// Handle complete media pipelines. // Handle complete media pipelines.
nsresult UpdateMediaPipelines(const JsepSession& session); nsresult UpdateMediaPipelines(const JsepSession& session);
@ -491,6 +494,7 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
void AddIceCandidate_s(const std::string& aCandidate, const std::string& aMid, void AddIceCandidate_s(const std::string& aCandidate, const std::string& aMid,
uint32_t aMLine); uint32_t aMLine);
void UpdateNetworkState_s(bool online);
// ICE events // ICE events
void IceGatheringStateChange_s(NrIceCtx* ctx, void IceGatheringStateChange_s(NrIceCtx* ctx,