author | Jan-Ivar Bruaroey <jib@mozilla.com> |
Tue, 03 Mar 2015 09:51:05 -0500 | |
changeset 236425 | b9458ee8b29704620b7bac91d60bfb5f41efd6c1 |
parent 236424 | 880c836bd395fd012ef8831ce99ce636a77d1bea |
child 236426 | c47fa3802a576b6f42232b8a9a3b86e9658e5e61 |
push id | 57667 |
push user | rjesup@wgate.com |
push date | Sun, 29 Mar 2015 05:19:06 +0000 |
treeherder | mozilla-inbound@13068deb2193 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | smaug, jesup |
bugs | 1046245 |
milestone | 39.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
new file mode 100644 --- /dev/null +++ b/dom/media/MediaDeviceInfo.cpp @@ -0,0 +1,67 @@ +/* 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 "mozilla/dom/MediaDeviceInfo.h" +#include "mozilla/dom/MediaStreamBinding.h" +#include "mozilla/MediaManager.h" +#include "nsIScriptGlobalObject.h" + +namespace mozilla { +namespace dom { + +MediaDeviceInfo::MediaDeviceInfo(const nsAString& aDeviceId, + MediaDeviceKind aKind, + const nsAString& aLabel, + const nsAString& aGroupId) + : mKind(aKind) + , mDeviceId(aDeviceId) + , mLabel(aLabel) + , mGroupId(aGroupId) {} + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(MediaDeviceInfo) +NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaDeviceInfo) +NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaDeviceInfo) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaDeviceInfo) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +JSObject* +MediaDeviceInfo::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) +{ + return MediaDeviceInfoBinding::Wrap(aCx, this, aGivenProto); +} + +nsISupports* MediaDeviceInfo::GetParentObject() +{ + return nullptr; +} + +void MediaDeviceInfo::GetDeviceId(nsString& retval) +{ + retval = mDeviceId; +} + +MediaDeviceKind +MediaDeviceInfo::Kind() +{ + return mKind; +} + +void MediaDeviceInfo::GetGroupId(nsString& retval) +{ + retval = mGroupId; +} + +void MediaDeviceInfo::GetLabel(nsString& retval) +{ + retval = mLabel; +} + +MediaDeviceKind Kind(); +void GetLabel(nsString& retval); +void GetGroupId(nsString& retval); + +} // namespace dom +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/dom/media/MediaDeviceInfo.h @@ -0,0 +1,60 @@ +/* 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/. */ + +#ifndef mozilla_dom_MediaDeviceInfo_h +#define mozilla_dom_MediaDeviceInfo_h + +#include "mozilla/ErrorResult.h" +#include "nsISupportsImpl.h" +#include "mozilla/dom/BindingUtils.h" +#include "MediaDeviceInfoBinding.h" +#include "nsPIDOMWindow.h" + +namespace mozilla { +namespace dom { + +class Promise; +struct MediaStreamConstraints; + +#define MOZILLA_DOM_MEDIADEVICEINFO_IMPLEMENTATION_IID \ +{0x25091870, 0x84d6, 0x4acf, {0xaf, 0x97, 0x6e, 0xd5, 0x5b, 0xe0, 0x47, 0xb2}} + +class MediaDeviceInfo final : public nsISupports, public nsWrapperCache +{ +public: + explicit MediaDeviceInfo(const nsAString& aDeviceId, + MediaDeviceKind aKind, + const nsAString& aLabel, + const nsAString& aGroupId = nsString()); + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaDeviceInfo) + NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOM_MEDIADEVICEINFO_IMPLEMENTATION_IID) + + JSObject* + WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override; + + nsISupports* GetParentObject(); + + void GetDeviceId(nsString& retval); + MediaDeviceKind Kind(); + void GetLabel(nsString& retval); + void GetGroupId(nsString& retval); + +private: + MediaDeviceKind mKind; + nsString mDeviceId; + nsString mLabel; + nsString mGroupId; + + virtual ~MediaDeviceInfo() {} +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(MediaDeviceInfo, + MOZILLA_DOM_MEDIADEVICEINFO_IMPLEMENTATION_IID) + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_MediaDeviceInfo_h
--- a/dom/media/MediaDevices.cpp +++ b/dom/media/MediaDevices.cpp @@ -32,16 +32,77 @@ public: return NS_OK; } private: virtual ~GumResolver() {} nsRefPtr<Promise> mPromise; }; +class MediaDevices::EnumDevResolver : public nsIGetUserMediaDevicesSuccessCallback +{ +public: + NS_DECL_ISUPPORTS + + explicit EnumDevResolver(Promise* aPromise) : mPromise(aPromise) {} + + NS_IMETHOD + OnSuccess(nsIVariant* aDevices) override + { + // Cribbed from MediaPermissionGonk.cpp + nsIID elementIID; + uint16_t elementType; + + // Create array for nsIMediaDevice + nsTArray<nsCOMPtr<nsIMediaDevice>> devices; + // Contain the fumes + { + void* rawArray; + uint32_t arrayLen; + nsresult rv; + rv = aDevices->GetAsArray(&elementType, &elementIID, &arrayLen, &rawArray); + NS_ENSURE_SUCCESS(rv, rv); + + if (elementType != nsIDataType::VTYPE_INTERFACE) { + NS_Free(rawArray); + return NS_ERROR_FAILURE; + } + + nsISupports **supportsArray = reinterpret_cast<nsISupports **>(rawArray); + for (uint32_t i = 0; i < arrayLen; ++i) { + nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supportsArray[i])); + devices.AppendElement(device); + NS_IF_RELEASE(supportsArray[i]); // explicitly decrease refcount for rawptr + } + NS_Free(rawArray); // explicitly free memory from nsIVariant::GetAsArray + } + nsTArray<nsRefPtr<MediaDeviceInfo>> infos; + for (auto& device : devices) { + nsString type; + device->GetType(type); + bool isVideo = type.EqualsLiteral("video"); + bool isAudio = type.EqualsLiteral("audio"); + if (isVideo || isAudio) { + MediaDeviceKind kind = isVideo ? + MediaDeviceKind::Videoinput : MediaDeviceKind::Audioinput; + // TODO: return anonymized id, +label (origins w/gUM permission) (1046245) + nsRefPtr<MediaDeviceInfo> info = new MediaDeviceInfo(nsString(), kind, + nsString()); + infos.AppendElement(info); + } + } + mPromise->MaybeResolve(infos); + return NS_OK; + } + +private: + virtual ~EnumDevResolver() {} + nsRefPtr<Promise> mPromise; +}; + class MediaDevices::GumRejecter : public nsIDOMGetUserMediaErrorCallback { public: NS_DECL_ISUPPORTS explicit GumRejecter(Promise* aPromise) : mPromise(aPromise) {} NS_IMETHOD @@ -56,36 +117,51 @@ public: } private: virtual ~GumRejecter() {} nsRefPtr<Promise> mPromise; }; NS_IMPL_ISUPPORTS(MediaDevices::GumResolver, nsIDOMGetUserMediaSuccessCallback) +NS_IMPL_ISUPPORTS(MediaDevices::EnumDevResolver, nsIGetUserMediaDevicesSuccessCallback) NS_IMPL_ISUPPORTS(MediaDevices::GumRejecter, nsIDOMGetUserMediaErrorCallback) already_AddRefed<Promise> MediaDevices::GetUserMedia(const MediaStreamConstraints& aConstraints, ErrorResult &aRv) { - ErrorResult rv; nsPIDOMWindow* window = GetOwner(); nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(window); nsRefPtr<Promise> p = Promise::Create(go, aRv); - NS_ENSURE_TRUE(!rv.Failed(), nullptr); + NS_ENSURE_TRUE(!aRv.Failed(), nullptr); nsRefPtr<GumResolver> resolver = new GumResolver(p); nsRefPtr<GumRejecter> rejecter = new GumRejecter(p); aRv = MediaManager::Get()->GetUserMedia(window, aConstraints, resolver, rejecter); return p.forget(); } +already_AddRefed<Promise> +MediaDevices::EnumerateDevices(ErrorResult &aRv) +{ + nsPIDOMWindow* window = GetOwner(); + nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(window); + nsRefPtr<Promise> p = Promise::Create(go, aRv); + NS_ENSURE_TRUE(!aRv.Failed(), nullptr); + + nsRefPtr<EnumDevResolver> resolver = new EnumDevResolver(p); + nsRefPtr<GumRejecter> rejecter = new GumRejecter(p); + + aRv = MediaManager::Get()->EnumerateDevices(window, resolver, rejecter); + return p.forget(); +} + NS_IMPL_ADDREF_INHERITED(MediaDevices, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(MediaDevices, DOMEventTargetHelper) NS_INTERFACE_MAP_BEGIN(MediaDevices) NS_INTERFACE_MAP_ENTRY(MediaDevices) NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) JSObject* MediaDevices::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
--- a/dom/media/MediaDevices.h +++ b/dom/media/MediaDevices.h @@ -1,14 +1,14 @@ /* 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/. */ -#ifndef MediaDevices_h__ -#define MediaDevices_h__ +#ifndef mozilla_dom_MediaDevices_h +#define mozilla_dom_MediaDevices_h #include "mozilla/ErrorResult.h" #include "nsISupportsImpl.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/dom/BindingUtils.h" #include "nsPIDOMWindow.h" namespace mozilla { @@ -30,22 +30,26 @@ public: NS_DECL_ISUPPORTS_INHERITED NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOM_MEDIADEVICES_IMPLEMENTATION_IID) JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override; already_AddRefed<Promise> GetUserMedia(const MediaStreamConstraints& aConstraints, ErrorResult &aRv); + already_AddRefed<Promise> + EnumerateDevices(ErrorResult &aRv); + private: class GumResolver; + class EnumDevResolver; class GumRejecter; virtual ~MediaDevices() {} }; NS_DEFINE_STATIC_IID_ACCESSOR(MediaDevices, MOZILLA_DOM_MEDIADEVICES_IMPLEMENTATION_IID) } // namespace dom } // namespace mozilla -#endif // MediaDevices_h__ +#endif // mozilla_dom_MediaDevices_h
--- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -1572,26 +1572,18 @@ MediaManager::GetUserMedia( // Hack: should init singleton earlier unless it's expensive (mem or CPU) (void) MediaManager::Get(); #ifdef MOZ_B2G // Initialize MediaPermissionManager before send out any permission request. (void) MediaPermissionManager::GetInstance(); #endif //MOZ_B2G } - // 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(); - // This is safe since we're on main-thread, and the windowlist can only - // be invalidated from the main-thread (see OnNavigation) - StreamListeners* listeners = GetActiveWindows()->Get(windowID); - if (!listeners) { - listeners = new StreamListeners; - GetActiveWindows()->Put(windowID, listeners); - } + StreamListeners* listeners = AddWindowID(windowID); // Create a disabled listener to act as a placeholder GetUserMediaCallbackMediaStreamListener* listener = new GetUserMediaCallbackMediaStreamListener(mMediaThread, windowID); // No need for locking because we always do this in the main thread. listeners->AppendElement(listener); @@ -1823,16 +1815,31 @@ MediaManager::GetUserMediaDevices(nsPIDO new GetUserMediaDevicesTask( aConstraints, onSuccess.forget(), onFailure.forget(), (aInnerWindowID ? aInnerWindowID : aWindow->WindowID()), loopbackAudioDevice, loopbackVideoDevice, useFakeStreams)); return NS_OK; } +nsresult +MediaManager::EnumerateDevices(nsPIDOMWindow* aWindow, + nsIGetUserMediaDevicesSuccessCallback* aOnSuccess, + nsIDOMGetUserMediaErrorCallback* aOnFailure) +{ + NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); + + MediaStreamConstraints c; + c.mVideo.SetAsBoolean() = true; + c.mAudio.SetAsBoolean() = true; + + AddWindowID(aWindow->WindowID()); + return GetUserMediaDevices(aWindow, c, aOnSuccess, aOnFailure, 0); +} + MediaEngine* MediaManager::GetBackend(uint64_t aWindowId) { // Plugin backends as appropriate. The default engine also currently // includes picture support for Android. // This IS called off main-thread. MutexAutoLock lock(mMutex); if (!mBackend) { @@ -1891,16 +1898,32 @@ MediaManager::OnNavigation(uint64_t aWin (nsGlobalWindow::GetInnerWindowWithId(aWindowID)); if (window) { IterateWindowListeners(window, StopSharingCallback, nullptr); } else { RemoveWindowID(aWindowID); } } +StreamListeners* +MediaManager::AddWindowID(uint64_t aWindowId) +{ + NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); + // Store the WindowID in a hash table and mark as active. The entry is removed + // when this window is closed or navigated away from. + // This is safe since we're on main-thread, and the windowlist can only + // be invalidated from the main-thread (see OnNavigation) + StreamListeners* listeners = GetActiveWindows()->Get(aWindowId); + if (!listeners) { + listeners = new StreamListeners; + GetActiveWindows()->Put(aWindowId, listeners); + } + return listeners; +} + void MediaManager::RemoveWindowID(uint64_t aWindowId) { mActiveWindows.Remove(aWindowId); // get outer windowID nsPIDOMWindow *window = static_cast<nsPIDOMWindow*> (nsGlobalWindow::GetInnerWindowWithId(aWindowId));
--- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -591,21 +591,28 @@ public: nsIDOMGetUserMediaSuccessCallback* onSuccess, nsIDOMGetUserMediaErrorCallback* onError); nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow, const dom::MediaStreamConstraints& aConstraints, nsIGetUserMediaDevicesSuccessCallback* onSuccess, nsIDOMGetUserMediaErrorCallback* onError, uint64_t aInnerWindowID = 0); + + nsresult EnumerateDevices(nsPIDOMWindow* aWindow, + nsIGetUserMediaDevicesSuccessCallback* aOnSuccess, + nsIDOMGetUserMediaErrorCallback* aOnFailure); + + nsresult EnumerateDevices(nsPIDOMWindow* aWindow, dom::Promise& aPromise); void OnNavigation(uint64_t aWindowID); MediaEnginePrefs mPrefs; private: + StreamListeners* AddWindowID(uint64_t aWindowId); WindowTable *GetActiveWindows() { NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread"); return &mActiveWindows; } void GetPref(nsIPrefBranch *aBranch, const char *aPref, const char *aData, int32_t *aVal); void GetPrefBool(nsIPrefBranch *aBranch, const char *aPref,
--- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -141,16 +141,17 @@ if CONFIG['MOZ_B2G']: 'MediaPermissionGonk.h', ] EXPORTS.mozilla.dom += [ 'AudioStreamTrack.h', 'AudioTrack.h', 'AudioTrackList.h', 'GetUserMediaRequest.h', + 'MediaDeviceInfo.h', 'MediaDevices.h', 'MediaStreamError.h', 'MediaStreamTrack.h', 'RTCIdentityProviderRegistrar.h', 'TextTrack.h', 'TextTrackCue.h', 'TextTrackCueList.h', 'TextTrackList.h', @@ -178,16 +179,17 @@ UNIFIED_SOURCES += [ 'GetUserMediaRequest.cpp', 'GraphDriver.cpp', 'Latency.cpp', 'MediaCache.cpp', 'MediaData.cpp', 'MediaDecoder.cpp', 'MediaDecoderReader.cpp', 'MediaDecoderStateMachine.cpp', + 'MediaDeviceInfo.cpp', 'MediaDevices.cpp', 'MediaManager.cpp', 'MediaRecorder.cpp', 'MediaResource.cpp', 'MediaShutdownManager.cpp', 'MediaStreamError.cpp', 'MediaStreamGraph.cpp', 'MediaStreamTrack.cpp',
--- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -640,16 +640,18 @@ var interfaceNamesInGlobalScope = "KeyEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "KeyboardEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "LocalMediaStream", // IMPORTANT: Do not change this list without review from a DOM peer! "Location", // IMPORTANT: Do not change this list without review from a DOM peer! + "MediaDeviceInfo", +// IMPORTANT: Do not change this list without review from a DOM peer! "MediaDevices", // IMPORTANT: Do not change this list without review from a DOM peer! "MediaElementAudioSourceNode", // IMPORTANT: Do not change this list without review from a DOM peer! "MediaError", // IMPORTANT: Do not change this list without review from a DOM peer! {name: "MediaKeyError", pref: "media.eme.apiVisible"}, // IMPORTANT: Do not change this list without review from a DOM peer!
new file mode 100644 --- /dev/null +++ b/dom/webidl/MediaDeviceInfo.webidl @@ -0,0 +1,22 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * http://dev.w3.org/2011/webrtc/editor/getusermedia.html + */ + +enum MediaDeviceKind { + "audioinput", + "audiooutput", + "videoinput" +}; + +[Func="Navigator::HasUserMediaSupport"] +interface MediaDeviceInfo { + readonly attribute DOMString deviceId; + readonly attribute MediaDeviceKind kind; + readonly attribute DOMString label; + readonly attribute DOMString groupId; +};
--- a/dom/webidl/MediaDevices.webidl +++ b/dom/webidl/MediaDevices.webidl @@ -7,17 +7,17 @@ * http://dev.w3.org/2011/webrtc/editor/getusermedia.html * * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. */ [Func="Navigator::HasUserMediaSupport"] interface MediaDevices : EventTarget { -// attribute EventHandler ondevicechange; -// -// void enumerateDevices (MediaDeviceInfoCallback resultCallback); -// +// attribute EventHandler ondevicechange; // static Dictionary getSupportedConstraints (DOMString kind); - [Throws, Func="Navigator::HasUserMediaSupport"] + [Throws] + Promise<sequence<MediaDeviceInfo>> enumerateDevices(); + + [Throws] Promise<MediaStream> getUserMedia(optional MediaStreamConstraints constraints); };
--- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -257,16 +257,17 @@ WEBIDL_FILES = [ 'KeyAlgorithm.webidl', 'KeyboardEvent.webidl', 'KeyEvent.webidl', 'LegacyQueryInterface.webidl', 'LinkStyle.webidl', 'ListBoxObject.webidl', 'LocalMediaStream.webidl', 'Location.webidl', + 'MediaDeviceInfo.webidl', 'MediaDevices.webidl', 'MediaElementAudioSourceNode.webidl', 'MediaError.webidl', 'MediaList.webidl', 'MediaQueryList.webidl', 'MediaRecorder.webidl', 'MediaSource.webidl', 'MediaStream.webidl',