Bug 1634192 - Implement Seek and SetPosition for MPRIS r=media-playback-reviewers,stransky,alwu,win-reviewers,gstoll
Differential Revision: https://phabricator.services.mozilla.com/D212939
This commit is contained in:
@@ -54,8 +54,8 @@ interface MediaController : EventTarget {
|
||||
undefined stop();
|
||||
undefined prevTrack();
|
||||
undefined nextTrack();
|
||||
undefined seekBackward();
|
||||
undefined seekForward();
|
||||
undefined seekBackward(double seekOffset);
|
||||
undefined seekForward(double seekOffset);
|
||||
undefined skipAd();
|
||||
undefined seekTo(double seekTime, optional boolean fastSeek = false);
|
||||
};
|
||||
|
||||
@@ -120,12 +120,22 @@ void ContentPlaybackController::Pause() {
|
||||
}
|
||||
}
|
||||
|
||||
void ContentPlaybackController::SeekBackward() {
|
||||
NotifyMediaSessionWhenActionIsSupported(MediaSessionAction::Seekbackward);
|
||||
void ContentPlaybackController::SeekBackward(double aSeekOffset) {
|
||||
MediaSessionActionDetails details;
|
||||
details.mAction = MediaSessionAction::Seekbackward;
|
||||
details.mSeekOffset.Construct(aSeekOffset);
|
||||
if (IsMediaSessionActionSupported(details.mAction)) {
|
||||
NotifyMediaSession(details);
|
||||
}
|
||||
}
|
||||
|
||||
void ContentPlaybackController::SeekForward() {
|
||||
NotifyMediaSessionWhenActionIsSupported(MediaSessionAction::Seekforward);
|
||||
void ContentPlaybackController::SeekForward(double aSeekOffset) {
|
||||
MediaSessionActionDetails details;
|
||||
details.mAction = MediaSessionAction::Seekforward;
|
||||
details.mSeekOffset.Construct(aSeekOffset);
|
||||
if (IsMediaSessionActionSupported(details.mAction)) {
|
||||
NotifyMediaSession(details);
|
||||
}
|
||||
}
|
||||
|
||||
void ContentPlaybackController::PreviousTrack() {
|
||||
@@ -195,18 +205,26 @@ void ContentMediaControlKeyHandler::HandleMediaControlAction(
|
||||
case MediaControlKey::Nexttrack:
|
||||
controller.NextTrack();
|
||||
return;
|
||||
case MediaControlKey::Seekbackward:
|
||||
controller.SeekBackward();
|
||||
case MediaControlKey::Seekbackward: {
|
||||
const SeekDetails& details = *aAction.mDetails;
|
||||
MOZ_ASSERT(details.mRelativeSeekOffset);
|
||||
controller.SeekBackward(details.mRelativeSeekOffset.value());
|
||||
return;
|
||||
case MediaControlKey::Seekforward:
|
||||
controller.SeekForward();
|
||||
}
|
||||
case MediaControlKey::Seekforward: {
|
||||
const SeekDetails& details = *aAction.mDetails;
|
||||
MOZ_ASSERT(details.mRelativeSeekOffset);
|
||||
controller.SeekForward(details.mRelativeSeekOffset.value());
|
||||
return;
|
||||
}
|
||||
case MediaControlKey::Skipad:
|
||||
controller.SkipAd();
|
||||
return;
|
||||
case MediaControlKey::Seekto: {
|
||||
const SeekDetails& details = *aAction.mDetails;
|
||||
controller.SeekTo(details.mSeekTime, details.mFastSeek);
|
||||
MOZ_ASSERT(details.mAbsolute);
|
||||
controller.SeekTo(details.mAbsolute->mSeekTime,
|
||||
details.mAbsolute->mFastSeek);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -42,8 +42,8 @@ class MOZ_STACK_CLASS ContentPlaybackController {
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY void Focus();
|
||||
void Play();
|
||||
void Pause();
|
||||
void SeekBackward();
|
||||
void SeekForward();
|
||||
void SeekBackward(double aSeekOffset);
|
||||
void SeekForward(double aSeekOffset);
|
||||
void PreviousTrack();
|
||||
void NextTrack();
|
||||
void SkipAd();
|
||||
|
||||
@@ -35,8 +35,8 @@ struct ParamTraits<mozilla::dom::MediaAudibleState>
|
||||
mozilla::dom::MediaAudibleState::eAudible> {};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::SeekDetails> {
|
||||
typedef mozilla::dom::SeekDetails paramType;
|
||||
struct ParamTraits<mozilla::dom::AbsoluteSeek> {
|
||||
typedef mozilla::dom::AbsoluteSeek paramType;
|
||||
|
||||
static void Write(MessageWriter* aWriter, const paramType& aParam) {
|
||||
WriteParam(aWriter, aParam.mSeekTime);
|
||||
@@ -52,6 +52,24 @@ struct ParamTraits<mozilla::dom::SeekDetails> {
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::SeekDetails> {
|
||||
typedef mozilla::dom::SeekDetails paramType;
|
||||
|
||||
static void Write(MessageWriter* aWriter, const paramType& aParam) {
|
||||
WriteParam(aWriter, aParam.mAbsolute);
|
||||
WriteParam(aWriter, aParam.mRelativeSeekOffset);
|
||||
}
|
||||
|
||||
static bool Read(MessageReader* aReader, paramType* aResult) {
|
||||
if (!ReadParam(aReader, &aResult->mAbsolute) ||
|
||||
!ReadParam(aReader, &aResult->mRelativeSeekOffset)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::dom::MediaControlAction> {
|
||||
typedef mozilla::dom::MediaControlAction paramType;
|
||||
|
||||
@@ -64,18 +64,26 @@ void MediaControlKeyHandler::OnActionPerformed(
|
||||
case MediaControlKey::Nexttrack:
|
||||
controller->NextTrack();
|
||||
return;
|
||||
case MediaControlKey::Seekbackward:
|
||||
controller->SeekBackward();
|
||||
case MediaControlKey::Seekbackward: {
|
||||
const SeekDetails& details = *aAction.mDetails;
|
||||
MOZ_ASSERT(details.mRelativeSeekOffset);
|
||||
controller->SeekBackward(fmin(details.mRelativeSeekOffset.value(), 10.0));
|
||||
return;
|
||||
case MediaControlKey::Seekforward:
|
||||
controller->SeekForward();
|
||||
}
|
||||
case MediaControlKey::Seekforward: {
|
||||
const SeekDetails& details = *aAction.mDetails;
|
||||
MOZ_ASSERT(details.mRelativeSeekOffset);
|
||||
controller->SeekForward(fmin(details.mRelativeSeekOffset.value(), 10.0));
|
||||
return;
|
||||
}
|
||||
case MediaControlKey::Skipad:
|
||||
controller->SkipAd();
|
||||
return;
|
||||
case MediaControlKey::Seekto: {
|
||||
const SeekDetails& details = *aAction.mDetails;
|
||||
controller->SeekTo(details.mSeekTime, details.mFastSeek);
|
||||
MOZ_ASSERT(details.mAbsolute);
|
||||
controller->SeekTo(details.mAbsolute->mSeekTime,
|
||||
details.mAbsolute->mFastSeek);
|
||||
return;
|
||||
}
|
||||
case MediaControlKey::Stop:
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef DOM_MEDIA_MEDIACONTROL_MEDIACONTROLKEYSOURCE_H_
|
||||
#define DOM_MEDIA_MEDIACONTROL_MEDIACONTROLKEYSOURCE_H_
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/dom/MediaControllerBinding.h"
|
||||
#include "mozilla/dom/MediaMetadata.h"
|
||||
#include "mozilla/dom/MediaSession.h"
|
||||
@@ -15,15 +16,20 @@
|
||||
namespace mozilla::dom {
|
||||
|
||||
// This is used to store seek related properties from MediaSessionActionDetails.
|
||||
// However, currently we have no plan to support `seekOffset`.
|
||||
// https://w3c.github.io/mediasession/#the-mediasessionactiondetails-dictionary
|
||||
struct AbsoluteSeek {
|
||||
double mSeekTime;
|
||||
bool mFastSeek;
|
||||
};
|
||||
struct SeekDetails {
|
||||
Maybe<AbsoluteSeek> mAbsolute;
|
||||
Maybe<double> mRelativeSeekOffset;
|
||||
|
||||
SeekDetails() = default;
|
||||
explicit SeekDetails(double aSeekTime) : mSeekTime(aSeekTime) {}
|
||||
SeekDetails(double aSeekTime, bool aFastSeek)
|
||||
: mSeekTime(aSeekTime), mFastSeek(aFastSeek) {}
|
||||
double mSeekTime = 0.0;
|
||||
bool mFastSeek = false;
|
||||
: mAbsolute(Some(AbsoluteSeek{aSeekTime, aFastSeek})) {}
|
||||
explicit SeekDetails(double aRelativeSeekOffset)
|
||||
: mRelativeSeekOffset(Some(aRelativeSeekOffset)) {}
|
||||
};
|
||||
|
||||
struct MediaControlAction {
|
||||
|
||||
@@ -307,11 +307,18 @@ void MediaControlService::GenerateTestMediaControlKey(MediaControlKey aKey) {
|
||||
if (!StaticPrefs::media_mediacontrol_testingevents_enabled()) {
|
||||
return;
|
||||
}
|
||||
// Generate a seek details for `seekto`
|
||||
if (aKey == MediaControlKey::Seekto) {
|
||||
// Generate seek details when necessary
|
||||
switch (aKey) {
|
||||
case MediaControlKey::Seekto:
|
||||
mMediaKeysHandler->OnActionPerformed(
|
||||
MediaControlAction(aKey, SeekDetails()));
|
||||
} else {
|
||||
MediaControlAction(aKey, SeekDetails(0.0, false /* fast seek */)));
|
||||
break;
|
||||
case MediaControlKey::Seekbackward:
|
||||
case MediaControlKey::Seekforward:
|
||||
mMediaKeysHandler->OnActionPerformed(
|
||||
MediaControlAction(aKey, SeekDetails(0.0)));
|
||||
break;
|
||||
default:
|
||||
mMediaKeysHandler->OnActionPerformed(MediaControlAction(aKey));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,16 +142,16 @@ void MediaController::NextTrack() {
|
||||
MediaControlAction(MediaControlKey::Nexttrack));
|
||||
}
|
||||
|
||||
void MediaController::SeekBackward() {
|
||||
void MediaController::SeekBackward(double aSeekOffset) {
|
||||
LOG("Seek Backward");
|
||||
UpdateMediaControlActionToContentMediaIfNeeded(
|
||||
MediaControlAction(MediaControlKey::Seekbackward));
|
||||
UpdateMediaControlActionToContentMediaIfNeeded(MediaControlAction(
|
||||
MediaControlKey::Seekbackward, SeekDetails(aSeekOffset)));
|
||||
}
|
||||
|
||||
void MediaController::SeekForward() {
|
||||
void MediaController::SeekForward(double aSeekOffset) {
|
||||
LOG("Seek Forward");
|
||||
UpdateMediaControlActionToContentMediaIfNeeded(
|
||||
MediaControlAction(MediaControlKey::Seekforward));
|
||||
UpdateMediaControlActionToContentMediaIfNeeded(MediaControlAction(
|
||||
MediaControlKey::Seekforward, SeekDetails(aSeekOffset)));
|
||||
}
|
||||
|
||||
void MediaController::SkipAd() {
|
||||
|
||||
@@ -36,8 +36,8 @@ class IMediaController {
|
||||
virtual void Stop() = 0;
|
||||
virtual void PrevTrack() = 0;
|
||||
virtual void NextTrack() = 0;
|
||||
virtual void SeekBackward() = 0;
|
||||
virtual void SeekForward() = 0;
|
||||
virtual void SeekBackward(double aSeekOffset) = 0;
|
||||
virtual void SeekForward(double aSeekOffset) = 0;
|
||||
virtual void SkipAd() = 0;
|
||||
virtual void SeekTo(double aSeekTime, bool aFastSeek) = 0;
|
||||
|
||||
@@ -104,8 +104,8 @@ class MediaController final : public DOMEventTargetHelper,
|
||||
void Stop() override;
|
||||
void PrevTrack() override;
|
||||
void NextTrack() override;
|
||||
void SeekBackward() override;
|
||||
void SeekForward() override;
|
||||
void SeekBackward(double aSeekOffset) override;
|
||||
void SeekForward(double aSeekOffset) override;
|
||||
void SkipAd() override;
|
||||
void SeekTo(double aSeekTime, bool aFastSeek) override;
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ skip-if = ["verify && os == 'mac'"] # bug 1673509
|
||||
["browser_media_control_position_state.js"]
|
||||
skip-if = ["apple_catalina && !debug"] # Bug 1775892
|
||||
|
||||
["browser_media_control_seekto.js"]
|
||||
["browser_media_control_seek.js"]
|
||||
|
||||
["browser_media_control_stop_timer.js"]
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ add_task(async function testSetPositionState() {
|
||||
seekTime: seektime,
|
||||
});
|
||||
|
||||
info(`seek to ${seektime} seconds and set fastseek to boolean`);
|
||||
info(`seek to ${seektime} seconds and set fastseek to true`);
|
||||
await PerformSeekTo(tab, {
|
||||
seekTime: seektime,
|
||||
fastSeek: true,
|
||||
@@ -44,6 +44,28 @@ add_task(async function testSetPositionState() {
|
||||
await tab.close();
|
||||
});
|
||||
|
||||
add_task(async function testSeekRelative() {
|
||||
info(`open media page`);
|
||||
const tab = await createLoadedTabWrapper(PAGE_URL);
|
||||
|
||||
info(`start media`);
|
||||
await playMedia(tab, testVideoId);
|
||||
|
||||
const seekoffset = 5;
|
||||
info(`seek forward ${seekoffset} seconds`);
|
||||
await PerformSeekRelative(tab, "seekforward", {
|
||||
seekOffset: seekoffset,
|
||||
});
|
||||
|
||||
info(`seek backward ${seekoffset} seconds`);
|
||||
await PerformSeekRelative(tab, "seekbackward", {
|
||||
seekOffset: seekoffset,
|
||||
});
|
||||
|
||||
info(`remove tab`);
|
||||
await tab.close();
|
||||
});
|
||||
|
||||
/**
|
||||
* The following is helper function.
|
||||
*/
|
||||
@@ -82,10 +104,46 @@ async function PerformSeekTo(tab, seekDetails) {
|
||||
[testVideoId],
|
||||
Id => {
|
||||
const video = content.document.getElementById(Id);
|
||||
return new Promise(r => (video.onseeking = r()));
|
||||
return new Promise(r => (video.onseeked = r()));
|
||||
}
|
||||
);
|
||||
const { seekTime, fastSeek } = seekDetails;
|
||||
tab.linkedBrowser.browsingContext.mediaController.seekTo(seekTime, fastSeek);
|
||||
await seekPromise;
|
||||
}
|
||||
|
||||
async function PerformSeekRelative(tab, mode, seekDetails) {
|
||||
await SpecialPowers.spawn(
|
||||
tab.linkedBrowser,
|
||||
[seekDetails, mode, testVideoId],
|
||||
(seekDetails, mode, Id) => {
|
||||
const { seekOffset } = seekDetails;
|
||||
content.navigator.mediaSession.setActionHandler(mode, details => {
|
||||
Assert.notEqual(
|
||||
details.seekOffset,
|
||||
undefined,
|
||||
"Seekoffset must be presented"
|
||||
);
|
||||
is(seekOffset, details.seekOffset, "Get correct seekoffset");
|
||||
|
||||
content.document.getElementById(Id).currentTime +=
|
||||
mode == "seekForward" ? seekOffset : -seekOffset;
|
||||
});
|
||||
}
|
||||
);
|
||||
const seekPromise = SpecialPowers.spawn(
|
||||
tab.linkedBrowser,
|
||||
[testVideoId],
|
||||
Id => {
|
||||
const video = content.document.getElementById(Id);
|
||||
return new Promise(r => (video.onseeked = r()));
|
||||
}
|
||||
);
|
||||
const { seekOffset } = seekDetails;
|
||||
if (mode === "seekforward") {
|
||||
tab.linkedBrowser.browsingContext.mediaController.seekForward(seekOffset);
|
||||
} else {
|
||||
tab.linkedBrowser.browsingContext.mediaController.seekBackward(seekOffset);
|
||||
}
|
||||
await seekPromise;
|
||||
}
|
||||
@@ -49,7 +49,9 @@ static inline Maybe<dom::MediaControlKey> GetMediaControlKey(
|
||||
{"Pause", dom::MediaControlKey::Pause},
|
||||
{"PlayPause", dom::MediaControlKey::Playpause},
|
||||
{"Stop", dom::MediaControlKey::Stop},
|
||||
{"Play", dom::MediaControlKey::Play}};
|
||||
{"Play", dom::MediaControlKey::Play},
|
||||
{"SetPosition", dom::MediaControlKey::Seekto},
|
||||
{"Seek", dom::MediaControlKey::Seekforward}};
|
||||
|
||||
auto it = map.find(aMethodName);
|
||||
return it == map.end() ? Nothing() : Some(it->second);
|
||||
@@ -73,8 +75,33 @@ static void HandleMethodCall(GDBusConnection* aConnection, const gchar* aSender,
|
||||
return;
|
||||
}
|
||||
|
||||
dom::SeekDetails seekDetails{};
|
||||
if (key.value() == dom::MediaControlKey::Seekto ||
|
||||
key.value() == dom::MediaControlKey::Seekforward) {
|
||||
RefPtr<GVariant> child = dont_AddRef(g_variant_get_child_value(
|
||||
aParameters, key.value() == dom::MediaControlKey::Seekto));
|
||||
double seekValue;
|
||||
if (g_variant_is_of_type(child, G_VARIANT_TYPE_INT64)) {
|
||||
seekValue = (double)g_variant_get_int64(child) / 1000000.0;
|
||||
} else {
|
||||
g_dbus_method_invocation_return_error(
|
||||
aInvocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid arguments for %s.%s.%s", aObjectPath, aInterfaceName,
|
||||
aMethodName);
|
||||
return;
|
||||
}
|
||||
if (key.value() == dom::MediaControlKey::Seekto) {
|
||||
seekDetails = dom::SeekDetails(seekValue, false /* fast seek */);
|
||||
} else if (seekValue > 0.0) {
|
||||
seekDetails = dom::SeekDetails(seekValue);
|
||||
} else {
|
||||
key = Some(dom::MediaControlKey::Seekbackward);
|
||||
seekDetails = dom::SeekDetails(-1 * seekValue);
|
||||
}
|
||||
}
|
||||
|
||||
MPRISServiceHandler* handler = static_cast<MPRISServiceHandler*>(aUserData);
|
||||
if (handler->PressKey(key.value())) {
|
||||
if (handler->PressKey(dom::MediaControlAction(key.value(), seekDetails))) {
|
||||
g_dbus_method_invocation_return_value(aInvocation, nullptr);
|
||||
} else {
|
||||
g_dbus_method_invocation_return_error(
|
||||
@@ -100,6 +127,7 @@ enum class Property : uint8_t {
|
||||
eCanControl,
|
||||
eGetPlaybackStatus,
|
||||
eGetMetadata,
|
||||
eGetPosition,
|
||||
};
|
||||
|
||||
static inline Maybe<dom::MediaControlKey> GetPairedKey(Property aProperty) {
|
||||
@@ -137,7 +165,8 @@ static inline Maybe<Property> GetProperty(const gchar* aPropertyName) {
|
||||
{"CanSeek", Property::eCanSeek},
|
||||
{"CanControl", Property::eCanControl},
|
||||
{"PlaybackStatus", Property::eGetPlaybackStatus},
|
||||
{"Metadata", Property::eGetMetadata}};
|
||||
{"Metadata", Property::eGetMetadata},
|
||||
{"Position", Property::eGetPosition}};
|
||||
|
||||
auto it = map.find(aPropertyName);
|
||||
return (it == map.end() ? Nothing() : Some(it->second));
|
||||
@@ -170,16 +199,21 @@ static GVariant* HandleGetProperty(GDBusConnection* aConnection,
|
||||
return handler->GetPlaybackStatus();
|
||||
case Property::eGetMetadata:
|
||||
return handler->GetMetadataAsGVariant();
|
||||
case Property::eGetPosition: {
|
||||
CheckedInt64 position =
|
||||
CheckedInt64((int64_t)handler->GetPositionSeconds()) * 1000000;
|
||||
return g_variant_new_int64(position.isValid() ? position.value() : 0);
|
||||
}
|
||||
case Property::eIdentity:
|
||||
return g_variant_new_string(handler->Identity());
|
||||
case Property::eDesktopEntry:
|
||||
return g_variant_new_string(handler->DesktopEntry());
|
||||
case Property::eHasTrackList:
|
||||
case Property::eCanQuit:
|
||||
case Property::eCanSeek:
|
||||
return g_variant_new_boolean(false);
|
||||
// Play/Pause would be blocked if CanControl is false
|
||||
case Property::eCanControl:
|
||||
case Property::eCanSeek:
|
||||
return g_variant_new_boolean(true);
|
||||
case Property::eCanRaise:
|
||||
case Property::eCanGoNext:
|
||||
@@ -443,14 +477,16 @@ const char* MPRISServiceHandler::DesktopEntry() const {
|
||||
return mDesktopEntry.get();
|
||||
}
|
||||
|
||||
bool MPRISServiceHandler::PressKey(dom::MediaControlKey aKey) const {
|
||||
bool MPRISServiceHandler::PressKey(
|
||||
const dom::MediaControlAction& aAction) const {
|
||||
MOZ_ASSERT(mInitialized);
|
||||
if (!IsMediaKeySupported(aKey)) {
|
||||
LOGMPRIS("%s is not supported", dom::GetEnumString(aKey).get());
|
||||
if (!IsMediaKeySupported(aAction.mKey.value())) {
|
||||
LOGMPRIS("%s is not supported",
|
||||
dom::GetEnumString(aAction.mKey.value()).get());
|
||||
return false;
|
||||
}
|
||||
LOGMPRIS("Press %s", dom::GetEnumString(aKey).get());
|
||||
EmitEvent(aKey);
|
||||
LOGMPRIS("Press %s", dom::GetEnumString(aAction.mKey.value()).get());
|
||||
EmitEvent(aAction);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -812,9 +848,10 @@ GVariant* MPRISServiceHandler::GetMetadataAsGVariant() const {
|
||||
return g_variant_builder_end(&builder);
|
||||
}
|
||||
|
||||
void MPRISServiceHandler::EmitEvent(dom::MediaControlKey aKey) const {
|
||||
void MPRISServiceHandler::EmitEvent(
|
||||
const dom::MediaControlAction& aAction) const {
|
||||
for (const auto& listener : mListeners) {
|
||||
listener->OnActionPerformed(dom::MediaControlAction(aKey));
|
||||
listener->OnActionPerformed(aAction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -860,6 +897,18 @@ void MPRISServiceHandler::SetSupportedMediaKeys(
|
||||
}
|
||||
}
|
||||
|
||||
void MPRISServiceHandler::SetPositionState(
|
||||
const Maybe<dom::PositionState>& aState) {
|
||||
mPositionState = aState;
|
||||
}
|
||||
|
||||
double MPRISServiceHandler::GetPositionSeconds() const {
|
||||
if (mPositionState.isSome()) {
|
||||
return mPositionState.value().CurrentPlaybackPosition();
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool MPRISServiceHandler::IsMediaKeySupported(dom::MediaControlKey aKey) const {
|
||||
return mSupportedKeys & GetMediaKeyMask(aKey);
|
||||
}
|
||||
|
||||
@@ -72,13 +72,16 @@ class MPRISServiceHandler final : public dom::MediaControlKeySource {
|
||||
|
||||
const char* Identity() const;
|
||||
const char* DesktopEntry() const;
|
||||
bool PressKey(dom::MediaControlKey aKey) const;
|
||||
bool PressKey(const dom::MediaControlAction& aAction) const;
|
||||
|
||||
void SetMediaMetadata(const dom::MediaMetadataBase& aMetadata) override;
|
||||
GVariant* GetMetadataAsGVariant() const;
|
||||
|
||||
void SetSupportedMediaKeys(const MediaKeysArray& aSupportedKeys) override;
|
||||
|
||||
void SetPositionState(const Maybe<dom::PositionState>& aState) override;
|
||||
double GetPositionSeconds() const;
|
||||
|
||||
bool IsMediaKeySupported(dom::MediaControlKey aKey) const;
|
||||
|
||||
void OwnName(GDBusConnection* aConnection);
|
||||
@@ -110,6 +113,8 @@ class MPRISServiceHandler final : public dom::MediaControlKeySource {
|
||||
// A bitmask indicating what keys are enabled
|
||||
uint32_t mSupportedKeys = 0;
|
||||
|
||||
Maybe<dom::PositionState> mPositionState;
|
||||
|
||||
class MPRISMetadata : public dom::MediaMetadataBase {
|
||||
public:
|
||||
MPRISMetadata() = default;
|
||||
@@ -168,7 +173,7 @@ class MPRISServiceHandler final : public dom::MediaControlKeySource {
|
||||
static void OnBusAcquiredStatic(GDBusConnection* aConnection,
|
||||
const gchar* aName, gpointer aUserData);
|
||||
|
||||
void EmitEvent(dom::MediaControlKey aKey) const;
|
||||
void EmitEvent(const dom::MediaControlAction& aAction) const;
|
||||
|
||||
bool EmitMetadataChanged() const;
|
||||
|
||||
|
||||
@@ -426,9 +426,9 @@ void WindowsSMTCProvider::OnPositionChangeRequested(double aPosition) const {
|
||||
}
|
||||
|
||||
for (const auto& listener : mListeners) {
|
||||
listener->OnActionPerformed(
|
||||
mozilla::dom::MediaControlAction(mozilla::dom::MediaControlKey::Seekto,
|
||||
mozilla::dom::SeekDetails(aPosition)));
|
||||
listener->OnActionPerformed(mozilla::dom::MediaControlAction(
|
||||
mozilla::dom::MediaControlKey::Seekto,
|
||||
mozilla::dom::SeekDetails(aPosition, false /* fast seek */)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user