diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 5ea6fed0567..ce54dd28afe 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -142,7 +142,6 @@ @BINPATH@/components/content_canvas.xpt @BINPATH@/components/content_htmldoc.xpt @BINPATH@/components/content_html.xpt -@BINPATH@/components/content_media.xpt @BINPATH@/components/content_xslt.xpt @BINPATH@/components/content_xtf.xpt @BINPATH@/components/cookie.xpt @@ -167,6 +166,7 @@ @BINPATH@/components/dom_devicestorage.xpt @BINPATH@/components/dom_events.xpt @BINPATH@/components/dom_geolocation.xpt +@BINPATH@/components/dom_media.xpt @BINPATH@/components/dom_network.xpt @BINPATH@/components/dom_notification.xpt @BINPATH@/components/dom_html.xpt diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 2629b6ccb9e..6662d499272 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -2,7 +2,7 @@ ; License, v. 2.0. If a copy of the MPL was not distributed with this ; file, You can obtain one at http://mozilla.org/MPL/2.0/. -; Package file for the Firefox build. +; Package file for the Firefox build. ; ; Packaging manifest is used to copy files from dist/bin ; to the staging directory. @@ -147,7 +147,6 @@ @BINPATH@/components/content_canvas.xpt @BINPATH@/components/content_htmldoc.xpt @BINPATH@/components/content_html.xpt -@BINPATH@/components/content_media.xpt @BINPATH@/components/content_xslt.xpt @BINPATH@/components/content_xtf.xpt @BINPATH@/components/cookie.xpt @@ -172,6 +171,7 @@ @BINPATH@/components/dom_devicestorage.xpt @BINPATH@/components/dom_events.xpt @BINPATH@/components/dom_geolocation.xpt +@BINPATH@/components/dom_media.xpt @BINPATH@/components/dom_network.xpt @BINPATH@/components/dom_notification.xpt @BINPATH@/components/dom_html.xpt diff --git a/configure.in b/configure.in index 15527067a5e..dde6c6f9a84 100644 --- a/configure.in +++ b/configure.in @@ -4548,6 +4548,7 @@ MOZ_MEDIA= MOZ_OPUS=1 MOZ_WEBM=1 MOZ_MEDIA_PLUGINS= +MOZ_MEDIA_NAVIGATOR= MOZ_OMX_PLUGIN= MOZ_VP8_ERROR_CONCEALMENT= MOZ_VP8_ENCODER= @@ -5638,6 +5639,18 @@ if test -n "$MOZ_MEDIA_PLUGINS"; then AC_DEFINE(MOZ_MEDIA_PLUGINS) fi +dnl ======================================================== +dnl = Enable getUserMedia support +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(media-navigator, +[ --enable-media-navigator Enable support for getUserMedia], + MOZ_MEDIA_NAVIGATOR=1, + MOZ_MEDIA_NAVIGATOR=) + +if test -n "$MOZ_MEDIA_NAVIGATOR"; then + AC_DEFINE(MOZ_MEDIA_NAVIGATOR) +fi + dnl ======================================================== dnl = Enable building OMX media plugin (B2G) dnl ======================================================== diff --git a/content/media/Makefile.in b/content/media/Makefile.in index 9ec752794be..1e319cd5c1e 100644 --- a/content/media/Makefile.in +++ b/content/media/Makefile.in @@ -12,11 +12,6 @@ include $(DEPTH)/config/autoconf.mk MODULE = content LIBRARY_NAME = gkconmedia_s LIBXUL_LIBRARY = 1 -XPIDL_MODULE = content_media - -XPIDLSRCS = \ - nsIDOMMediaStream.idl \ - $(NULL) EXPORTS = \ AudioSegment.h \ diff --git a/content/media/MediaEngineDefault.cpp b/content/media/MediaEngineDefault.cpp index a47849d6a58..4f8ef27c426 100644 --- a/content/media/MediaEngineDefault.cpp +++ b/content/media/MediaEngineDefault.cpp @@ -285,4 +285,4 @@ MediaEngineDefault::EnumerateAudioDevices(nsTArray win = do_QueryReferent(mWindow); + + if (!win || !win->GetOuterWindow() || + win->GetOuterWindow()->GetCurrentInnerWindow() != win) { + return NS_ERROR_NOT_AVAILABLE; + } + + return manager->GetUserMedia(win->WindowID(), aParams, onSuccess, onError); +} +#endif + //***************************************************************************** // Navigator::nsIDOMNavigatorDesktopNotification //***************************************************************************** @@ -1201,6 +1232,17 @@ Navigator::SetWindow(nsPIDOMWindow *aInnerWindow) mWindow = do_GetWeakReference(aInnerWindow); } +void +Navigator::OnNavigation() +{ + // Inform MediaManager in case there are live streams or pending callbacks. +#ifdef MOZ_MEDIA_NAVIGATOR + MediaManager *manager = MediaManager::Get(); + nsCOMPtr win = do_QueryReferent(mWindow); + return manager->OnNavigation(win->WindowID()); +#endif +} + } // namespace dom } // namespace mozilla diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 1fe48827bd1..208a326089e 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -25,6 +25,10 @@ class nsDesktopNotificationCenter; class nsPIDOMWindow; class nsIDOMMozConnection; +#ifdef MOZ_MEDIA_NAVIGATOR +#include "nsIDOMNavigatorUserMedia.h" +#endif + #ifdef MOZ_B2G_RIL #include "nsIDOMNavigatorTelephony.h" class nsIDOMTelephony; @@ -65,6 +69,9 @@ class Navigator : public nsIDOMNavigator , public nsIDOMNavigatorDesktopNotification , public nsIDOMMozNavigatorBattery , public nsIDOMMozNavigatorSms +#ifdef MOZ_MEDIA_NAVIGATOR + , public nsIDOMNavigatorUserMedia +#endif #ifdef MOZ_B2G_RIL , public nsIDOMNavigatorTelephony #endif @@ -72,6 +79,7 @@ class Navigator : public nsIDOMNavigator #ifdef MOZ_B2G_BT , public nsIDOMNavigatorBluetooth #endif + { public: Navigator(nsPIDOMWindow *aInnerWindow); @@ -85,6 +93,9 @@ public: NS_DECL_NSIDOMNAVIGATORDESKTOPNOTIFICATION NS_DECL_NSIDOMMOZNAVIGATORBATTERY NS_DECL_NSIDOMMOZNAVIGATORSMS +#ifdef MOZ_MEDIA_NAVIGATOR + NS_DECL_NSIDOMNAVIGATORUSERMEDIA +#endif #ifdef MOZ_B2G_RIL NS_DECL_NSIDOMNAVIGATORTELEPHONY #endif @@ -110,6 +121,11 @@ public: */ void SetWindow(nsPIDOMWindow *aInnerWindow); + /** + * Called when the inner window navigates to a new page. + */ + void OnNavigation(); + private: bool IsSmsAllowed() const; bool IsSmsSupported() const; diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 14e8e94cf30..b99f910e1a7 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -427,6 +427,11 @@ #include "nsIDOMGeoPositionCoords.h" #include "nsIDOMGeoPositionError.h" +// User media +#ifdef MOZ_MEDIA_NAVIGATOR +#include "nsIDOMNavigatorUserMedia.h" +#endif + // Workers #include "mozilla/dom/workers/Workers.h" @@ -2455,6 +2460,9 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMMozNavigatorBattery, battery::BatteryManager::HasSupport()) DOM_CLASSINFO_MAP_ENTRY(nsIDOMMozNavigatorSms) +#ifdef MOZ_MEDIA_NAVIGATOR + DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorUserMedia) +#endif #ifdef MOZ_B2G_RIL DOM_CLASSINFO_MAP_ENTRY(nsIDOMNavigatorTelephony) #endif diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 2a46ab51153..4b19d71d521 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1083,6 +1083,7 @@ nsGlobalWindow::FreeInnerObjects() mHistory = nsnull; if (mNavigator) { + mNavigator->OnNavigation(); mNavigator->Invalidate(); mNavigator = nsnull; } @@ -1748,6 +1749,10 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal(); + if (currentInner && currentInner->mNavigator) { + currentInner->mNavigator->OnNavigation(); + } + nsRefPtr newInnerWindow; bool createdInnerWindow = false; diff --git a/dom/dom-config.mk b/dom/dom-config.mk index 73a8a13ea4e..183c6d05945 100644 --- a/dom/dom-config.mk +++ b/dom/dom-config.mk @@ -6,6 +6,7 @@ DOM_SRCDIRS = \ dom/base \ dom/battery \ dom/power \ + dom/media \ dom/network/src \ dom/settings \ dom/sms/src \ diff --git a/dom/media/Makefile.in b/dom/media/Makefile.in new file mode 100644 index 00000000000..47b722fbf17 --- /dev/null +++ b/dom/media/Makefile.in @@ -0,0 +1,38 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at http://mozilla.org/MPL/2.0/. + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +relativesrcdir = dom/media + +include $(DEPTH)/config/autoconf.mk + +MODULE = dom +XPIDL_MODULE = dom_media +LIBRARY_NAME = dom_media_s +LIBXUL_LIBRARY = 1 +FORCE_STATIC_LIB = 1 + +include $(topsrcdir)/dom/dom-config.mk + +XPIDLSRCS = \ + nsIDOMMediaStream.idl \ + nsIDOMNavigatorUserMedia.idl \ + $(NULL) + +EXPORTS_NAMESPACE = mozilla + +EXPORTS_mozilla = \ + MediaManager.h \ + $(NULL) + +CPPSRCS = \ + MediaManager.cpp \ + $(NULL) + +include $(topsrcdir)/config/config.mk +include $(topsrcdir)/config/rules.mk diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp new file mode 100644 index 00000000000..222b928c096 --- /dev/null +++ b/dom/media/MediaManager.cpp @@ -0,0 +1,458 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MediaManager.h" + +#include "MediaStreamGraph.h" +#include "MediaEngineDefault.h" + +#include "nsIDOMFile.h" +#include "nsIEventTarget.h" +#include "nsIScriptGlobalObject.h" + +#include "nsJSUtils.h" +#include "nsDOMFile.h" + +namespace mozilla { + +/** + * Send an error back to content. The error is the form a string. + * Do this only on the main thread. + */ +class ErrorCallbackRunnable : public nsRunnable +{ +public: + ErrorCallbackRunnable(nsIDOMGetUserMediaErrorCallback* aError, + const nsString& aErrorMsg, PRUint64 aWindowID) + : mError(aError) + , mErrorMsg(aErrorMsg) + , mWindowID(aWindowID) {} + + NS_IMETHOD + Run() + { + // Only run if the window is still active. + WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows(); + if (activeWindows->Get(mWindowID)) { + mError->OnError(mErrorMsg); + } + return NS_OK; + } + +private: + nsCOMPtr mError; + const nsString mErrorMsg; + PRUint64 mWindowID; +}; + +/** + * Invoke the "onSuccess" callback in content. The callback will take a + * DOMBlob in the case of {picture:true}, and a MediaStream in the case of + * {audio:true} or {video:true}. There is a constructor available for each + * form. Do this only on the main thread. + */ +class SuccessCallbackRunnable : public nsRunnable +{ +public: + SuccessCallbackRunnable(nsIDOMGetUserMediaSuccessCallback* aSuccess, + nsIDOMFile* aFile, PRUint64 aWindowID) + : mSuccess(aSuccess) + , mFile(aFile) + , mWindowID(aWindowID) {} + + SuccessCallbackRunnable(nsIDOMGetUserMediaSuccessCallback* aSuccess, + nsIDOMMediaStream* aStream, PRUint64 aWindowID) + : mSuccess(aSuccess) + , mStream(aStream) + , mWindowID(aWindowID) {} + + NS_IMETHOD + Run() + { + // Only run if the window is still active. + WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows(); + if (activeWindows->Get(mWindowID)) { + // XPConnect is a magical unicorn. + if (mFile) { + mSuccess->OnSuccess(mFile); + } else if (mStream) { + mSuccess->OnSuccess(mStream); + } + } + return NS_OK; + } + +private: + nsCOMPtr mSuccess; + nsCOMPtr mFile; + nsCOMPtr mStream; + PRUint64 mWindowID; +}; + +/** + * This runnable creates a nsDOMMediaStream from a given MediaEngineSource + * and returns it via a success callback. Both must be done on the main thread. + */ +class GetUserMediaCallbackRunnable : public nsRunnable +{ +public: + GetUserMediaCallbackRunnable(MediaEngineSource* aSource, TrackID aId, + nsIDOMGetUserMediaSuccessCallback* aSuccess, + nsIDOMGetUserMediaErrorCallback* aError, + PRUint64 aWindowID, + StreamListeners* aListeners) + : mSource(aSource) + , mId(aId) + , mSuccess(aSuccess) + , mError(aError) + , mWindowID(aWindowID) + , mListeners(aListeners) {} + + NS_IMETHOD + Run() + { + /** + * Normally we would now get the name & UUID for the device and ask the + * user permission. We will do that when we have some UI. Currently, + * only the Android {picture:true} backend is functional, which does not + * need a permission prompt, as permission is implicit by user action. + * + * See bug 748835 for progress on the desktop UI. + */ + nsCOMPtr comStream = mSource->Allocate(); + if (!comStream) { + NS_DispatchToMainThread(new ErrorCallbackRunnable( + mError, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID + )); + return NS_OK; + } + + // Add our listener. We'll call Start() on the source when get a callback + // that the MediaStream has started consuming. The listener is freed + // when the page is invalidated (on navigation or close). + GetUserMediaCallbackMediaStreamListener* listener = + new GetUserMediaCallbackMediaStreamListener(mSource, comStream, mId); + comStream->GetStream()->AddListener(listener); + + { + MutexAutoLock lock(*(MediaManager::Get()->GetLock())); + mListeners->AppendElement(listener); + } + + // Add the listener to CallbackRunnables so it can be invalidated. + NS_DispatchToMainThread(new SuccessCallbackRunnable( + mSuccess, comStream.get(), mWindowID + )); + return NS_OK; + } + +private: + nsCOMPtr mSource; + TrackID mId; + nsCOMPtr mSuccess; + nsCOMPtr mError; + PRUint64 mWindowID; + StreamListeners* mListeners; +}; + +/** + * This runnable creates a nsIDOMFile from a MediaEngineVideoSource and + * passes the result back via a SuccessRunnable. Both must be done on the + * main thread. + */ +class GetUserMediaSnapshotCallbackRunable : public nsRunnable +{ +public: + GetUserMediaSnapshotCallbackRunable(MediaEngineSource* aSource, + PRUint32 aDuration, + nsIDOMGetUserMediaSuccessCallback* aSuccessCallback, + nsIDOMGetUserMediaErrorCallback* aErrorCallback, + PRUint64 aWindowID) + : mSource(aSource) + , mDuration(aDuration) + , mSuccessCallback(aSuccessCallback) + , mErrorCallback(aErrorCallback) + , mWindowID(aWindowID) {} + + NS_IMETHOD + Run() + { + nsCOMPtr comStream = mSource->Allocate(); + if (!comStream) { + NS_DispatchToMainThread(new ErrorCallbackRunnable( + mErrorCallback, NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"), mWindowID + )); + return NS_OK; + } + + nsCOMPtr file; + mSource->Snapshot(mDuration, getter_AddRefs(file)); + mSource->Deallocate(); + + NS_DispatchToMainThread(new SuccessCallbackRunnable( + mSuccessCallback, file, mWindowID + )); + return NS_OK; + } + +private: + nsCOMPtr mSource; + PRUint32 mDuration; + nsCOMPtr mSuccessCallback; + nsCOMPtr mErrorCallback; + PRUint64 mWindowID; +}; + +/** + * Runs on a seperate thread and is responsible for enumerating devices. + * Depending on whether a picture or stream was asked for, either + * GetUserMediaCallbackRunnable or GetUserMediaSnapshotCallbackRunnable + * will be dispatched to the main thread to return the result to DOM. + * + * Do not run this on the main thread. + */ +class GetUserMediaRunnable : public nsRunnable +{ +public: + GetUserMediaRunnable(bool aAudio, bool aVideo, bool aPicture, + nsIDOMGetUserMediaSuccessCallback* aSuccess, + nsIDOMGetUserMediaErrorCallback* aError, + PRUint64 aWindowID, StreamListeners* aListeners) + : mAudio(aAudio) + , mVideo(aVideo) + , mPicture(aPicture) + , mSuccess(aSuccess) + , mError(aError) + , mWindowID(aWindowID) + , mListeners(aListeners) {} + + ~GetUserMediaRunnable() {} + + // We only support 1 audio and 1 video track for now. + enum { + kVideoTrack = 1, + kAudioTrack = 2 + }; + + NS_IMETHOD + Run() + { + mManager = MediaManager::Get(); + + if (mPicture) { + SendPicture(); + return NS_OK; + } + + // XXX: Implement merging two streams (See bug 758391). + if (mAudio && mVideo) { + NS_DispatchToMainThread(new ErrorCallbackRunnable( + mError, NS_LITERAL_STRING("NOT_IMPLEMENTED"), mWindowID + )); + return NS_OK; + } + + if (mVideo) { + SendVideo(); + return NS_OK; + } + + if (mAudio) { + SendAudio(); + return NS_OK; + } + + return NS_OK; + } + + // {picture:true} + void + SendPicture() + { + nsTArray > videoSources; + mManager->GetBackend()->EnumerateVideoDevices(&videoSources); + + PRUint32 count = videoSources.Length(); + if (!count) { + NS_DispatchToMainThread(new ErrorCallbackRunnable( + mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID + )); + return; + } + MediaEngineVideoSource* videoSource = videoSources[count - 1]; + NS_DispatchToMainThread(new GetUserMediaSnapshotCallbackRunable( + videoSource, 0 /* duration */, mSuccess, mError, mWindowID + )); + } + + // {video:true} + void + SendVideo() + { + nsTArray > videoSources; + mManager->GetBackend()->EnumerateVideoDevices(&videoSources); + + PRUint32 count = videoSources.Length(); + if (!count) { + NS_DispatchToMainThread(new ErrorCallbackRunnable( + mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID + )); + return; + } + + MediaEngineVideoSource* videoSource = videoSources[count - 1]; + NS_DispatchToMainThread(new GetUserMediaCallbackRunnable( + videoSource, kVideoTrack, mSuccess, mError, mWindowID, mListeners + )); + } + + // {audio:true} + void + SendAudio() + { + nsTArray > audioSources; + mManager->GetBackend()->EnumerateAudioDevices(&audioSources); + + PRUint32 count = audioSources.Length(); + if (!count) { + NS_DispatchToMainThread(new ErrorCallbackRunnable( + mError, NS_LITERAL_STRING("NO_DEVICES_FOUND"), mWindowID + )); + return; + } + + MediaEngineAudioSource* audioSource = audioSources[count - 1]; + NS_DispatchToMainThread(new GetUserMediaCallbackRunnable( + audioSource, kAudioTrack, mSuccess, mError, mWindowID, mListeners + )); + } + +private: + bool mAudio; + bool mVideo; + bool mPicture; + + nsCOMPtr mSuccess; + nsCOMPtr mError; + PRUint64 mWindowID; + StreamListeners* mListeners; + + MediaManager* mManager; +}; + + +nsRefPtr MediaManager::sSingleton; + +NS_IMPL_ISUPPORTS1(MediaManager, nsIObserver) + +/** + * The entry point for this file. A call from Navigator::mozGetUserMedia + * will end up here. MediaManager is a singleton that is responsible + * for handling all incoming getUserMedia calls from every window. + */ +nsresult +MediaManager::GetUserMedia(PRUint64 aWindowID, nsIMediaStreamOptions* aParams, + nsIDOMGetUserMediaSuccessCallback* onSuccess, + nsIDOMGetUserMediaErrorCallback* onError) +{ + NS_ENSURE_TRUE(aParams, NS_ERROR_NULL_POINTER); + + bool audio, video, picture; + nsresult rv = aParams->GetPicture(&picture); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aParams->GetAudio(&audio); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aParams->GetVideo(&video); + NS_ENSURE_SUCCESS(rv, rv); + + // We only support "front" or "back". TBD: Send to GetUserMediaRunnable. + nsString cameraType; + rv = aParams->GetCamera(cameraType); + NS_ENSURE_SUCCESS(rv, rv); + + // Store the WindowID in a hash table and mark as active. The entry is removed + // when this window is closed or navigated away from. + StreamListeners* listeners = mActiveWindows.Get(aWindowID); + if (!listeners) { + listeners = new StreamListeners; + mActiveWindows.Put(aWindowID, listeners); + } + + // Pass runanbles along to GetUserMediaRunnable so it can add the + // MediaStreamListener to the runnable list. + nsCOMPtr gUMRunnable = new GetUserMediaRunnable( + audio, video, picture, onSuccess, onError, aWindowID, listeners + ); + + // Reuse the same thread to save memory. + if (!mMediaThread) { + rv = NS_NewThread(getter_AddRefs(mMediaThread)); + NS_ENSURE_SUCCESS(rv, rv); + } + + mMediaThread->Dispatch(gUMRunnable, NS_DISPATCH_NORMAL); + return NS_OK; +} + +MediaEngine* +MediaManager::GetBackend() +{ + // Plugin backends as appropriate. Only default is available for now, which + // also includes picture support for Android. + if (!mBackend) { + mBackend = new MediaEngineDefault(); + } + return mBackend; +} + +WindowTable* +MediaManager::GetActiveWindows() +{ + return &mActiveWindows; +} + +void +MediaManager::OnNavigation(PRUint64 aWindowID) +{ + // Invalidate this window. The runnables check this value before making + // a call to content. + StreamListeners* listeners = mActiveWindows.Get(aWindowID); + if (!listeners) { + return; + } + + MutexAutoLock lock(*mLock); + PRUint32 length = listeners->Length(); + for (PRUint32 i = 0; i < length; i++) { + nsRefPtr listener = + listeners->ElementAt(i); + listener->Invalidate(); + listener = nsnull; + } + listeners->Clear(); + + mActiveWindows.Remove(aWindowID); +} + +nsresult +MediaManager::Observe(nsISupports* aSubject, const char* aTopic, + const PRUnichar* aData) +{ + if (strcmp(aTopic, "xpcom-shutdown")) { + return NS_OK; + } + + nsCOMPtr obs = mozilla::services::GetObserverService(); + obs->RemoveObserver(this, "xpcom-shutdown"); + + // Close off any remaining active windows. + mActiveWindows.Clear(); + sSingleton = nsnull; + + return NS_OK; +} + +} // namespace mozilla diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h new file mode 100644 index 00000000000..cf93860f55e --- /dev/null +++ b/dom/media/MediaManager.h @@ -0,0 +1,128 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "MediaEngine.h" +#include "mozilla/Services.h" + +#include "nsHashKeys.h" +#include "nsClassHashtable.h" +#include "nsObserverService.h" + +#include "nsIDOMNavigatorUserMedia.h" + +#include "stdio.h" + +namespace mozilla { + +/** + * This class is an implementation of MediaStreamListener. This is used + * to Start() and Stop() the underlying MediaEngineSource when MediaStreams + * are assigned and deassigned in content. + */ +class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener +{ +public: + GetUserMediaCallbackMediaStreamListener(MediaEngineSource* aSource, + nsDOMMediaStream* aStream, TrackID aListenId) + : mSource(aSource) + , mStream(aStream) + , mId(aListenId) + , mValid(true) {} + + void + Invalidate() + { + if (!mValid) { + return; + } + + mValid = false; + mSource->Stop(); + mSource->Deallocate(); + } + + void + NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming) + { + if (aConsuming == CONSUMED) { + nsRefPtr stream = mStream->GetStream()->AsSourceStream(); + mSource->Start(stream, mId); + return; + } + + // NOT_CONSUMED + Invalidate(); + return; + } + + void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) {} + void NotifyOutput(MediaStreamGraph* aGraph) {} + void NotifyFinished(MediaStreamGraph* aGraph) {} + void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID, + TrackRate aTrackRate, TrackTicks aTrackOffset, + PRUint32 aTrackEvents, const MediaSegment& aQueuedMedia) {} + nsresult Run() { return NS_OK; } + +private: + nsCOMPtr mSource; + nsCOMPtr mStream; + TrackID mId; + bool mValid; +}; + +typedef nsTArray > StreamListeners; +typedef nsClassHashtable WindowTable; + +class MediaManager : public nsIObserver { +public: + static MediaManager* Get() { + if (!sSingleton) { + sSingleton = new MediaManager(); + + nsCOMPtr obs = services::GetObserverService(); + obs->AddObserver(sSingleton, "xpcom-shutdown", false); + } + return sSingleton; + } + + NS_DECL_ISUPPORTS + NS_DECL_NSIOBSERVER + + Mutex* GetLock() { + return mLock; + } + + MediaEngine* GetBackend(); + WindowTable* GetActiveWindows(); + + nsresult GetUserMedia(PRUint64 aWindowID, nsIMediaStreamOptions* aParams, + nsIDOMGetUserMediaSuccessCallback* onSuccess, + nsIDOMGetUserMediaErrorCallback* onError); + void OnNavigation(PRUint64 aWindowID); + +private: + // Make private because we want only one instance of this class + MediaManager() + : mBackend(nsnull) + , mMediaThread(nsnull) { + mLock = new mozilla::Mutex("MediaManager::StreamListenersLock"); + mActiveWindows.Init(); + }; + MediaManager(MediaManager const&) {}; + + ~MediaManager() { + delete mLock; + delete mBackend; + }; + + MediaEngine* mBackend; + nsCOMPtr mMediaThread; + + Mutex* mLock; + WindowTable mActiveWindows; + + static nsRefPtr sSingleton; +}; + +} // namespace mozilla diff --git a/content/media/nsIDOMMediaStream.idl b/dom/media/nsIDOMMediaStream.idl similarity index 100% rename from content/media/nsIDOMMediaStream.idl rename to dom/media/nsIDOMMediaStream.idl diff --git a/dom/media/nsIDOMNavigatorUserMedia.idl b/dom/media/nsIDOMNavigatorUserMedia.idl new file mode 100644 index 00000000000..33448bc67ae --- /dev/null +++ b/dom/media/nsIDOMNavigatorUserMedia.idl @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" +#include "nsIDOMMediaStream.idl" + +[scriptable, function, uuid(f2a144fc-3534-4761-8c5d-989ae720f89a)] +interface nsIDOMGetUserMediaSuccessCallback : nsISupports +{ + /* + * value must be a nsIDOMBlob if picture is true and a + * nsIDOMMediaStream if either audio or video are true. + */ + void onSuccess(in nsISupports value); +}; + +[scriptable, function, uuid(2614bbcf-85cc-43e5-8740-964f52bdc7ca)] +interface nsIDOMGetUserMediaErrorCallback : nsISupports +{ + void onError(in DOMString error); +}; + +[scriptable, uuid(8a26205e-e8f7-4372-bd15-97ff982b4c1c)] +interface nsIMediaStreamOptions : nsISupports +{ + readonly attribute boolean audio; + readonly attribute boolean video; + readonly attribute boolean picture; + readonly attribute DOMString camera; +}; + +[scriptable, uuid(381e0071-0be5-4f6b-ae21-8e3407a37faa)] +interface nsIDOMNavigatorUserMedia : nsISupports +{ + void mozGetUserMedia(in nsIMediaStreamOptions params, + in nsIDOMGetUserMediaSuccessCallback onsuccess, + in nsIDOMGetUserMediaErrorCallback onerror); +}; diff --git a/layout/build/Makefile.in b/layout/build/Makefile.in index 4991e103322..20ad0e677bf 100644 --- a/layout/build/Makefile.in +++ b/layout/build/Makefile.in @@ -66,6 +66,7 @@ SHARED_LIBRARY_LIBS = \ $(DEPTH)/dom/power/$(LIB_PREFIX)dom_power_s.$(LIB_SUFFIX) \ $(DEPTH)/dom/settings/$(LIB_PREFIX)jsdomsettings_s.$(LIB_SUFFIX) \ $(DEPTH)/dom/network/src/$(LIB_PREFIX)dom_network_s.$(LIB_SUFFIX) \ + $(DEPTH)/dom/media/$(LIB_PREFIX)dom_media_s.$(LIB_SUFFIX) \ $(DEPTH)/dom/sms/src/$(LIB_PREFIX)dom_sms_s.$(LIB_SUFFIX) \ $(DEPTH)/dom/src/events/$(LIB_PREFIX)jsdomevents_s.$(LIB_SUFFIX) \ $(DEPTH)/dom/src/json/$(LIB_PREFIX)json_s.$(LIB_SUFFIX) \ diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index df8d043f468..363caa82c6b 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -148,7 +148,6 @@ @BINPATH@/components/content_canvas.xpt @BINPATH@/components/content_htmldoc.xpt @BINPATH@/components/content_html.xpt -@BINPATH@/components/content_media.xpt @BINPATH@/components/content_xslt.xpt @BINPATH@/components/content_xtf.xpt @BINPATH@/components/cookie.xpt @@ -163,6 +162,7 @@ @BINPATH@/components/dom_css.xpt @BINPATH@/components/dom_events.xpt @BINPATH@/components/dom_geolocation.xpt +@BINPATH@/components/dom_media.xpt @BINPATH@/components/dom_network.xpt @BINPATH@/components/dom_notification.xpt @BINPATH@/components/dom_html.xpt diff --git a/mobile/xul/installer/package-manifest.in b/mobile/xul/installer/package-manifest.in index 6f677122244..bc78e2a99ae 100644 --- a/mobile/xul/installer/package-manifest.in +++ b/mobile/xul/installer/package-manifest.in @@ -2,7 +2,7 @@ ; License, v. 2.0. If a copy of the MPL was not distributed with this ; file, You can obtain one at http://mozilla.org/MPL/2.0/. -; Package file for the Fennec build. +; Package file for the Fennec build. ; ; File format: ; @@ -148,7 +148,6 @@ @BINPATH@/components/content_canvas.xpt @BINPATH@/components/content_htmldoc.xpt @BINPATH@/components/content_html.xpt -@BINPATH@/components/content_media.xpt @BINPATH@/components/content_xslt.xpt @BINPATH@/components/content_xtf.xpt @BINPATH@/components/cookie.xpt