зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1060738 - Switch to using chromium's Thread/tasks in MediaManager. On Windows, use MessagePumpForNonMainUIThreads for the background media thread. r=jesup
This commit is contained in:
Родитель
9d266c73b6
Коммит
041794c1f3
|
@ -149,12 +149,6 @@
|
|||
#include "nsHtml5TreeOpExecutor.h"
|
||||
#include "mozilla/dom/HTMLLinkElement.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
#include "mozilla/MediaManager.h"
|
||||
#endif // MOZ_MEDIA_NAVIGATOR
|
||||
#ifdef MOZ_WEBRTC
|
||||
#include "IPeerConnection.h"
|
||||
#endif // MOZ_WEBRTC
|
||||
|
||||
#include "mozAutoDocUpdate.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
|
@ -229,6 +223,13 @@
|
|||
#include "nsWindowMemoryReporter.h"
|
||||
#include "nsLocation.h"
|
||||
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
#include "mozilla/MediaManager.h"
|
||||
#endif // MOZ_MEDIA_NAVIGATOR
|
||||
#ifdef MOZ_WEBRTC
|
||||
#include "IPeerConnection.h"
|
||||
#endif // MOZ_WEBRTC
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
|
|
|
@ -851,15 +851,13 @@ public:
|
|||
|
||||
// Dispatch to the media thread to ask it to start the sources,
|
||||
// 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, trackunion,
|
||||
tracksAvailableCallback,
|
||||
mAudioSource, mVideoSource, false, mWindowID,
|
||||
mError.forget()));
|
||||
mediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
// Pass ownership of trackunion to the MediaOperationTask
|
||||
// to ensure it's kept alive until the MediaOperationTask runs (at least).
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
new MediaOperationTask(MEDIA_START, mListener, trackunion,
|
||||
tracksAvailableCallback,
|
||||
mAudioSource, mVideoSource, false, mWindowID,
|
||||
mError.forget()));
|
||||
|
||||
// We won't need mError now.
|
||||
mError = nullptr;
|
||||
|
@ -1050,10 +1048,10 @@ static SourceSet *
|
|||
* Do not run this on the main thread. The success and error callbacks *MUST*
|
||||
* be dispatched on the main thread!
|
||||
*/
|
||||
class GetUserMediaRunnable : public nsRunnable
|
||||
class GetUserMediaTask : public Task
|
||||
{
|
||||
public:
|
||||
GetUserMediaRunnable(
|
||||
GetUserMediaTask(
|
||||
const MediaStreamConstraints& aConstraints,
|
||||
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
|
||||
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
|
||||
|
@ -1074,7 +1072,7 @@ public:
|
|||
* The caller can also choose to provide their own backend instead of
|
||||
* using the one provided by MediaManager::GetBackend.
|
||||
*/
|
||||
GetUserMediaRunnable(
|
||||
GetUserMediaTask(
|
||||
const MediaStreamConstraints& aConstraints,
|
||||
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
|
||||
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
|
||||
|
@ -1092,7 +1090,7 @@ public:
|
|||
, mManager(MediaManager::GetInstance())
|
||||
{}
|
||||
|
||||
~GetUserMediaRunnable() {
|
||||
~GetUserMediaTask() {
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1106,7 +1104,7 @@ public:
|
|||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
void
|
||||
Run()
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
|
||||
|
@ -1123,7 +1121,7 @@ public:
|
|||
if (!mDeviceChosen) {
|
||||
nsresult rv = SelectDevice(backend);
|
||||
if (rv != NS_OK) {
|
||||
return rv;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1131,12 +1129,12 @@ public:
|
|||
if (mConstraints.mPicture &&
|
||||
(IsOn(mConstraints.mAudio) || IsOn(mConstraints.mVideo))) {
|
||||
Fail(NS_LITERAL_STRING("NOT_SUPPORTED_ERR"));
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mConstraints.mPicture) {
|
||||
ProcessGetUserMediaSnapshot(mVideoDevice->GetSource(), 0);
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
// There's a bug in the permission code that can leave us with mAudio but no audio device
|
||||
|
@ -1144,7 +1142,6 @@ public:
|
|||
mAudioDevice->GetSource() : nullptr),
|
||||
((IsOn(mConstraints.mVideo) && mVideoDevice) ?
|
||||
mVideoDevice->GetSource() : nullptr));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -1334,16 +1331,38 @@ private:
|
|||
nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
|
||||
};
|
||||
|
||||
#if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
|
||||
class GetUserMediaRunnableWrapper : public nsRunnable
|
||||
{
|
||||
public:
|
||||
// This object must take ownership of task
|
||||
GetUserMediaRunnableWrapper(GetUserMediaTask* task) :
|
||||
mTask(task) {
|
||||
}
|
||||
|
||||
~GetUserMediaRunnableWrapper() {
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mTask->Run();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsAutoPtr<GetUserMediaTask> mTask;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Similar to GetUserMediaRunnable, but used for the chrome-only
|
||||
* Similar to GetUserMediaTask, but used for the chrome-only
|
||||
* GetUserMediaDevices function. Enumerates a list of audio & video devices,
|
||||
* wraps them up in nsIMediaDevice objects and returns it to the success
|
||||
* callback.
|
||||
*/
|
||||
class GetUserMediaDevicesRunnable : public nsRunnable
|
||||
class GetUserMediaDevicesTask : public Task
|
||||
{
|
||||
public:
|
||||
GetUserMediaDevicesRunnable(
|
||||
GetUserMediaDevicesTask(
|
||||
const MediaStreamConstraints& aConstraints,
|
||||
already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> aSuccess,
|
||||
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
|
||||
|
@ -1357,7 +1376,7 @@ public:
|
|||
, mLoopbackAudioDevice(aAudioLoopbackDev)
|
||||
, mLoopbackVideoDevice(aVideoLoopbackDev) {}
|
||||
|
||||
NS_IMETHOD
|
||||
void // NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
|
||||
|
@ -1389,7 +1408,6 @@ public:
|
|||
final.forget()));
|
||||
// DeviceSuccessCallbackRunnable should have taken these.
|
||||
MOZ_ASSERT(!mSuccess && !mError);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -1437,12 +1455,23 @@ NS_IMPL_ISUPPORTS(MediaManager, nsIMediaManagerService, nsIObserver)
|
|||
/* static */ MediaManager*
|
||||
MediaManager::Get() {
|
||||
if (!sSingleton) {
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only create MediaManager on main thread");
|
||||
|
||||
sSingleton = new MediaManager();
|
||||
|
||||
NS_NewNamedThread("MediaManager", getter_AddRefs(sSingleton->mMediaThread));
|
||||
sSingleton->mMediaThread = new base::Thread("MediaManager");
|
||||
base::Thread::Options options;
|
||||
#if defined(_WIN32)
|
||||
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD;
|
||||
#else
|
||||
options.message_loop_type = MessageLoop::TYPE_MOZILLA_NONMAINTHREAD;
|
||||
#endif
|
||||
if (!sSingleton->mMediaThread->StartWithOptions(options)) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
LOG(("New Media thread for gum"));
|
||||
|
||||
NS_ASSERTION(NS_IsMainThread(), "Only create MediaManager on main thread");
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(sSingleton, "xpcom-shutdown", false);
|
||||
|
@ -1471,6 +1500,15 @@ MediaManager::GetInstance()
|
|||
return service.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
MessageLoop*
|
||||
MediaManager::GetMessageLoop()
|
||||
{
|
||||
NS_ASSERTION(Get(), "MediaManager singleton?");
|
||||
NS_ASSERTION(Get()->mMediaThread, "No thread yet");
|
||||
return Get()->mMediaThread->message_loop();
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
MediaManager::NotifyRecordingStatusChange(nsPIDOMWindow* aWindow,
|
||||
const nsString& aMsg,
|
||||
|
@ -1606,12 +1644,9 @@ MediaManager::GetUserMedia(bool aPrivileged,
|
|||
GetActiveWindows()->Put(windowID, listeners);
|
||||
}
|
||||
|
||||
// Ensure there's a thread for gum to proxy to off main thread
|
||||
nsIThread *mediaThread = MediaManager::GetThread();
|
||||
|
||||
// Create a disabled listener to act as a placeholder
|
||||
GetUserMediaCallbackMediaStreamListener* listener =
|
||||
new GetUserMediaCallbackMediaStreamListener(mediaThread, windowID);
|
||||
new GetUserMediaCallbackMediaStreamListener(mMediaThread, windowID);
|
||||
|
||||
// No need for locking because we always do this in the main thread.
|
||||
listeners->AppendElement(listener);
|
||||
|
@ -1663,15 +1698,15 @@ MediaManager::GetUserMedia(bool aPrivileged,
|
|||
}
|
||||
}
|
||||
|
||||
// Pass callbacks and MediaStreamListener along to GetUserMediaRunnable.
|
||||
nsRefPtr<GetUserMediaRunnable> runnable;
|
||||
// Pass callbacks and MediaStreamListener along to GetUserMediaTask.
|
||||
nsAutoPtr<GetUserMediaTask> task;
|
||||
if (c.mFake) {
|
||||
// Fake stream from default backend.
|
||||
runnable = new GetUserMediaRunnable(c, onSuccess.forget(),
|
||||
task = new GetUserMediaTask(c, onSuccess.forget(),
|
||||
onError.forget(), windowID, listener, mPrefs, new MediaEngineDefault());
|
||||
} else {
|
||||
// Stream from default device from WebRTC backend.
|
||||
runnable = new GetUserMediaRunnable(c, onSuccess.forget(),
|
||||
task = new GetUserMediaTask(c, onSuccess.forget(),
|
||||
onError.forget(), windowID, listener, mPrefs);
|
||||
}
|
||||
|
||||
|
@ -1683,10 +1718,10 @@ MediaManager::GetUserMedia(bool aPrivileged,
|
|||
if (tc.mMediaSource != dom::MediaSourceEnum::Camera) {
|
||||
if (tc.mMediaSource == dom::MediaSourceEnum::Browser) {
|
||||
if (!Preferences::GetBool("media.getusermedia.browser.enabled", false)) {
|
||||
return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
}
|
||||
} else if (!Preferences::GetBool("media.getusermedia.screensharing.enabled", false)) {
|
||||
return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
}
|
||||
/* Deny screensharing if the requesting document is not from a host
|
||||
on the whitelist. */
|
||||
|
@ -1704,7 +1739,7 @@ MediaManager::GetUserMedia(bool aPrivileged,
|
|||
) ||
|
||||
#endif
|
||||
(!aPrivileged && !HostHasPermission(*docURI))) {
|
||||
return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1718,7 +1753,8 @@ MediaManager::GetUserMedia(bool aPrivileged,
|
|||
#if defined(ANDROID) && !defined(MOZ_WIDGET_GONK)
|
||||
if (c.mPicture) {
|
||||
// ShowFilePickerForMimeType() must run on the Main Thread! (on Android)
|
||||
NS_DispatchToMainThread(runnable);
|
||||
// Note, GetUserMediaRunnableWrapper takes ownership of task.
|
||||
NS_DispatchToMainThread(new GetUserMediaRunnableWrapper(task.forget()));
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
@ -1737,7 +1773,7 @@ MediaManager::GetUserMedia(bool aPrivileged,
|
|||
// XXX No full support for picture in Desktop yet (needs proper UI)
|
||||
if (aPrivileged ||
|
||||
(c.mFake && !Preferences::GetBool("media.navigator.permission.fake"))) {
|
||||
mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE, task.forget());
|
||||
} else {
|
||||
bool isHTTPS = false;
|
||||
if (docURI) {
|
||||
|
@ -1766,12 +1802,12 @@ MediaManager::GetUserMedia(bool aPrivileged,
|
|||
|
||||
if ((!IsOn(c.mAudio) || audioPerm == nsIPermissionManager::DENY_ACTION) &&
|
||||
(!IsOn(c.mVideo) || videoPerm == nsIPermissionManager::DENY_ACTION)) {
|
||||
return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
}
|
||||
|
||||
// Ask for user permission, and dispatch runnable (or not) when a response
|
||||
// Ask for user permission, and dispatch task (or not) when a response
|
||||
// is received via an observer notification. Each call is paired with its
|
||||
// runnable by a GUID.
|
||||
// task by a GUID.
|
||||
nsCOMPtr<nsIUUIDGenerator> uuidgen =
|
||||
do_GetService("@mozilla.org/uuid-generator;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1785,8 +1821,8 @@ MediaManager::GetUserMedia(bool aPrivileged,
|
|||
id.ToProvidedString(buffer);
|
||||
NS_ConvertUTF8toUTF16 callID(buffer);
|
||||
|
||||
// Store the current unarmed runnable w/callbacks.
|
||||
mActiveCallbacks.Put(callID, runnable);
|
||||
// Store the current unarmed task w/callbacks.
|
||||
mActiveCallbacks.Put(callID, task.forget());
|
||||
|
||||
// Add a WindowID cross-reference so OnNavigation can tear things down
|
||||
nsTArray<nsString>* array;
|
||||
|
@ -1831,12 +1867,12 @@ MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
|
|||
nsAdoptingCString loopbackVideoDevice =
|
||||
Preferences::GetCString("media.video_loopback_dev");
|
||||
|
||||
nsCOMPtr<nsIRunnable> gUMDRunnable = new GetUserMediaDevicesRunnable(
|
||||
aConstraints, onSuccess.forget(), onError.forget(),
|
||||
(aInnerWindowID ? aInnerWindowID : aWindow->WindowID()),
|
||||
loopbackAudioDevice, loopbackVideoDevice);
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
new GetUserMediaDevicesTask(
|
||||
aConstraints, onSuccess.forget(), onError.forget(),
|
||||
(aInnerWindowID ? aInnerWindowID : aWindow->WindowID()),
|
||||
loopbackAudioDevice, loopbackVideoDevice));
|
||||
|
||||
mMediaThread->Dispatch(gUMDRunnable, NS_DISPATCH_NORMAL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2018,8 +2054,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
// Note: won't be released immediately as the Observer has a ref to us
|
||||
sSingleton = nullptr;
|
||||
if (mMediaThread) {
|
||||
mMediaThread->Shutdown();
|
||||
mMediaThread = nullptr;
|
||||
mMediaThread->Stop();
|
||||
}
|
||||
mBackend = nullptr;
|
||||
}
|
||||
|
@ -2028,11 +2063,11 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
|
||||
} else if (!strcmp(aTopic, "getUserMedia:response:allow")) {
|
||||
nsString key(aData);
|
||||
nsRefPtr<GetUserMediaRunnable> runnable;
|
||||
if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
|
||||
nsAutoPtr<GetUserMediaTask> task;
|
||||
mActiveCallbacks.RemoveAndForget(key, task);
|
||||
if (!task) {
|
||||
return NS_OK;
|
||||
}
|
||||
mActiveCallbacks.Remove(key);
|
||||
|
||||
if (aSubject) {
|
||||
// A particular device or devices were chosen by the user.
|
||||
|
@ -2044,7 +2079,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
MOZ_ASSERT(len);
|
||||
if (!len) {
|
||||
// neither audio nor video were selected
|
||||
runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
|
||||
return NS_OK;
|
||||
}
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
|
@ -2056,9 +2091,9 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
nsString type;
|
||||
device->GetType(type);
|
||||
if (type.EqualsLiteral("video")) {
|
||||
runnable->SetVideoDevice(static_cast<VideoDevice*>(device.get()));
|
||||
task->SetVideoDevice(static_cast<VideoDevice*>(device.get()));
|
||||
} else if (type.EqualsLiteral("audio")) {
|
||||
runnable->SetAudioDevice(static_cast<AudioDevice*>(device.get()));
|
||||
task->SetAudioDevice(static_cast<AudioDevice*>(device.get()));
|
||||
} else {
|
||||
NS_WARNING("Unknown device type in getUserMedia");
|
||||
}
|
||||
|
@ -2067,7 +2102,7 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
}
|
||||
|
||||
// Reuse the same thread to save memory.
|
||||
mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE, task.forget());
|
||||
return NS_OK;
|
||||
|
||||
} else if (!strcmp(aTopic, "getUserMedia:response:deny")) {
|
||||
|
@ -2082,12 +2117,11 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
}
|
||||
|
||||
nsString key(aData);
|
||||
nsRefPtr<GetUserMediaRunnable> runnable;
|
||||
if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
|
||||
return NS_OK;
|
||||
nsAutoPtr<GetUserMediaTask> task;
|
||||
mActiveCallbacks.RemoveAndForget(key, task);
|
||||
if (task) {
|
||||
task->Denied(errorMessage);
|
||||
}
|
||||
mActiveCallbacks.Remove(key);
|
||||
runnable->Denied(errorMessage);
|
||||
return NS_OK;
|
||||
|
||||
} else if (!strcmp(aTopic, "getUserMedia:revoke")) {
|
||||
|
@ -2342,21 +2376,36 @@ MediaManager::StopMediaStreams()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetUserMediaCallbackMediaStreamListener::AudioConfig(bool aEchoOn,
|
||||
uint32_t aEcho,
|
||||
bool aAgcOn, uint32_t aAGC,
|
||||
bool aNoiseOn, uint32_t aNoise,
|
||||
int32_t aPlayoutDelay)
|
||||
{
|
||||
if (mAudioSource) {
|
||||
#ifdef MOZ_WEBRTC
|
||||
mMediaThread->message_loop()->PostTask(FROM_HERE,
|
||||
NewRunnableMethod(mAudioSource.get(), &MediaEngineSource::Config,
|
||||
aEchoOn, aEcho, aAgcOn, aAGC, aNoiseOn,
|
||||
aNoise, aPlayoutDelay));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Can be invoked from EITHER MainThread or MSG thread
|
||||
void
|
||||
GetUserMediaCallbackMediaStreamListener::Invalidate()
|
||||
{
|
||||
|
||||
nsRefPtr<MediaOperationRunnable> runnable;
|
||||
// We can't take a chance on blocking here, so proxy this to another
|
||||
// thread.
|
||||
// Pass a ref to us (which is threadsafe) so it can query us for the
|
||||
// source stream info.
|
||||
runnable = new MediaOperationRunnable(MEDIA_STOP,
|
||||
this, nullptr, nullptr,
|
||||
mAudioSource, mVideoSource,
|
||||
mFinished, mWindowID, nullptr);
|
||||
mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
new MediaOperationTask(MEDIA_STOP,
|
||||
this, nullptr, nullptr,
|
||||
mAudioSource, mVideoSource,
|
||||
mFinished, mWindowID, nullptr));
|
||||
}
|
||||
|
||||
// Doesn't kill audio
|
||||
|
@ -2370,12 +2419,11 @@ GetUserMediaCallbackMediaStreamListener::StopScreenWindowSharing()
|
|||
mVideoSource->GetMediaSource() == MediaSourceType::Application ||
|
||||
mVideoSource->GetMediaSource() == MediaSourceType::Window)) {
|
||||
// Stop the whole stream if there's no audio; just the video track if we have both
|
||||
nsRefPtr<MediaOperationRunnable> runnable(
|
||||
new MediaOperationRunnable(mAudioSource ? MEDIA_STOP_TRACK : MEDIA_STOP,
|
||||
this, nullptr, nullptr,
|
||||
nullptr, mVideoSource,
|
||||
mFinished, mWindowID, nullptr));
|
||||
mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
new MediaOperationTask(mAudioSource ? MEDIA_STOP_TRACK : MEDIA_STOP,
|
||||
this, nullptr, nullptr,
|
||||
nullptr, mVideoSource,
|
||||
mFinished, mWindowID, nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2389,13 +2437,12 @@ GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aID, bool aIsAudio)
|
|||
{
|
||||
// XXX to support multiple tracks of a type in a stream, this should key off
|
||||
// the TrackID and not just the type
|
||||
nsRefPtr<MediaOperationRunnable> runnable(
|
||||
new MediaOperationRunnable(MEDIA_STOP_TRACK,
|
||||
this, nullptr, nullptr,
|
||||
aIsAudio ? mAudioSource : nullptr,
|
||||
!aIsAudio ? mVideoSource : nullptr,
|
||||
mFinished, mWindowID, nullptr));
|
||||
mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
new MediaOperationTask(MEDIA_STOP_TRACK,
|
||||
this, nullptr, nullptr,
|
||||
aIsAudio ? mAudioSource : nullptr,
|
||||
!aIsAudio ? mVideoSource : nullptr,
|
||||
mFinished, mWindowID, nullptr));
|
||||
} else {
|
||||
LOG(("gUM track %d ended, but we don't have type %s",
|
||||
aID, aIsAudio ? "audio" : "video"));
|
||||
|
@ -2416,12 +2463,11 @@ void
|
|||
GetUserMediaCallbackMediaStreamListener::NotifyDirectListeners(MediaStreamGraph* aGraph,
|
||||
bool aHasListeners)
|
||||
{
|
||||
nsRefPtr<MediaOperationRunnable> runnable;
|
||||
runnable = new MediaOperationRunnable(MEDIA_DIRECT_LISTENERS,
|
||||
this, nullptr, nullptr,
|
||||
mAudioSource, mVideoSource,
|
||||
aHasListeners, mWindowID, nullptr);
|
||||
mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
|
||||
new MediaOperationTask(MEDIA_DIRECT_LISTENERS,
|
||||
this, nullptr, nullptr,
|
||||
mAudioSource, mVideoSource,
|
||||
aHasListeners, mWindowID, nullptr));
|
||||
}
|
||||
|
||||
// Called from the MediaStreamGraph thread
|
||||
|
|
|
@ -30,6 +30,10 @@
|
|||
#include "mtransport/runnable_utils.h"
|
||||
#endif
|
||||
|
||||
// Note, these suck in Windows headers, unfortunately.
|
||||
#include "base/thread.h"
|
||||
#include "base/task.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "DOMCameraManager.h"
|
||||
#endif
|
||||
|
@ -57,7 +61,7 @@ class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener
|
|||
{
|
||||
public:
|
||||
// Create in an inactive state
|
||||
GetUserMediaCallbackMediaStreamListener(nsIThread *aThread,
|
||||
GetUserMediaCallbackMediaStreamListener(base::Thread *aThread,
|
||||
uint64_t aWindowID)
|
||||
: mMediaThread(aThread)
|
||||
, mWindowID(aWindowID)
|
||||
|
@ -144,7 +148,7 @@ public:
|
|||
mStopped = true;
|
||||
}
|
||||
|
||||
// implement in .cpp to avoid circular dependency with MediaOperationRunnable
|
||||
// implement in .cpp to avoid circular dependency with MediaOperationTask
|
||||
// Can be invoked from EITHER MainThread or MSG thread
|
||||
void Invalidate();
|
||||
|
||||
|
@ -152,19 +156,7 @@ public:
|
|||
AudioConfig(bool aEchoOn, uint32_t aEcho,
|
||||
bool aAgcOn, uint32_t aAGC,
|
||||
bool aNoiseOn, uint32_t aNoise,
|
||||
int32_t aPlayoutDelay)
|
||||
{
|
||||
if (mAudioSource) {
|
||||
#ifdef MOZ_WEBRTC
|
||||
// Right now these configs are only of use if webrtc is available
|
||||
RUN_ON_THREAD(mMediaThread,
|
||||
WrapRunnable(nsRefPtr<MediaEngineSource>(mAudioSource), // threadsafe
|
||||
&MediaEngineSource::Config,
|
||||
aEchoOn, aEcho, aAgcOn, aAGC, aNoiseOn, aNoise, aPlayoutDelay),
|
||||
NS_DISPATCH_NORMAL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
int32_t aPlayoutDelay);
|
||||
|
||||
void
|
||||
Remove()
|
||||
|
@ -230,7 +222,7 @@ public:
|
|||
|
||||
private:
|
||||
// Set at construction
|
||||
nsCOMPtr<nsIThread> mMediaThread;
|
||||
base::Thread* mMediaThread;
|
||||
uint64_t mWindowID;
|
||||
|
||||
bool mStopped; // MainThread only
|
||||
|
@ -299,7 +291,7 @@ typedef enum {
|
|||
} MediaOperation;
|
||||
|
||||
class MediaManager;
|
||||
class GetUserMediaRunnable;
|
||||
class GetUserMediaTask;
|
||||
|
||||
/**
|
||||
* Send an error back to content. The error is the form a string.
|
||||
|
@ -340,11 +332,11 @@ private:
|
|||
// Generic class for running long media operations like Start off the main
|
||||
// thread, and then (because nsDOMMediaStreams aren't threadsafe),
|
||||
// ProxyReleases mStream since it's cycle collected.
|
||||
class MediaOperationRunnable : public nsRunnable
|
||||
class MediaOperationTask : public Task
|
||||
{
|
||||
public:
|
||||
// so we can send Stop without AddRef()ing from the MSG thread
|
||||
MediaOperationRunnable(MediaOperation aType,
|
||||
MediaOperationTask(MediaOperation aType,
|
||||
GetUserMediaCallbackMediaStreamListener* aListener,
|
||||
DOMMediaStream* aStream,
|
||||
DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback,
|
||||
|
@ -364,12 +356,13 @@ public:
|
|||
, mError(aError)
|
||||
{}
|
||||
|
||||
~MediaOperationRunnable()
|
||||
~MediaOperationTask()
|
||||
{
|
||||
// MediaStreams can be released on any thread.
|
||||
}
|
||||
|
||||
nsresult returnAndCallbackError(nsresult rv, const char* errorLog)
|
||||
void
|
||||
ReturnCallbackError(nsresult rv, const char* errorLog)
|
||||
{
|
||||
MM_LOG(("%s , rv=%d", errorLog, rv));
|
||||
NS_DispatchToMainThread(new ReleaseMediaOperationResource(mStream.forget(),
|
||||
|
@ -380,17 +373,16 @@ public:
|
|||
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success;
|
||||
NS_DispatchToMainThread(new ErrorCallbackRunnable(success, mError,
|
||||
log, mWindowID));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() MOZ_OVERRIDE
|
||||
void
|
||||
Run()
|
||||
{
|
||||
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 (!source) // means the stream was never Activated()
|
||||
return NS_OK;
|
||||
return;
|
||||
|
||||
switch (mType) {
|
||||
case MEDIA_START:
|
||||
|
@ -406,7 +398,8 @@ public:
|
|||
if (NS_SUCCEEDED(rv)) {
|
||||
expectedTracks |= DOMMediaStream::HINT_CONTENTS_AUDIO;
|
||||
} else {
|
||||
return returnAndCallbackError(rv, "Starting audio failed");
|
||||
ReturnCallbackError(rv, "Starting audio failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mVideoSource) {
|
||||
|
@ -414,7 +407,8 @@ public:
|
|||
if (NS_SUCCEEDED(rv)) {
|
||||
expectedTracks |= DOMMediaStream::HINT_CONTENTS_VIDEO;
|
||||
} else {
|
||||
return returnAndCallbackError(rv, "Starting video failed");
|
||||
ReturnCallbackError(rv, "Starting video failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,7 +475,6 @@ public:
|
|||
MOZ_ASSERT(false,"invalid MediaManager operation");
|
||||
break;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -545,16 +538,13 @@ public:
|
|||
// thread from the MainThread, as we NS_DISPATCH_SYNC to MainThread
|
||||
// from MediaManager thread.
|
||||
static MediaManager* Get();
|
||||
static MessageLoop* GetMessageLoop();
|
||||
|
||||
static bool Exists()
|
||||
{
|
||||
return !!sSingleton;
|
||||
}
|
||||
|
||||
static nsIThread* GetThread() {
|
||||
return Get()->mMediaThread;
|
||||
}
|
||||
|
||||
static nsresult NotifyRecordingStatusChange(nsPIDOMWindow* aWindow,
|
||||
const nsString& aMsg,
|
||||
const bool& aIsAudio,
|
||||
|
@ -621,10 +611,10 @@ private:
|
|||
|
||||
// ONLY access from MainThread so we don't need to lock
|
||||
WindowTable mActiveWindows;
|
||||
nsRefPtrHashtable<nsStringHashKey, GetUserMediaRunnable> mActiveCallbacks;
|
||||
nsClassHashtable<nsStringHashKey, GetUserMediaTask> mActiveCallbacks;
|
||||
nsClassHashtable<nsUint64HashKey, nsTArray<nsString>> mCallIds;
|
||||
// Always exists
|
||||
nsCOMPtr<nsIThread> mMediaThread;
|
||||
nsAutoPtr<base::Thread> mMediaThread;
|
||||
|
||||
Mutex mMutex;
|
||||
// protected with mMutex:
|
||||
|
|
Загрузка…
Ссылка в новой задаче