Bug 1208371 - Count the users of a MediaStream to ease Destroy() responsibility. r?roc
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -1591,16 +1591,17 @@ MediaStream::MediaStream(DOMMediaStream*
, mNotifiedBlocked(false)
, mHasCurrentData(false)
, mNotifiedHasCurrentData(false)
, mWrapper(aWrapper)
, mMainThreadCurrentTime(0)
, mMainThreadFinished(false)
, mFinishedNotificationSent(false)
, mMainThreadDestroyed(false)
+ , mNrOfMainThreadUsers(0)
, mGraph(nullptr)
, mAudioChannelType(dom::AudioChannel::Normal)
{
MOZ_COUNT_CTOR(MediaStream);
// aWrapper should not already be connected to a MediaStream! It needs
// to be hooked up to this stream, and since this stream is only just
// being created now, aWrapper must not be connected to anything.
NS_ASSERTION(!aWrapper || !aWrapper->GetPlaybackStream(),
@@ -1734,16 +1735,18 @@ MediaStream::DestroyImpl()
mConsumers[i]->Disconnect();
}
mGraph = nullptr;
}
void
MediaStream::Destroy()
{
+ NS_ASSERTION(mNrOfMainThreadUsers == 0,
+ "Do not mix Destroy() and RegisterUser()/UnregisterUser()");
// Keep this stream alive until we leave this method
RefPtr<MediaStream> kungFuDeathGrip = this;
class Message : public ControlMessage {
public:
explicit Message(MediaStream* aStream) : ControlMessage(aStream) {}
virtual void Run()
{
@@ -1759,16 +1762,36 @@ MediaStream::Destroy()
GraphImpl()->AppendMessage(new Message(this));
// Message::RunDuringShutdown may have removed this stream from the graph,
// but our kungFuDeathGrip above will have kept this stream alive if
// necessary.
mMainThreadDestroyed = true;
}
void
+MediaStream::RegisterUser()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ ++mNrOfMainThreadUsers;
+}
+
+void
+MediaStream::UnregisterUser()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ --mNrOfMainThreadUsers;
+ NS_ASSERTION(mNrOfMainThreadUsers >= 0, "Double-removal of main thread user");
+ NS_ASSERTION(!IsDestroyed(), "Do not mix Destroy() and RegisterUser()/UnregisterUser()");
+ if (mNrOfMainThreadUsers == 0) {
+ Destroy();
+ }
+}
+
+void
MediaStream::AddAudioOutput(void* aKey)
{
class Message : public ControlMessage {
public:
Message(MediaStream* aStream, void* aKey) : ControlMessage(aStream), mKey(aKey) {}
virtual void Run()
{
mStream->AddAudioOutputImpl(mKey);
--- a/dom/media/MediaStreamGraph.h
+++ b/dom/media/MediaStreamGraph.h
@@ -393,18 +393,29 @@ public:
* and has not started, then the runnable will be run
* synchronously/immediately. (There are no pending updates in these
* situations.)
*
* Main thread only.
*/
void RunAfterPendingUpdates(already_AddRefed<nsIRunnable> aRunnable);
- // Signal that the client is done with this MediaStream. It will be deleted later.
+ // Signal that the client is done with this MediaStream. It will be deleted
+ // later. Do not mix usage of Destroy() with RegisterUser()/UnregisterUser().
+ // That will cause the MediaStream to be destroyed twice, which will cause
+ // some assertions to fail.
virtual void Destroy();
+ // Signal that a client is using this MediaStream. Useful to not have to
+ // explicitly manage ownership (responsibility to Destroy()) when there are
+ // multiple clients using a MediaStream.
+ void RegisterUser();
+ // Signal that a client no longer needs this MediaStream. When the number of
+ // clients using this MediaStream reaches 0, it will be destroyed.
+ void UnregisterUser();
+
// Returns the main-thread's view of how much data has been processed by
// this stream.
StreamTime GetCurrentTime()
{
NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
return mMainThreadCurrentTime;
}
// Return the main thread's view of whether this stream has finished.
@@ -668,16 +679,17 @@ protected:
// This state is only used on the main thread.
DOMMediaStream* mWrapper;
// Main-thread views of state
StreamTime mMainThreadCurrentTime;
bool mMainThreadFinished;
bool mFinishedNotificationSent;
bool mMainThreadDestroyed;
+ int mNrOfMainThreadUsers;
// Our media stream graph. null if destroyed on the graph thread.
MediaStreamGraphImpl* mGraph;
dom::AudioChannel mAudioChannelType;
};
/**