Bug 812886: Watch network (tear)down events and kill PeerConnections r=ekr,smaug,bsmith

This commit is contained in:
Randell Jesup 2012-11-18 23:53:14 -05:00
parent 208ddd52f5
commit 645ded6229
4 changed files with 42 additions and 22 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);