use std::time::Duration;
use windows::{
Foundation::{TimeSpan, TypedEventHandler},
Media::{
MediaPlaybackStatus, MediaPlaybackType, Playback::MediaPlayer,
SystemMediaTransportControls, SystemMediaTransportControlsButton,
SystemMediaTransportControlsButtonPressedEventArgs,
SystemMediaTransportControlsTimelineProperties,
},
Storage::{FileProperties::ThumbnailMode, StorageFile, Streams::RandomAccessStreamReference},
core::{HSTRING, Result},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SmtcEvent {
Play,
Pause,
Previous,
Next,
Stop,
}
pub struct SmtcPlayer {
_player: MediaPlayer,
smtc: SystemMediaTransportControls,
}
impl SmtcPlayer {
pub fn new() -> Result<Self> {
let player = MediaPlayer::new()?;
player.CommandManager()?.SetIsEnabled(false)?;
let smtc = player.SystemMediaTransportControls()?;
smtc.SetIsPlayEnabled(true)?;
smtc.SetIsPauseEnabled(true)?;
smtc.SetIsStopEnabled(true)?;
smtc.SetIsNextEnabled(true)?;
smtc.SetIsPreviousEnabled(true)?;
smtc.SetIsEnabled(true)?;
Ok(Self {
_player: player,
smtc,
})
}
pub fn on_event<F>(&self, mut callback: F) -> Result<()>
where
F: FnMut(SmtcEvent) + Send + 'static,
{
self.smtc.ButtonPressed(&TypedEventHandler::new(
move |sender: &Option<SystemMediaTransportControls>,
args: &Option<SystemMediaTransportControlsButtonPressedEventArgs>| {
let _ = sender;
let args = args.as_ref().ok_or(windows::core::Error::empty())?;
let button = args.Button()?;
let event = match button {
SystemMediaTransportControlsButton::Play => SmtcEvent::Play,
SystemMediaTransportControlsButton::Pause => SmtcEvent::Pause,
SystemMediaTransportControlsButton::Next => SmtcEvent::Next,
SystemMediaTransportControlsButton::Previous => SmtcEvent::Previous,
SystemMediaTransportControlsButton::Stop => SmtcEvent::Stop,
_ => return Ok(()),
};
callback(event);
Ok(())
},
))?;
Ok(())
}
pub fn set_playback_status(&self, playing: bool) -> Result<()> {
let status = if playing {
MediaPlaybackStatus::Playing
} else {
MediaPlaybackStatus::Paused
};
self.smtc.SetPlaybackStatus(status)?;
Ok(())
}
pub fn set_media_info(
&self,
title: &str,
artist: &str,
album: &str,
thumbnail_path: Option<&str>,
) -> Result<()> {
let updater = self.smtc.DisplayUpdater()?;
updater.SetType(MediaPlaybackType::Music)?;
let music = updater.MusicProperties()?;
music.SetTitle(&HSTRING::from(title))?;
music.SetArtist(&HSTRING::from(artist))?;
music.SetAlbumTitle(&HSTRING::from(album))?;
if let Some(path) = thumbnail_path {
let file = StorageFile::GetFileFromPathAsync(&HSTRING::from(path))?.get()?;
let thumbnail = file
.GetThumbnailAsyncOverloadDefaultSizeDefaultOptions(ThumbnailMode::MusicView)?
.get()?;
updater.SetThumbnail(&RandomAccessStreamReference::CreateFromStream(&thumbnail)?)?;
}
updater.Update()?;
Ok(())
}
pub fn set_timeline(&self, position: Duration, duration: Duration) -> Result<()> {
let timeline = SystemMediaTransportControlsTimelineProperties::new()?;
timeline.SetStartTime(TimeSpan::from(Duration::ZERO))?;
timeline.SetEndTime(TimeSpan::from(duration))?;
timeline.SetPosition(TimeSpan::from(position))?;
timeline.SetMinSeekTime(TimeSpan::from(Duration::ZERO))?;
timeline.SetMaxSeekTime(TimeSpan::from(duration))?;
self.smtc.UpdateTimelineProperties(&timeline)?;
Ok(())
}
pub fn close(&self) -> Result<()> {
self._player.Close()?;
Ok(())
}
}