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
This commit is contained in:
Chun-Min Chang 2020-08-18 18:28:19 +00:00
parent 8b6cb52259
commit f0910370b4
4 changed files with 102 additions and 52 deletions

View File

@ -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<uint8_t>(aKey);
}
} // namespace dom
} // namespace mozilla

View File

@ -735,10 +735,6 @@ void MPRISServiceHandler::EmitEvent(mozilla::dom::MediaControlKey aKey) const {
}
}
static uint32_t GetMediaKeyMask(mozilla::dom::MediaControlKey aKey) {
return 1 << static_cast<uint8_t>(aKey);
}
struct InterfaceProperty {
const char* interface;
const char* property;

View File

@ -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) {

View File

@ -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<ISMTC> mControls;
ComPtr<ISMTCDisplayUpdater> mDisplay;