2014-09-20 06:20:41 +00:00
|
|
|
/* 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/MediaDevices.h"
|
|
|
|
#include "mozilla/dom/MediaStreamBinding.h"
|
2016-02-16 21:55:33 +00:00
|
|
|
#include "mozilla/dom/MediaDeviceInfo.h"
|
2014-09-20 06:20:41 +00:00
|
|
|
#include "mozilla/dom/MediaDevicesBinding.h"
|
2018-07-28 04:40:26 +00:00
|
|
|
#include "mozilla/dom/NavigatorBinding.h"
|
2014-09-20 06:20:41 +00:00
|
|
|
#include "mozilla/dom/Promise.h"
|
|
|
|
#include "mozilla/MediaManager.h"
|
2015-07-02 18:21:49 +00:00
|
|
|
#include "MediaTrackConstraints.h"
|
2017-09-19 01:56:48 +00:00
|
|
|
#include "nsContentUtils.h"
|
2014-09-20 06:20:41 +00:00
|
|
|
#include "nsIEventTarget.h"
|
2017-07-26 18:18:20 +00:00
|
|
|
#include "nsINamed.h"
|
2014-09-20 06:20:41 +00:00
|
|
|
#include "nsIScriptGlobalObject.h"
|
2015-03-03 14:51:05 +00:00
|
|
|
#include "nsIPermissionManager.h"
|
2014-09-20 06:20:41 +00:00
|
|
|
#include "nsPIDOMWindow.h"
|
2015-04-15 16:47:03 +00:00
|
|
|
#include "nsQueryObject.h"
|
2014-09-20 06:20:41 +00:00
|
|
|
|
2017-01-26 16:08:06 +00:00
|
|
|
#define DEVICECHANGE_HOLD_TIME_IN_MS 1000
|
|
|
|
|
2014-09-20 06:20:41 +00:00
|
|
|
namespace mozilla {
|
|
|
|
namespace dom {
|
|
|
|
|
2017-07-26 18:18:20 +00:00
|
|
|
class FuzzTimerCallBack final : public nsITimerCallback, public nsINamed {
|
2017-01-26 16:08:06 +00:00
|
|
|
~FuzzTimerCallBack() {}
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit FuzzTimerCallBack(MediaDevices* aMediaDevices)
|
|
|
|
: mMediaDevices(aMediaDevices) {}
|
|
|
|
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
2018-02-06 06:46:57 +00:00
|
|
|
NS_IMETHOD Notify(nsITimer* aTimer) final {
|
2017-01-26 16:08:06 +00:00
|
|
|
mMediaDevices->DispatchTrustedEvent(NS_LITERAL_STRING("devicechange"));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-07-26 18:18:20 +00:00
|
|
|
NS_IMETHOD GetName(nsACString& aName) override {
|
|
|
|
aName.AssignLiteral("FuzzTimerCallBack");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-01-26 16:08:06 +00:00
|
|
|
private:
|
|
|
|
nsCOMPtr<MediaDevices> mMediaDevices;
|
|
|
|
};
|
|
|
|
|
2017-07-26 18:18:20 +00:00
|
|
|
NS_IMPL_ISUPPORTS(FuzzTimerCallBack, nsITimerCallback, nsINamed)
|
2017-01-26 16:08:06 +00:00
|
|
|
|
2016-11-21 06:59:51 +00:00
|
|
|
MediaDevices::~MediaDevices() {
|
|
|
|
MediaManager* mediamanager = MediaManager::GetIfExists();
|
|
|
|
if (mediamanager) {
|
|
|
|
mediamanager->RemoveDeviceChangeCallback(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-03 23:50:22 +00:00
|
|
|
static bool IsSameOriginWithAllParentDocs(nsINode* aDoc) {
|
|
|
|
MOZ_ASSERT(aDoc);
|
|
|
|
nsINode* node = aDoc;
|
|
|
|
while ((node = nsContentUtils::GetCrossDocParentNode(node))) {
|
|
|
|
if (NS_FAILED(nsContentUtils::CheckSameOrigin(aDoc, node))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-20 06:20:41 +00:00
|
|
|
already_AddRefed<Promise> MediaDevices::GetUserMedia(
|
|
|
|
const MediaStreamConstraints& aConstraints, CallerType aCallerType,
|
|
|
|
ErrorResult& aRv) {
|
2019-05-22 19:02:37 +00:00
|
|
|
if (RefPtr<nsPIDOMWindowInner> owner = GetOwner()) {
|
|
|
|
if (Document* doc = owner->GetExtantDoc()) {
|
|
|
|
if (!owner->IsSecureContext()) {
|
|
|
|
doc->SetDocumentAndPageUseCounter(eUseCounter_custom_GetUserMediaInsec);
|
|
|
|
}
|
|
|
|
if (!IsSameOriginWithAllParentDocs(doc)) {
|
|
|
|
doc->SetDocumentAndPageUseCounter(
|
|
|
|
eUseCounter_custom_GetUserMediaXOrigin);
|
|
|
|
}
|
|
|
|
Document* topDoc = doc->GetTopLevelContentDocument();
|
|
|
|
IgnoredErrorResult ignored;
|
|
|
|
if (topDoc && !topDoc->HasFocus(ignored)) {
|
|
|
|
doc->SetDocumentAndPageUseCounter(
|
|
|
|
eUseCounter_custom_GetUserMediaUnfocused);
|
|
|
|
}
|
2019-05-03 23:50:22 +00:00
|
|
|
}
|
|
|
|
}
|
2018-02-22 22:28:39 +00:00
|
|
|
RefPtr<Promise> p = Promise::Create(GetParentObject(), aRv);
|
2018-11-30 05:13:58 +00:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
RefPtr<MediaDevices> self(this);
|
|
|
|
MediaManager::Get()
|
|
|
|
->GetUserMedia(GetOwner(), aConstraints, aCallerType)
|
|
|
|
->Then(
|
|
|
|
GetCurrentThreadSerialEventTarget(), __func__,
|
|
|
|
[this, self, p](RefPtr<DOMMediaStream>&& aStream) {
|
2018-11-30 05:15:54 +00:00
|
|
|
if (!GetWindowIfCurrent()) {
|
2018-11-30 05:13:58 +00:00
|
|
|
return; // Leave Promise pending after navigation by design.
|
|
|
|
}
|
|
|
|
p->MaybeResolve(std::move(aStream));
|
|
|
|
},
|
2018-11-30 05:15:54 +00:00
|
|
|
[this, self, p](const RefPtr<MediaMgrError>& error) {
|
|
|
|
nsPIDOMWindowInner* window = GetWindowIfCurrent();
|
|
|
|
if (!window) {
|
2018-11-30 05:13:58 +00:00
|
|
|
return; // Leave Promise pending after navigation by design.
|
|
|
|
}
|
2018-11-30 05:15:54 +00:00
|
|
|
p->MaybeReject(MakeRefPtr<MediaStreamError>(window, *error));
|
2018-11-30 05:13:58 +00:00
|
|
|
});
|
2014-09-20 06:20:41 +00:00
|
|
|
return p.forget();
|
|
|
|
}
|
|
|
|
|
2017-09-18 01:52:06 +00:00
|
|
|
already_AddRefed<Promise> MediaDevices::EnumerateDevices(CallerType aCallerType,
|
|
|
|
ErrorResult& aRv) {
|
2018-11-30 05:14:05 +00:00
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2019-05-03 23:50:22 +00:00
|
|
|
|
2019-05-22 19:02:37 +00:00
|
|
|
if (RefPtr<nsPIDOMWindowInner> owner = GetOwner()) {
|
|
|
|
if (Document* doc = owner->GetExtantDoc()) {
|
|
|
|
if (!owner->IsSecureContext()) {
|
|
|
|
doc->SetDocumentAndPageUseCounter(
|
|
|
|
eUseCounter_custom_EnumerateDevicesInsec);
|
|
|
|
}
|
|
|
|
Document* topDoc = doc->GetTopLevelContentDocument();
|
|
|
|
IgnoredErrorResult ignored;
|
|
|
|
if (topDoc && !topDoc->HasFocus(ignored)) {
|
|
|
|
doc->SetDocumentAndPageUseCounter(
|
|
|
|
eUseCounter_custom_EnumerateDevicesUnfocused);
|
|
|
|
}
|
2019-05-03 23:50:22 +00:00
|
|
|
}
|
|
|
|
}
|
2018-02-22 22:28:39 +00:00
|
|
|
RefPtr<Promise> p = Promise::Create(GetParentObject(), aRv);
|
2018-11-30 05:14:05 +00:00
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
RefPtr<MediaDevices> self(this);
|
|
|
|
MediaManager::Get()
|
|
|
|
->EnumerateDevices(GetOwner(), aCallerType)
|
|
|
|
->Then(
|
|
|
|
GetCurrentThreadSerialEventTarget(), __func__,
|
|
|
|
[this, self,
|
|
|
|
p](RefPtr<MediaManager::MediaDeviceSetRefCnt>&& aDevices) {
|
2018-11-30 05:15:54 +00:00
|
|
|
nsPIDOMWindowInner* window = GetWindowIfCurrent();
|
|
|
|
if (!window) {
|
2018-11-30 05:14:05 +00:00
|
|
|
return; // Leave Promise pending after navigation by design.
|
|
|
|
}
|
2018-11-30 05:15:54 +00:00
|
|
|
auto windowId = window->WindowID();
|
2018-11-30 05:14:05 +00:00
|
|
|
nsTArray<RefPtr<MediaDeviceInfo>> infos;
|
2018-11-30 05:15:34 +00:00
|
|
|
for (auto& device : *aDevices) {
|
2018-11-30 05:14:05 +00:00
|
|
|
MOZ_ASSERT(device->mKind == dom::MediaDeviceKind::Audioinput ||
|
|
|
|
device->mKind == dom::MediaDeviceKind::Videoinput ||
|
|
|
|
device->mKind == dom::MediaDeviceKind::Audiooutput);
|
|
|
|
// Include name only if page currently has a gUM stream active
|
|
|
|
// or persistent permissions (audio or video) have been granted
|
|
|
|
nsString label;
|
|
|
|
if (MediaManager::Get()->IsActivelyCapturingOrHasAPermission(
|
|
|
|
windowId) ||
|
|
|
|
Preferences::GetBool("media.navigator.permission.disabled",
|
|
|
|
false)) {
|
|
|
|
label = device->mName;
|
|
|
|
}
|
|
|
|
infos.AppendElement(MakeRefPtr<MediaDeviceInfo>(
|
2019-03-08 11:51:45 +00:00
|
|
|
device->mID, device->mKind, label, device->mGroupID));
|
2018-11-30 05:14:05 +00:00
|
|
|
}
|
|
|
|
p->MaybeResolve(std::move(infos));
|
|
|
|
},
|
2018-11-30 05:15:54 +00:00
|
|
|
[this, self, p](const RefPtr<MediaMgrError>& error) {
|
|
|
|
nsPIDOMWindowInner* window = GetWindowIfCurrent();
|
|
|
|
if (!window) {
|
2018-11-30 05:14:05 +00:00
|
|
|
return; // Leave Promise pending after navigation by design.
|
|
|
|
}
|
2018-11-30 05:15:54 +00:00
|
|
|
p->MaybeReject(MakeRefPtr<MediaStreamError>(window, *error));
|
2018-11-30 05:14:05 +00:00
|
|
|
});
|
2015-03-03 14:51:05 +00:00
|
|
|
return p.forget();
|
|
|
|
}
|
|
|
|
|
2018-12-28 03:12:57 +00:00
|
|
|
already_AddRefed<Promise> MediaDevices::GetDisplayMedia(
|
|
|
|
const DisplayMediaStreamConstraints& aConstraints, CallerType aCallerType,
|
|
|
|
ErrorResult& aRv) {
|
2019-05-22 19:02:37 +00:00
|
|
|
if (RefPtr<nsPIDOMWindowInner> owner = GetOwner()) {
|
|
|
|
if (Document* doc = owner->GetExtantDoc()) {
|
|
|
|
if (!IsSameOriginWithAllParentDocs(doc)) {
|
|
|
|
doc->SetDocumentAndPageUseCounter(
|
|
|
|
eUseCounter_custom_GetDisplayMediaXOrigin);
|
|
|
|
}
|
2019-05-03 23:50:22 +00:00
|
|
|
}
|
|
|
|
}
|
2018-12-28 03:12:57 +00:00
|
|
|
RefPtr<Promise> p = Promise::Create(GetParentObject(), aRv);
|
|
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
RefPtr<MediaDevices> self(this);
|
|
|
|
MediaManager::Get()
|
|
|
|
->GetDisplayMedia(GetOwner(), aConstraints, aCallerType)
|
|
|
|
->Then(
|
|
|
|
GetCurrentThreadSerialEventTarget(), __func__,
|
|
|
|
[this, self, p](RefPtr<DOMMediaStream>&& aStream) {
|
|
|
|
if (!GetWindowIfCurrent()) {
|
|
|
|
return; // leave promise pending after navigation.
|
|
|
|
}
|
|
|
|
p->MaybeResolve(std::move(aStream));
|
|
|
|
},
|
|
|
|
[this, self, p](RefPtr<MediaMgrError>&& error) {
|
|
|
|
nsPIDOMWindowInner* window = GetWindowIfCurrent();
|
|
|
|
if (!window) {
|
|
|
|
return; // leave promise pending after navigation.
|
|
|
|
}
|
|
|
|
p->MaybeReject(MakeRefPtr<MediaStreamError>(window, *error));
|
|
|
|
});
|
|
|
|
return p.forget();
|
|
|
|
}
|
|
|
|
|
2014-09-20 06:20:41 +00:00
|
|
|
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)
|
|
|
|
|
2016-08-11 17:04:49 +00:00
|
|
|
void MediaDevices::OnDeviceChange() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
2019-04-01 16:46:46 +00:00
|
|
|
nsresult rv = CheckCurrentGlobalCorrectness();
|
2017-01-26 16:08:06 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
MOZ_ASSERT(false);
|
2016-08-11 17:04:49 +00:00
|
|
|
return;
|
2017-01-26 16:08:06 +00:00
|
|
|
}
|
2016-08-11 17:04:49 +00:00
|
|
|
|
|
|
|
if (!(MediaManager::Get()->IsActivelyCapturingOrHasAPermission(
|
|
|
|
GetOwner()->WindowID()) ||
|
|
|
|
Preferences::GetBool("media.navigator.permission.disabled", false))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-09-19 01:56:48 +00:00
|
|
|
// Do not fire event to content script when
|
|
|
|
// privacy.resistFingerprinting is true.
|
|
|
|
if (nsContentUtils::ShouldResistFingerprinting()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-26 16:08:06 +00:00
|
|
|
if (!mFuzzTimer) {
|
2017-10-16 06:15:40 +00:00
|
|
|
mFuzzTimer = NS_NewTimer();
|
2017-01-26 16:08:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!mFuzzTimer) {
|
|
|
|
MOZ_ASSERT(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mFuzzTimer->Cancel();
|
|
|
|
RefPtr<FuzzTimerCallBack> cb = new FuzzTimerCallBack(this);
|
|
|
|
mFuzzTimer->InitWithCallback(cb, DEVICECHANGE_HOLD_TIME_IN_MS,
|
|
|
|
nsITimer::TYPE_ONE_SHOT);
|
2016-08-11 17:04:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mozilla::dom::EventHandlerNonNull* MediaDevices::GetOndevicechange() {
|
2018-07-24 22:15:19 +00:00
|
|
|
return GetEventHandler(nsGkAtoms::ondevicechange);
|
2016-08-11 17:04:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MediaDevices::SetOndevicechange(
|
|
|
|
mozilla::dom::EventHandlerNonNull* aCallback) {
|
2018-07-24 22:15:19 +00:00
|
|
|
SetEventHandler(nsGkAtoms::ondevicechange, aCallback);
|
2016-08-11 17:04:49 +00:00
|
|
|
|
|
|
|
MediaManager::Get()->AddDeviceChangeCallback(this);
|
|
|
|
}
|
|
|
|
|
2018-04-05 17:42:42 +00:00
|
|
|
void MediaDevices::EventListenerAdded(nsAtom* aType) {
|
2016-08-11 17:04:49 +00:00
|
|
|
MediaManager::Get()->AddDeviceChangeCallback(this);
|
2018-04-05 17:42:42 +00:00
|
|
|
DOMEventTargetHelper::EventListenerAdded(aType);
|
2016-08-11 17:04:49 +00:00
|
|
|
}
|
|
|
|
|
Bug 1117172 part 3. Change the wrappercached WrapObject methods to allow passing in aGivenProto. r=peterv
The only manual changes here are to BindingUtils.h, BindingUtils.cpp,
Codegen.py, Element.cpp, IDBFileRequest.cpp, IDBObjectStore.cpp,
dom/workers/Navigator.cpp, WorkerPrivate.cpp, DeviceStorageRequestChild.cpp,
Notification.cpp, nsGlobalWindow.cpp, MessagePort.cpp, nsJSEnvironment.cpp,
Sandbox.cpp, XPCConvert.cpp, ExportHelpers.cpp, and DataStoreService.cpp. The
rest of this diff was generated by running the following commands:
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObjectInternal\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapNode\((?:aCx|cx|aContext|aCtx|js))\)/\1, aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(WrapObject\(JSContext *\* *(?:aCx|cx|aContext|aCtx|js))\)/\1, JS::Handle<JSObject*> aGivenProto)/g'
find . -name "*.h" -o -name "*.cpp" | xargs perl -pi -e 'BEGIN { $/ = undef } s/(Binding(?:_workers)?::Wrap\((?:aCx|cx|aContext|aCtx|js), [^,)]+)\)/\1, aGivenProto)/g'
2015-03-19 14:13:33 +00:00
|
|
|
JSObject* MediaDevices::WrapObject(JSContext* aCx,
|
|
|
|
JS::Handle<JSObject*> aGivenProto) {
|
2018-06-25 21:20:54 +00:00
|
|
|
return MediaDevices_Binding::Wrap(aCx, this, aGivenProto);
|
2014-09-20 06:20:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace dom
|
|
|
|
} // namespace mozilla
|