// Copyright (c) Arlo Godfrey. All Rights Reserved.
// Licensed under the GNU Lesser General Public License, Version 3.0 with additional terms.
// See the LICENSE, LICENSE.LESSER and LICENSE.ADDITIONAL files in the project root for more information.
using System;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Diagnostics;
using StrixMusic.Sdk.AppModels;
using StrixMusic.Sdk.BaseModels;
using StrixMusic.Sdk.CoreModels;
namespace StrixMusic.Sdk.MediaPlayback.LocalDevice
{
///
/// The default playback device for the app.
///
public sealed class StrixDevice : IDevice
{
private readonly IPlaybackHandlerService _playbackHandler;
///
/// Creates a new instance of .
///
public StrixDevice(IPlaybackHandlerService playbackHandler)
{
_playbackHandler = playbackHandler;
PlaybackContext = null;
// TODO: Implement StrixPlaybackQueueCollection
//PlaybackQueue = new StrixPlaybackQueueCollection();
AttachEvents();
}
private void AttachEvents()
{
_playbackHandler.RepeatStateChanged += PlaybackHandler_RepeatStateChanged;
_playbackHandler.ShuffleStateChanged += PlaybackHandler_ShuffleStateChanged;
_playbackHandler.PlaybackSpeedChanged += PlaybackHandler_PlaybackSpeedChanged;
_playbackHandler.PlaybackStateChanged += PlaybackHandler_PlaybackStateChanged;
_playbackHandler.PositionChanged += PlaybackHandler_PositionChanged;
_playbackHandler.VolumeChanged += PlaybackHandler_VolumeChanged;
_playbackHandler.CurrentItemChanged += PlaybackHandler_CurrentItemChanged;
}
private void DetachEvents()
{
_playbackHandler.RepeatStateChanged -= PlaybackHandler_RepeatStateChanged;
_playbackHandler.ShuffleStateChanged -= PlaybackHandler_ShuffleStateChanged;
_playbackHandler.PlaybackSpeedChanged -= PlaybackHandler_PlaybackSpeedChanged;
_playbackHandler.PlaybackStateChanged -= PlaybackHandler_PlaybackStateChanged;
_playbackHandler.PositionChanged -= PlaybackHandler_PositionChanged;
_playbackHandler.VolumeChanged -= PlaybackHandler_VolumeChanged;
_playbackHandler.CurrentItemChanged -= PlaybackHandler_CurrentItemChanged;
}
private void PlaybackHandler_CurrentItemChanged(object sender, PlaybackItem? e)
{
Guard.IsNotNull(e, nameof(e));
SetPlaybackData(PlaybackContext, e);
}
private void PlaybackHandler_PlaybackStateChanged(object sender, PlaybackState e) => PlaybackStateChanged?.Invoke(sender, e);
private void PlaybackHandler_PositionChanged(object sender, TimeSpan e) => PositionChanged?.Invoke(sender, e);
private void PlaybackHandler_VolumeChanged(object sender, double e) => VolumeChanged?.Invoke(this, e);
private void PlaybackHandler_PlaybackSpeedChanged(object sender, double e) => PlaybackSpeedChanged?.Invoke(sender, e);
private void PlaybackHandler_RepeatStateChanged(object sender, RepeatState e) => RepeatStateChanged?.Invoke(sender, e);
private void PlaybackHandler_ShuffleStateChanged(object sender, bool e) => ShuffleStateChanged?.Invoke(sender, e);
///
public event EventHandler? IsActiveChanged;
///
public event EventHandler? PlaybackContextChanged;
///
public event EventHandler? NowPlayingChanged;
///
public event EventHandler? ShuffleStateChanged;
///
public event EventHandler? PositionChanged;
///
public event EventHandler? RepeatStateChanged;
///
public event EventHandler? PlaybackStateChanged;
///
public event EventHandler? VolumeChanged;
///
public event EventHandler? PlaybackSpeedChanged;
///
public TimeSpan Position => _playbackHandler.Position;
///
public PlaybackState PlaybackState => _playbackHandler.PlaybackState;
///
public double Volume => _playbackHandler.Volume;
///
public double PlaybackSpeed => _playbackHandler.PlaybackSpeed;
///
public Task ResumeAsync(CancellationToken cancellationToken = default) => _playbackHandler.ResumeAsync(cancellationToken);
///
public Task PauseAsync(CancellationToken cancellationToken = default) => _playbackHandler.PauseAsync(cancellationToken);
///
public Task SeekAsync(TimeSpan position, CancellationToken cancellationToken = default) => _playbackHandler.SeekAsync(position, cancellationToken);
///
public Task ChangePlaybackSpeedAsync(double speed, CancellationToken cancellationToken = default) => _playbackHandler.ChangePlaybackSpeedAsync(speed, cancellationToken);
///
public Task ChangeVolumeAsync(double volume, CancellationToken cancellationToken = default) => _playbackHandler.ChangeVolumeAsync(volume, cancellationToken);
///
public string Id => "609EBD5A-EBA1-4DDE-9828-C72B096D35DF";
///
public string Name => "This Device";
///
public bool IsActive { get; private set; }
///
public ICore? SourceCore { get; }
///
public ICoreDevice? Source { get; }
///
public ITrackCollection? PlaybackQueue { get; }
///
public IPlayableBase? PlaybackContext { get; private set; }
///
public PlaybackItem? NowPlaying { get; private set; }
///
public DeviceType Type => DeviceType.Local;
///
public bool ShuffleState => _playbackHandler.ShuffleState;
///
public RepeatState RepeatState => _playbackHandler.RepeatState;
///
public bool IsSeekAsyncAvailable => true;
///
public bool IsResumeAsyncAvailable => true;
///
public bool IsPauseAsyncAvailable => true;
///
public bool IsChangeVolumeAsyncAvailable => true;
///
public bool IsChangePlaybackSpeedAvailable => true;
///
public bool IsNextAsyncAvailable => true;
///
public bool IsPreviousAsyncAvailable => true;
///
public bool IsToggleShuffleAsyncAvailable => true;
///
public bool IsToggleRepeatAsyncAvailable => true;
///
public Task NextAsync(CancellationToken cancellationToken = default) => _playbackHandler.NextAsync(cancellationToken);
///
public Task PreviousAsync(CancellationToken cancellationToken = default) => _playbackHandler.PreviousAsync(cancellationToken);
///
public Task SwitchToAsync(CancellationToken cancellationToken = default)
{
IsActive = true;
IsActiveChanged?.Invoke(this, IsActive);
// Maybe preload some things?
return Task.CompletedTask;
}
///
/// Sets playback data for this device.
///
/// The playback context.
/// The track that is playing.
internal void SetPlaybackData(IPlayableBase? playbackContext, PlaybackItem nowPlaying)
{
PlaybackContext = playbackContext;
PlaybackContextChanged?.Invoke(this, playbackContext);
NowPlaying = nowPlaying;
NowPlayingChanged?.Invoke(this, nowPlaying);
}
///
public Task ToggleShuffleAsync(CancellationToken cancellationToken = default) => _playbackHandler.ToggleShuffleAsync(cancellationToken);
///
public Task ToggleRepeatAsync(CancellationToken cancellationToken = default) => _playbackHandler.ToggleRepeatAsync(cancellationToken);
///
public ValueTask DisposeAsync()
{
DetachEvents();
return default;
}
}
}