| // Copyright 2017 The Cobalt Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "starboard/shared/uwp/xb1_media_session_client.h" |
| #include "starboard/common/log.h" |
| |
| #include "starboard/common/semaphore.h" |
| #include "starboard/key.h" |
| #include "starboard/once.h" |
| #include "starboard/shared/uwp/app_accessors.h" |
| |
| using starboard::shared::uwp::DisplayRequestActive; |
| using starboard::shared::uwp::DisplayRequestRelease; |
| using starboard::shared::uwp::GetTransportControls; |
| using starboard::shared::uwp::InjectKeypress; |
| using Windows::Foundation::TypedEventHandler; |
| using Windows::Media::MediaPlaybackStatus; |
| using Windows::Media::SystemMediaTransportControls; |
| using Windows::Media::SystemMediaTransportControlsButton; |
| using Windows::Media::SystemMediaTransportControlsButtonPressedEventArgs; |
| using Windows::Media::Playback::MediaPlayer; |
| using Windows::UI::Core::CoreDispatcherPriority; |
| using Windows::UI::Core::DispatchedHandler; |
| |
| namespace { |
| |
| MediaPlaybackStatus MediaSessionPlaybackStateToMediaPlaybackState( |
| CobaltExtensionMediaSessionPlaybackState playback_state) { |
| switch (playback_state) { |
| case kCobaltExtensionMediaSessionNone: |
| return MediaPlaybackStatus::Stopped; |
| case kCobaltExtensionMediaSessionPaused: |
| return MediaPlaybackStatus::Paused; |
| case kCobaltExtensionMediaSessionPlaying: |
| return MediaPlaybackStatus::Playing; |
| default: |
| SB_NOTREACHED() << "Invalid playback_state " << playback_state; |
| } |
| return MediaPlaybackStatus::Closed; |
| } |
| |
| SbOnceControl once_flag = SB_ONCE_INITIALIZER; |
| SbMutex mutex; |
| |
| // Callbacks to the last MediaSessionClient to become active, or null. |
| // In practice, only one MediaSessionClient will become active at a time. |
| // Protected by "mutex" |
| CobaltExtensionMediaSessionUpdatePlatformPlaybackStateCallback |
| g_update_platform_playback_state_callback; |
| void* g_callback_context; |
| |
| bool button_press_callback_registered = false; |
| bool active = false; |
| bool media_playing = false; |
| |
| void OnceInit() { |
| SbMutexCreate(&mutex); |
| } |
| |
| void InitButtonCallbackOnce() { |
| if (button_press_callback_registered) { |
| return; |
| } |
| button_press_callback_registered = true; |
| Platform::Agile<SystemMediaTransportControls> transport_controls = |
| GetTransportControls(); |
| |
| transport_controls->ButtonPressed += ref new TypedEventHandler< |
| SystemMediaTransportControls ^, |
| SystemMediaTransportControlsButtonPressedEventArgs ^>( |
| [](SystemMediaTransportControls ^ controls, |
| SystemMediaTransportControlsButtonPressedEventArgs ^ args) { |
| SbKey key_code; |
| switch (args->Button) { |
| case SystemMediaTransportControlsButton::ChannelDown: |
| key_code = kSbKeyChannelDown; |
| break; |
| case SystemMediaTransportControlsButton::ChannelUp: |
| key_code = kSbKeyChannelUp; |
| break; |
| case SystemMediaTransportControlsButton::Next: |
| key_code = kSbKeyMediaNextTrack; |
| break; |
| case SystemMediaTransportControlsButton::Pause: |
| case SystemMediaTransportControlsButton::Play: |
| key_code = kSbKeyMediaPlayPause; |
| break; |
| case SystemMediaTransportControlsButton::Previous: |
| key_code = kSbKeyMediaPrevTrack; |
| break; |
| case SystemMediaTransportControlsButton::Stop: |
| key_code = kSbKeyMediaStop; |
| break; |
| case SystemMediaTransportControlsButton::FastForward: |
| key_code = kSbKeyMediaFastForward; |
| break; |
| case SystemMediaTransportControlsButton::Rewind: |
| key_code = kSbKeyMediaRewind; |
| break; |
| default: |
| key_code = kSbKeyUnknown; |
| break; |
| } |
| if (key_code != kSbKeyUnknown) { |
| InjectKeypress(key_code); |
| } |
| }); |
| } |
| |
| void OnMediaSessionStateChanged( |
| const CobaltExtensionMediaSessionState session_state) { |
| const CobaltExtensionMediaSessionPlaybackState playback_state = |
| session_state.actual_playback_state; |
| |
| SbOnce(&once_flag, OnceInit); |
| SbMutexAcquire(&mutex); |
| |
| InitButtonCallbackOnce(); |
| Platform::Agile<SystemMediaTransportControls> transport_controls = |
| GetTransportControls(); |
| |
| SbMutexRelease(&mutex); |
| |
| const bool sessionActive = kCobaltExtensionMediaSessionNone == playback_state; |
| |
| bool now_active = false; |
| bool now_media_playing = false; |
| |
| switch (playback_state) { |
| case kCobaltExtensionMediaSessionPlaying: |
| now_active = true; |
| now_media_playing = true; |
| break; |
| case kCobaltExtensionMediaSessionPaused: |
| now_active = true; |
| now_media_playing = false; |
| break; |
| case kCobaltExtensionMediaSessionNone: |
| now_active = false; |
| now_media_playing = false; |
| break; |
| default: |
| SB_NOTREACHED() << "Unknown state reached " << playback_state; |
| } |
| if (now_media_playing && !media_playing) { |
| DisplayRequestActive(); |
| } else if (!now_media_playing && media_playing) { |
| DisplayRequestRelease(); |
| } |
| |
| transport_controls->IsEnabled = now_active; |
| |
| active = now_active; |
| media_playing = now_media_playing; |
| |
| transport_controls->IsChannelDownEnabled = now_active; |
| transport_controls->IsChannelUpEnabled = now_active; |
| transport_controls->IsFastForwardEnabled = now_active; |
| transport_controls->IsNextEnabled = now_active; |
| transport_controls->IsPauseEnabled = now_active; |
| transport_controls->IsPlayEnabled = now_active; |
| transport_controls->IsPreviousEnabled = now_active; |
| transport_controls->IsRecordEnabled = now_active; |
| transport_controls->IsRewindEnabled = now_active; |
| transport_controls->IsStopEnabled = now_active; |
| |
| if (!active) { |
| return; |
| } |
| |
| transport_controls->PlaybackStatus = |
| MediaSessionPlaybackStateToMediaPlaybackState(playback_state); |
| } |
| |
| void RegisterMediaSessionCallbacks( |
| void* callback_context, |
| CobaltExtensionMediaSessionInvokeActionCallback invoke_action_callback, |
| CobaltExtensionMediaSessionUpdatePlatformPlaybackStateCallback |
| update_platform_playback_state_callback) { |
| SbOnce(&once_flag, OnceInit); |
| SbMutexAcquire(&mutex); |
| |
| g_callback_context = callback_context; |
| g_update_platform_playback_state_callback = |
| update_platform_playback_state_callback; |
| |
| SbMutexRelease(&mutex); |
| } |
| |
| void DestroyMediaSessionClientCallback() { |
| SbOnce(&once_flag, OnceInit); |
| SbMutexAcquire(&mutex); |
| |
| g_callback_context = NULL; |
| g_update_platform_playback_state_callback = NULL; |
| |
| SbMutexRelease(&mutex); |
| } |
| |
| void UpdateActiveSessionPlatformPlaybackState( |
| CobaltExtensionMediaSessionPlaybackState state) { |
| SbOnce(&once_flag, OnceInit); |
| SbMutexAcquire(&mutex); |
| |
| if (g_update_platform_playback_state_callback != NULL && |
| g_callback_context != NULL) { |
| g_update_platform_playback_state_callback(state, g_callback_context); |
| } |
| |
| SbMutexRelease(&mutex); |
| } |
| } // namespace |
| |
| namespace starboard { |
| namespace shared { |
| namespace uwp { |
| |
| const CobaltExtensionMediaSessionApi kMediaSessionApi = { |
| kCobaltExtensionMediaSessionName, |
| 1, |
| &OnMediaSessionStateChanged, |
| &RegisterMediaSessionCallbacks, |
| &DestroyMediaSessionClientCallback, |
| &UpdateActiveSessionPlatformPlaybackState}; |
| |
| const void* GetMediaSessionApi() { |
| return &kMediaSessionApi; |
| } |
| } // namespace uwp |
| } // namespace shared |
| } // namespace starboard |