From 086c044dc34dfc0f74fbe41f4ecb402b2cd34884 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:13:33 +0200 Subject: Merging upstream version 125.0.1. Signed-off-by: Daniel Baumann --- widget/windows/WindowsSMTCProvider.cpp | 179 ++++++++++++++++++++++++++++++++- 1 file changed, 176 insertions(+), 3 deletions(-) (limited to 'widget/windows/WindowsSMTCProvider.cpp') diff --git a/widget/windows/WindowsSMTCProvider.cpp b/widget/windows/WindowsSMTCProvider.cpp index 04d833a8e7..69915cafd8 100644 --- a/widget/windows/WindowsSMTCProvider.cpp +++ b/widget/windows/WindowsSMTCProvider.cpp @@ -255,6 +255,25 @@ void WindowsSMTCProvider::UnregisterEvents() { if (mControls && mButtonPressedToken.value != 0) { mControls->remove_ButtonPressed(mButtonPressedToken); } + + if (mControls && mSeekRegistrationToken.value != 0) { + ComPtr smtc2; + HRESULT hr = mControls.As(&smtc2); + if (FAILED(hr)) { + LOG("Failed to cast controls to ISystemMediaTransportControls2 (hr=%lx)", + hr); + return; + } + MOZ_ASSERT(smtc2); + + hr = smtc2->remove_PlaybackPositionChangeRequested(mSeekRegistrationToken); + if (FAILED(hr)) { + LOG("SystemMediaTransportControls: Failed unregister position change " + "event (hr=%lx)", + hr); + return; + } + } } bool WindowsSMTCProvider::RegisterEvents() { @@ -289,6 +308,48 @@ bool WindowsSMTCProvider::RegisterEvents() { return false; } + ComPtr smtc2; + HRESULT hr = mControls.As(&smtc2); + if (FAILED(hr)) { + LOG("Failed to cast controls to ISystemMediaTransportControls2 (hr=%lx)", + hr); + return false; + } + MOZ_ASSERT(smtc2); + + auto positionChangeRequested = + Callback>( + [this, self]( + ISystemMediaTransportControls*, + IPlaybackPositionChangeRequestedEventArgs* pArgs) -> HRESULT { + MOZ_ASSERT(pArgs); + + TimeSpan value; + HRESULT hr = pArgs->get_RequestedPlaybackPosition(&value); + if (FAILED(hr)) { + LOG("SystemMediaTransportControls: Playback Position Change - " + "failed to get requested position (hr=%lx)", + hr); + return S_OK; // Propagating the error probably wouldn't help. + } + + double position = + static_cast(value.Duration) / (1e6 * 10.0); + this->OnPositionChangeRequested(position); + + return S_OK; + }); + + hr = smtc2->add_PlaybackPositionChangeRequested(positionChangeRequested.Get(), + &mSeekRegistrationToken); + if (FAILED(hr)) { + LOG("SystemMediaTransportControls: Failed to register position change " + "event (hr=%lx)", + hr); + return false; + } + return true; } @@ -309,12 +370,14 @@ bool WindowsSMTCProvider::EnableControl(bool aEnabled) const { return SUCCEEDED(mControls->put_IsEnabled(aEnabled)); } -bool WindowsSMTCProvider::UpdateButtons() const { +bool WindowsSMTCProvider::UpdateButtons() { static const mozilla::dom::MediaControlKey kKeys[] = { - mozilla::dom::MediaControlKey::Play, mozilla::dom::MediaControlKey::Pause, + mozilla::dom::MediaControlKey::Play, + mozilla::dom::MediaControlKey::Pause, mozilla::dom::MediaControlKey::Previoustrack, mozilla::dom::MediaControlKey::Nexttrack, - mozilla::dom::MediaControlKey::Stop}; + mozilla::dom::MediaControlKey::Stop, + mozilla::dom::MediaControlKey::Seekto}; bool success = true; for (const mozilla::dom::MediaControlKey& key : kKeys) { @@ -347,12 +410,28 @@ bool WindowsSMTCProvider::EnableKey(mozilla::dom::MediaControlKey aKey, return SUCCEEDED(mControls->put_IsNextEnabled(aEnable)); case mozilla::dom::MediaControlKey::Stop: return SUCCEEDED(mControls->put_IsStopEnabled(aEnable)); + case mozilla::dom::MediaControlKey::Seekto: + // The callback for the event checks if the key is supported + return mSeekRegistrationToken.value != 0; default: LOG("No button for %s", ToMediaControlKeyStr(aKey)); return false; } } +void WindowsSMTCProvider::OnPositionChangeRequested(double aPosition) const { + if (!IsKeySupported(mozilla::dom::MediaControlKey::Seekto)) { + LOG("Seekto is not supported"); + return; + } + + for (const auto& listener : mListeners) { + listener->OnActionPerformed( + mozilla::dom::MediaControlAction(mozilla::dom::MediaControlKey::Seekto, + mozilla::dom::SeekDetails(aPosition))); + } +} + bool WindowsSMTCProvider::InitDisplayAndControls() { // As Open() might be called multiple times, "cache" the results of the COM // API @@ -422,6 +501,100 @@ bool WindowsSMTCProvider::SetMusicMetadata(const nsString& aArtist, return true; } +void WindowsSMTCProvider::SetPositionState( + const mozilla::Maybe& aState) { + ComPtr smtc2; + HRESULT hr = mControls.As(&smtc2); + if (FAILED(hr)) { + LOG("Failed to cast controls to ISystemMediaTransportControls2 (hr=%lx)", + hr); + return; + } + MOZ_ASSERT(smtc2); + + ComPtr properties; + hr = RoActivateInstance( + HStringReference( + RuntimeClass_Windows_Media_SystemMediaTransportControlsTimelineProperties) + .Get(), + &properties); + if (FAILED(hr)) { + LOG("Failed to create timeline properties (hr=%lx)", hr); + return; + } + MOZ_ASSERT(properties); + + // Converts a value in seconds to a TimeSpan + // The TimeSpan's Duration is a value in 100ns ticks + // https://learn.microsoft.com/en-us/windows/win32/api/windows.foundation/ns-windows-foundation-timespan#members + auto toTimeSpan = [this](double seconds) { + constexpr double kMaxMicroseconds = + static_cast(std::numeric_limits::max() / 10); + + double microseconds = seconds * 1e6; + + if (microseconds > kMaxMicroseconds) { + LOG("Failed to convert %f microseconds to TimeSpan (overflow)", + microseconds); + return TimeSpan{0}; + } + + return TimeSpan{static_cast(microseconds * 10.0)}; + }; + + TimeSpan endTime{0}; + TimeSpan position{0}; + double playbackRate = 1.0; + + if (aState) { + endTime = toTimeSpan(aState->mDuration); + position = toTimeSpan(aState->CurrentPlaybackPosition()); + playbackRate = aState->mPlaybackRate; + } + + hr = properties->put_StartTime({0}); + if (FAILED(hr)) { + LOG("Failed to set the start time (hr=%lx)", hr); + return; + } + + hr = properties->put_MinSeekTime({0}); + if (FAILED(hr)) { + LOG("Failed to set the min seek time (hr=%lx)", hr); + return; + } + + hr = properties->put_EndTime(endTime); + if (FAILED(hr)) { + LOG("Failed to set the end time (hr=%lx)", hr); + return; + } + + hr = properties->put_MaxSeekTime(endTime); + if (FAILED(hr)) { + LOG("Failed to set the max seek time (hr=%lx)", hr); + return; + } + + hr = properties->put_Position(position); + if (FAILED(hr)) { + LOG("Failed to set the playback position (hr=%lx)", hr); + return; + } + + hr = smtc2->UpdateTimelineProperties(properties.Get()); + if (FAILED(hr)) { + LOG("Failed to update timeline properties (hr=%lx)", hr); + return; + } + + hr = smtc2->put_PlaybackRate(playbackRate); + if (FAILED(hr)) { + LOG("Failed to set the playback rate (hr=%lx)", hr); + return; + } +} + void WindowsSMTCProvider::LoadThumbnail( const nsTArray& aArtwork) { MOZ_ASSERT(NS_IsMainThread()); -- cgit v1.2.3