From f0910370b4ded40191beed3586c1614ca75a9b9e Mon Sep 17 00:00:00 2001 From: Chun-Min Chang Date: Tue, 18 Aug 2020 18:28:19 +0000 Subject: [PATCH] Bug 1635209 - Implement SetSupportedMediaKeys on Windows r=alwu Enable the media keys on the SMTC UI panel only when their key-press handlers are set Differential Revision: https://phabricator.services.mozilla.com/D86226 --- dom/media/mediacontrol/MediaControlUtils.h | 4 + widget/gtk/MPRISServiceHandler.cpp | 4 - widget/windows/WindowsSMTCProvider.cpp | 111 ++++++++++++++++----- widget/windows/WindowsSMTCProvider.h | 35 +++---- 4 files changed, 102 insertions(+), 52 deletions(-) diff --git a/dom/media/mediacontrol/MediaControlUtils.h b/dom/media/mediacontrol/MediaControlUtils.h index a23952f53b39..66ded7fb35f9 100644 --- a/dom/media/mediacontrol/MediaControlUtils.h +++ b/dom/media/mediacontrol/MediaControlUtils.h @@ -207,6 +207,10 @@ inline bool IsValidImageUrl(const nsAString& aUrl) { StringBeginsWith(aUrl, u"https://"_ns); } +inline uint32_t GetMediaKeyMask(mozilla::dom::MediaControlKey aKey) { + return 1 << static_cast(aKey); +} + } // namespace dom } // namespace mozilla diff --git a/widget/gtk/MPRISServiceHandler.cpp b/widget/gtk/MPRISServiceHandler.cpp index cda1b66f66ba..072df115599f 100644 --- a/widget/gtk/MPRISServiceHandler.cpp +++ b/widget/gtk/MPRISServiceHandler.cpp @@ -735,10 +735,6 @@ void MPRISServiceHandler::EmitEvent(mozilla::dom::MediaControlKey aKey) const { } } -static uint32_t GetMediaKeyMask(mozilla::dom::MediaControlKey aKey) { - return 1 << static_cast(aKey); -} - struct InterfaceProperty { const char* interface; const char* property; diff --git a/widget/windows/WindowsSMTCProvider.cpp b/widget/windows/WindowsSMTCProvider.cpp index fa1d430b8700..0933508a1ff8 100644 --- a/widget/windows/WindowsSMTCProvider.cpp +++ b/widget/windows/WindowsSMTCProvider.cpp @@ -148,13 +148,20 @@ bool WindowsSMTCProvider::Open() { return false; } - if (!SetControlAttributes(SMTCControlAttributes::EnableAll())) { - LOG("Failed to set control attributes"); + if (!EnableControl(true)) { + LOG("Failed to enable SMTC control"); + return false; + } + + if (!UpdateButtons()) { + LOG("Failed to initialize the buttons"); + Unused << EnableControl(false); return false; } if (!RegisterEvents()) { LOG("Failed to register SMTC key-event listener"); + Unused << EnableControl(false); return false; } @@ -167,7 +174,7 @@ void WindowsSMTCProvider::Close() { MediaControlKeySource::Close(); if (mInitialized) { // Prevent calling Set methods when init failed SetPlaybackState(mozilla::dom::MediaSessionPlaybackState::None); - SetControlAttributes(SMTCControlAttributes::DisableAll()); + EnableControl(false); mInitialized = false; } @@ -183,6 +190,8 @@ void WindowsSMTCProvider::Close() { mProcessingUrl = EmptyString(); mNextImageIndex = 0; + + mSupportedKeys = 0; } void WindowsSMTCProvider::SetPlaybackState( @@ -227,6 +236,25 @@ void WindowsSMTCProvider::SetMediaMetadata( LoadThumbnail(aMetadata.mArtwork); } +void WindowsSMTCProvider::SetSupportedMediaKeys( + const MediaKeysArray& aSupportedKeys) { + MOZ_ASSERT(mInitialized); + + uint32_t supportedKeys = 0; + for (const mozilla::dom::MediaControlKey& key : aSupportedKeys) { + supportedKeys |= GetMediaKeyMask(key); + } + + if (supportedKeys == mSupportedKeys) { + LOG("Supported keys stay the same"); + return; + } + + LOG("Update supported keys"); + mSupportedKeys = supportedKeys; + UpdateButtons(); +} + void WindowsSMTCProvider::UnregisterEvents() { if (mControls && mButtonPressedToken.value != 0) { mControls->remove_ButtonPressed(mButtonPressedToken); @@ -268,12 +296,64 @@ bool WindowsSMTCProvider::RegisterEvents() { return true; } -void WindowsSMTCProvider::OnButtonPressed(mozilla::dom::MediaControlKey aKey) { +void WindowsSMTCProvider::OnButtonPressed( + mozilla::dom::MediaControlKey aKey) const { + if (!IsKeySupported(aKey)) { + LOG("key: %s is not supported", ToMediaControlKeyStr(aKey)); + return; + } + for (auto& listener : mListeners) { listener->OnActionPerformed(mozilla::dom::MediaControlAction(aKey)); } } +bool WindowsSMTCProvider::EnableControl(bool aEnabled) const { + MOZ_ASSERT(mControls); + return SUCCEEDED(mControls->put_IsEnabled(aEnabled)); +} + +bool WindowsSMTCProvider::UpdateButtons() const { + static const mozilla::dom::MediaControlKey kKeys[] = { + mozilla::dom::MediaControlKey::Play, mozilla::dom::MediaControlKey::Pause, + mozilla::dom::MediaControlKey::Previoustrack, + mozilla::dom::MediaControlKey::Nexttrack}; + + bool success = true; + for (const mozilla::dom::MediaControlKey& key : kKeys) { + if (!EnableKey(key, IsKeySupported(key))) { + success = false; + LOG("Failed to set %s=%s", ToMediaControlKeyStr(key), + IsKeySupported(key) ? "true" : "false"); + } + } + + return success; +} + +bool WindowsSMTCProvider::IsKeySupported( + mozilla::dom::MediaControlKey aKey) const { + return mSupportedKeys & GetMediaKeyMask(aKey); +} + +bool WindowsSMTCProvider::EnableKey(mozilla::dom::MediaControlKey aKey, + bool aEnable) const { + MOZ_ASSERT(mControls); + switch (aKey) { + case mozilla::dom::MediaControlKey::Play: + return SUCCEEDED(mControls->put_IsPlayEnabled(aEnable)); + case mozilla::dom::MediaControlKey::Pause: + return SUCCEEDED(mControls->put_IsPauseEnabled(aEnable)); + case mozilla::dom::MediaControlKey::Previoustrack: + return SUCCEEDED(mControls->put_IsPreviousEnabled(aEnable)); + case mozilla::dom::MediaControlKey::Nexttrack: + return SUCCEEDED(mControls->put_IsNextEnabled(aEnable)); + default: + LOG("No button for %s", ToMediaControlKeyStr(aKey)); + return false; + } +} + bool WindowsSMTCProvider::InitDisplayAndControls() { // As Open() might be called multiple times, "cache" the results of the COM // API @@ -308,29 +388,6 @@ bool WindowsSMTCProvider::InitDisplayAndControls() { return true; } -bool WindowsSMTCProvider::SetControlAttributes( - SMTCControlAttributes aAttributes) { - MOZ_ASSERT(mControls); - - if (FAILED(mControls->put_IsEnabled(aAttributes.mEnabled))) { - return false; - } - if (FAILED(mControls->put_IsPauseEnabled(aAttributes.mPlayPauseEnabled))) { - return false; - } - if (FAILED(mControls->put_IsPlayEnabled(aAttributes.mPlayPauseEnabled))) { - return false; - } - if (FAILED(mControls->put_IsNextEnabled(aAttributes.mNextEnabled))) { - return false; - } - if (FAILED(mControls->put_IsPreviousEnabled(aAttributes.mPreviousEnabled))) { - return false; - } - - return true; -} - bool WindowsSMTCProvider::SetMusicMetadata(const wchar_t* aArtist, const wchar_t* aTitle, const wchar_t* aAlbumArtist) { diff --git a/widget/windows/WindowsSMTCProvider.h b/widget/windows/WindowsSMTCProvider.h index ba5a08071e34..2fd9bec6bbba 100644 --- a/widget/windows/WindowsSMTCProvider.h +++ b/widget/windows/WindowsSMTCProvider.h @@ -28,20 +28,6 @@ using ABI::Windows::Storage::Streams::IRandomAccessStream; using ABI::Windows::Storage::Streams::IRandomAccessStreamReference; using Microsoft::WRL::ComPtr; -struct SMTCControlAttributes { - bool mEnabled; - bool mPlayPauseEnabled; - bool mNextEnabled; - bool mPreviousEnabled; - - static constexpr SMTCControlAttributes EnableAll() { - return {true, true, true, true}; - } - static constexpr SMTCControlAttributes DisableAll() { - return {false, false, false, false}; - } -}; - class WindowsSMTCProvider final : public mozilla::dom::MediaControlKeySource { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WindowsSMTCProvider, override) @@ -58,21 +44,24 @@ class WindowsSMTCProvider final : public mozilla::dom::MediaControlKeySource { void SetMediaMetadata( const mozilla::dom::MediaMetadataBase& aMetadata) override; - // TODO : modify the virtual control interface based on the supported keys - void SetSupportedMediaKeys(const MediaKeysArray& aSupportedKeys) override {} + void SetSupportedMediaKeys(const MediaKeysArray& aSupportedKeys) override; private: ~WindowsSMTCProvider(); void UnregisterEvents(); bool RegisterEvents(); - void OnButtonPressed(mozilla::dom::MediaControlKey aKey); + + void OnButtonPressed(mozilla::dom::MediaControlKey aKey) const; + // Enable the SMTC interface + bool EnableControl(bool aEnabled) const; + // Sets the play, pause, next, previous buttons on the SMTC interface by + // mSupportedKeys + bool UpdateButtons() const; + bool IsKeySupported(mozilla::dom::MediaControlKey aKey) const; + bool EnableKey(mozilla::dom::MediaControlKey aKey, bool aEnable) const; bool InitDisplayAndControls(); - // Sets the state of the UI Panel (enabled, can use PlayPause, Next, Previous - // Buttons) - bool SetControlAttributes(SMTCControlAttributes aAttributes); - // Sets the Metadata for the currently playing media and sets the playback // type to "MUSIC" bool SetMusicMetadata(const wchar_t* aArtist, const wchar_t* aTitle, @@ -94,6 +83,10 @@ class WindowsSMTCProvider final : public mozilla::dom::MediaControlKeySource { void CancelPendingStoreAsyncOperation() const; bool mInitialized = false; + + // A bit table indicating what keys are enabled + uint32_t mSupportedKeys = 0; + ComPtr mControls; ComPtr mDisplay;