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