Bug 1793629 - Implement attention indicator for the unified extensions button, r...
[gecko.git] / widget / cocoa / MediaHardwareKeysEventSourceMacMediaCenter.mm
bloba258c7900cd3961ef378c8071dab785d33df63c3
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3  * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #import <MediaPlayer/MediaPlayer.h>
7 #include "MediaHardwareKeysEventSourceMacMediaCenter.h"
9 #include "mozilla/dom/MediaControlUtils.h"
10 #include "nsCocoaUtils.h"
12 using namespace mozilla::dom;
14 // avoid redefined macro in unified build
15 #undef LOG
16 #define LOG(msg, ...)                        \
17   MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
18           ("MediaHardwareKeysEventSourceMacMediaCenter=%p, " msg, this, ##__VA_ARGS__))
20 namespace mozilla {
21 namespace widget {
23 MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayPauseHandler() {
24   return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
25     MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
26     center.playbackState = center.playbackState == MPNowPlayingPlaybackStatePlaying
27                                ? MPNowPlayingPlaybackStatePaused
28                                : MPNowPlayingPlaybackStatePlaying;
29     HandleEvent(MediaControlKey::Playpause);
30     return MPRemoteCommandHandlerStatusSuccess;
31   });
34 MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreateNextTrackHandler() {
35   return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
36     HandleEvent(MediaControlKey::Nexttrack);
37     return MPRemoteCommandHandlerStatusSuccess;
38   });
41 MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePreviousTrackHandler() {
42   return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
43     HandleEvent(MediaControlKey::Previoustrack);
44     return MPRemoteCommandHandlerStatusSuccess;
45   });
48 MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePlayHandler() {
49   return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
50     MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
51     if (center.playbackState != MPNowPlayingPlaybackStatePlaying) {
52       center.playbackState = MPNowPlayingPlaybackStatePlaying;
53     }
54     HandleEvent(MediaControlKey::Play);
55     return MPRemoteCommandHandlerStatusSuccess;
56   });
59 MediaCenterEventHandler MediaHardwareKeysEventSourceMacMediaCenter::CreatePauseHandler() {
60   return Block_copy(^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent* event) {
61     MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
62     if (center.playbackState != MPNowPlayingPlaybackStatePaused) {
63       center.playbackState = MPNowPlayingPlaybackStatePaused;
64     }
65     HandleEvent(MediaControlKey::Pause);
66     return MPRemoteCommandHandlerStatusSuccess;
67   });
70 MediaHardwareKeysEventSourceMacMediaCenter::MediaHardwareKeysEventSourceMacMediaCenter() {
71   mPlayPauseHandler = CreatePlayPauseHandler();
72   mNextTrackHandler = CreateNextTrackHandler();
73   mPreviousTrackHandler = CreatePreviousTrackHandler();
74   mPlayHandler = CreatePlayHandler();
75   mPauseHandler = CreatePauseHandler();
76   LOG("Create MediaHardwareKeysEventSourceMacMediaCenter");
79 MediaHardwareKeysEventSourceMacMediaCenter::~MediaHardwareKeysEventSourceMacMediaCenter() {
80   LOG("Destroy MediaHardwareKeysEventSourceMacMediaCenter");
81   EndListeningForEvents();
82   MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
83   center.playbackState = MPNowPlayingPlaybackStateStopped;
86 void MediaHardwareKeysEventSourceMacMediaCenter::BeginListeningForEvents() {
87   MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
88   center.playbackState = MPNowPlayingPlaybackStatePlaying;
89   MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
90   commandCenter.togglePlayPauseCommand.enabled = true;
91   [commandCenter.togglePlayPauseCommand addTargetWithHandler:mPlayPauseHandler];
92   commandCenter.nextTrackCommand.enabled = true;
93   [commandCenter.nextTrackCommand addTargetWithHandler:mNextTrackHandler];
94   commandCenter.previousTrackCommand.enabled = true;
95   [commandCenter.previousTrackCommand addTargetWithHandler:mPreviousTrackHandler];
96   commandCenter.playCommand.enabled = true;
97   [commandCenter.playCommand addTargetWithHandler:mPlayHandler];
98   commandCenter.pauseCommand.enabled = true;
99   [commandCenter.pauseCommand addTargetWithHandler:mPauseHandler];
102 void MediaHardwareKeysEventSourceMacMediaCenter::EndListeningForEvents() {
103   MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
104   center.playbackState = MPNowPlayingPlaybackStatePaused;
105   center.nowPlayingInfo = nil;
106   MPRemoteCommandCenter* commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
107   commandCenter.togglePlayPauseCommand.enabled = false;
108   [commandCenter.togglePlayPauseCommand removeTarget:nil];
109   commandCenter.nextTrackCommand.enabled = false;
110   [commandCenter.nextTrackCommand removeTarget:nil];
111   commandCenter.previousTrackCommand.enabled = false;
112   [commandCenter.previousTrackCommand removeTarget:nil];
113   commandCenter.playCommand.enabled = false;
114   [commandCenter.playCommand removeTarget:nil];
115   commandCenter.pauseCommand.enabled = false;
116   [commandCenter.pauseCommand removeTarget:nil];
119 bool MediaHardwareKeysEventSourceMacMediaCenter::Open() {
120   LOG("Open MediaHardwareKeysEventSourceMacMediaCenter");
121   mOpened = true;
122   BeginListeningForEvents();
123   return true;
126 void MediaHardwareKeysEventSourceMacMediaCenter::Close() {
127   LOG("Close MediaHardwareKeysEventSourceMacMediaCenter");
128   SetPlaybackState(dom::MediaSessionPlaybackState::None);
129   EndListeningForEvents();
130   mOpened = false;
131   MediaControlKeySource::Close();
134 bool MediaHardwareKeysEventSourceMacMediaCenter::IsOpened() const { return mOpened; }
136 void MediaHardwareKeysEventSourceMacMediaCenter::HandleEvent(MediaControlKey aEvent) {
137   for (auto iter = mListeners.begin(); iter != mListeners.end(); ++iter) {
138     (*iter)->OnActionPerformed(MediaControlAction(aEvent));
139   }
142 void MediaHardwareKeysEventSourceMacMediaCenter::SetPlaybackState(
143     MediaSessionPlaybackState aState) {
144   MPNowPlayingInfoCenter* center = [MPNowPlayingInfoCenter defaultCenter];
145   if (aState == MediaSessionPlaybackState::Playing) {
146     center.playbackState = MPNowPlayingPlaybackStatePlaying;
147   } else if (aState == MediaSessionPlaybackState::Paused) {
148     center.playbackState = MPNowPlayingPlaybackStatePaused;
149   } else if (aState == MediaSessionPlaybackState::None) {
150     center.playbackState = MPNowPlayingPlaybackStateStopped;
151   }
152   MediaControlKeySource::SetPlaybackState(aState);
155 void MediaHardwareKeysEventSourceMacMediaCenter::SetMediaMetadata(
156     const dom::MediaMetadataBase& aMetadata) {
157   NSMutableDictionary* nowPlayingInfo = [NSMutableDictionary dictionary];
158   [nowPlayingInfo setObject:nsCocoaUtils::ToNSString(aMetadata.mTitle)
159                      forKey:MPMediaItemPropertyTitle];
160   [nowPlayingInfo setObject:nsCocoaUtils::ToNSString(aMetadata.mArtist)
161                      forKey:MPMediaItemPropertyArtist];
162   [nowPlayingInfo setObject:nsCocoaUtils::ToNSString(aMetadata.mAlbum)
163                      forKey:MPMediaItemPropertyAlbumTitle];
164   // The procedure of updating `nowPlayingInfo` is actually an async operation
165   // from our testing, Apple's documentation doesn't mention that though. So be
166   // aware that checking `nowPlayingInfo` immedately after setting it might not
167   // yield the expected result.
168   [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = nowPlayingInfo;