#if OPENZUNE using LibVLCSharp.Shared; using StrixMusic.Sdk.MediaPlayback; using System; using System.Threading; using System.Threading.Tasks; using StrixPlaybackState = StrixMusic.Sdk.MediaPlayback.PlaybackState; namespace Microsoft.Zune.Playback { public class VlcAudioService : IAudioPlayerService { readonly LibVLC m_vlc; readonly MediaPlayer m_player; private Media m_media, m_nextMedia; private PlaybackItem m_currentSource; private TimeSpan m_position; public static VlcAudioService Instance => new(); private VlcAudioService() { Core.Initialize(@"C:\Program Files\VideoLAN\VLC"); bool debug = #if DEBUG true; #else false; #endif m_vlc = new(enableDebugLogs: debug); m_player = new(m_vlc); m_player.TimeChanged += (sender, e) => Position = TimeSpan.FromMilliseconds(e.Time); } public PlaybackItem CurrentSource { get => m_currentSource; set { m_currentSource = value; CurrentSourceChanged?.Invoke(this, value); } } public TimeSpan Position { get => m_position; set { m_position = value; PositionChanged?.Invoke(this, value); } } public StrixPlaybackState PlaybackState => m_player.State switch { VLCState.Playing => StrixPlaybackState.Playing, VLCState.Paused or VLCState.Stopped => StrixPlaybackState.Paused, VLCState.Opening or VLCState.Buffering => StrixPlaybackState.Loading, VLCState.Error => StrixPlaybackState.Failed, _ => StrixPlaybackState.None }; public double Volume { get => m_player.Volume / 100d; private set { m_player.Volume = (int)(value * 100); VolumeChanged?.Invoke(this, value); } } public double PlaybackSpeed { get => m_player.Rate; private set { m_player.SetRate((float)value); PlaybackSpeedChanged?.Invoke(this, value); } } public event EventHandler CurrentSourceChanged; public event EventHandler QuantumProcessed; public event EventHandler PositionChanged; public event EventHandler PlaybackStateChanged; public event EventHandler VolumeChanged; public event EventHandler PlaybackSpeedChanged; public Task ChangePlaybackSpeedAsync(double speed, CancellationToken cancellationToken = default) { PlaybackSpeed = speed; return Task.CompletedTask; } public Task ChangeVolumeAsync(double volume, CancellationToken cancellationToken = default) { Volume = (float)volume; return Task.CompletedTask; } public Task PauseAsync(CancellationToken cancellationToken = default) { m_player.Pause(); if (m_player.Media != null) PlaybackStateChanged?.Invoke(this, PlaybackState); return Task.CompletedTask; } public async Task Play(PlaybackItem sourceConfig, CancellationToken cancellationToken = default) { if (CurrentSource != sourceConfig) { PlaybackStateChanged?.Invoke(this, StrixPlaybackState.Loading); CurrentSource = sourceConfig; m_media = CreateMedia(sourceConfig); var parseStatus = await m_media.Parse(MediaParseOptions.ParseNetwork | MediaParseOptions.ParseLocal, cancellationToken: cancellationToken); if (parseStatus == MediaParsedStatus.Failed || parseStatus == MediaParsedStatus.Timeout) PlaybackStateChanged?.Invoke(this, StrixPlaybackState.Failed); else if (parseStatus == MediaParsedStatus.Done || parseStatus == MediaParsedStatus.Skipped) PlaybackStateChanged?.Invoke(this, PlaybackState); m_player.Media = m_media; } if (m_player.Play()) PlaybackStateChanged?.Invoke(this, PlaybackState); } public async Task Preload(PlaybackItem sourceConfig, CancellationToken cancellationToken = default) { m_nextMedia = CreateMedia(sourceConfig); await m_nextMedia.Parse(MediaParseOptions.ParseNetwork | MediaParseOptions.ParseLocal, cancellationToken: cancellationToken); } public Task ResumeAsync(CancellationToken cancellationToken = default) { m_player.Play(); return Task.CompletedTask; } public Task SeekAsync(TimeSpan position, CancellationToken cancellationToken = default) { if (m_player.IsSeekable) m_player.SeekTo(position); return Task.CompletedTask; } private Media CreateMedia(PlaybackItem sourceConfig) { var uri = sourceConfig.MediaConfig.MediaSourceUri; var stream = sourceConfig.MediaConfig.FileStreamSource; if (uri != null) return new(m_vlc, uri); else if (stream != null) return new(m_vlc, new StreamMediaInput(stream)); throw new NotImplementedException(); } } } #endif