Changeset 272445 in webkit


Ignore:
Timestamp:
Feb 5, 2021 3:18:55 PM (18 months ago)
Author:
eric.carlson@apple.com
Message:

[Mac] Connect MediaSession with MediaRemote and NowPlaying
https://bugs.webkit.org/show_bug.cgi?id=221431
<rdar://problem/74000363>

Reviewed by Jer Noble.

Source/WebCore:

Route all remote control commands to navigator.mediaSession when it has any
registered action handlers, and pass navigator.mediaSession.metadata to NowPlaying.

Tested with new API tests in Tools/TestWebKitAPI/Tests/WebKitCocoa/MediaSession.mm.

  • Modules/mediasession/MediaImage.h:

(WebCore::MediaImage::encode const):
(WebCore::MediaImage::decode):

  • Modules/mediasession/MediaMetadata.cpp:

(WebCore::MediaMetadata::setTitle):
(WebCore::MediaMetadata::setArtist):
(WebCore::MediaMetadata::setAlbum):
(WebCore::MediaMetadata::setArtwork):

  • Modules/mediasession/MediaMetadata.h:

(WebCore::MediaMetadata::title const):
(WebCore::MediaMetadata::artist const):
(WebCore::MediaMetadata::album const):
(WebCore::MediaMetadata::artwork const):
(WebCore::MediaMetadata::metadata const):

  • Modules/mediasession/MediaMetadataInit.h:

(WebCore::MediaMetadataInit::encode const):
(WebCore::MediaMetadataInit::decode):

  • Modules/mediasession/MediaSession.cpp:

(WebCore::nextLogIdentifier):
(WebCore::logChannel):
(WebCore::logClassName):
(WebCore::platformCommandForMediaSessionAction):
(WebCore::MediaSession::MediaSession):
(WebCore::MediaSession::setMetadata):
(WebCore::MediaSession::setPlaybackState):
(WebCore::MediaSession::setActionHandler):
(WebCore::MediaSession::setPositionState):

  • Modules/mediasession/MediaSession.h:

(WebCore::MediaSession::hasActiveActionHandlers const):
(WebCore::MediaSession::logger const):
(WebCore::MediaSession::logIdentifier const):
(WTF::LogArgument<WebCore::MediaSessionPlaybackState>::toString):
(WTF::LogArgument<WebCore::MediaSessionAction>::toString):

  • WebCore.xcodeproj/project.pbxproj:
  • html/HTMLMediaElement.cpp:

(WebCore::HTMLMediaElement::didReceiveRemoteControlCommand):

  • html/MediaElementSession.cpp:

(WebCore::MediaElementSession::didReceiveRemoteControlCommand):
(WebCore::MediaElementSession::nowPlayingInfo const):

  • html/MediaElementSession.h:
  • page/ChromeClient.h:
  • platform/RemoteCommandListener.cpp:

(WebCore::RemoteCommandListener::scheduleSupportedCommandsUpdate):
(WebCore::RemoteCommandListener::addSupportedCommand):
(WebCore::RemoteCommandListener::removeSupportedCommand):

  • platform/RemoteCommandListener.h:
  • platform/audio/NowPlayingInfo.h:

(WebCore::NowPlayingInfo::decode):

  • platform/audio/PlatformMediaSession.cpp:

(WebCore::convertEnumerationToString):

  • platform/audio/PlatformMediaSession.h:
  • platform/audio/PlatformMediaSessionManager.h:

(WebCore::PlatformMediaSessionManager::addSupportedCommand):
(WebCore::PlatformMediaSessionManager::removeSupportedCommand):

  • platform/audio/cocoa/MediaSessionManagerCocoa.h:
  • platform/audio/cocoa/MediaSessionManagerCocoa.mm:

(WebCore::MediaSessionManagerCocoa::scheduleSessionStatusUpdate):
(WebCore::MediaSessionManagerCocoa::sessionCanProduceAudioChanged):
(WebCore::MediaSessionManagerCocoa::addSupportedCommand):
(WebCore::MediaSessionManagerCocoa::removeSupportedCommand):
(WebCore::MediaSessionManagerCocoa::setNowPlayingInfo):

  • platform/mac/MediaRemoteSoftLink.cpp:
  • platform/mac/MediaRemoteSoftLink.h:
  • platform/mac/RemoteCommandListenerMac.h:
  • platform/mac/RemoteCommandListenerMac.mm:

(WebCore::mediaRemoteCommandForPlatformCommand):
(WebCore::RemoteCommandListenerMac::defaultCommands):
(WebCore::isSeekCommand):
(WebCore::RemoteCommandListenerMac::updateSupportedCommands):
(WebCore::RemoteCommandListenerMac::RemoteCommandListenerMac):

Source/WebCore/PAL:

  • pal/spi/mac/MediaRemoteSPI.h:

Source/WebKit:

Add a private preference so the new MediaSession API test can enable the feature.

  • UIProcess/API/Cocoa/WKPreferences.mm:

(-[WKPreferences _mediaSessionEnabled]):
(-[WKPreferences _setMediaSessionEnabled:]):

  • UIProcess/API/Cocoa/WKPreferencesPrivate.h:

Tools:

  • TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
  • TestWebKitAPI/Tests/WebKitCocoa/MediaSession.mm: Added.

(TestWebKitAPI::MediaSessionTest::webView):
(TestWebKitAPI::MediaSessionTest::webViewPid):
(TestWebKitAPI::MediaSessionTest::getNowPlayingClient):
(TestWebKitAPI::MediaSessionTest::getNowPlayingClientPid):
(TestWebKitAPI::MediaSessionTest::loadPageAndBecomeNowPlaying):
(TestWebKitAPI::MediaSessionTest::runScriptWithUserGesture):
(TestWebKitAPI::MediaSessionTest::play):
(TestWebKitAPI::MediaSessionTest::pause):
(TestWebKitAPI::MediaSessionTest::sendMediaRemoteCommand):
(TestWebKitAPI::MediaSessionTest::sendMediaRemoteSeekCommand):
(TestWebKitAPI::MediaSessionTest::listenForEventMessages):
(TestWebKitAPI::MediaSessionTest::eventListenerWasCalled):
(TestWebKitAPI::MediaSessionTest::waitForEventListenerToBeCalled):
(TestWebKitAPI::MediaSessionTest::listenForSessionHandlerMessages):
(TestWebKitAPI::MediaSessionTest::sessionHandlerWasCalled):
(TestWebKitAPI::MediaSessionTest::waitForSessionHandlerToBeCalled):
(TestWebKitAPI::MediaSessionTest::getSupportedCommands):
(TestWebKitAPI::TEST_F):

  • TestWebKitAPI/Tests/WebKitCocoa/media-remote.html: Added.
Location:
trunk
Files:
2 added
31 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r272439 r272445  
     12021-02-05  Eric Carlson  <eric.carlson@apple.com>
     2
     3        [Mac] Connect MediaSession with MediaRemote and NowPlaying
     4        https://bugs.webkit.org/show_bug.cgi?id=221431
     5        <rdar://problem/74000363>
     6
     7        Reviewed by Jer Noble.
     8
     9        Route all remote control commands to navigator.mediaSession when it has any
     10        registered action handlers, and pass navigator.mediaSession.metadata to NowPlaying.
     11
     12        Tested with new API tests in Tools/TestWebKitAPI/Tests/WebKitCocoa/MediaSession.mm.
     13
     14        * Modules/mediasession/MediaImage.h:
     15        (WebCore::MediaImage::encode const):
     16        (WebCore::MediaImage::decode):
     17        * Modules/mediasession/MediaMetadata.cpp:
     18        (WebCore::MediaMetadata::setTitle):
     19        (WebCore::MediaMetadata::setArtist):
     20        (WebCore::MediaMetadata::setAlbum):
     21        (WebCore::MediaMetadata::setArtwork):
     22        * Modules/mediasession/MediaMetadata.h:
     23        (WebCore::MediaMetadata::title const):
     24        (WebCore::MediaMetadata::artist const):
     25        (WebCore::MediaMetadata::album const):
     26        (WebCore::MediaMetadata::artwork const):
     27        (WebCore::MediaMetadata::metadata const):
     28        * Modules/mediasession/MediaMetadataInit.h:
     29        (WebCore::MediaMetadataInit::encode const):
     30        (WebCore::MediaMetadataInit::decode):
     31        * Modules/mediasession/MediaSession.cpp:
     32        (WebCore::nextLogIdentifier):
     33        (WebCore::logChannel):
     34        (WebCore::logClassName):
     35        (WebCore::platformCommandForMediaSessionAction):
     36        (WebCore::MediaSession::MediaSession):
     37        (WebCore::MediaSession::setMetadata):
     38        (WebCore::MediaSession::setPlaybackState):
     39        (WebCore::MediaSession::setActionHandler):
     40        (WebCore::MediaSession::setPositionState):
     41        * Modules/mediasession/MediaSession.h:
     42        (WebCore::MediaSession::hasActiveActionHandlers const):
     43        (WebCore::MediaSession::logger const):
     44        (WebCore::MediaSession::logIdentifier const):
     45        (WTF::LogArgument<WebCore::MediaSessionPlaybackState>::toString):
     46        (WTF::LogArgument<WebCore::MediaSessionAction>::toString):
     47        * WebCore.xcodeproj/project.pbxproj:
     48        * html/HTMLMediaElement.cpp:
     49        (WebCore::HTMLMediaElement::didReceiveRemoteControlCommand):
     50        * html/MediaElementSession.cpp:
     51        (WebCore::MediaElementSession::didReceiveRemoteControlCommand):
     52        (WebCore::MediaElementSession::nowPlayingInfo const):
     53        * html/MediaElementSession.h:
     54        * page/ChromeClient.h:
     55        * platform/RemoteCommandListener.cpp:
     56        (WebCore::RemoteCommandListener::scheduleSupportedCommandsUpdate):
     57        (WebCore::RemoteCommandListener::addSupportedCommand):
     58        (WebCore::RemoteCommandListener::removeSupportedCommand):
     59        * platform/RemoteCommandListener.h:
     60        * platform/audio/NowPlayingInfo.h:
     61        (WebCore::NowPlayingInfo::decode):
     62        * platform/audio/PlatformMediaSession.cpp:
     63        (WebCore::convertEnumerationToString):
     64        * platform/audio/PlatformMediaSession.h:
     65        * platform/audio/PlatformMediaSessionManager.h:
     66        (WebCore::PlatformMediaSessionManager::addSupportedCommand):
     67        (WebCore::PlatformMediaSessionManager::removeSupportedCommand):
     68        * platform/audio/cocoa/MediaSessionManagerCocoa.h:
     69        * platform/audio/cocoa/MediaSessionManagerCocoa.mm:
     70        (WebCore::MediaSessionManagerCocoa::scheduleSessionStatusUpdate):
     71        (WebCore::MediaSessionManagerCocoa::sessionCanProduceAudioChanged):
     72        (WebCore::MediaSessionManagerCocoa::addSupportedCommand):
     73        (WebCore::MediaSessionManagerCocoa::removeSupportedCommand):
     74        (WebCore::MediaSessionManagerCocoa::setNowPlayingInfo):
     75        * platform/mac/MediaRemoteSoftLink.cpp:
     76        * platform/mac/MediaRemoteSoftLink.h:
     77        * platform/mac/RemoteCommandListenerMac.h:
     78        * platform/mac/RemoteCommandListenerMac.mm:
     79        (WebCore::mediaRemoteCommandForPlatformCommand):
     80        (WebCore::RemoteCommandListenerMac::defaultCommands):
     81        (WebCore::isSeekCommand):
     82        (WebCore::RemoteCommandListenerMac::updateSupportedCommands):
     83        (WebCore::RemoteCommandListenerMac::RemoteCommandListenerMac):
     84
    1852021-02-05  Jer Noble  <jer.noble@apple.com>
    286
  • trunk/Source/WebCore/Modules/mediasession/MediaImage.h

    r268735 r272445  
    11/*
    2  * Copyright (C) 2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3434    String sizes;
    3535    String type;
     36
     37    template<class Encoder> void encode(Encoder&) const;
     38    template<class Decoder> static Optional<MediaImage> decode(Decoder&);
    3639};
     40
     41template<class Encoder> inline void MediaImage::encode(Encoder& encoder) const
     42{
     43    encoder << src << sizes << type;
     44}
     45
     46template<class Decoder> inline Optional<MediaImage> MediaImage::decode(Decoder& decoder)
     47{
     48    String src;
     49    if (!decoder.decode(src))
     50        return { };
     51
     52    String sizes;
     53    if (!decoder.decode(sizes))
     54        return { };
     55
     56    String type;
     57    if (!decoder.decode(type))
     58        return { };
     59
     60    return MediaImage { WTFMove(src), WTFMove(sizes), WTFMove(type) };
     61}
    3762
    3863}
  • trunk/Source/WebCore/Modules/mediasession/MediaMetadata.cpp

    r268735 r272445  
    11/*
    2  * Copyright (C) 2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    6565void MediaMetadata::setTitle(const String& title)
    6666{
    67     if (m_title == title)
     67    if (m_metadata.title == title)
    6868        return;
    69     m_title = title;
     69
     70    m_metadata.title = title;
    7071    metadataUpdated();
    7172}
     
    7374void MediaMetadata::setArtist(const String& artist)
    7475{
    75     if (m_artist == artist)
     76    if (m_metadata.artist == artist)
    7677        return;
    77     m_artist = artist;
     78
     79    m_metadata.artist = artist;
    7880    metadataUpdated();
    7981}
     
    8183void MediaMetadata::setAlbum(const String& album)
    8284{
    83     if (m_album == album)
     85    if (m_metadata.album == album)
    8486        return;
    85     m_album = album;
     87
     88    m_metadata.album = album;
    8689    metadataUpdated();
    8790}
     
    98101    }
    99102
    100     m_artwork = WTFMove(resolvedArtwork);
     103    m_metadata.artwork = WTFMove(resolvedArtwork);
    101104    metadataUpdated();
    102105    return { };
  • trunk/Source/WebCore/Modules/mediasession/MediaMetadata.h

    r268735 r272445  
    11/*
    2  * Copyright (C) 2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2828#if ENABLE(MEDIA_SESSION)
    2929
     30#include "MediaMetadataInit.h"
    3031#include "MediaSession.h"
    3132#include <wtf/Optional.h>
     
    3536namespace WebCore {
    3637
    37 class Document;
    38 class MediaSession;
    3938struct MediaImage;
    40 struct MediaMetadataInit;
     39
     40using MediaSessionMetadata = MediaMetadataInit;
    4141
    4242class MediaMetadata : public RefCounted<MediaMetadata> {
     
    4848    void resetMediaSession();
    4949
    50     const String& title() const { return m_title; }
     50    const String& title() const { return m_metadata.title; }
    5151    void setTitle(const String&);
    5252
    53     const String& artist() const { return m_artist; }
     53    const String& artist() const { return m_metadata.artist; }
    5454    void setArtist(const String&);
    5555
    56     const String& album() const { return m_album; }
     56    const String& album() const { return m_metadata.album; }
    5757    void setAlbum(const String&);
    5858
    59     const Vector<MediaImage>& artwork() const { return m_artwork; }
     59    const Vector<MediaImage>& artwork() const { return m_metadata.artwork; }
    6060    ExceptionOr<void> setArtwork(ScriptExecutionContext&, Vector<MediaImage>&&);
     61
     62    const MediaSessionMetadata& metadata() const { return m_metadata; }
    6163
    6264private:
     
    6567
    6668    WeakPtr<MediaSession> m_session;
    67     String m_title;
    68     String m_artist;
    69     String m_album;
    70     Vector<MediaImage> m_artwork;
     69    MediaSessionMetadata m_metadata;
    7170};
    7271
  • trunk/Source/WebCore/Modules/mediasession/MediaMetadataInit.h

    r268735 r272445  
    11/*
    2  * Copyright (C) 2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3737    String album;
    3838    Vector<MediaImage> artwork;
     39
     40    template<class Encoder> void encode(Encoder&) const;
     41    template<class Decoder> static Optional<MediaMetadataInit> decode(Decoder&);
    3942};
     43
     44template<class Encoder> inline void MediaMetadataInit::encode(Encoder& encoder) const
     45{
     46    encoder << title << artist << album << artwork;
     47}
     48
     49template<class Decoder> inline Optional<MediaMetadataInit> MediaMetadataInit::decode(Decoder& decoder)
     50{
     51    String title;
     52    if (!decoder.decode(title))
     53        return { };
     54
     55    String artist;
     56    if (!decoder.decode(artist))
     57        return { };
     58
     59    String album;
     60    if (!decoder.decode(album))
     61        return { };
     62
     63    Vector<MediaImage> artwork;
     64    if (!decoder.decode(artwork))
     65        return { };
     66
     67    return MediaMetadataInit { WTFMove(title), WTFMove(artist), WTFMove(album), WTFMove(artwork) };
     68}
    4069
    4170}
  • trunk/Source/WebCore/Modules/mediasession/MediaSession.cpp

    r268769 r272445  
    11/*
    2  * Copyright (C) 2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2929#if ENABLE(MEDIA_SESSION)
    3030
     31#include "Logging.h"
    3132#include "MediaMetadata.h"
    3233#include "Navigator.h"
     34#include "PlatformMediaSessionManager.h"
    3335
    3436namespace WebCore {
     37
     38static const void* nextLogIdentifier()
     39{
     40    static uint64_t logIdentifier = cryptographicallyRandomNumber();
     41    return reinterpret_cast<const void*>(++logIdentifier);
     42}
     43
     44static WTFLogChannel& logChannel() { return LogMedia; }
     45static const char* logClassName() { return "MediaSession"; }
     46
     47static PlatformMediaSession::RemoteControlCommandType platformCommandForMediaSessionAction(MediaSessionAction action)
     48{
     49    static const auto commandMap = makeNeverDestroyed([] {
     50        using ActionToCommandMap = HashMap<MediaSessionAction, PlatformMediaSession::RemoteControlCommandType, WTF::IntHash<MediaSessionAction>, WTF::StrongEnumHashTraits<MediaSessionAction>>;
     51
     52        return ActionToCommandMap {
     53            { MediaSessionAction::Play, PlatformMediaSession::PlayCommand },
     54            { MediaSessionAction::Pause, PlatformMediaSession::PauseCommand },
     55            { MediaSessionAction::Seekforward, PlatformMediaSession::SkipForwardCommand },
     56            { MediaSessionAction::Seekbackward, PlatformMediaSession::SkipBackwardCommand },
     57            { MediaSessionAction::Previoustrack, PlatformMediaSession::NextTrackCommand },
     58            { MediaSessionAction::Nexttrack, PlatformMediaSession::PreviousTrackCommand },
     59            { MediaSessionAction::Stop, PlatformMediaSession::StopCommand },
     60            { MediaSessionAction::Seekto, PlatformMediaSession::SeekToPlaybackPositionCommand },
     61        };
     62    }());
     63
     64    auto it = commandMap.get().find(action);
     65    if (it != commandMap.get().end())
     66        return it->value;
     67
     68    return PlatformMediaSession::NoCommand;
     69}
    3570
    3671Ref<MediaSession> MediaSession::create(Navigator& navigator)
     
    4277    : m_navigator(makeWeakPtr(navigator))
    4378{
     79    m_logger = makeRefPtr(Document::sharedLogger());
     80    m_logIdentifier = nextLogIdentifier();
     81
     82    ALWAYS_LOG(LOGIDENTIFIER);
    4483}
    4584
     
    4887void MediaSession::setMetadata(RefPtr<MediaMetadata>&& metadata)
    4988{
     89    ALWAYS_LOG(LOGIDENTIFIER);
     90
    5091    if (m_metadata)
    5192        m_metadata->resetMediaSession();
     
    61102        return;
    62103
     104    ALWAYS_LOG(LOGIDENTIFIER, state);
     105
    63106    auto currentPosition = this->currentPosition();
    64107    if (m_positionState && currentPosition) {
     
    71114void MediaSession::setActionHandler(MediaSessionAction action, RefPtr<MediaSessionActionHandler>&& handler)
    72115{
    73     if (handler)
     116    if (handler) {
     117        ALWAYS_LOG(LOGIDENTIFIER, "adding ", action);
    74118        m_actionHandlers.set(action, handler);
    75     else
    76         m_actionHandlers.remove(action);
     119        PlatformMediaSessionManager::sharedManager().addSupportedCommand(platformCommandForMediaSessionAction(action));
     120    } else {
     121        if (m_actionHandlers.contains(action)) {
     122            ALWAYS_LOG(LOGIDENTIFIER, "removing ", action);
     123            m_actionHandlers.remove(action);
     124        }
     125        PlatformMediaSessionManager::sharedManager().removeSupportedCommand(platformCommandForMediaSessionAction(action));
     126    }
     127   
    77128    actionHandlersUpdated();
    78129}
     
    90141ExceptionOr<void> MediaSession::setPositionState(Optional<MediaPositionState>&& state)
    91142{
     143    ALWAYS_LOG(LOGIDENTIFIER);
     144
    92145    if (!state) {
    93146        m_positionState = WTF::nullopt;
  • trunk/Source/WebCore/Modules/mediasession/MediaSession.h

    r268769 r272445  
    11/*
    2  * Copyright (C) 2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2828#if ENABLE(MEDIA_SESSION)
    2929
     30#include "JSMediaPositionState.h"
     31#include "JSMediaSessionAction.h"
     32#include "JSMediaSessionPlaybackState.h"
    3033#include "MediaPositionState.h"
    3134#include "MediaSessionAction.h"
    3235#include "MediaSessionActionHandler.h"
    3336#include "MediaSessionPlaybackState.h"
     37#include <wtf/Logger.h>
    3438#include <wtf/MonotonicTime.h>
    3539#include <wtf/Optional.h>
     
    5862
    5963    void metadataUpdated();
     64
    6065    void actionHandlersUpdated();
    6166    bool hasActionHandler(MediaSessionAction) const;
    6267    WEBCORE_EXPORT RefPtr<MediaSessionActionHandler> handlerForAction(MediaSessionAction) const;
     68    bool hasActiveActionHandlers() const { return !m_actionHandlers.isEmpty(); }
    6369
    6470private:
    6571    explicit MediaSession(Navigator&);
     72
     73    const Logger& logger() const { return *m_logger.get(); }
     74    const void* logIdentifier() const { return m_logIdentifier; }
    6675
    6776    WeakPtr<Navigator> m_navigator;
     
    7281    MonotonicTime m_timeAtLastPositionUpdate;
    7382    HashMap<MediaSessionAction, RefPtr<MediaSessionActionHandler>, WTF::IntHash<MediaSessionAction>, WTF::StrongEnumHashTraits<MediaSessionAction>> m_actionHandlers;
     83    RefPtr<const Logger> m_logger;
     84    const void* m_logIdentifier;
     85};
     86
     87}
     88
     89namespace WTF {
     90
     91template<> struct LogArgument<WebCore::MediaSessionPlaybackState> {
     92    static String toString(WebCore::MediaSessionPlaybackState state) { return convertEnumerationToString(state); }
     93};
     94
     95template<> struct LogArgument<WebCore::MediaSessionAction> {
     96    static String toString(WebCore::MediaSessionAction action) { return convertEnumerationToString(action); }
    7497};
    7598
  • trunk/Source/WebCore/PAL/ChangeLog

    r272188 r272445  
     12021-02-05  Eric Carlson  <eric.carlson@apple.com>
     2
     3        [Mac] Connect MediaSession with MediaRemote and NowPlaying
     4        https://bugs.webkit.org/show_bug.cgi?id=221431
     5        <rdar://problem/74000363>
     6
     7        Reviewed by Jer Noble.
     8
     9        * pal/spi/mac/MediaRemoteSPI.h:
     10
    1112021-02-01  Jer Noble  <jer.noble@apple.com>
    212
  • trunk/Source/WebCore/PAL/pal/spi/mac/MediaRemoteSPI.h

    r261110 r272445  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2016-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    9393
    9494typedef uint32_t MRMediaRemoteError;
     95typedef uint32_t MRSendCommandAppOptions;
     96typedef uint32_t MRSendCommandError;
    9597typedef struct _MROrigin *MROriginRef;
    9698typedef struct _MRMediaRemoteCommandInfo *MRMediaRemoteCommandInfoRef;
     
    104106void* MRMediaRemoteAddAsyncCommandHandlerBlock(MRMediaRemoteAsyncCommandHandlerBlock);
    105107void MRMediaRemoteRemoveCommandHandlerBlock(void *observer);
    106 void MRMediaRemoteSetSupportedCommands(CFArrayRef commands, MROriginRef, dispatch_queue_t replyQ, void(^completion)(MRMediaRemoteError err));
     108void MRMediaRemoteSetSupportedCommands(CFArrayRef, MROriginRef, dispatch_queue_t, void(^completion)(MRMediaRemoteError));
     109void MRMediaRemoteGetSupportedCommandsForOrigin(MROriginRef, dispatch_queue_t, void(^completion)(CFArrayRef));
    107110void MRMediaRemoteSetNowPlayingVisibility(MROriginRef, MRNowPlayingClientVisibility);
     111Boolean MRMediaRemoteSendCommandToApp(MRMediaRemoteCommand, CFDictionaryRef, MROriginRef, CFStringRef, MRSendCommandAppOptions, dispatch_queue_t, void(^completion)(MRSendCommandError, CFArrayRef));
    108112
    109113#pragma mark - MROrigin
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r272396 r272445  
    140140                077B64131B94F12E003E9AD5 /* MediaPlaybackTargetPickerMock.h in Headers */ = {isa = PBXBuildFile; fileRef = 077B64111B94F12E003E9AD5 /* MediaPlaybackTargetPickerMock.h */; settings = {ATTRIBUTES = (Private, ); }; };
    141141                077B64171B95F703003E9AD5 /* MediaPlaybackTargetMock.h in Headers */ = {isa = PBXBuildFile; fileRef = 077B64151B95F703003E9AD5 /* MediaPlaybackTargetMock.h */; settings = {ATTRIBUTES = (Private, ); }; };
     142                0782894825C23FE500A7BA03 /* MediaMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = CDDDEA2D2538CE0400A1300C /* MediaMetadata.h */; settings = {ATTRIBUTES = (Private, ); }; };
     143                0782894A25C36FCF00A7BA03 /* MediaSession.h in Headers */ = {isa = PBXBuildFile; fileRef = CDDDEA232538CD8000A1300C /* MediaSession.h */; };
     144                0782894B25C36FED00A7BA03 /* MediaImage.h in Headers */ = {isa = PBXBuildFile; fileRef = CDDDEA322538CE3500A1300C /* MediaImage.h */; };
     145                0782894C25C3700B00A7BA03 /* MediaMetadataInit.h in Headers */ = {isa = PBXBuildFile; fileRef = CDDDEA302538CE1E00A1300C /* MediaMetadataInit.h */; };
    142146                0783228518013ED800999E0C /* MediaStreamAudioSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 0783228318013ED800999E0C /* MediaStreamAudioSource.h */; };
    143147                07846343145B151A00A58DF1 /* JSTrackEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 07846341145B151A00A58DF1 /* JSTrackEvent.h */; };
     
    3370333707                                4E1959220A39DABA00220FE5 /* MediaFeatureNames.h in Headers */,
    3370433708                                07A6D1EC1491137700051D0C /* MediaFragmentURIParser.h in Headers */,
     33709                                0782894B25C36FED00A7BA03 /* MediaImage.h in Headers */,
    3370533710                                CDF4B71A1E01D3D000E235A2 /* MediaKeySessionType.idl in Headers */,
    3370633711                                CDF4B7281E03C57300E235A2 /* MediaKeysRequirement.idl in Headers */,
    3370733712                                CDF4B7181E01CB9100E235A2 /* MediaKeysRestrictions.h in Headers */,
    3370833713                                A8EA800E0A19516E00A8EF5F /* MediaList.h in Headers */,
     33714                                0782894825C23FE500A7BA03 /* MediaMetadata.h in Headers */,
     33715                                0782894C25C3700B00A7BA03 /* MediaMetadataInit.h in Headers */,
    3370933716                                5EBB89311C7777FF00C65D41 /* MediaPayload.h in Headers */,
    3371033717                                07E3DFD11A9E786500764CA8 /* MediaPlaybackTarget.h in Headers */,
     
    3374733754                                CDBEAEAD19D92B6C00BEBA88 /* MediaSelectionGroupAVFObjC.h in Headers */,
    3374833755                                A17D275E1EAC579800BF01E7 /* MediaSelectionOption.h in Headers */,
     33756                                0782894A25C36FCF00A7BA03 /* MediaSession.h in Headers */,
    3374933757                                416ECAE525B58CC400B34DA5 /* MediaSessionGroupIdentifier.h in Headers */,
    3375033758                                CDA9593F2412BAE000910EEF /* MediaSessionHelperIOS.h in Headers */,
  • trunk/Source/WebCore/html/HTMLMediaElement.cpp

    r272429 r272445  
    11/*
    2  * Copyright (C) 2007-2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2007-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    75207520
    75217521    UserGestureIndicator remoteControlUserGesture(ProcessingUserGesture, &document());
     7522    double offset = 15;
    75227523    switch (command) {
    75237524    case PlatformMediaSession::PlayCommand:
     
    75417542        endScanning();
    75427543        break;
     7544    case PlatformMediaSession::SkipForwardCommand:
     7545        if (argument)
     7546            offset = argument->asDouble;
     7547        handleSeekToPlaybackPosition(offset);
     7548        break;
     7549    case PlatformMediaSession::SkipBackwardCommand:
     7550        if (argument)
     7551            offset = argument->asDouble;
     7552        handleSeekToPlaybackPosition(0 - offset);
     7553        break;
    75437554    case PlatformMediaSession::SeekToPlaybackPositionCommand:
    75447555        ASSERT(argument);
  • trunk/Source/WebCore/html/MediaElementSession.cpp

    r271870 r272445  
    11/*
    2  * Copyright (C) 2014 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    5555#include <wtf/text/StringBuilder.h>
    5656
     57#if ENABLE(MEDIA_SESSION)
     58#include "MediaMetadata.h"
     59#include "MediaSession.h"
     60#include "NavigatorMediaSession.h"
     61#endif
     62
    5763#if PLATFORM(IOS_FAMILY)
    5864#include "AudioSession.h"
     
    10221028}
    10231029
     1030#if ENABLE(MEDIA_SESSION)
     1031void MediaElementSession::didReceiveRemoteControlCommand(RemoteControlCommandType commandType, const RemoteCommandArgument* argument)
     1032{
     1033    auto* window = m_element.document().domWindow();
     1034    auto* session = window ? &NavigatorMediaSession::mediaSession(window->navigator()) : nullptr;
     1035    if (!session || !session->hasActiveActionHandlers()) {
     1036        PlatformMediaSession::didReceiveRemoteControlCommand(commandType, argument);
     1037        return;
     1038    }
     1039
     1040    MediaSessionActionDetails actionDetails;
     1041    switch (commandType) {
     1042    case NoCommand:
     1043        return;
     1044    case PlayCommand:
     1045        actionDetails.action = MediaSessionAction::Play;
     1046        break;
     1047    case PauseCommand:
     1048        actionDetails.action = MediaSessionAction::Pause;
     1049        break;
     1050    case StopCommand:
     1051        actionDetails.action = MediaSessionAction::Stop;
     1052        break;
     1053    case TogglePlayPauseCommand:
     1054        actionDetails.action = m_element.paused() ? MediaSessionAction::Play : MediaSessionAction::Pause;
     1055        break;
     1056    case SeekToPlaybackPositionCommand:
     1057        ASSERT(argument);
     1058        if (!argument)
     1059            return;
     1060        actionDetails.action = MediaSessionAction::Seekto;
     1061        actionDetails.seekTime = argument->asDouble;
     1062        break;
     1063    case SkipForwardCommand:
     1064        if (argument)
     1065            actionDetails.seekOffset = argument->asDouble;
     1066        actionDetails.action = MediaSessionAction::Seekforward;
     1067        break;
     1068    case SkipBackwardCommand:
     1069        if (argument)
     1070            actionDetails.seekOffset = argument->asDouble;
     1071        actionDetails.action = MediaSessionAction::Seekbackward;
     1072        break;
     1073    case NextTrackCommand:
     1074        actionDetails.action = MediaSessionAction::Nexttrack;
     1075        break;
     1076    case PreviousTrackCommand:
     1077        actionDetails.action = MediaSessionAction::Previoustrack;
     1078        break;
     1079    case BeginSeekingBackwardCommand:
     1080    case EndSeekingBackwardCommand:
     1081    case BeginSeekingForwardCommand:
     1082    case EndSeekingForwardCommand:
     1083        ASSERT_NOT_REACHED();
     1084        break;
     1085    }
     1086   
     1087    if (auto handler = session->handlerForAction(actionDetails.action))
     1088        handler->handleEvent(actionDetails);
     1089    else
     1090        ALWAYS_LOG(LOGIDENTIFIER, "Ignoring command, no action handler registered for ", actionDetails.action);
     1091}
     1092#endif
     1093
    10241094Optional<NowPlayingInfo> MediaElementSession::nowPlayingInfo() const
    10251095{
     
    10331103        currentTime = MediaPlayer::invalidTime();
    10341104
    1035     return NowPlayingInfo { m_element.mediaSessionTitle(), m_element.sourceApplicationIdentifier(), duration, currentTime, supportsSeeking, m_element.mediaSessionUniqueIdentifier(), isPlaying, allowsNowPlayingControlsVisibility };
     1105#if ENABLE(MEDIA_SESSION)
     1106    auto* window = m_element.document().domWindow();
     1107    auto* sessionMetadata = window ? NavigatorMediaSession::mediaSession(window->navigator()).metadata() : nullptr;
     1108    if (sessionMetadata)
     1109        return NowPlayingInfo { sessionMetadata->title(), sessionMetadata->artist(), sessionMetadata->album(), m_element.sourceApplicationIdentifier(), duration, currentTime, supportsSeeking, m_element.mediaSessionUniqueIdentifier(), isPlaying, allowsNowPlayingControlsVisibility };
     1110#endif
     1111
     1112    return NowPlayingInfo { m_element.mediaSessionTitle(), emptyString(), emptyString(), m_element.sourceApplicationIdentifier(), duration, currentTime, supportsSeeking, m_element.mediaSessionUniqueIdentifier(), isPlaying, allowsNowPlayingControlsVisibility };
    10361113}
    10371114
  • trunk/Source/WebCore/html/MediaElementSession.h

    r271870 r272445  
    11/*
    2  * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    175175#endif
    176176
     177#if ENABLE(MEDIA_SESSION)
     178    void didReceiveRemoteControlCommand(RemoteControlCommandType, const RemoteCommandArgument* = nullptr) final;
     179#endif
     180
    177181private:
    178182
  • trunk/Source/WebCore/page/ChromeClient.h

    r272236 r272445  
    102102class HitTestResult;
    103103class IntRect;
    104 class MediaSessionMetadata;
    105104class NavigationAction;
    106105class Node;
  • trunk/Source/WebCore/platform/RemoteCommandListener.cpp

    r261093 r272445  
    11/*
    2  * Copyright (C) 2014 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3838#endif
    3939
     40void RemoteCommandListener::scheduleSupportedCommandsUpdate()
     41{
     42    if (!m_updateCommandsTask.hasPendingTask()) {
     43        m_updateCommandsTask.scheduleTask([this] ()  {
     44            updateSupportedCommands();
     45        });
     46    }
    4047}
     48
     49void RemoteCommandListener::addSupportedCommand(PlatformMediaSession::RemoteControlCommandType command)
     50{
     51    m_registeredCommands.add(command);
     52    scheduleSupportedCommandsUpdate();
     53}
     54
     55void RemoteCommandListener::removeSupportedCommand(PlatformMediaSession::RemoteControlCommandType command)
     56{
     57    m_registeredCommands.remove(command);
     58    scheduleSupportedCommandsUpdate();
     59}
     60
     61}
  • trunk/Source/WebCore/platform/RemoteCommandListener.h

    r233650 r272445  
    11/*
    2  * Copyright (C) 2014 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2727#define RemoteCommandListener_h
    2828
     29#include "DeferrableTask.h"
    2930#include "PlatformMediaSession.h"
    3031
     
    4647    virtual ~RemoteCommandListener() = default;
    4748
     49    void addSupportedCommand(PlatformMediaSession::RemoteControlCommandType);
     50    void removeSupportedCommand(PlatformMediaSession::RemoteControlCommandType);
    4851    virtual void updateSupportedCommands() { }
     52    void scheduleSupportedCommandsUpdate();
    4953
    5054    RemoteCommandListenerClient& client() const { return m_client; }
     
    5256protected:
    5357    RemoteCommandListenerClient& m_client;
     58
     59    using RemoteCommandsSet = HashSet<PlatformMediaSession::RemoteControlCommandType, WTF::IntHash<PlatformMediaSession::RemoteControlCommandType>, WTF::StrongEnumHashTraits<PlatformMediaSession::RemoteControlCommandType>>;
     60    RemoteCommandsSet m_registeredCommands;
     61
     62    DeferrableTask<Timer> m_updateCommandsTask;
    5463};
    5564
  • trunk/Source/WebCore/platform/audio/NowPlayingInfo.h

    r258024 r272445  
    11/*
    2  * Copyright (C) 2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3333struct NowPlayingInfo {
    3434    String title;
     35    String artist;
     36    String album;
    3537    String sourceApplicationIdentifier;
    3638    double duration { 0 };
     
    5456    String title;
    5557    if (!decoder.decode(title))
     58        return { };
     59
     60    String artist;
     61    if (!decoder.decode(artist))
     62        return { };
     63
     64    String album;
     65    if (!decoder.decode(album))
    5666        return { };
    5767
     
    8494        return { };
    8595
    86     return NowPlayingInfo { WTFMove(title), WTFMove(sourceApplicationIdentifier), duration, currentTime, supportsSeeking, uniqueIdentifier, isPlaying, allowsNowPlayingControlsVisibility };
     96    return NowPlayingInfo { WTFMove(title), WTFMove(artist), WTFMove(album), WTFMove(sourceApplicationIdentifier), duration, currentTime, supportsSeeking, uniqueIdentifier, isPlaying, allowsNowPlayingControlsVisibility };
    8797}
    8898
  • trunk/Source/WebCore/platform/audio/PlatformMediaSession.cpp

    r271698 r272445  
    11/*
    2  * Copyright (C) 2014-2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    9494        MAKE_STATIC_STRING_IMPL("EndSeekingForwardCommand"),
    9595        MAKE_STATIC_STRING_IMPL("SeekToPlaybackPositionCommand"),
     96        MAKE_STATIC_STRING_IMPL("SkipForwardCommand"),
     97        MAKE_STATIC_STRING_IMPL("SkipBackwardCommand"),
     98        MAKE_STATIC_STRING_IMPL("NextTrackCommand"),
     99        MAKE_STATIC_STRING_IMPL("PreviousTrackCommand"),
    96100    };
    97101    static_assert(!static_cast<size_t>(PlatformMediaSession::NoCommand), "PlatformMediaSession::NoCommand is not 0 as expected");
     
    105109    static_assert(static_cast<size_t>(PlatformMediaSession::EndSeekingForwardCommand) == 8, "PlatformMediaSession::EndSeekingForwardCommand is not 8 as expected");
    106110    static_assert(static_cast<size_t>(PlatformMediaSession::SeekToPlaybackPositionCommand) == 9, "PlatformMediaSession::SeekToPlaybackPositionCommand is not 9 as expected");
     111    static_assert(static_cast<size_t>(PlatformMediaSession::SkipForwardCommand) == 10, "PlatformMediaSession::SkipForwardCommand is not 10 as expected");
     112    static_assert(static_cast<size_t>(PlatformMediaSession::SkipBackwardCommand) == 11, "PlatformMediaSession::SkipBackwardCommand is not 11 as expected");
     113    static_assert(static_cast<size_t>(PlatformMediaSession::NextTrackCommand) == 12, "PlatformMediaSession::NextTrackCommand is not 12 as expected");
     114    static_assert(static_cast<size_t>(PlatformMediaSession::PreviousTrackCommand) == 13, "PlatformMediaSession::PreviousTrackCommand is not 13 as expected");
    107115    ASSERT(static_cast<size_t>(command) < WTF_ARRAY_LENGTH(values));
    108116    return values[static_cast<size_t>(command)];
  • trunk/Source/WebCore/platform/audio/PlatformMediaSession.h

    r271643 r272445  
    11/*
    2  * Copyright (C) 2014-2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    131131        EndSeekingForwardCommand,
    132132        SeekToPlaybackPositionCommand,
     133        SkipForwardCommand,
     134        SkipBackwardCommand,
     135        NextTrackCommand,
     136        PreviousTrackCommand,
    133137    };
    134138    bool canReceiveRemoteControlCommands() const;
    135     void didReceiveRemoteControlCommand(RemoteControlCommandType, const RemoteCommandArgument* argument = nullptr);
     139    virtual void didReceiveRemoteControlCommand(RemoteControlCommandType, const RemoteCommandArgument* = nullptr);
    136140    bool supportsSeeking() const;
    137141
  • trunk/Source/WebCore/platform/audio/PlatformMediaSessionManager.h

    r271643 r272445  
    11/*
    2  * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    153153    bool hasNoSession() const;
    154154
     155    virtual void addSupportedCommand(PlatformMediaSession::RemoteControlCommandType) { };
     156    virtual void removeSupportedCommand(PlatformMediaSession::RemoteControlCommandType) { };
     157
    155158protected:
    156159    friend class PlatformMediaSession;
  • trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.h

    r266121 r272445  
    11/*
    2  * Copyright (C) 2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2020-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    8585    GenericTaskQueue<Timer>& taskQueue() { return m_taskQueue; }
    8686
     87    void addSupportedCommand(PlatformMediaSession::RemoteControlCommandType) final;
     88    void removeSupportedCommand(PlatformMediaSession::RemoteControlCommandType) final;
     89
    8790private:
    8891#if !RELEASE_LOG_DISABLED
  • trunk/Source/WebCore/platform/audio/cocoa/MediaSessionManagerCocoa.mm

    r270943 r272445  
    11/*
    2  * Copyright (C) 2013-2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    154154{
    155155    m_taskQueue.enqueueTask([this] () mutable {
     156        if (m_remoteCommandListener)
     157            m_remoteCommandListener->updateSupportedCommands();
     158
    156159        updateNowPlayingInfo();
    157160
     
    233236void MediaSessionManagerCocoa::sessionCanProduceAudioChanged()
    234237{
     238    ALWAYS_LOG(LOGIDENTIFIER);
    235239    PlatformMediaSessionManager::sessionCanProduceAudioChanged();
    236240    scheduleSessionStatusUpdate();
     241}
     242
     243void MediaSessionManagerCocoa::addSupportedCommand(PlatformMediaSession::RemoteControlCommandType command)
     244{
     245    if (m_remoteCommandListener)
     246        m_remoteCommandListener->addSupportedCommand(command);
     247}
     248
     249void MediaSessionManagerCocoa::removeSupportedCommand(PlatformMediaSession::RemoteControlCommandType command)
     250{
     251    if (m_remoteCommandListener)
     252        m_remoteCommandListener->removeSupportedCommand(command);
    237253}
    238254
     
    261277    auto info = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
    262278
     279    if (!nowPlayingInfo.artist.isEmpty())
     280        CFDictionarySetValue(info.get(), kMRMediaRemoteNowPlayingInfoArtist, nowPlayingInfo.artist.createCFString().get());
     281
     282    if (!nowPlayingInfo.album.isEmpty())
     283        CFDictionarySetValue(info.get(), kMRMediaRemoteNowPlayingInfoAlbum, nowPlayingInfo.album.createCFString().get());
     284
    263285    if (!nowPlayingInfo.title.isEmpty())
    264286        CFDictionarySetValue(info.get(), kMRMediaRemoteNowPlayingInfoTitle, nowPlayingInfo.title.createCFString().get());
  • trunk/Source/WebCore/platform/mac/MediaRemoteSoftLink.h

    r261110 r272445  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2016-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    5959SOFT_LINK_CONSTANT_FOR_HEADER(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoTitle, CFStringRef);
    6060#define kMRMediaRemoteNowPlayingInfoTitle get_MediaRemote_kMRMediaRemoteNowPlayingInfoTitle()
     61SOFT_LINK_CONSTANT_FOR_HEADER(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoArtist, CFStringRef);
     62#define kMRMediaRemoteNowPlayingInfoArtist get_MediaRemote_kMRMediaRemoteNowPlayingInfoArtist()
     63SOFT_LINK_CONSTANT_FOR_HEADER(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoAlbum, CFStringRef);
     64#define kMRMediaRemoteNowPlayingInfoAlbum get_MediaRemote_kMRMediaRemoteNowPlayingInfoAlbum()
     65SOFT_LINK_CONSTANT_FOR_HEADER(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoArtworkData, CFStringRef);
     66#define kMRMediaRemoteNowPlayingInfoArtworkData get_MediaRemote_kMRMediaRemoteNowPlayingInfoArtworkData()
     67SOFT_LINK_CONSTANT_FOR_HEADER(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoArtworkMIMEType, CFStringRef);
     68#define kMRMediaRemoteNowPlayingInfoArtworkMIMEType get_MediaRemote_kMRMediaRemoteNowPlayingInfoArtworkMIMEType()
    6169SOFT_LINK_CONSTANT_FOR_HEADER(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoDuration, CFStringRef);
    6270#define kMRMediaRemoteNowPlayingInfoDuration get_MediaRemote_kMRMediaRemoteNowPlayingInfoDuration()
     
    6977SOFT_LINK_CONSTANT_FOR_HEADER(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoUniqueIdentifier, CFStringRef);
    7078#define kMRMediaRemoteNowPlayingInfoUniqueIdentifier get_MediaRemote_kMRMediaRemoteNowPlayingInfoUniqueIdentifier()
     79SOFT_LINK_CONSTANT_FOR_HEADER(WebCore, MediaRemote, kMRMediaRemoteOptionSkipInterval, CFStringRef);
     80#define kMRMediaRemoteOptionSkipInterval get_MediaRemote_kMRMediaRemoteOptionSkipInterval()
    7181
    7282#if PLATFORM(IOS_FAMILY)
  • trunk/Source/WebCore/platform/mac/MediaRemoteSoftLink.mm

    r271982 r272445  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2016-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4545SOFT_LINK_FUNCTION_MAY_FAIL_FOR_SOURCE(WebCore, MediaRemote, MRMediaRemoteSetParentApplication, void, (MROriginRef origin, CFStringRef parentAppDisplayID), (origin, parentAppDisplayID))
    4646SOFT_LINK_CONSTANT_FOR_SOURCE(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoTitle, CFStringRef);
     47SOFT_LINK_CONSTANT_FOR_SOURCE(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoArtist, CFStringRef);
     48SOFT_LINK_CONSTANT_FOR_SOURCE(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoAlbum, CFStringRef);
     49SOFT_LINK_CONSTANT_FOR_SOURCE(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoArtworkData, CFStringRef);
     50SOFT_LINK_CONSTANT_FOR_SOURCE(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoArtworkMIMEType, CFStringRef);
    4751SOFT_LINK_CONSTANT_FOR_SOURCE(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoDuration, CFStringRef);
    4852SOFT_LINK_CONSTANT_FOR_SOURCE(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoElapsedTime, CFStringRef);
     
    5054SOFT_LINK_CONSTANT_FOR_SOURCE(WebCore, MediaRemote, kMRMediaRemoteOptionPlaybackPosition, CFStringRef);
    5155SOFT_LINK_CONSTANT_FOR_SOURCE(WebCore, MediaRemote, kMRMediaRemoteNowPlayingInfoUniqueIdentifier, CFStringRef);
     56SOFT_LINK_CONSTANT_FOR_SOURCE(WebCore, MediaRemote, kMRMediaRemoteOptionSkipInterval, CFStringRef);
    5257
    5358#if PLATFORM(IOS_FAMILY)
  • trunk/Source/WebCore/platform/mac/RemoteCommandListenerMac.h

    r232613 r272445  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2016-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4040
    4141protected:
    42     void updateSupportedCommands() override;
     42    void updateSupportedCommands() final;
    4343
    4444    void* m_commandHandler { nullptr };
     45
     46    const RemoteCommandsSet& defaultCommands();
     47    RemoteCommandsSet m_currentCommands;
     48    bool m_supportsSeeking { false };
    4549};
    4650   
  • trunk/Source/WebCore/platform/mac/RemoteCommandListenerMac.mm

    r261110 r272445  
    11/*
    2  * Copyright (C) 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2016-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3636namespace WebCore {
    3737
     38static Optional<MRMediaRemoteCommand> mediaRemoteCommandForPlatformCommand(PlatformMediaSession::RemoteControlCommandType command)
     39{
     40    static const auto commandMap = makeNeverDestroyed([] {
     41        using CommandToActionMap = HashMap<PlatformMediaSession::RemoteControlCommandType, MRMediaRemoteCommand, WTF::IntHash<PlatformMediaSession::RemoteControlCommandType>, WTF::StrongEnumHashTraits<PlatformMediaSession::RemoteControlCommandType>>;
     42
     43        return CommandToActionMap {
     44            { PlatformMediaSession::PlayCommand, MRMediaRemoteCommandPlay },
     45            { PlatformMediaSession::PauseCommand, MRMediaRemoteCommandPause },
     46            { PlatformMediaSession::StopCommand, MRMediaRemoteCommandStop },
     47            { PlatformMediaSession::TogglePlayPauseCommand, MRMediaRemoteCommandTogglePlayPause },
     48            { PlatformMediaSession::BeginSeekingBackwardCommand, MRMediaRemoteCommandBeginRewind },
     49            { PlatformMediaSession::EndSeekingBackwardCommand, MRMediaRemoteCommandEndRewind },
     50            { PlatformMediaSession::BeginSeekingForwardCommand, MRMediaRemoteCommandBeginFastForward },
     51            { PlatformMediaSession::EndSeekingForwardCommand, MRMediaRemoteCommandEndFastForward },
     52            { PlatformMediaSession::SeekToPlaybackPositionCommand, MRMediaRemoteCommandSeekToPlaybackPosition },
     53            { PlatformMediaSession::SkipForwardCommand, MRMediaRemoteCommandSkipForward },
     54            { PlatformMediaSession::SkipBackwardCommand, MRMediaRemoteCommandSkipBackward },
     55            { PlatformMediaSession::NextTrackCommand, MRMediaRemoteCommandNextTrack },
     56            { PlatformMediaSession::PreviousTrackCommand, MRMediaRemoteCommandPreviousTrack },
     57        };
     58    }());
     59
     60    auto it = commandMap.get().find(command);
     61    if (it != commandMap.get().end())
     62        return { it->value };
     63
     64    return { };
     65}
     66
    3867std::unique_ptr<RemoteCommandListener> RemoteCommandListener::create(RemoteCommandListenerClient& client)
    3968{
    4069    return makeUnique<RemoteCommandListenerMac>(client);
     70}
     71
     72const RemoteCommandListener::RemoteCommandsSet& RemoteCommandListenerMac::defaultCommands()
     73{
     74    static NeverDestroyed<RemoteCommandsSet> commands(std::initializer_list<PlatformMediaSession::RemoteControlCommandType> {
     75        PlatformMediaSession::PlayCommand,
     76        PlatformMediaSession::PauseCommand,
     77        PlatformMediaSession::TogglePlayPauseCommand,
     78        PlatformMediaSession::BeginSeekingForwardCommand,
     79        PlatformMediaSession::EndSeekingForwardCommand,
     80        PlatformMediaSession::BeginSeekingBackwardCommand,
     81        PlatformMediaSession::EndSeekingBackwardCommand,
     82        PlatformMediaSession::SeekToPlaybackPositionCommand,
     83        PlatformMediaSession::SkipForwardCommand,
     84        PlatformMediaSession::SkipBackwardCommand,
     85    });
     86
     87    return commands;
     88}
     89
     90static bool isSeekCommand(PlatformMediaSession::RemoteControlCommandType command)
     91{
     92    return command == PlatformMediaSession::SeekToPlaybackPositionCommand
     93        || command == PlatformMediaSession::SkipForwardCommand
     94        || command == PlatformMediaSession::SkipBackwardCommand
     95        || command == PlatformMediaSession::BeginSeekingForwardCommand
     96        || command == PlatformMediaSession::BeginSeekingBackwardCommand;
    4197}
    4298
     
    46102        return;
    47103
    48     static const MRMediaRemoteCommand supportedCommands[] = {
    49         MRMediaRemoteCommandPlay,
    50         MRMediaRemoteCommandPause,
    51         MRMediaRemoteCommandTogglePlayPause,
    52         MRMediaRemoteCommandBeginFastForward,
    53         MRMediaRemoteCommandEndFastForward,
    54         MRMediaRemoteCommandBeginRewind,
    55         MRMediaRemoteCommandEndRewind,
    56         MRMediaRemoteCommandSeekToPlaybackPosition,
    57     };
    58 
    59     auto commandInfoArray = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, sizeof(supportedCommands) / sizeof(MRMediaRemoteCommand), &kCFTypeArrayCallBacks));
    60 
    61     for (auto command : supportedCommands) {
     104    auto& supportedCommands = !m_registeredCommands.isEmpty() ? m_registeredCommands : defaultCommands();
     105    if (m_supportsSeeking == client().supportsSeeking() && m_currentCommands == supportedCommands)
     106        return;
     107
     108    auto commandInfoArray = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, supportedCommands.size(), &kCFTypeArrayCallBacks));
     109    for (auto platformCommand : supportedCommands) {
     110        if (isSeekCommand(platformCommand) && !client().supportsSeeking())
     111            continue;
     112
     113        auto command = mediaRemoteCommandForPlatformCommand(platformCommand);
     114        ASSERT(command);
     115        if (!command)
     116            continue;
     117
    62118        auto commandInfo = adoptCF(MRMediaRemoteCommandInfoCreate(kCFAllocatorDefault));
    63         MRMediaRemoteCommandInfoSetCommand(commandInfo.get(), command);
     119        MRMediaRemoteCommandInfoSetCommand(commandInfo.get(), command.value());
    64120        MRMediaRemoteCommandInfoSetEnabled(commandInfo.get(), true);
    65121        CFArrayAppendValue(commandInfoArray.get(), commandInfo.get());
    66122    }
    67123
    68     auto seekCommandInfo = adoptCF(MRMediaRemoteCommandInfoCreate(kCFAllocatorDefault));
    69     MRMediaRemoteCommandInfoSetCommand(seekCommandInfo.get(), MRMediaRemoteCommandSeekToPlaybackPosition);
    70     MRMediaRemoteCommandInfoSetEnabled(seekCommandInfo.get(), client().supportsSeeking());
    71     CFArrayAppendValue(commandInfoArray.get(), seekCommandInfo.get());
    72 
    73124    MRMediaRemoteSetSupportedCommands(commandInfoArray.get(), MRMediaRemoteGetLocalOrigin(), nullptr, nullptr);
     125    m_currentCommands = supportedCommands;
     126    m_supportsSeeking = client().supportsSeeking();
    74127}
    75128
     
    80133        return;
    81134
    82     updateSupportedCommands();
     135    scheduleSupportedCommandsUpdate();
    83136
    84137    auto weakThis = makeWeakPtr(*this);
     
    89142        PlatformMediaSession::RemoteControlCommandType platformCommand { PlatformMediaSession::NoCommand };
    90143        PlatformMediaSession::RemoteCommandArgument argument { 0 };
     144        PlatformMediaSession::RemoteCommandArgument* argumentPtr = nullptr;
    91145        MRMediaRemoteCommandHandlerStatus status = MRMediaRemoteCommandHandlerStatusSuccess;
    92146
     
    129183
    130184            CFNumberGetValue(positionRef, kCFNumberDoubleType, &argument.asDouble);
     185            argumentPtr = &argument;
    131186            platformCommand = PlatformMediaSession::SeekToPlaybackPositionCommand;
    132187            break;
    133188        }
     189        case MRMediaRemoteCommandSkipForward:
     190        case MRMediaRemoteCommandSkipBackward:
     191            if (!client.supportsSeeking()) {
     192                status = MRMediaRemoteCommandHandlerStatusCommandFailed;
     193                break;
     194            }
     195
     196            if (auto positionRef = static_cast<CFNumberRef>(CFDictionaryGetValue(options, kMRMediaRemoteOptionSkipInterval))) {
     197                CFNumberGetValue(positionRef, kCFNumberDoubleType, &argument.asDouble);
     198                argumentPtr = &argument;
     199            }
     200
     201            platformCommand = (command == MRMediaRemoteCommandSkipForward) ? PlatformMediaSession::SkipForwardCommand : PlatformMediaSession::SkipBackwardCommand;
     202            break;
     203        case MRMediaRemoteCommandNextTrack:
     204            platformCommand = PlatformMediaSession::NextTrackCommand;
     205            break;
     206        case MRMediaRemoteCommandPreviousTrack:
     207            platformCommand = PlatformMediaSession::PreviousTrackCommand;
     208            break;
    134209        default:
    135210            LOG(Media, "RemoteCommandListenerMac::RemoteCommandListenerMac - command %u not supported!", command);
     
    138213
    139214        if (weakThis && status != MRMediaRemoteCommandHandlerStatusCommandFailed)
    140             weakThis->m_client.didReceiveRemoteControlCommand(platformCommand, &argument);
     215            weakThis->m_client.didReceiveRemoteControlCommand(platformCommand, argumentPtr);
    141216
    142217        completion((__bridge CFArrayRef)@[@(status)]);
  • trunk/Source/WebKit/ChangeLog

    r272434 r272445  
     12021-02-05  Eric Carlson  <eric.carlson@apple.com>
     2
     3        [Mac] Connect MediaSession with MediaRemote and NowPlaying
     4        https://bugs.webkit.org/show_bug.cgi?id=221431
     5        <rdar://problem/74000363>
     6
     7        Reviewed by Jer Noble.
     8
     9        Add a private preference so the new MediaSession API test can enable the feature.
     10
     11        * UIProcess/API/Cocoa/WKPreferences.mm:
     12        (-[WKPreferences _mediaSessionEnabled]):
     13        (-[WKPreferences _setMediaSessionEnabled:]):
     14        * UIProcess/API/Cocoa/WKPreferencesPrivate.h:
     15
    1162021-02-05  Youenn Fablet  <youenn@apple.com>
    217
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm

    r271219 r272445  
    14801480}
    14811481
     1482- (BOOL)_mediaSessionEnabled
     1483{
     1484    return _preferences->mediaSessionEnabled();
     1485}
     1486
     1487- (void)_setMediaSessionEnabled:(BOOL)mediaSessionEnabled
     1488{
     1489    _preferences->setMediaSessionEnabled(mediaSessionEnabled);
     1490}
     1491
    14821492@end
    14831493
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h

    r271813 r272445  
    171171@property (nonatomic, setter=_setPrivateClickMeasurementEnabled:) BOOL _privateClickMeasurementEnabled WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
    172172@property (nonatomic, setter=_setPitchCorrectionAlgorithm:) _WKPitchCorrectionAlgorithm _pitchCorrectionAlgorithm WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
     173@property (nonatomic, setter=_setMediaSessionEnabled:) BOOL _mediaSessionEnabled WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
    173174
    174175#if !TARGET_OS_IPHONE
  • trunk/Tools/ChangeLog

    r272436 r272445  
     12021-02-05  Eric Carlson  <eric.carlson@apple.com>
     2
     3        [Mac] Connect MediaSession with MediaRemote and NowPlaying
     4        https://bugs.webkit.org/show_bug.cgi?id=221431
     5        <rdar://problem/74000363>
     6
     7        Reviewed by Jer Noble.
     8
     9        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
     10        * TestWebKitAPI/Tests/WebKitCocoa/MediaSession.mm: Added.
     11        (TestWebKitAPI::MediaSessionTest::webView):
     12        (TestWebKitAPI::MediaSessionTest::webViewPid):
     13        (TestWebKitAPI::MediaSessionTest::getNowPlayingClient):
     14        (TestWebKitAPI::MediaSessionTest::getNowPlayingClientPid):
     15        (TestWebKitAPI::MediaSessionTest::loadPageAndBecomeNowPlaying):
     16        (TestWebKitAPI::MediaSessionTest::runScriptWithUserGesture):
     17        (TestWebKitAPI::MediaSessionTest::play):
     18        (TestWebKitAPI::MediaSessionTest::pause):
     19        (TestWebKitAPI::MediaSessionTest::sendMediaRemoteCommand):
     20        (TestWebKitAPI::MediaSessionTest::sendMediaRemoteSeekCommand):
     21        (TestWebKitAPI::MediaSessionTest::listenForEventMessages):
     22        (TestWebKitAPI::MediaSessionTest::eventListenerWasCalled):
     23        (TestWebKitAPI::MediaSessionTest::waitForEventListenerToBeCalled):
     24        (TestWebKitAPI::MediaSessionTest::listenForSessionHandlerMessages):
     25        (TestWebKitAPI::MediaSessionTest::sessionHandlerWasCalled):
     26        (TestWebKitAPI::MediaSessionTest::waitForSessionHandlerToBeCalled):
     27        (TestWebKitAPI::MediaSessionTest::getSupportedCommands):
     28        (TestWebKitAPI::TEST_F):
     29        * TestWebKitAPI/Tests/WebKitCocoa/media-remote.html: Added.
     30
    1312021-02-05  Sam Weinig  <weinig@apple.com>
    232
  • trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

    r271969 r272445  
    5757                076E507F1F4513D6006E9F5A /* Logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 076E507E1F45031E006E9F5A /* Logging.cpp */; };
    5858                077A5AF3230638A600A7105C /* AccessibilityTestPlugin.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0746645822FF630500E3451A /* AccessibilityTestPlugin.mm */; };
     59                0794740D25CA0BDE00C597EB /* MediaSession.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0794740C25CA0BDE00C597EB /* MediaSession.mm */; };
     60                0794742D25CB33FD00C597EB /* media-remote.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 0794742C25CB33B000C597EB /* media-remote.html */; };
    5961                0799C3491EBA2D7B003B7532 /* UserMediaDisabled.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07EDEFAC1EB9400C00D43292 /* UserMediaDisabled.mm */; };
    6062                0799C34B1EBA3301003B7532 /* disableGetUserMedia.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 0799C34A1EBA32F4003B7532 /* disableGetUserMedia.html */; };
     
    15601562                                7772ECE122FE06C60009A799 /* many-same-origin-iframes.html in Copy Resources */,
    15611563                                CD8394DF232AF7C000149495 /* media-loading.html in Copy Resources */,
     1564                                0794742D25CB33FD00C597EB /* media-remote.html in Copy Resources */,
    15621565                                CDA3159A1ED548F1009F60D3 /* MediaPlaybackSleepAssertion.html in Copy Resources */,
    15631566                                CDC9442F1EF205D60059C3C4 /* mediastreamtrack-detached.html in Copy Resources */,
     
    17231726                0766DD1F1A5AD5200023E3BB /* PendingAPIRequestURL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PendingAPIRequestURL.cpp; sourceTree = "<group>"; };
    17241727                076E507E1F45031E006E9F5A /* Logging.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Logging.cpp; sourceTree = "<group>"; };
     1728                0794740C25CA0BDE00C597EB /* MediaSession.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MediaSession.mm; sourceTree = "<group>"; };
     1729                0794742C25CB33B000C597EB /* media-remote.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "media-remote.html"; sourceTree = "<group>"; };
    17251730                0799C34A1EBA32F4003B7532 /* disableGetUserMedia.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = disableGetUserMedia.html; sourceTree = "<group>"; };
    17261731                07C046C91E42573E007201E7 /* CARingBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CARingBuffer.cpp; sourceTree = "<group>"; };
     
    33603365                                CD0370E224A44B7A00BA3CAE /* MediaLoading.mm */,
    33613366                                07EF76D42540FC060053ED53 /* MediaMutedState.mm */,
     3367                                0794740C25CA0BDE00C597EB /* MediaSession.mm */,
    33623368                                51BE9E652376089500B4E117 /* MediaType.mm */,
    33633369                                5165FE03201EE617009F7EC3 /* MessagePortProviders.mm */,
     
    39233929                                46C519E41D35629600DAA51A /* LocalStorageNullEntries.localstorage-shm */,
    39243930                                7A6A2C711DCCFB0200C0D085 /* LocalStorageQuirkEnabled.html */,
     3931                                0794742C25CB33B000C597EB /* media-remote.html */,
    39253932                                9B59F12920340854009E63D5 /* mso-list-compat-mode.html */,
    39263933                                9BCD4119206D5ED7001D71BE /* mso-list-on-h4.html */,
     
    53845391                                07EF76D52540FC060053ED53 /* MediaMutedState.mm in Sources */,
    53855392                                CDA315981ED53651009F60D3 /* MediaPlaybackSleepAssertion.mm in Sources */,
     5393                                0794740D25CA0BDE00C597EB /* MediaSession.mm in Sources */,
    53865394                                CDC9442E1EF1FC080059C3C4 /* MediaStreamTrackDetached.mm in Sources */,
    53875395                                51BE9E662376089F00B4E117 /* MediaType.mm in Sources */,
     
    54225430                                CEBCA12F1E3A660100C73293 /* OverrideContentSecurityPolicy.mm in Sources */,
    54235431                                2DA2586F225C67DC00B45C1C /* OverrideViewportArguments.mm in Sources */,
     5432                                953ABB3525C0D682004C8B73 /* PageExtendedBackgroundColor.mm in Sources */,
    54245433                                7CCB4DA91C83AE7300CC6918 /* PageGroup.cpp in Sources */,
    54255434                                7CCE7F071A411AE600447C4C /* PageLoadBasic.cpp in Sources */,
     
    54655474                                FEC2A85624CEB65F00ADBC35 /* PropertySlot.cpp in Sources */,
    54665475                                7C83E0C11D0A652F00FEBCF3 /* ProvisionalURLNotChange.mm in Sources */,
    5467                                 953ABB3525C0D682004C8B73 /* PageExtendedBackgroundColor.mm in Sources */,
    54685476                                5CFACF65226FD2DC0056C7D0 /* Proxy.mm in Sources */,
    54695477                                041A1E34216FFDBC00789E0A /* PublicSuffix.cpp in Sources */,
Note: See TracChangeset for help on using the changeset viewer.