diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index 9987e2ace28..234be094b5c 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -22,8 +22,10 @@ const PC_MANAGER_CID = Components.ID("{7293e901-2be3-4c02-b4bd-cbef6fc24f78}"); // Global list of PeerConnection objects, so they can be cleaned up when // a page is torn down. (Maps inner window ID to an array of PC objects). function GlobalPCList() { - this._list = {}; + this._list = []; Services.obs.addObserver(this, "inner-window-destroyed", true); + Services.obs.addObserver(this, "profile-change-net-teardown", true); + Services.obs.addObserver(this, "network:offline-about-to-go-offline", true); } GlobalPCList.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, @@ -63,19 +65,32 @@ GlobalPCList.prototype = { }, observe: function(subject, topic, data) { - if (topic != "inner-window-destroyed") { - return; + if (topic == "inner-window-destroyed") { + let winID = subject.QueryInterface(Ci.nsISupportsPRUint64).data; + if (this._list[winID]) { + this._list[winID].forEach(function(pc) { + pc._pc.close(false); + delete pc._observer; + pc._pc = null; + }); + delete this._list[winID]; + } + } else if (topic == "profile-change-net-teardown" || + topic == "network:offline-about-to-go-offline") { + // Delete all peerconnections on shutdown - synchronously (we need + // them to be done deleting transports before we return)! + // Also kill them if "Work Offline" is selected - more can be created + // while offline, but attempts to connect them should fail. + let array; + while ((array = this._list.pop()) != undefined) { + array.forEach(function(pc) { + pc._pc.close(true); + delete pc._observer; + pc._pc = null; + }); + }; } - let winID = subject.QueryInterface(Ci.nsISupportsPRUint64).data; - if (this._list[winID]) { - this._list[winID].forEach(function(pc) { - pc._pc.close(); - delete pc._observer; - pc._pc = null; - }); - delete this._list[winID]; - } - } + }, }; let _globalPCList = new GlobalPCList(); @@ -453,7 +468,7 @@ PeerConnection.prototype = { close: function() { this._queueOrRun({ func: this._pc.close, - args: [], + args: [false], wait: false }); this._closed = true; diff --git a/dom/media/bridge/IPeerConnection.idl b/dom/media/bridge/IPeerConnection.idl index 8b36635fb4f..9873a761705 100644 --- a/dom/media/bridge/IPeerConnection.idl +++ b/dom/media/bridge/IPeerConnection.idl @@ -65,7 +65,7 @@ interface IPeerConnectionObserver : nsISupports void foundIceCandidate(in string candidate); }; -[scriptable, uuid(f6819246-f5af-40f2-ab82-e166d5da7ba0)] +[scriptable, uuid(c86903c7-0a2e-42b4-903c-1518f03b9ba5)] interface IPeerConnection : nsISupports { const unsigned long kHintAudio = 0x00000001; @@ -113,7 +113,7 @@ interface IPeerConnection : nsISupports void addIceCandidate(in string candidate, in string mid, in unsigned short level); /* Puts the SIPCC engine back to 'kIdle', shuts down threads, deletes state */ - void close(); + void close(in bool isSynchronous); /* Attributes */ readonly attribute string localDescription; diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index fc1d7d1db6d..1f76c5b4d71 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -278,7 +278,7 @@ PeerConnectionImpl::PeerConnectionImpl() PeerConnectionImpl::~PeerConnectionImpl() { - Close(); + Close(false); // Since this and Initialize() occur on MainThread, they can't both be // running at once // Might be more optimal to release off a timer (and XPCOM Shutdown) @@ -935,7 +935,7 @@ PeerConnectionImpl::GetIceState(uint32_t* aState) } NS_IMETHODIMP -PeerConnectionImpl::Close() +PeerConnectionImpl::Close(bool aIsSynchronous) { if (mCall != NULL) mCall->endCall(); @@ -944,7 +944,7 @@ PeerConnectionImpl::Close() mDataConnection->CloseAll(); #endif - ShutdownMedia(); + ShutdownMedia(aIsSynchronous); // DataConnection will need to stay alive until all threads/runnables exit @@ -952,7 +952,7 @@ PeerConnectionImpl::Close() } void -PeerConnectionImpl::ShutdownMedia() +PeerConnectionImpl::ShutdownMedia(bool aIsSynchronous) { // Check that we are on the main thread. if (mThread) { @@ -969,10 +969,15 @@ PeerConnectionImpl::ShutdownMedia() // This avoids reentrancy issues with the garbage collector. // Note that no media calls may be made after this point // because we have removed the pointer. + // For the aIsSynchronous case, we *know* the PeerConnection is + // still alive, and are shutting it down on network teardown/etc, so + // recursive GC isn't an issue. (Recursive GC should assert) + // Forget the reference so that we can transfer it to // SelfDestruct(). RUN_ON_THREAD(mThread, WrapRunnable(mMedia.forget().get(), - &PeerConnectionMedia::SelfDestruct), NS_DISPATCH_NORMAL); + &PeerConnectionMedia::SelfDestruct), + aIsSynchronous ? NS_DISPATCH_SYNC : NS_DISPATCH_NORMAL); } void diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h index 333242fdc83..ea3f1f296c8 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h @@ -166,7 +166,7 @@ private: } // Shut down media. Called on any thread. - void ShutdownMedia(); + void ShutdownMedia(bool isSynchronous); nsresult MakeMediaStream(uint32_t aHint, nsIDOMMediaStream** aStream); nsresult MakeRemoteSource(nsDOMMediaStream* aStream, RemoteSourceStreamInfo** aInfo);