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" ||
topic == "network:offline-about-to-go-offline") {
// Delete all peerconnections on shutdown - mostly synchronously (we
// need them to be done deleting transports and streams before we
// 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);
}
// As Necko doesn't prevent us from accessing the network we still need to
// monitor the network offline/online state here. See bug 1326483
this._networkdown = true;
} else if (topic == "network:offline-status-changed") {
if (data == "offline") {
// this._list shold be empty here
this._networkdown = true;
} else if (data == "online") {
this._networkdown = false;
@ -1211,9 +1203,11 @@ RTCPeerConnection.prototype = {
},
changeIceConnectionState: function(state) {
this._iceConnectionState = state;
_globalPCList.notifyLifecycleObservers(this, "iceconnectionstatechange");
this.dispatchEvent(new this._win.Event("iceconnectionstatechange"));
if (state != this._iceConnectionState) {
this._iceConnectionState = state;
_globalPCList.notifyLifecycleObservers(this, "iceconnectionstatechange");
this.dispatchEvent(new this._win.Event("iceconnectionstatechange"));
}
},
getStats: function(selector, onSucc, onErr) {
@ -1370,35 +1364,25 @@ PeerConnectionObserver.prototype = {
//
// iceConnectionState:
// -------------------
// new The ICE Agent is gathering addresses and/or waiting for
// remote candidates to be supplied.
// new Any of the RTCIceTransports are in the new state and none
// of them are in the checking, failed or disconnected state.
//
// checking The ICE Agent has received remote candidates on at least
// one component, and is checking candidate pairs but has not
// yet found a connection. In addition to checking, it may
// also still be gathering.
// checking Any of the RTCIceTransports are in the checking state and
// none of them are in the failed or disconnected state.
//
// connected The ICE Agent has found a usable connection for all
// components but is still checking other candidate pairs to
// 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
// connected All RTCIceTransports are in the connected, completed or
// closed state and at least one of them is in the connected
// state.
//
// failed The ICE Agent is finished checking all candidate pairs and
// failed to find a connection for at least one component.
// Connections may have been found for some components.
// completed All RTCIceTransports are in the completed or closed state
// and at least one of them is in the completed state.
//
// disconnected Liveness checks have failed for one or more components.
// This is more aggressive than failed, and may trigger
// intermittently (and resolve itself without action) on a
// flaky network.
// failed Any of the RTCIceTransports are in the failed state.
//
// closed The ICE Agent has shut down and is no longer responding to
// STUN requests.
// disconnected Any of the RTCIceTransports are in the disconnected state
// and none of them are in the failed state.
//
// closed All of the RTCIceTransports are in the closed state.
handleIceConnectionStateChange: function(iceConnectionState) {
let pc = this._dompc;

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

@ -971,6 +971,16 @@ nsresult NrIceCtx::Finalize() {
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) {
if (state == connection_state_)
return;

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

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

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

@ -1366,6 +1366,26 @@ class IceTestPeer : public sigslot::has_slots<> {
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_; }
void SetControlling(NrIceCtx::Controlling controlling) {
@ -3350,6 +3370,49 @@ TEST_F(WebRtcIceConnectTest, TestConsentDelayed) {
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) {
if (turn_server_.empty())
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) {
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)
@ -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->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)
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:
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);
nr_ice_component_consent_request_timed_out(comp);
nr_ice_component_disconnected(comp);
break;
default:
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;
int r;
if (comp->consent_timer) {
NR_async_timer_cancel(comp->consent_timer);
}
comp->consent_timer = 0;
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)) {
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);
/* 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);
@ -1384,6 +1392,11 @@ void nr_ice_component_consent_schedule_consent_timer(nr_ice_component *comp)
&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)
{
if (comp->consent_timer) {
@ -1401,6 +1414,7 @@ void nr_ice_component_consent_destroy(nr_ice_component *comp)
}
if (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",
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,
&comp->active->remote->addr, 0,
&comp->consent_ctx))
@ -1423,6 +1439,7 @@ int nr_ice_component_setup_consent(nr_ice_component *comp)
ABORT(r);
comp->can_send = 1;
comp->disconnected = 0;
nr_ice_component_consent_refreshed(comp);
nr_ice_component_consent_calc_consent_timer(comp);

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

@ -75,6 +75,7 @@ struct nr_ice_component_ {
void *consent_timeout;
void *consent_handle;
int can_send;
int disconnected;
struct timeval consent_last_seen;
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_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);
void nr_ice_component_refresh_consent_now(nr_ice_component *comp);
void nr_ice_component_disconnected(nr_ice_component *comp);
#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"
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);
@ -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->trigger_check_queue);
stream->disconnected = 0;
stream->component_ct=components;
stream->ice_state = NR_ICE_MEDIA_STREAM_UNPAIRED;
*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);
}
if (stream->ice_state != NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED) {
if (stream->ice_state != NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED) {
if(!pair){
/* Find the highest priority WAITING check and move it to RUNNING */
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
* triggered check request which needs to fire, but not change our stream
* 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)) {
ABORT(r);
}
@ -584,6 +585,80 @@ int nr_ice_media_stream_set_state(nr_ice_media_stream *str, int state)
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,
the stream is ready */
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... */
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 */
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
*/
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);
}
_status=0;
abort:

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

@ -59,9 +59,14 @@ struct nr_ice_media_stream_ {
#define NR_ICE_MEDIA_STREAM_UNPAIRED 1
#define NR_ICE_MEDIA_STREAM_CHECKS_FROZEN 2
#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
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 trigger_check_queue;
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_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);
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_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);

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

@ -648,12 +648,45 @@ int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out)
}
#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)
{
if (pctx->reported_connected &&
pctx->handler &&
pctx->handler->vtbl->ice_disconnected) {
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);
while(str){
if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_COMPLETED){
if(str->ice_state==NR_ICE_MEDIA_STREAM_CHECKS_CONNECTED){
succeeded++;
}
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:
_status=0;
// abort:
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_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_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_connected(nr_ice_peer_ctx *pctx);
int nr_ice_peer_ctx_dump_state(nr_ice_peer_ctx *pctx,FILE *out);

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

@ -22,9 +22,12 @@
#include "nsServiceManagerUtils.h" // do_GetService
#include "nsIObserverService.h"
#include "nsIObserver.h"
#include "nsIIOService.h" // NS_IOSERVICE_*
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "nsCRTGlue.h"
#include "gmp-video-decode.h" // GMP_API_VIDEO_DECODER
#include "gmp-video-encode.h" // GMP_API_VIDEO_ENCODER
@ -34,12 +37,12 @@ namespace mozilla {
using namespace dom;
class PeerConnectionCtxShutdown : public nsIObserver
class PeerConnectionCtxObserver : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
PeerConnectionCtxShutdown() {}
PeerConnectionCtxObserver() {}
void Init()
{
@ -55,6 +58,10 @@ public:
NS_XPCOM_SHUTDOWN_OBSERVER_ID,
false);
MOZ_ALWAYS_SUCCEEDS(rv);
rv = observerService->AddObserver(this,
NS_IOSERVICE_OFFLINE_STATUS_TOPIC,
false);
MOZ_ALWAYS_SUCCEEDS(rv);
#endif
(void) rv;
}
@ -71,34 +78,52 @@ public:
return NS_ERROR_FAILURE;
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);
// Make sure we're not deleted while still inside ::Observe()
RefPtr<PeerConnectionCtxShutdown> kungFuDeathGrip(this);
PeerConnectionCtx::gPeerConnectionCtxShutdown = nullptr;
RefPtr<PeerConnectionCtxObserver> kungFuDeathGrip(this);
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;
}
private:
virtual ~PeerConnectionCtxShutdown()
virtual ~PeerConnectionCtxObserver()
{
nsCOMPtr<nsIObserverService> observerService =
services::GetObserverService();
if (observerService)
observerService->RemoveObserver(this, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
}
};
NS_IMPL_ISUPPORTS(PeerConnectionCtxShutdown, nsIObserver);
NS_IMPL_ISUPPORTS(PeerConnectionCtxObserver, nsIObserver);
}
namespace mozilla {
PeerConnectionCtx* PeerConnectionCtx::gInstance;
nsIThread* PeerConnectionCtx::gMainThread;
StaticRefPtr<PeerConnectionCtxShutdown> PeerConnectionCtx::gPeerConnectionCtxShutdown;
StaticRefPtr<PeerConnectionCtxObserver> PeerConnectionCtx::gPeerConnectionCtxObserver;
const std::map<const std::string, PeerConnectionImpl *>&
PeerConnectionCtx::mGetPeerConnections()
@ -129,9 +154,9 @@ nsresult PeerConnectionCtx::InitializeGlobal(nsIThread *mainThread,
gInstance = ctx;
if (!PeerConnectionCtx::gPeerConnectionCtxShutdown) {
PeerConnectionCtx::gPeerConnectionCtxShutdown = new PeerConnectionCtxShutdown();
PeerConnectionCtx::gPeerConnectionCtxShutdown->Init();
if (!PeerConnectionCtx::gPeerConnectionCtxObserver) {
PeerConnectionCtx::gPeerConnectionCtxObserver = new PeerConnectionCtxObserver();
PeerConnectionCtx::gPeerConnectionCtxObserver->Init();
}
}
@ -334,6 +359,17 @@ PeerConnectionCtx::EverySecondTelemetryCallback_m(nsITimer* timer, void *closure
}
#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() {
initGMP();

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

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

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

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

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

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

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

@ -858,6 +858,7 @@ PeerConnectionMedia::AddIceCandidate(const std::string& candidate,
aMLine),
NS_DISPATCH_NORMAL);
}
void
PeerConnectionMedia::AddIceCandidate_s(const std::string& aCandidate,
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
PeerConnectionMedia::FlushIceCtxOperationQueueIfReady()
{

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

@ -292,6 +292,9 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
void AddIceCandidate(const std::string& candidate, const std::string& mid,
uint32_t aMLine);
// Handle notifications of network online/offline events.
void UpdateNetworkState(bool online);
// Handle complete media pipelines.
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,
uint32_t aMLine);
void UpdateNetworkState_s(bool online);
// ICE events
void IceGatheringStateChange_s(NrIceCtx* ctx,