Skip to content

Commit

Permalink
Bug 1732410 wait for focus before proceeding for enumerateDevices() P…
Browse files Browse the repository at this point in the history
…romises r=jib,nika

w3c/mediacapture-main#574

Focus on browser chrome widgets is accepted provided the tab is fully active
and foreground.
w3c/mediacapture-main#752 (comment)

Differential Revision: https://phabricator.services.mozilla.com/D127051
  • Loading branch information
karlt committed Oct 11, 2021
1 parent bef2241 commit 9edf2f2
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 19 deletions.
10 changes: 8 additions & 2 deletions docshell/base/BrowsingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "mozilla/dom/HTMLIFrameElement.h"
#include "mozilla/dom/Location.h"
#include "mozilla/dom/LocationBinding.h"
#include "mozilla/dom/MediaDevices.h"
#include "mozilla/dom/PopupBlocker.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SessionStorageManager.h"
Expand Down Expand Up @@ -2930,14 +2931,19 @@ void BrowsingContext::DidSet(FieldIndex<IDX_IsActiveBrowserWindowInternal>,
if (RefPtr<Document> doc = aContext->GetExtantDocument()) {
doc->UpdateDocumentStates(NS_DOCUMENT_STATE_WINDOW_INACTIVE, true);

RefPtr<nsPIDOMWindowInner> win = doc->GetInnerWindow();
RefPtr<MediaDevices> devices;
if (isActivateEvent && (devices = win->GetExtantMediaDevices())) {
devices->BrowserWindowBecameActive();
}

if (XRE_IsContentProcess() &&
(!aContext->GetParent() || !aContext->GetParent()->IsInProcess())) {
// Send the inner window an activate/deactivate event if
// the context is the top of a sub-tree of in-process
// contexts.
nsContentUtils::DispatchEventOnlyToChrome(
doc, doc->GetWindow()->GetCurrentInnerWindow(),
isActivateEvent ? u"activate"_ns : u"deactivate"_ns,
doc, win, isActivateEvent ? u"activate"_ns : u"deactivate"_ns,
CanBubble::eYes, Cancelable::eYes, nullptr);
}
}
Expand Down
1 change: 1 addition & 0 deletions dom/base/Navigator.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ class Navigator final : public nsISupports, public nsWrapperCache {
already_AddRefed<LegacyMozTCPSocket> MozTCPSocket();
network::Connection* GetConnection(ErrorResult& aRv);
MediaDevices* GetMediaDevices(ErrorResult& aRv);
MediaDevices* GetExtantMediaDevices() const { return mMediaDevices; };

void GetGamepads(nsTArray<RefPtr<Gamepad>>& aGamepads, ErrorResult& aRv);
GamepadServiceTest* RequestGamepadServiceTest();
Expand Down
16 changes: 16 additions & 0 deletions dom/base/nsGlobalWindowInner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
#include "mozilla/dom/LocalStorage.h"
#include "mozilla/dom/LocalStorageCommon.h"
#include "mozilla/dom/Location.h"
#include "mozilla/dom/MediaDevices.h"
#include "mozilla/dom/MediaKeys.h"
#include "mozilla/dom/NavigatorBinding.h"
#include "mozilla/dom/Nullable.h"
Expand Down Expand Up @@ -2310,6 +2311,10 @@ Navigator* nsPIDOMWindowInner::Navigator() {
return mNavigator;
}

MediaDevices* nsPIDOMWindowInner::GetExtantMediaDevices() const {
return mNavigator ? mNavigator->GetExtantMediaDevices() : nullptr;
}

VisualViewport* nsGlobalWindowInner::VisualViewport() {
if (!mVisualViewport) {
mVisualViewport = new mozilla::dom::VisualViewport(this);
Expand Down Expand Up @@ -5570,6 +5575,10 @@ void nsGlobalWindowInner::Resume(bool aIncludeSubWindows) {
mAudioContexts[i]->ResumeFromChrome();
}

if (RefPtr<MediaDevices> devices = GetExtantMediaDevices()) {
devices->WindowResumed();
}

mTimeoutManager->Resume();

ResumeIdleRequests();
Expand Down Expand Up @@ -5721,6 +5730,13 @@ void nsGlobalWindowInner::SyncStateFromParentWindow() {
}
}

void nsGlobalWindowInner::UpdateBackgroundState() {
if (RefPtr<MediaDevices> devices = GetExtantMediaDevices()) {
devices->BackgroundStateChanged();
}
mTimeoutManager->UpdateBackgroundState();
}

template <typename Method, typename... Args>
CallState nsGlobalWindowInner::CallOnInProcessDescendantsInternal(
BrowsingContext* aBrowsingContext, bool aChildOnly, Method aMethod,
Expand Down
6 changes: 6 additions & 0 deletions dom/base/nsGlobalWindowInner.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,12 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
virtual bool IsFrozen() const override;
void SyncStateFromParentWindow();

// Called on the current inner window of a browsing context when its
// background state changes according to selected tab or visibility of the
// browser window. Used with Suspend()/Resume() or Freeze()/Thaw() because
// background state may change while the inner window is not current.
void UpdateBackgroundState();

mozilla::dom::DebuggerNotificationManager*
GetOrCreateDebuggerNotificationManager() override;

Expand Down
2 changes: 1 addition & 1 deletion dom/base/nsGlobalWindowOuter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6757,7 +6757,7 @@ void nsGlobalWindowOuter::SetIsBackground(bool aIsBackground) {
nsGlobalWindowInner* inner = GetCurrentInnerWindowInternal();

if (inner && changed) {
inner->mTimeoutManager->UpdateBackgroundState();
inner->UpdateBackgroundState();
}

if (aIsBackground) {
Expand Down
2 changes: 2 additions & 0 deletions dom/base/nsPIDOMWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class DocGroup;
class Document;
class Element;
class Location;
class MediaDevices;
class MediaKeys;
class Navigator;
class Performance;
Expand Down Expand Up @@ -577,6 +578,7 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
uint32_t GetMarkedCCGeneration() { return mMarkedCCGeneration; }

mozilla::dom::Navigator* Navigator();
mozilla::dom::MediaDevices* GetExtantMediaDevices() const;
virtual mozilla::dom::Location* Location() = 0;

virtual nsresult GetControllers(nsIControllers** aControllers) = 0;
Expand Down
46 changes: 39 additions & 7 deletions dom/media/MediaDevices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "mozilla/dom/MediaDevices.h"

#include "AudioDeviceInfo.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/MediaStreamBinding.h"
#include "mozilla/dom/MediaDeviceInfo.h"
Expand Down Expand Up @@ -139,10 +140,39 @@ already_AddRefed<Promise> MediaDevices::EnumerateDevices(ErrorResult& aRv) {
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
mPendingEnumerateDevicesPromises.AppendElement(p);
MaybeResumeDeviceExposure();
return p.forget();
}

void MediaDevices::MaybeResumeDeviceExposure() {
if (mPendingEnumerateDevicesPromises.IsEmpty()) {
return;
}
nsPIDOMWindowInner* window = GetOwner();
if (!window || !window->IsFullyActive()) {
return;
}
BrowsingContext* bc = window->GetBrowsingContext();
if (!bc->IsActive() || // not foreground tab
!bc->GetIsActiveBrowserWindow()) { // browser window does not have focus
return;
}

auto pending = std::move(mPendingEnumerateDevicesPromises);
for (auto& promise : pending) {
ResumeEnumerateDevices(std::move(promise));
}
}

void MediaDevices::ResumeEnumerateDevices(RefPtr<Promise> aPromise) {
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
MOZ_ASSERT(window, "Fully active document should have window");
RefPtr<MediaDevices> self(this);
MediaManager::Get()->EnumerateDevices(owner)->Then(
MediaManager::Get()->EnumerateDevices(window)->Then(
GetCurrentSerialEventTarget(), __func__,
[this, self, p](RefPtr<MediaManager::MediaDeviceSetRefCnt>&& aDevices) {
[this, self,
aPromise](RefPtr<MediaManager::MediaDeviceSetRefCnt>&& aDevices) {
nsPIDOMWindowInner* window = GetWindowIfCurrent();
if (!window) {
return; // Leave Promise pending after navigation by design.
Expand Down Expand Up @@ -189,16 +219,15 @@ already_AddRefed<Promise> MediaDevices::EnumerateDevices(ErrorResult& aRv) {
infos.AppendElement(MakeRefPtr<MediaDeviceInfo>(
device->mID, device->mKind, label, device->mGroupID));
}
p->MaybeResolve(std::move(infos));
aPromise->MaybeResolve(std::move(infos));
},
[this, self, p](const RefPtr<MediaMgrError>& error) {
[this, self, aPromise](const RefPtr<MediaMgrError>& error) {
nsPIDOMWindowInner* window = GetWindowIfCurrent();
if (!window) {
return; // Leave Promise pending after navigation by design.
}
error->Reject(p);
error->Reject(aPromise);
});
return p.forget();
}

already_AddRefed<Promise> MediaDevices::GetDisplayMedia(
Expand Down Expand Up @@ -479,7 +508,10 @@ RefPtr<MediaDevices::SinkInfoPromise> MediaDevices::GetSinkDevice(
});
}

NS_IMPL_ISUPPORTS_INHERITED0(MediaDevices, DOMEventTargetHelper)
NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(MediaDevices,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaDevices, DOMEventTargetHelper,
mPendingEnumerateDevicesPromises)

void MediaDevices::OnDeviceChange() {
MOZ_ASSERT(NS_IsMainThread());
Expand Down
8 changes: 8 additions & 0 deletions dom/media/MediaDevices.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class MediaDevices final : public DOMEventTargetHelper {
explicit MediaDevices(nsPIDOMWindowInner* aWindow);

NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaDevices, DOMEventTargetHelper)

JSObject* WrapObject(JSContext* cx,
JS::Handle<JSObject*> aGivenProto) override;
Expand Down Expand Up @@ -79,14 +80,21 @@ class MediaDevices final : public DOMEventTargetHelper {
void EventListenerAdded(nsAtom* aType) override;
using DOMEventTargetHelper::EventListenerAdded;

void BackgroundStateChanged() { MaybeResumeDeviceExposure(); }
void WindowResumed() { MaybeResumeDeviceExposure(); }
void BrowserWindowBecameActive() { MaybeResumeDeviceExposure(); }

private:
class GumResolver;
class EnumDevResolver;
class GumRejecter;

virtual ~MediaDevices();
void MaybeResumeDeviceExposure();
void ResumeEnumerateDevices(RefPtr<Promise> aPromise);

nsTHashSet<nsString> mExplicitlyGrantedAudioOutputIds;
nsTArray<RefPtr<Promise>> mPendingEnumerateDevicesPromises;
nsCOMPtr<nsITimer> mFuzzTimer;

// Connect/Disconnect on main thread only
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
[enumerateDevices-in-background.https.html]
disabled:
if buildapp != 'browser': uses Firefox-for-Desktop specific API
[enumerateDevices in background]
expected: FAIL

This file was deleted.

0 comments on commit 9edf2f2

Please sign in to comment.