2 * Copyright (C) 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #import "RemoteCommandListenerIOS.h"
31 #import <MediaPlayer/MPRemoteCommand.h>
32 #import <MediaPlayer/MPRemoteCommandCenter.h>
33 #import <MediaPlayer/MPRemoteCommandEvent.h>
34 #import <wtf/SoftLinking.h>
36 SOFT_LINK_FRAMEWORK_OPTIONAL(MediaPlayer)
37 SOFT_LINK_CLASS(MediaPlayer, MPRemoteCommandCenter)
38 SOFT_LINK_CLASS(MediaPlayer, MPSeekCommandEvent)
39 SOFT_LINK_CLASS(MediaPlayer, MPChangePlaybackPositionCommandEvent)
43 std::unique_ptr<RemoteCommandListener> RemoteCommandListener::create(RemoteCommandListenerClient& client)
45 if (!MediaPlayerLibrary())
48 return std::make_unique<RemoteCommandListenerIOS>(client);
51 RemoteCommandListenerIOS::RemoteCommandListenerIOS(RemoteCommandListenerClient& client)
52 : RemoteCommandListener(client)
54 MPRemoteCommandCenter *center = [getMPRemoteCommandCenterClass() sharedCommandCenter];
55 auto weakThis = createWeakPtr();
57 m_pauseTarget = [[center pauseCommand] addTargetWithHandler:^(MPRemoteCommandEvent *) {
58 callOnMainThread([weakThis] {
61 weakThis->m_client.didReceiveRemoteControlCommand(PlatformMediaSession::PauseCommand, nullptr);
64 return MPRemoteCommandHandlerStatusSuccess;
67 m_playTarget = [[center playCommand] addTargetWithHandler:^(MPRemoteCommandEvent *) {
68 callOnMainThread([weakThis] {
71 weakThis->m_client.didReceiveRemoteControlCommand(PlatformMediaSession::PlayCommand, nullptr);
74 return MPRemoteCommandHandlerStatusSuccess;
77 m_togglePlayPauseTarget = [[center togglePlayPauseCommand] addTargetWithHandler:^(MPRemoteCommandEvent *) {
78 callOnMainThread([weakThis] {
81 weakThis->m_client.didReceiveRemoteControlCommand(PlatformMediaSession::TogglePlayPauseCommand, nullptr);
84 return MPRemoteCommandHandlerStatusSuccess;
87 m_seekBackwardTarget = [[center seekBackwardCommand] addTargetWithHandler:^(MPRemoteCommandEvent *event) {
88 ASSERT([event isKindOfClass:getMPSeekCommandEventClass()]);
90 MPSeekCommandEvent* seekEvent = static_cast<MPSeekCommandEvent *>(event);
91 PlatformMediaSession::RemoteControlCommandType command = [seekEvent type] == MPSeekCommandEventTypeBeginSeeking ? PlatformMediaSession::BeginSeekingBackwardCommand : PlatformMediaSession::EndSeekingBackwardCommand;
93 callOnMainThread([weakThis, command] {
96 weakThis->m_client.didReceiveRemoteControlCommand(command, nullptr);
99 return MPRemoteCommandHandlerStatusSuccess;
102 m_seekForwardTarget = [[center seekForwardCommand] addTargetWithHandler:^(MPRemoteCommandEvent *event) {
103 ASSERT([event isKindOfClass:getMPSeekCommandEventClass()]);
104 MPSeekCommandEvent* seekEvent = static_cast<MPSeekCommandEvent *>(event);
106 PlatformMediaSession::RemoteControlCommandType command = [seekEvent type] == MPSeekCommandEventTypeBeginSeeking ? PlatformMediaSession::BeginSeekingForwardCommand : PlatformMediaSession::EndSeekingForwardCommand;
108 callOnMainThread([weakThis, command] {
111 weakThis->m_client.didReceiveRemoteControlCommand(command, nullptr);
114 return MPRemoteCommandHandlerStatusSuccess;
117 m_seekToTimeTarget = [[center changePlaybackPositionCommand] addTargetWithHandler:^(MPRemoteCommandEvent *event) {
118 ASSERT([event isKindOfClass:getMPChangePlaybackPositionCommandEventClass()]);
120 if (!client.supportsSeeking())
121 return MPRemoteCommandHandlerStatusCommandFailed;
123 MPChangePlaybackPositionCommandEvent* seekEvent = static_cast<MPChangePlaybackPositionCommandEvent *>(event);
124 PlatformMediaSession::RemoteCommandArgument argument { [seekEvent positionTime] };
126 callOnMainThread([weakThis, argument] {
129 weakThis->m_client.didReceiveRemoteControlCommand(PlatformMediaSession::SeekToPlaybackPositionCommand, &argument);
132 return MPRemoteCommandHandlerStatusSuccess;
136 RemoteCommandListenerIOS::~RemoteCommandListenerIOS()
138 MPRemoteCommandCenter *center = [getMPRemoteCommandCenterClass() sharedCommandCenter];
139 [[center pauseCommand] removeTarget:m_pauseTarget.get()];
140 [[center playCommand] removeTarget:m_playTarget.get()];
141 [[center togglePlayPauseCommand] removeTarget:m_togglePlayPauseTarget.get()];
142 [[center seekForwardCommand] removeTarget:m_seekForwardTarget.get()];
143 [[center seekBackwardCommand] removeTarget:m_seekBackwardTarget.get()];
144 [[center changePlaybackPositionCommand] removeTarget:m_seekToTimeTarget.get()];
147 void RemoteCommandListenerIOS::updateSupportedCommands()
149 [[[getMPRemoteCommandCenterClass() sharedCommandCenter] changePlaybackPositionCommand] setEnabled:!!client().supportsSeeking()];
154 #endif // PLATFORM(IOS)