mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 822956. Part 2: Don't wrap getUserMedia's SourceMediaStream in a DOM object wrapper. Create an nsDOMUserMediaStream wrapper specifically to clean up the SourceMediaStream and the MediaInputPort. r=jesup
This commit is contained in:
parent
24ac0fe4a6
commit
d254dc4188
@ -78,9 +78,7 @@ already_AddRefed<nsDOMMediaStream>
|
||||
nsDOMMediaStream::CreateSourceStream(uint32_t aHintContents)
|
||||
{
|
||||
nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream();
|
||||
stream->SetHintContents(aHintContents);
|
||||
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
||||
stream->mStream = gm->CreateSourceStream(stream);
|
||||
stream->InitSourceStream(aHintContents);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
@ -88,9 +86,7 @@ already_AddRefed<nsDOMLocalMediaStream>
|
||||
nsDOMLocalMediaStream::CreateSourceStream(uint32_t aHintContents)
|
||||
{
|
||||
nsRefPtr<nsDOMLocalMediaStream> stream = new nsDOMLocalMediaStream();
|
||||
stream->SetHintContents(aHintContents);
|
||||
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
||||
stream->mStream = gm->CreateSourceStream(stream);
|
||||
stream->InitSourceStream(aHintContents);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
@ -98,9 +94,7 @@ already_AddRefed<nsDOMMediaStream>
|
||||
nsDOMMediaStream::CreateTrackUnionStream(uint32_t aHintContents)
|
||||
{
|
||||
nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream();
|
||||
stream->SetHintContents(aHintContents);
|
||||
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
||||
stream->mStream = gm->CreateTrackUnionStream(stream);
|
||||
stream->InitTrackUnionStream(aHintContents);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
@ -108,9 +102,7 @@ already_AddRefed<nsDOMLocalMediaStream>
|
||||
nsDOMLocalMediaStream::CreateTrackUnionStream(uint32_t aHintContents)
|
||||
{
|
||||
nsRefPtr<nsDOMLocalMediaStream> stream = new nsDOMLocalMediaStream();
|
||||
stream->SetHintContents(aHintContents);
|
||||
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
||||
stream->mStream = gm->CreateTrackUnionStream(stream);
|
||||
stream->InitTrackUnionStream(aHintContents);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
|
@ -26,9 +26,11 @@ class nsXPCClassInfo;
|
||||
class nsDOMMediaStream : public nsIDOMMediaStream
|
||||
{
|
||||
friend class nsDOMLocalMediaStream;
|
||||
typedef mozilla::MediaStream MediaStream;
|
||||
|
||||
public:
|
||||
typedef mozilla::MediaStream MediaStream;
|
||||
typedef mozilla::MediaStreamGraph MediaStreamGraph;
|
||||
|
||||
nsDOMMediaStream() : mStream(nullptr), mHintContents(0) {}
|
||||
virtual ~nsDOMMediaStream();
|
||||
|
||||
@ -73,6 +75,19 @@ public:
|
||||
static already_AddRefed<nsDOMMediaStream> CreateTrackUnionStream(uint32_t aHintContents = 0);
|
||||
|
||||
protected:
|
||||
void InitSourceStream(uint32_t aHintContents)
|
||||
{
|
||||
SetHintContents(aHintContents);
|
||||
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
||||
mStream = gm->CreateSourceStream(this);
|
||||
}
|
||||
void InitTrackUnionStream(uint32_t aHintContents)
|
||||
{
|
||||
SetHintContents(aHintContents);
|
||||
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
||||
mStream = gm->CreateTrackUnionStream(this);
|
||||
}
|
||||
|
||||
// MediaStream is owned by the graph, but we tell it when to die, and it won't
|
||||
// die until we let it.
|
||||
MediaStream* mStream;
|
||||
|
@ -221,6 +221,37 @@ MediaDevice::GetSource()
|
||||
return mSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* A subclass that we only use to stash internal pointers to MediaStreamGraph objects
|
||||
* that need to be cleaned up.
|
||||
*/
|
||||
class nsDOMUserMediaStream : public nsDOMLocalMediaStream
|
||||
{
|
||||
public:
|
||||
static already_AddRefed<nsDOMUserMediaStream>
|
||||
CreateTrackUnionStream(uint32_t aHintContents)
|
||||
{
|
||||
nsRefPtr<nsDOMUserMediaStream> stream = new nsDOMUserMediaStream();
|
||||
stream->InitTrackUnionStream(aHintContents);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
virtual ~nsDOMUserMediaStream()
|
||||
{
|
||||
if (mPort) {
|
||||
mPort->Destroy();
|
||||
}
|
||||
if (mSourceStream) {
|
||||
mSourceStream->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// The actual MediaStream is a TrackUnionStream. But these resources need to be
|
||||
// explicitly destroyed too.
|
||||
nsRefPtr<SourceMediaStream> mSourceStream;
|
||||
nsRefPtr<MediaInputPort> mPort;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a MediaStream, attaches a listener and fires off a success callback
|
||||
* to the DOM with the stream. We also pass in the error callback so it can
|
||||
@ -267,29 +298,31 @@ public:
|
||||
}
|
||||
|
||||
// Create a media stream.
|
||||
nsRefPtr<nsDOMLocalMediaStream> stream;
|
||||
nsRefPtr<nsDOMLocalMediaStream> trackunion;
|
||||
uint32_t hints = (mAudioSource ? nsDOMMediaStream::HINT_CONTENTS_AUDIO : 0);
|
||||
hints |= (mVideoSource ? nsDOMMediaStream::HINT_CONTENTS_VIDEO : 0);
|
||||
|
||||
stream = nsDOMLocalMediaStream::CreateSourceStream(hints);
|
||||
trackunion = nsDOMLocalMediaStream::CreateTrackUnionStream(hints);
|
||||
if (!stream || !trackunion) {
|
||||
nsRefPtr<nsDOMUserMediaStream> trackunion =
|
||||
nsDOMUserMediaStream::CreateTrackUnionStream(hints);
|
||||
if (!trackunion) {
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
|
||||
LOG(("Returning error for getUserMedia() - no stream"));
|
||||
error->OnError(NS_LITERAL_STRING("NO_STREAM"));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
|
||||
nsRefPtr<SourceMediaStream> stream = gm->CreateSourceStream(nullptr);
|
||||
|
||||
// connect the source stream to the track union stream to avoid us blocking
|
||||
trackunion->GetStream()->AsProcessedStream()->SetAutofinish(true);
|
||||
nsRefPtr<MediaInputPort> port = trackunion->GetStream()->AsProcessedStream()->
|
||||
AllocateInputPort(stream->GetStream()->AsSourceStream(),
|
||||
MediaInputPort::FLAG_BLOCK_OUTPUT);
|
||||
AllocateInputPort(stream, MediaInputPort::FLAG_BLOCK_OUTPUT);
|
||||
trackunion->mSourceStream = stream;
|
||||
trackunion->mPort = port;
|
||||
|
||||
nsPIDOMWindow *window = static_cast<nsPIDOMWindow*>
|
||||
(nsGlobalWindow::GetInnerWindowWithId(mWindowID));
|
||||
if (window && window->GetExtantDoc()) {
|
||||
stream->CombineWithPrincipal(window->GetExtantDoc()->NodePrincipal());
|
||||
trackunion->CombineWithPrincipal(window->GetExtantDoc()->NodePrincipal());
|
||||
}
|
||||
|
||||
@ -300,11 +333,11 @@ public:
|
||||
// that the MediaStream has started consuming. The listener is freed
|
||||
// when the page is invalidated (on navigation or close).
|
||||
GetUserMediaCallbackMediaStreamListener* listener =
|
||||
new GetUserMediaCallbackMediaStreamListener(mediaThread, stream,
|
||||
new GetUserMediaCallbackMediaStreamListener(mediaThread, stream.forget(),
|
||||
port.forget(),
|
||||
mAudioSource,
|
||||
mVideoSource);
|
||||
stream->GetStream()->AddListener(listener);
|
||||
listener->Stream()->AddListener(listener);
|
||||
|
||||
// No need for locking because we always do this in the main thread.
|
||||
listeners->AppendElement(listener);
|
||||
@ -312,7 +345,7 @@ public:
|
||||
// Dispatch to the media thread to ask it to start the sources,
|
||||
// because that can take a while
|
||||
nsRefPtr<MediaOperationRunnable> runnable(
|
||||
new MediaOperationRunnable(MEDIA_START, stream,
|
||||
new MediaOperationRunnable(MEDIA_START, listener,
|
||||
mAudioSource, mVideoSource));
|
||||
mediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
|
||||
|
@ -70,7 +70,7 @@ class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener
|
||||
{
|
||||
public:
|
||||
GetUserMediaCallbackMediaStreamListener(nsIThread *aThread,
|
||||
nsDOMMediaStream* aStream,
|
||||
already_AddRefed<SourceMediaStream> aStream,
|
||||
already_AddRefed<MediaInputPort> aPort,
|
||||
MediaEngineSource* aAudioSource,
|
||||
MediaEngineSource* aVideoSource)
|
||||
@ -79,25 +79,22 @@ public:
|
||||
, mVideoSource(aVideoSource)
|
||||
, mStream(aStream)
|
||||
, mPort(aPort)
|
||||
, mSourceStream(aStream->GetStream()->AsSourceStream())
|
||||
, mLastEndTimeAudio(0)
|
||||
, mLastEndTimeVideo(0) { MOZ_ASSERT(mSourceStream); }
|
||||
, mLastEndTimeVideo(0) {}
|
||||
|
||||
~GetUserMediaCallbackMediaStreamListener()
|
||||
{
|
||||
// In theory this could be released from the MediaStreamGraph thread (RemoveListener)
|
||||
if (mStream) {
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
nsDOMMediaStream *stream;
|
||||
mStream.forget(&stream);
|
||||
// Releases directly if on MainThread already
|
||||
NS_ProxyRelease(mainThread, stream, false);
|
||||
}
|
||||
// It's OK to release mStream and mPort on any thread; they have thread-safe
|
||||
// refcounts.
|
||||
}
|
||||
|
||||
MediaStream *Stream()
|
||||
{
|
||||
return mStream;
|
||||
}
|
||||
SourceMediaStream *GetSourceStream()
|
||||
{
|
||||
return mStream->GetStream()->AsSourceStream();
|
||||
return mStream->AsSourceStream();
|
||||
}
|
||||
|
||||
void
|
||||
@ -108,7 +105,7 @@ public:
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||
// Caller holds strong reference to us, so no death grip required
|
||||
mStream->GetStream()->RemoveListener(this);
|
||||
mStream->RemoveListener(this);
|
||||
}
|
||||
|
||||
// Proxy NotifyPull() to sources
|
||||
@ -118,10 +115,10 @@ public:
|
||||
// Currently audio sources ignore NotifyPull, but they could
|
||||
// watch it especially for fake audio.
|
||||
if (mAudioSource) {
|
||||
mAudioSource->NotifyPull(aGraph, mSourceStream, kAudioTrack, aDesiredTime, mLastEndTimeAudio);
|
||||
mAudioSource->NotifyPull(aGraph, mStream, kAudioTrack, aDesiredTime, mLastEndTimeAudio);
|
||||
}
|
||||
if (mVideoSource) {
|
||||
mVideoSource->NotifyPull(aGraph, mSourceStream, kVideoTrack, aDesiredTime, mLastEndTimeVideo);
|
||||
mVideoSource->NotifyPull(aGraph, mStream, kVideoTrack, aDesiredTime, mLastEndTimeVideo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,9 +133,8 @@ private:
|
||||
nsCOMPtr<nsIThread> mMediaThread;
|
||||
nsRefPtr<MediaEngineSource> mAudioSource;
|
||||
nsRefPtr<MediaEngineSource> mVideoSource;
|
||||
nsRefPtr<nsDOMMediaStream> mStream;
|
||||
nsRefPtr<SourceMediaStream> mStream;
|
||||
nsRefPtr<MediaInputPort> mPort;
|
||||
SourceMediaStream *mSourceStream; // mStream controls ownership
|
||||
TrackTicks mLastEndTimeAudio;
|
||||
TrackTicks mLastEndTimeVideo;
|
||||
};
|
||||
@ -154,16 +150,6 @@ typedef enum {
|
||||
class MediaOperationRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
MediaOperationRunnable(MediaOperation aType,
|
||||
nsDOMMediaStream* aStream,
|
||||
MediaEngineSource* aAudioSource,
|
||||
MediaEngineSource* aVideoSource)
|
||||
: mType(aType)
|
||||
, mAudioSource(aAudioSource)
|
||||
, mVideoSource(aVideoSource)
|
||||
, mStream(aStream)
|
||||
{}
|
||||
|
||||
// so we can send Stop without AddRef()ing from the MSG thread
|
||||
MediaOperationRunnable(MediaOperation aType,
|
||||
GetUserMediaCallbackMediaStreamListener* aListener,
|
||||
@ -172,33 +158,20 @@ public:
|
||||
: mType(aType)
|
||||
, mAudioSource(aAudioSource)
|
||||
, mVideoSource(aVideoSource)
|
||||
, mStream(nullptr)
|
||||
, mListener(aListener)
|
||||
{}
|
||||
|
||||
~MediaOperationRunnable()
|
||||
{
|
||||
// nsDOMMediaStreams are cycle-collected and thus main-thread-only for
|
||||
// refcounting and releasing
|
||||
if (mStream) {
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
nsDOMMediaStream *stream;
|
||||
mStream.forget(&stream);
|
||||
NS_ProxyRelease(mainThread, stream, true);
|
||||
}
|
||||
// MediaStreams can be released on any thread.
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
SourceMediaStream *source;
|
||||
SourceMediaStream *source = mListener->GetSourceStream();
|
||||
// No locking between these is required as all the callbacks for the
|
||||
// same MediaStream will occur on the same thread.
|
||||
if (mStream) {
|
||||
source = mStream->GetStream()->AsSourceStream();
|
||||
} else {
|
||||
source = mListener->GetSourceStream();
|
||||
}
|
||||
MOZ_ASSERT(source);
|
||||
if (!source) // paranoia
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -266,7 +239,6 @@ private:
|
||||
MediaOperation mType;
|
||||
nsRefPtr<MediaEngineSource> mAudioSource; // threadsafe
|
||||
nsRefPtr<MediaEngineSource> mVideoSource; // threadsafe
|
||||
nsRefPtr<nsDOMMediaStream> mStream; // not threadsafe
|
||||
nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user