зеркало из https://github.com/mozilla/gecko-dev.git
Bug 866514. Part 2: Delay delivering getUserMedia stream result until the DOM object has asynchronously acquired the desired tracks. r=jesup
This commit is contained in:
Родитель
6d42b1300e
Коммит
95251bed50
|
@ -326,6 +326,41 @@ public:
|
|||
|
||||
~GetUserMediaStreamRunnable() {}
|
||||
|
||||
class TracksAvailableCallback : public DOMMediaStream::OnTracksAvailableCallback
|
||||
{
|
||||
public:
|
||||
TracksAvailableCallback(MediaManager* aManager,
|
||||
nsIDOMGetUserMediaSuccessCallback* aSuccess,
|
||||
uint64_t aWindowID,
|
||||
DOMMediaStream* aStream)
|
||||
: mWindowID(aWindowID), mSuccess(aSuccess), mManager(aManager),
|
||||
mStream(aStream) {}
|
||||
virtual void NotifyTracksAvailable(DOMMediaStream* aStream) MOZ_OVERRIDE
|
||||
{
|
||||
// We're in the main thread, so no worries here.
|
||||
if (!(mManager->IsWindowStillActive(mWindowID))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is safe since we're on main-thread, and the windowlist can only
|
||||
// be invalidated from the main-thread (see OnNavigation)
|
||||
LOG(("Returning success for getUserMedia()"));
|
||||
mSuccess->OnSuccess(aStream);
|
||||
}
|
||||
uint64_t mWindowID;
|
||||
nsRefPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
nsRefPtr<MediaManager> mManager;
|
||||
// Keep the DOMMediaStream alive until the NotifyTracksAvailable callback
|
||||
// has fired, otherwise we might immediately destroy the DOMMediaStream and
|
||||
// shut down the underlying MediaStream prematurely.
|
||||
// This creates a cycle which is broken when NotifyTracksAvailable
|
||||
// is fired (which will happen unless the browser shuts down,
|
||||
// since we only add this callback when we've successfully appended
|
||||
// the desired tracks in the MediaStreamGraph) or when
|
||||
// DOMMediaStream::NotifyMediaStreamGraphShutdown is called.
|
||||
nsRefPtr<DOMMediaStream> mStream;
|
||||
};
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
|
@ -342,13 +377,14 @@ public:
|
|||
}
|
||||
|
||||
// Create a media stream.
|
||||
uint32_t hints = (mAudioSource ? DOMMediaStream::HINT_CONTENTS_AUDIO : 0);
|
||||
hints |= (mVideoSource ? DOMMediaStream::HINT_CONTENTS_VIDEO : 0);
|
||||
DOMMediaStream::TrackTypeHints hints =
|
||||
(mAudioSource ? DOMMediaStream::HINT_CONTENTS_AUDIO : 0) |
|
||||
(mVideoSource ? DOMMediaStream::HINT_CONTENTS_VIDEO : 0);
|
||||
|
||||
nsRefPtr<nsDOMUserMediaStream> trackunion =
|
||||
nsDOMUserMediaStream::CreateTrackUnionStream(window, hints);
|
||||
if (!trackunion) {
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget();
|
||||
LOG(("Returning error for getUserMedia() - no stream"));
|
||||
error->OnError(NS_LITERAL_STRING("NO_STREAM"));
|
||||
return NS_OK;
|
||||
|
@ -372,11 +408,17 @@ public:
|
|||
// when the page is invalidated (on navigation or close).
|
||||
mListener->Activate(stream.forget(), mAudioSource, mVideoSource);
|
||||
|
||||
TracksAvailableCallback* tracksAvailableCallback =
|
||||
new TracksAvailableCallback(mManager, mSuccess, mWindowID, trackunion);
|
||||
|
||||
// Dispatch to the media thread to ask it to start the sources,
|
||||
// because that can take a while
|
||||
// because that can take a while.
|
||||
// Pass ownership of trackunion to the MediaOperationRunnable
|
||||
// to ensure it's kept alive until the MediaOperationRunnable runs (at least).
|
||||
nsIThread *mediaThread = MediaManager::GetThread();
|
||||
nsRefPtr<MediaOperationRunnable> runnable(
|
||||
new MediaOperationRunnable(MEDIA_START, mListener,
|
||||
new MediaOperationRunnable(MEDIA_START, mListener, trackunion,
|
||||
tracksAvailableCallback,
|
||||
mAudioSource, mVideoSource, false));
|
||||
mediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
|
||||
|
@ -407,24 +449,14 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
// We're in the main thread, so no worries here either.
|
||||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
|
||||
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
|
||||
|
||||
if (!(mManager->IsWindowStillActive(mWindowID))) {
|
||||
return NS_OK;
|
||||
}
|
||||
// This is safe since we're on main-thread, and the windowlist can only
|
||||
// be invalidated from the main-thread (see OnNavigation)
|
||||
LOG(("Returning success for getUserMedia()"));
|
||||
success->OnSuccess(static_cast<nsIDOMLocalMediaStream*>(trackunion));
|
||||
|
||||
// We won't need mError now.
|
||||
mError = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
nsRefPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
|
||||
nsRefPtr<nsIDOMGetUserMediaErrorCallback> mError;
|
||||
nsRefPtr<MediaEngineSource> mAudioSource;
|
||||
nsRefPtr<MediaEngineSource> mVideoSource;
|
||||
uint64_t mWindowID;
|
||||
|
@ -1498,7 +1530,8 @@ GetUserMediaCallbackMediaStreamListener::Invalidate()
|
|||
// Pass a ref to us (which is threadsafe) so it can query us for the
|
||||
// source stream info.
|
||||
runnable = new MediaOperationRunnable(MEDIA_STOP,
|
||||
this, mAudioSource, mVideoSource,
|
||||
this, nullptr, nullptr,
|
||||
mAudioSource, mVideoSource,
|
||||
mFinished);
|
||||
mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "prlog.h"
|
||||
#include "DOMMediaStream.h"
|
||||
|
||||
#ifdef MOZ_WEBRTC
|
||||
#include "mtransport/runnable_utils.h"
|
||||
|
@ -200,8 +201,11 @@ class GetUserMediaNotificationEvent: public nsRunnable
|
|||
GetUserMediaStatus aStatus)
|
||||
: mListener(aListener), mStatus(aStatus) {}
|
||||
|
||||
GetUserMediaNotificationEvent(GetUserMediaStatus aStatus)
|
||||
: mListener(nullptr), mStatus(aStatus) {}
|
||||
GetUserMediaNotificationEvent(GetUserMediaStatus aStatus,
|
||||
already_AddRefed<DOMMediaStream> aStream,
|
||||
DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback)
|
||||
: mStream(aStream), mOnTracksAvailableCallback(aOnTracksAvailableCallback),
|
||||
mStatus(aStatus) {}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
|
@ -216,6 +220,7 @@ class GetUserMediaNotificationEvent: public nsRunnable
|
|||
switch (mStatus) {
|
||||
case STARTING:
|
||||
msg = NS_LITERAL_STRING("starting");
|
||||
mStream->OnTracksAvailable(mOnTracksAvailableCallback.forget());
|
||||
break;
|
||||
case STOPPING:
|
||||
msg = NS_LITERAL_STRING("shutdown");
|
||||
|
@ -237,6 +242,8 @@ class GetUserMediaNotificationEvent: public nsRunnable
|
|||
|
||||
protected:
|
||||
nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
|
||||
nsRefPtr<DOMMediaStream> mStream;
|
||||
nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
|
||||
GetUserMediaStatus mStatus;
|
||||
};
|
||||
|
||||
|
@ -254,10 +261,14 @@ public:
|
|||
// so we can send Stop without AddRef()ing from the MSG thread
|
||||
MediaOperationRunnable(MediaOperation aType,
|
||||
GetUserMediaCallbackMediaStreamListener* aListener,
|
||||
DOMMediaStream* aStream,
|
||||
DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback,
|
||||
MediaEngineSource* aAudioSource,
|
||||
MediaEngineSource* aVideoSource,
|
||||
bool aNeedsFinish)
|
||||
: mType(aType)
|
||||
, mStream(aStream)
|
||||
, mOnTracksAvailableCallback(aOnTracksAvailableCallback)
|
||||
, mAudioSource(aAudioSource)
|
||||
, mVideoSource(aVideoSource)
|
||||
, mListener(aListener)
|
||||
|
@ -286,24 +297,34 @@ public:
|
|||
|
||||
source->SetPullEnabled(true);
|
||||
|
||||
DOMMediaStream::TrackTypeHints expectedTracks = 0;
|
||||
if (mAudioSource) {
|
||||
rv = mAudioSource->Start(source, kAudioTrack);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
expectedTracks |= DOMMediaStream::HINT_CONTENTS_AUDIO;
|
||||
} else {
|
||||
MM_LOG(("Starting audio failed, rv=%d",rv));
|
||||
}
|
||||
}
|
||||
if (mVideoSource) {
|
||||
rv = mVideoSource->Start(source, kVideoTrack);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
expectedTracks |= DOMMediaStream::HINT_CONTENTS_VIDEO;
|
||||
} else {
|
||||
MM_LOG(("Starting video failed, rv=%d",rv));
|
||||
}
|
||||
}
|
||||
|
||||
mOnTracksAvailableCallback->SetExpectedTracks(expectedTracks);
|
||||
|
||||
MM_LOG(("started all sources"));
|
||||
// Forward mOnTracksAvailableCallback to GetUserMediaNotificationEvent,
|
||||
// because mOnTracksAvailableCallback needs to be added to mStream
|
||||
// on the main thread.
|
||||
nsRefPtr<GetUserMediaNotificationEvent> event =
|
||||
new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING);
|
||||
|
||||
|
||||
new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING,
|
||||
mStream.forget(),
|
||||
mOnTracksAvailableCallback.forget());
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
break;
|
||||
|
@ -339,6 +360,8 @@ public:
|
|||
|
||||
private:
|
||||
MediaOperation mType;
|
||||
nsRefPtr<DOMMediaStream> mStream;
|
||||
nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
|
||||
nsRefPtr<MediaEngineSource> mAudioSource; // threadsafe
|
||||
nsRefPtr<MediaEngineSource> mVideoSource; // threadsafe
|
||||
nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
|
||||
|
|
Загрузка…
Ссылка в новой задаче