123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/system_media_controls/win/system_media_controls_win.h"
- #include <systemmediatransportcontrolsinterop.h>
- #include <windows.media.control.h>
- #include <wrl/client.h>
- #include <wrl/event.h>
- #include "base/strings/string_piece.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/win/core_winrt_util.h"
- #include "base/win/scoped_hstring.h"
- #include "components/system_media_controls/system_media_controls_observer.h"
- #include "ui/gfx/codec/png_codec.h"
- #include "ui/gfx/win/singleton_hwnd.h"
- namespace system_media_controls {
- // static
- std::unique_ptr<SystemMediaControls> SystemMediaControls::Create(
- const std::string& product_name) {
- auto service = std::make_unique<internal::SystemMediaControlsWin>();
- if (service->Initialize())
- return std::move(service);
- return nullptr;
- }
- namespace internal {
- using ABI::Windows::Media::ISystemMediaTransportControls;
- using ABI::Windows::Media::ISystemMediaTransportControlsButtonPressedEventArgs;
- using ABI::Windows::Media::SystemMediaTransportControls;
- using ABI::Windows::Media::SystemMediaTransportControlsButton;
- using ABI::Windows::Media::SystemMediaTransportControlsButtonPressedEventArgs;
- using ABI::Windows::Storage::Streams::IDataWriter;
- using ABI::Windows::Storage::Streams::IDataWriterFactory;
- using ABI::Windows::Storage::Streams::IOutputStream;
- using ABI::Windows::Storage::Streams::IRandomAccessStream;
- using ABI::Windows::Storage::Streams::IRandomAccessStreamReference;
- using ABI::Windows::Storage::Streams::IRandomAccessStreamReferenceStatics;
- // static
- SystemMediaControlsWin* SystemMediaControlsWin::GetInstance() {
- return instance_;
- }
- // static
- SystemMediaControlsWin* SystemMediaControlsWin::instance_ = nullptr;
- SystemMediaControlsWin::SystemMediaControlsWin() {
- DCHECK(!instance_);
- instance_ = this;
- }
- SystemMediaControlsWin::~SystemMediaControlsWin() {
- if (has_valid_registration_token_) {
- DCHECK(system_media_controls_);
- system_media_controls_->remove_ButtonPressed(registration_token_);
- ClearMetadata();
- }
- DCHECK_EQ(instance_, this);
- instance_ = nullptr;
- }
- bool SystemMediaControlsWin::Initialize() {
- if (attempted_to_initialize_)
- return initialized_;
- attempted_to_initialize_ = true;
- if (!base::win::ResolveCoreWinRTDelayload() ||
- !base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) {
- return false;
- }
- Microsoft::WRL::ComPtr<ISystemMediaTransportControlsInterop> interop;
- HRESULT hr = base::win::GetActivationFactory<
- ISystemMediaTransportControlsInterop,
- RuntimeClass_Windows_Media_SystemMediaTransportControls>(&interop);
- if (FAILED(hr))
- return false;
- hr = interop->GetForWindow(gfx::SingletonHwnd::GetInstance()->hwnd(),
- IID_PPV_ARGS(&system_media_controls_));
- if (FAILED(hr))
- return false;
- auto handler =
- Microsoft::WRL::Callback<ABI::Windows::Foundation::ITypedEventHandler<
- SystemMediaTransportControls*,
- SystemMediaTransportControlsButtonPressedEventArgs*>>(
- &SystemMediaControlsWin::ButtonPressed);
- hr = system_media_controls_->add_ButtonPressed(handler.Get(),
- ®istration_token_);
- if (FAILED(hr))
- return false;
- has_valid_registration_token_ = true;
- hr = system_media_controls_->put_IsEnabled(true);
- if (FAILED(hr))
- return false;
- hr = system_media_controls_->get_DisplayUpdater(&display_updater_);
- if (FAILED(hr))
- return false;
- // The current MediaSession API implementation matches the SMTC music type
- // most closely, since MediaSession has the artist property which the SMTC
- // only presents to music playback types.
- hr = display_updater_->put_Type(
- ABI::Windows::Media::MediaPlaybackType::MediaPlaybackType_Music);
- if (FAILED(hr))
- return false;
- hr = display_updater_->get_MusicProperties(&display_properties_);
- if (FAILED(hr))
- return false;
- initialized_ = true;
- return true;
- }
- void SystemMediaControlsWin::AddObserver(
- SystemMediaControlsObserver* observer) {
- observers_.AddObserver(observer);
- if (initialized_)
- observer->OnServiceReady();
- }
- void SystemMediaControlsWin::RemoveObserver(
- SystemMediaControlsObserver* observer) {
- observers_.RemoveObserver(observer);
- }
- void SystemMediaControlsWin::SetEnabled(bool enabled) {
- DCHECK(initialized_);
- HRESULT hr = system_media_controls_->put_IsEnabled(enabled);
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::SetIsNextEnabled(bool value) {
- DCHECK(initialized_);
- HRESULT hr = system_media_controls_->put_IsNextEnabled(value);
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::SetIsPreviousEnabled(bool value) {
- DCHECK(initialized_);
- HRESULT hr = system_media_controls_->put_IsPreviousEnabled(value);
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::SetIsPlayPauseEnabled(bool value) {
- DCHECK(initialized_);
- HRESULT hr = system_media_controls_->put_IsPlayEnabled(value);
- DCHECK(SUCCEEDED(hr));
- hr = system_media_controls_->put_IsPauseEnabled(value);
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::SetIsStopEnabled(bool value) {
- DCHECK(initialized_);
- HRESULT hr = system_media_controls_->put_IsStopEnabled(value);
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::SetPlaybackStatus(PlaybackStatus status) {
- DCHECK(initialized_);
- HRESULT hr =
- system_media_controls_->put_PlaybackStatus(GetSmtcPlaybackStatus(status));
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::SetTitle(const std::u16string& title) {
- DCHECK(initialized_);
- DCHECK(display_properties_);
- base::win::ScopedHString h_title =
- base::win::ScopedHString::Create(base::UTF16ToWide(title));
- HRESULT hr = display_properties_->put_Title(h_title.get());
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::SetArtist(const std::u16string& artist) {
- DCHECK(initialized_);
- DCHECK(display_properties_);
- base::win::ScopedHString h_artist =
- base::win::ScopedHString::Create(base::UTF16ToWide(artist));
- HRESULT hr = display_properties_->put_Artist(h_artist.get());
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::SetThumbnail(const SkBitmap& bitmap) {
- DCHECK(initialized_);
- DCHECK(display_updater_);
- // Use |icon_data_writer_| to write the bitmap data into |icon_stream_| so we
- // can populate |icon_stream_reference_| and then give it to the SMTC. All of
- // these are member variables to avoid a race condition between them being
- // destructed and the async operation completing.
- base::win::ScopedHString id = base::win::ScopedHString::Create(
- RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream);
- HRESULT hr = base::win::RoActivateInstance(id.get(), &icon_stream_);
- DCHECK(SUCCEEDED(hr));
- Microsoft::WRL::ComPtr<IDataWriterFactory> data_writer_factory;
- hr = base::win::GetActivationFactory<
- IDataWriterFactory, RuntimeClass_Windows_Storage_Streams_DataWriter>(
- &data_writer_factory);
- DCHECK(SUCCEEDED(hr));
- Microsoft::WRL::ComPtr<IOutputStream> output_stream;
- hr = icon_stream_.As(&output_stream);
- DCHECK(SUCCEEDED(hr));
- hr = data_writer_factory->CreateDataWriter(output_stream.Get(),
- &icon_data_writer_);
- DCHECK(SUCCEEDED(hr));
- std::vector<unsigned char> icon_png;
- gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &icon_png);
- hr = icon_data_writer_->WriteBytes(icon_png.size(), (BYTE*)icon_png.data());
- DCHECK(SUCCEEDED(hr));
- // Store the written bytes in the stream, an async operation.
- Microsoft::WRL::ComPtr<
- ABI::Windows::Foundation::IAsyncOperation<unsigned int>>
- store_async_operation;
- hr = icon_data_writer_->StoreAsync(&store_async_operation);
- DCHECK(SUCCEEDED(hr));
- // Make a callback that gives the icon to the SMTC once the bits make it into
- // |icon_stream_|
- auto store_async_callback = Microsoft::WRL::Callback<
- ABI::Windows::Foundation::IAsyncOperationCompletedHandler<unsigned int>>(
- [this](ABI::Windows::Foundation::IAsyncOperation<unsigned int>* async_op,
- ABI::Windows::Foundation::AsyncStatus status) mutable {
- // Check the async operation completed successfully.
- ABI::Windows::Foundation::IAsyncInfo* async_info;
- HRESULT hr = async_op->QueryInterface(
- IID_IAsyncInfo, reinterpret_cast<void**>(&async_info));
- DCHECK(SUCCEEDED(hr));
- async_info->get_ErrorCode(&hr);
- if (SUCCEEDED(hr) &&
- status == ABI::Windows::Foundation::AsyncStatus::Completed) {
- Microsoft::WRL::ComPtr<IRandomAccessStreamReferenceStatics>
- reference_statics;
- HRESULT result = base::win::GetActivationFactory<
- IRandomAccessStreamReferenceStatics,
- RuntimeClass_Windows_Storage_Streams_RandomAccessStreamReference>(
- &reference_statics);
- DCHECK(SUCCEEDED(result));
- result = reference_statics->CreateFromStream(icon_stream_.Get(),
- &icon_stream_reference_);
- DCHECK(SUCCEEDED(result));
- result =
- display_updater_->put_Thumbnail(icon_stream_reference_.Get());
- DCHECK(SUCCEEDED(result));
- result = display_updater_->Update();
- DCHECK(SUCCEEDED(result));
- }
- return hr;
- });
- hr = store_async_operation->put_Completed(store_async_callback.Get());
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::ClearThumbnail() {
- DCHECK(initialized_);
- DCHECK(display_updater_);
- HRESULT hr = display_updater_->put_Thumbnail(nullptr);
- DCHECK(SUCCEEDED(hr));
- hr = display_updater_->Update();
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::ClearMetadata() {
- DCHECK(initialized_);
- DCHECK(display_updater_);
- HRESULT hr = display_updater_->ClearAll();
- DCHECK(SUCCEEDED(hr));
- // To prevent disabled controls and the executable name from showing up in the
- // SMTC, we need to tell them that we are disabled.
- hr = system_media_controls_->put_IsEnabled(false);
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::UpdateDisplay() {
- DCHECK(initialized_);
- DCHECK(system_media_controls_);
- DCHECK(display_updater_);
- HRESULT hr = system_media_controls_->put_IsEnabled(true);
- DCHECK(SUCCEEDED(hr));
- // |ClearAll()| unsets the type, if we don't set it again then the artist
- // won't be displayed.
- hr = display_updater_->put_Type(
- ABI::Windows::Media::MediaPlaybackType::MediaPlaybackType_Music);
- DCHECK(SUCCEEDED(hr));
- hr = display_updater_->Update();
- DCHECK(SUCCEEDED(hr));
- }
- void SystemMediaControlsWin::OnPlay() {
- for (SystemMediaControlsObserver& obs : observers_)
- obs.OnPlay();
- }
- void SystemMediaControlsWin::OnPause() {
- for (SystemMediaControlsObserver& obs : observers_)
- obs.OnPause();
- }
- void SystemMediaControlsWin::OnNext() {
- for (SystemMediaControlsObserver& obs : observers_)
- obs.OnNext();
- }
- void SystemMediaControlsWin::OnPrevious() {
- for (SystemMediaControlsObserver& obs : observers_)
- obs.OnPrevious();
- }
- void SystemMediaControlsWin::OnStop() {
- for (SystemMediaControlsObserver& obs : observers_)
- obs.OnStop();
- }
- ABI::Windows::Media::MediaPlaybackStatus
- SystemMediaControlsWin::GetSmtcPlaybackStatus(PlaybackStatus status) {
- switch (status) {
- case PlaybackStatus::kPlaying:
- return ABI::Windows::Media::MediaPlaybackStatus::
- MediaPlaybackStatus_Playing;
- case PlaybackStatus::kPaused:
- return ABI::Windows::Media::MediaPlaybackStatus::
- MediaPlaybackStatus_Paused;
- case PlaybackStatus::kStopped:
- return ABI::Windows::Media::MediaPlaybackStatus::
- MediaPlaybackStatus_Stopped;
- }
- NOTREACHED();
- return ABI::Windows::Media::MediaPlaybackStatus::MediaPlaybackStatus_Stopped;
- }
- // static
- HRESULT SystemMediaControlsWin::ButtonPressed(
- ISystemMediaTransportControls* sender,
- ISystemMediaTransportControlsButtonPressedEventArgs* args) {
- SystemMediaTransportControlsButton button;
- HRESULT hr = args->get_Button(&button);
- if (FAILED(hr))
- return hr;
- SystemMediaControlsWin* impl = GetInstance();
- switch (button) {
- case SystemMediaTransportControlsButton::
- SystemMediaTransportControlsButton_Play:
- impl->OnPlay();
- break;
- case SystemMediaTransportControlsButton::
- SystemMediaTransportControlsButton_Pause:
- impl->OnPause();
- break;
- case SystemMediaTransportControlsButton::
- SystemMediaTransportControlsButton_Next:
- impl->OnNext();
- break;
- case SystemMediaTransportControlsButton::
- SystemMediaTransportControlsButton_Previous:
- impl->OnPrevious();
- break;
- case SystemMediaTransportControlsButton::
- SystemMediaTransportControlsButton_Stop:
- impl->OnStop();
- break;
- case SystemMediaTransportControlsButton::
- SystemMediaTransportControlsButton_Record:
- case SystemMediaTransportControlsButton::
- SystemMediaTransportControlsButton_FastForward:
- case SystemMediaTransportControlsButton::
- SystemMediaTransportControlsButton_Rewind:
- case SystemMediaTransportControlsButton::
- SystemMediaTransportControlsButton_ChannelUp:
- case SystemMediaTransportControlsButton::
- SystemMediaTransportControlsButton_ChannelDown:
- break;
- }
- return S_OK;
- }
- } // namespace internal
- } // namespace system_media_controls
|