Bug 797796: Hookup getUserMedia backend with frontend UI; r=jesup

This commit is contained in:
Anant Narayanan 2012-10-05 17:20:47 -07:00
parent 8c1c3fe18b
commit 2fa83b8747
2 changed files with 124 additions and 21 deletions

View File

@ -7,9 +7,13 @@
#include "MediaStreamGraph.h"
#include "nsIDOMFile.h"
#include "nsIEventTarget.h"
#include "nsIUUIDGenerator.h"
#include "nsIScriptGlobalObject.h"
#include "nsIPopupWindowManager.h"
// For PR_snprintf
#include "prprf.h"
#include "nsJSUtils.h"
#include "nsDOMFile.h"
#include "nsGlobalWindow.h"
@ -385,6 +389,29 @@ public:
return NS_OK;
}
nsresult
Denied()
{
if (NS_IsMainThread()) {
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
error->OnError(NS_LITERAL_STRING("PERMISSION_DENIED"));
} else {
NS_DispatchToMainThread(new ErrorCallbackRunnable(
mSuccess, mError, NS_LITERAL_STRING("PERMISSION_DENIED"), mWindowID
));
}
return NS_OK;
}
nsresult
SetDevice(MediaDevice* aDevice)
{
mDevice = aDevice;
mDeviceChosen = true;
return NS_OK;
}
nsresult
SelectDevice()
{
@ -627,16 +654,6 @@ MediaManager::GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow,
}
#endif
/**
* UI integration point. Check for permission with the user!
* No UI for picture:true here, since user permission is implied by the
* preview dialog that will be shown by GetUserMediaRunnable in SendPicture.
*/
if (!aPrivileged && !picture) {
// To be filled in by code from bug 729522. If permission is denied, call
// onError, and do not continue.
}
// Store the WindowID in a hash table and mark as active. The entry is removed
// when this window is closed or navigated away from.
uint64_t windowID = aWindow->WindowID();
@ -655,7 +672,7 @@ MediaManager::GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow,
*
* If a fake stream was requested, we force the use of the default backend.
*/
nsCOMPtr<nsIRunnable> gUMRunnable;
nsRefPtr<GetUserMediaRunnable> gUMRunnable;
if (fake) {
// Fake stream from default backend.
gUMRunnable = new GetUserMediaRunnable(
@ -679,15 +696,50 @@ MediaManager::GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow,
if (picture) {
// ShowFilePickerForMimeType() must run on the Main Thread! (on Android)
NS_DispatchToMainThread(gUMRunnable);
} else {
// Reuse the same thread to save memory.
} else if (aPrivileged) {
if (!mMediaThread) {
rv = NS_NewThread(getter_AddRefs(mMediaThread));
nsresult rv = NS_NewThread(getter_AddRefs(mMediaThread));
NS_ENSURE_SUCCESS(rv, rv);
}
mMediaThread->Dispatch(gUMRunnable, NS_DISPATCH_NORMAL);
} else {
// Ask for user permission, and dispatch runnable (or not) when a response
// is received via an observer notification. Each call is paired with its
// runnable by a GUID.
nsresult rv;
nsCOMPtr<nsIUUIDGenerator> uuidgen =
do_GetService("@mozilla.org/uuid-generator;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Generate a call ID.
nsID id;
rv = uuidgen->GenerateUUIDInPlace(&id);
NS_ENSURE_SUCCESS(rv, rv);
char buffer[NSID_LENGTH];
id.ToProvidedString(buffer);
NS_ConvertUTF8toUTF16 callID(buffer);
// Store the current callback.
mActiveCallbacks.Put(callID, gUMRunnable);
// Construct JSON structure with both the windowID and the callID.
nsAutoString data;
data.Append(NS_LITERAL_STRING("{\"windowID\":"));
// Convert window ID to string.
char windowBuffer[32];
PR_snprintf(windowBuffer, 32, "%llu", aWindow->GetOuterWindow()->WindowID());
data.Append(NS_ConvertUTF8toUTF16(windowBuffer));
data.Append(NS_LITERAL_STRING(", \"callID\":\""));
data.Append(callID);
data.Append(NS_LITERAL_STRING("\"}"));
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
obs->NotifyObservers(aParams, "getUserMedia:request", data.get());
}
return NS_OK;
}
@ -762,16 +814,62 @@ nsresult
MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData)
{
if (strcmp(aTopic, "xpcom-shutdown")) {
NS_ASSERTION(NS_IsMainThread(), "Observer invoked off the main thread");
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (!strcmp(aTopic, "xpcom-shutdown")) {
obs->RemoveObserver(this, "xpcom-shutdown");
obs->RemoveObserver(this, "getUserMedia:response:allow");
obs->RemoveObserver(this, "getUserMedia:response:deny");
// Close off any remaining active windows.
mActiveWindows.Clear();
mActiveCallbacks.Clear();
sSingleton = nullptr;
return NS_OK;
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->RemoveObserver(this, "xpcom-shutdown");
if (!strcmp(aTopic, "getUserMedia:response:allow")) {
nsString key(aData);
nsRefPtr<nsRunnable> runnable;
if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
return NS_OK;
}
// Close off any remaining active windows.
mActiveWindows.Clear();
sSingleton = nullptr;
// Reuse the same thread to save memory.
if (!mMediaThread) {
nsresult rv = NS_NewThread(getter_AddRefs(mMediaThread));
NS_ENSURE_SUCCESS(rv, rv);
}
if (aSubject) {
// A particular device was chosen by the user.
nsCOMPtr<nsIMediaDevice> device = do_QueryInterface(aSubject);
if (device) {
GetUserMediaRunnable* gUMRunnable =
static_cast<GetUserMediaRunnable*>(runnable.get());
gUMRunnable->SetDevice(static_cast<MediaDevice*>(device.get()));
}
}
mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
mActiveCallbacks.Remove(key);
return NS_OK;
}
if (!strcmp(aTopic, "getUserMedia:response:deny")) {
nsString key(aData);
nsRefPtr<nsRunnable> runnable;
if (mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
GetUserMediaRunnable* gUMRunnable =
static_cast<GetUserMediaRunnable*>(runnable.get());
gUMRunnable->Denied();
mActiveCallbacks.Remove(key);
}
return NS_OK;
}
return NS_OK;
}

View File

@ -8,6 +8,7 @@
#include "nsHashKeys.h"
#include "nsGlobalWindow.h"
#include "nsClassHashtable.h"
#include "nsRefPtrHashtable.h"
#include "nsObserverService.h"
#include "nsPIDOMWindow.h"
@ -151,6 +152,8 @@ public:
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
obs->AddObserver(sSingleton, "xpcom-shutdown", false);
obs->AddObserver(sSingleton, "getUserMedia:response:allow", false);
obs->AddObserver(sSingleton, "getUserMedia:response:deny", false);
}
return sSingleton;
}
@ -176,6 +179,7 @@ private:
: mBackend(nullptr)
, mMediaThread(nullptr) {
mActiveWindows.Init();
mActiveCallbacks.Init();
};
MediaManager(MediaManager const&) {};
@ -186,6 +190,7 @@ private:
MediaEngine* mBackend;
nsCOMPtr<nsIThread> mMediaThread;
WindowTable mActiveWindows;
nsRefPtrHashtable<nsStringHashKey, nsRunnable> mActiveCallbacks;
static nsRefPtr<MediaManager> sSingleton;
};