зеркало из https://github.com/mozilla/gecko-dev.git
Bug 804387. Part 1.5: Clean up main-thread MediaStream event listeners. r=jesup
There is no need for these to be independent objects in general and we don't need to addref/release them. We can just require the caller to remove them before they die. We can also save some refcount churn by having DispatchToMainThreadAfterStreamStateUpdate take already_AddRefed. --HG-- extra : rebase_source : 751114a1befd73b405dff3ee986496efb6f76201
This commit is contained in:
Родитель
8f4990d761
Коммит
e945b5a3e3
|
@ -2450,13 +2450,13 @@ public:
|
||||||
} else {
|
} else {
|
||||||
event = NS_NewRunnableMethod(this, &StreamListener::DoNotifyUnblocked);
|
event = NS_NewRunnableMethod(this, &StreamListener::DoNotifyUnblocked);
|
||||||
}
|
}
|
||||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event);
|
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
||||||
}
|
}
|
||||||
virtual void NotifyFinished(MediaStreamGraph* aGraph)
|
virtual void NotifyFinished(MediaStreamGraph* aGraph)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIRunnable> event =
|
nsCOMPtr<nsIRunnable> event =
|
||||||
NS_NewRunnableMethod(this, &StreamListener::DoNotifyFinished);
|
NS_NewRunnableMethod(this, &StreamListener::DoNotifyFinished);
|
||||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event);
|
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
||||||
}
|
}
|
||||||
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph,
|
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph,
|
||||||
bool aHasCurrentData)
|
bool aHasCurrentData)
|
||||||
|
@ -2471,7 +2471,7 @@ public:
|
||||||
if (aHasCurrentData) {
|
if (aHasCurrentData) {
|
||||||
nsCOMPtr<nsIRunnable> event =
|
nsCOMPtr<nsIRunnable> event =
|
||||||
NS_NewRunnableMethod(this, &StreamListener::DoNotifyHaveCurrentData);
|
NS_NewRunnableMethod(this, &StreamListener::DoNotifyHaveCurrentData);
|
||||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event);
|
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void NotifyOutput(MediaStreamGraph* aGraph)
|
virtual void NotifyOutput(MediaStreamGraph* aGraph)
|
||||||
|
@ -2482,7 +2482,7 @@ public:
|
||||||
mPendingNotifyOutput = true;
|
mPendingNotifyOutput = true;
|
||||||
nsCOMPtr<nsIRunnable> event =
|
nsCOMPtr<nsIRunnable> event =
|
||||||
NS_NewRunnableMethod(this, &StreamListener::DoNotifyOutput);
|
NS_NewRunnableMethod(this, &StreamListener::DoNotifyOutput);
|
||||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event);
|
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -164,23 +164,29 @@ MediaDecoder::DecodedStreamData::DecodedStreamData(MediaDecoder* aDecoder,
|
||||||
mAudioFramesWritten(0),
|
mAudioFramesWritten(0),
|
||||||
mInitialTime(aInitialTime),
|
mInitialTime(aInitialTime),
|
||||||
mNextVideoTime(aInitialTime),
|
mNextVideoTime(aInitialTime),
|
||||||
|
mDecoder(aDecoder),
|
||||||
mStreamInitialized(false),
|
mStreamInitialized(false),
|
||||||
mHaveSentFinish(false),
|
mHaveSentFinish(false),
|
||||||
mHaveSentFinishAudio(false),
|
mHaveSentFinishAudio(false),
|
||||||
mHaveSentFinishVideo(false),
|
mHaveSentFinishVideo(false),
|
||||||
mStream(aStream),
|
mStream(aStream),
|
||||||
mMainThreadListener(new DecodedStreamMainThreadListener(aDecoder)),
|
|
||||||
mHaveBlockedForPlayState(false)
|
mHaveBlockedForPlayState(false)
|
||||||
{
|
{
|
||||||
mStream->AddMainThreadListener(mMainThreadListener);
|
mStream->AddMainThreadListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaDecoder::DecodedStreamData::~DecodedStreamData()
|
MediaDecoder::DecodedStreamData::~DecodedStreamData()
|
||||||
{
|
{
|
||||||
mStream->RemoveMainThreadListener(mMainThreadListener);
|
mStream->RemoveMainThreadListener(this);
|
||||||
mStream->Destroy();
|
mStream->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaDecoder::DecodedStreamData::NotifyMainThreadStateChanged()
|
||||||
|
{
|
||||||
|
mDecoder->NotifyDecodedStreamMainThreadStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void MediaDecoder::DestroyDecodedStream()
|
void MediaDecoder::DestroyDecodedStream()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
|
@ -235,7 +235,6 @@ class MediaDecoder : public nsIObserver,
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef mozilla::layers::Image Image;
|
typedef mozilla::layers::Image Image;
|
||||||
class DecodedStreamMainThreadListener;
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIOBSERVER
|
NS_DECL_NSIOBSERVER
|
||||||
|
@ -340,7 +339,7 @@ public:
|
||||||
// replaying after the input as ended. In the latter case, the new source is
|
// replaying after the input as ended. In the latter case, the new source is
|
||||||
// not connected to streams created by captureStreamUntilEnded.
|
// not connected to streams created by captureStreamUntilEnded.
|
||||||
|
|
||||||
struct DecodedStreamData {
|
struct DecodedStreamData MOZ_FINAL : public MainThreadMediaStreamListener {
|
||||||
DecodedStreamData(MediaDecoder* aDecoder,
|
DecodedStreamData(MediaDecoder* aDecoder,
|
||||||
int64_t aInitialTime, SourceMediaStream* aStream);
|
int64_t aInitialTime, SourceMediaStream* aStream);
|
||||||
~DecodedStreamData();
|
~DecodedStreamData();
|
||||||
|
@ -358,6 +357,7 @@ public:
|
||||||
// Therefore video packets starting at or after this time need to be copied
|
// Therefore video packets starting at or after this time need to be copied
|
||||||
// to the output stream.
|
// to the output stream.
|
||||||
int64_t mNextVideoTime; // microseconds
|
int64_t mNextVideoTime; // microseconds
|
||||||
|
MediaDecoder* mDecoder;
|
||||||
// The last video image sent to the stream. Useful if we need to replicate
|
// The last video image sent to the stream. Useful if we need to replicate
|
||||||
// the image.
|
// the image.
|
||||||
nsRefPtr<Image> mLastVideoImage;
|
nsRefPtr<Image> mLastVideoImage;
|
||||||
|
@ -372,12 +372,11 @@ public:
|
||||||
// The decoder is responsible for calling Destroy() on this stream.
|
// The decoder is responsible for calling Destroy() on this stream.
|
||||||
// Can be read from any thread.
|
// Can be read from any thread.
|
||||||
const nsRefPtr<SourceMediaStream> mStream;
|
const nsRefPtr<SourceMediaStream> mStream;
|
||||||
// A listener object that receives notifications when mStream's
|
|
||||||
// main-thread-visible state changes. Used on the main thread only.
|
|
||||||
const nsRefPtr<DecodedStreamMainThreadListener> mMainThreadListener;
|
|
||||||
// True when we've explicitly blocked this stream because we're
|
// True when we've explicitly blocked this stream because we're
|
||||||
// not in PLAY_STATE_PLAYING. Used on the main thread only.
|
// not in PLAY_STATE_PLAYING. Used on the main thread only.
|
||||||
bool mHaveBlockedForPlayState;
|
bool mHaveBlockedForPlayState;
|
||||||
|
|
||||||
|
virtual void NotifyMainThreadStateChanged() MOZ_OVERRIDE;
|
||||||
};
|
};
|
||||||
struct OutputStreamData {
|
struct OutputStreamData {
|
||||||
void Init(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
|
void Init(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
|
||||||
|
@ -421,16 +420,6 @@ public:
|
||||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||||
return mDecodedStream;
|
return mDecodedStream;
|
||||||
}
|
}
|
||||||
class DecodedStreamMainThreadListener : public MainThreadMediaStreamListener {
|
|
||||||
public:
|
|
||||||
DecodedStreamMainThreadListener(MediaDecoder* aDecoder)
|
|
||||||
: mDecoder(aDecoder) {}
|
|
||||||
virtual void NotifyMainThreadStateChanged()
|
|
||||||
{
|
|
||||||
mDecoder->NotifyDecodedStreamMainThreadStateChanged();
|
|
||||||
}
|
|
||||||
MediaDecoder* mDecoder;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Add an output stream. All decoder output will be sent to the stream.
|
// Add an output stream. All decoder output will be sent to the stream.
|
||||||
// The stream is initially blocked. The decoder is responsible for unblocking
|
// The stream is initially blocked. The decoder is responsible for unblocking
|
||||||
|
|
|
@ -172,19 +172,16 @@ public:
|
||||||
* This callback is invoked on the main thread when the main-thread-visible
|
* This callback is invoked on the main thread when the main-thread-visible
|
||||||
* state of a stream has changed.
|
* state of a stream has changed.
|
||||||
*
|
*
|
||||||
* These methods are called without the media graph monitor held, so
|
* These methods are called with the media graph monitor held, so
|
||||||
* reentry into media graph methods is possible, although very much discouraged!
|
* reentry into general media graph methods is not possible.
|
||||||
* You should do something non-blocking and non-reentrant (e.g. dispatch an
|
* You should do something non-blocking and non-reentrant (e.g. dispatch an
|
||||||
* event) and return.
|
* event) and return. DispatchFromMainThreadAfterNextStreamStateUpdate
|
||||||
|
* would be a good choice.
|
||||||
* The listener is allowed to synchronously remove itself from the stream, but
|
* The listener is allowed to synchronously remove itself from the stream, but
|
||||||
* not add or remove any other listeners.
|
* not add or remove any other listeners.
|
||||||
*/
|
*/
|
||||||
class MainThreadMediaStreamListener {
|
class MainThreadMediaStreamListener {
|
||||||
public:
|
public:
|
||||||
virtual ~MainThreadMediaStreamListener() {}
|
|
||||||
|
|
||||||
NS_INLINE_DECL_REFCOUNTING(MainThreadMediaStreamListener)
|
|
||||||
|
|
||||||
virtual void NotifyMainThreadStateChanged() = 0;
|
virtual void NotifyMainThreadStateChanged() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -274,7 +271,12 @@ public:
|
||||||
, mMainThreadDestroyed(false)
|
, mMainThreadDestroyed(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
virtual ~MediaStream() {}
|
virtual ~MediaStream()
|
||||||
|
{
|
||||||
|
NS_ASSERTION(mMainThreadDestroyed, "Should have been destroyed already");
|
||||||
|
NS_ASSERTION(mMainThreadListeners.IsEmpty(),
|
||||||
|
"All main thread listeners should have been removed");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the graph that owns this stream.
|
* Returns the graph that owns this stream.
|
||||||
|
@ -303,11 +305,15 @@ public:
|
||||||
// Events will be dispatched by calling methods of aListener.
|
// Events will be dispatched by calling methods of aListener.
|
||||||
void AddListener(MediaStreamListener* aListener);
|
void AddListener(MediaStreamListener* aListener);
|
||||||
void RemoveListener(MediaStreamListener* aListener);
|
void RemoveListener(MediaStreamListener* aListener);
|
||||||
|
// Events will be dispatched by calling methods of aListener. It is the
|
||||||
|
// responsibility of the caller to remove aListener before it is destroyed.
|
||||||
void AddMainThreadListener(MainThreadMediaStreamListener* aListener)
|
void AddMainThreadListener(MainThreadMediaStreamListener* aListener)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
|
NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
|
||||||
mMainThreadListeners.AppendElement(aListener);
|
mMainThreadListeners.AppendElement(aListener);
|
||||||
}
|
}
|
||||||
|
// It's safe to call this even if aListener is not currently a listener;
|
||||||
|
// the call will be ignored.
|
||||||
void RemoveMainThreadListener(MainThreadMediaStreamListener* aListener)
|
void RemoveMainThreadListener(MainThreadMediaStreamListener* aListener)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
|
NS_ASSERTION(NS_IsMainThread(), "Call only on main thread");
|
||||||
|
@ -424,7 +430,7 @@ protected:
|
||||||
// API, minus the number of times it has been explicitly unblocked.
|
// API, minus the number of times it has been explicitly unblocked.
|
||||||
TimeVarying<GraphTime,uint32_t> mExplicitBlockerCount;
|
TimeVarying<GraphTime,uint32_t> mExplicitBlockerCount;
|
||||||
nsTArray<nsRefPtr<MediaStreamListener> > mListeners;
|
nsTArray<nsRefPtr<MediaStreamListener> > mListeners;
|
||||||
nsTArray<nsRefPtr<MainThreadMediaStreamListener> > mMainThreadListeners;
|
nsTArray<MainThreadMediaStreamListener*> mMainThreadListeners;
|
||||||
|
|
||||||
// Precomputed blocking status (over GraphTime).
|
// Precomputed blocking status (over GraphTime).
|
||||||
// This is only valid between the graph's mCurrentTime and
|
// This is only valid between the graph's mCurrentTime and
|
||||||
|
@ -838,9 +844,9 @@ public:
|
||||||
* main-thread stream state has been next updated.
|
* main-thread stream state has been next updated.
|
||||||
* Should only be called during MediaStreamListener callbacks.
|
* Should only be called during MediaStreamListener callbacks.
|
||||||
*/
|
*/
|
||||||
void DispatchToMainThreadAfterStreamStateUpdate(nsIRunnable* aRunnable)
|
void DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
|
||||||
{
|
{
|
||||||
mPendingUpdateRunnables.AppendElement(aRunnable);
|
*mPendingUpdateRunnables.AppendElement() = aRunnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
Загрузка…
Ссылка в новой задаче