Added Windows SMTC support.

System Media Transport Controls.
This commit is contained in:
23rd 2021-05-29 17:13:12 +03:00 committed by John Preston
parent 690fbe83fd
commit 78dfe940ef
7 changed files with 195 additions and 2 deletions

View File

@ -923,6 +923,8 @@ PRIVATE
platform/win/windows_dlls.h
platform/win/windows_event_filter.cpp
platform/win/windows_event_filter.h
platform/win/windows_system_media_controls_manager.cpp
platform/win/windows_system_media_controls_manager.h
platform/platform_audio.h
platform/platform_file_utilities.h
platform/platform_launcher.h

View File

@ -139,4 +139,4 @@ bool Launcher::launch(
return true;
}
} // namespace
} // namespace Platform

View File

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/platform_notifications_manager.h"
#include "platform/win/windows_dlls.h"
#include "platform/win/windows_event_filter.h"
#include "platform/win/windows_system_media_controls_manager.h"
#include "window/notifications_manager.h"
#include "mainwindow.h"
#include "base/crc32hash.h"
@ -429,6 +430,10 @@ void MainWindow::initHook() {
}
psInitSysMenu();
if (IsWindows10OrGreater()) {
_smtcManager = std::make_unique<SystemMediaControlsManager>(psHwnd());
}
}
void MainWindow::initShadows() {

View File

@ -20,6 +20,8 @@ class PopupMenu;
namespace Platform {
class SystemMediaControlsManager;
class MainWindow : public Window::MainWindow {
public:
explicit MainWindow(not_null<Window::Controller*> controller);
@ -123,6 +125,8 @@ private:
HICON ps_iconSmall = nullptr;
HICON ps_iconOverlay = nullptr;
std::unique_ptr<Platform::SystemMediaControlsManager> _smtcManager;
int _deltaLeft = 0;
int _deltaTop = 0;
int _deltaRight = 0;

View File

@ -0,0 +1,148 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "platform/win/windows_system_media_controls_manager.h"
#include "base/observer.h"
#include "base/platform/win/base_windows_system_media_controls.h"
#include "core/application.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_file_origin.h"
#include "main/main_session.h"
#include "media/audio/media_audio.h"
#include "media/player/media_player_instance.h"
#include "ui/text/format_song_document_name.h"
namespace Platform {
SystemMediaControlsManager::SystemMediaControlsManager(HWND hwnd)
: _controls(std::make_unique<base::Platform::SystemMediaControlsWin>()) {
using PlaybackStatus =
base::Platform::SystemMediaControlsWin::PlaybackStatus;
using Command = base::Platform::SystemMediaControlsWin::Command;
_controls->init(hwnd);
const auto type = AudioMsgId::Type::Song;
const auto mediaPlayer = Media::Player::instance();
mediaPlayer->updatedNotifier(
) | rpl::filter([=](const Media::Player::TrackState &state) {
return state.id.type() == type;
}) | rpl::map([=](const Media::Player::TrackState &state) {
using namespace Media::Player;
if (IsStoppedOrStopping(state.state)) {
return PlaybackStatus::Stopped;
} else if (IsPausedOrPausing(state.state)) {
return PlaybackStatus::Paused;
}
return PlaybackStatus::Playing;
}) | rpl::distinct_until_changed(
) | rpl::start_with_next([=](PlaybackStatus status) {
_controls->setPlaybackStatus(status);
}, _lifetime);
rpl::merge(
mediaPlayer->stops(type) | rpl::map_to(false),
mediaPlayer->startsPlay(type) | rpl::map_to(true)
) | rpl::start_with_next([=](bool audio) {
if (audio) {
_controls->setEnabled(audio);
_controls->setIsNextEnabled(mediaPlayer->nextAvailable(type));
_controls->setIsPreviousEnabled(
mediaPlayer->previousAvailable(type));
_controls->setIsPlayPauseEnabled(true);
_controls->setIsStopEnabled(true);
_controls->setPlaybackStatus(PlaybackStatus::Playing);
_controls->updateDisplay();
} else {
_cachedMediaView.clear();
_controls->clearMetadata();
}
_lifetimeDownload.destroy();
}, _lifetime);
auto trackChanged = base::ObservableViewer(
mediaPlayer->trackChangedNotifier()
) | rpl::filter([=](AudioMsgId::Type audioType) {
return audioType == type;
});
auto unlocked = Core::App().passcodeLockChanges(
) | rpl::filter([](bool locked) {
return !locked;
}) | rpl::map([=] {
return type;
}) | rpl::before_next([=] {
_controls->setEnabled(true);
_controls->updateDisplay();
});
rpl::merge(
std::move(trackChanged),
std::move(unlocked)
) | rpl::start_with_next([=](AudioMsgId::Type audioType) {
_lifetimeDownload.destroy();
const auto current = mediaPlayer->current(audioType);
if (!current) {
return;
}
const auto document = current.audio();
const auto &[title, performer] = Ui::Text::FormatSongNameFor(document)
.composedName();
_controls->setArtist(performer);
_controls->setTitle(title);
if (document && document->isSongWithCover()) {
const auto view = document->createMediaView();
view->thumbnailWanted(current.contextId());
_cachedMediaView.push_back(view);
if (const auto imagePtr = view->thumbnail()) {
_controls->setThumbnail(imagePtr->original());
} else {
document->session().downloaderTaskFinished(
) | rpl::start_with_next([=] {
if (const auto imagePtr = view->thumbnail()) {
_controls->setThumbnail(imagePtr->original());
_lifetimeDownload.destroy();
}
}, _lifetimeDownload);
_controls->clearThumbnail();
}
} else {
_controls->clearThumbnail();
}
}, _lifetime);
_controls->commandRequests(
) | rpl::start_with_next([=](Command command) {
switch (command) {
case Command::Play: mediaPlayer->play(type); break;
case Command::Pause: mediaPlayer->pause(type); break;
case Command::Next: mediaPlayer->next(type); break;
case Command::Previous: mediaPlayer->previous(type); break;
case Command::Stop: mediaPlayer->stop(type); break;
}
}, _lifetime);
Core::App().passcodeLockValue(
) | rpl::filter([=](bool locked) {
return locked && Core::App().maybeActiveSession();
}) | rpl::start_with_next([=] {
_controls->setEnabled(false);
}, _lifetime);
}
SystemMediaControlsManager::~SystemMediaControlsManager() = default;
} // namespace Platform

View File

@ -0,0 +1,34 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
namespace base::Platform {
class SystemMediaControlsWin;
} // namespace base::Platform
namespace Data {
class DocumentMedia;
} // namespace Data
namespace Platform {
class SystemMediaControlsManager {
public:
SystemMediaControlsManager(HWND hwnd);
~SystemMediaControlsManager();
private:
const std::unique_ptr<base::Platform::SystemMediaControlsWin> _controls;
std::vector<std::shared_ptr<Data::DocumentMedia>> _cachedMediaView;
rpl::lifetime _lifetimeDownload;
rpl::lifetime _lifetime;
};
} // namespace Platform

@ -1 +1 @@
Subproject commit 95b23bd09b71c5599b6b89d6c708e7d35b8963aa
Subproject commit 54f214213cc67885a57cb246483893272c986c3a