2021-10-05 09:54:02 -07:00
|
|
|
using System.Runtime.InteropServices;
|
2021-07-04 23:17:30 -07:00
|
|
|
using ReactiveUI;
|
2021-03-19 17:07:27 -03:00
|
|
|
|
2021-07-12 15:40:56 -07:00
|
|
|
namespace RedBookPlayer.Models.Hardware
|
2021-03-19 17:07:27 -03:00
|
|
|
{
|
2021-07-04 23:17:30 -07:00
|
|
|
public class SoundOutput : ReactiveObject
|
2021-03-19 17:07:27 -03:00
|
|
|
{
|
2021-06-06 21:43:47 -07:00
|
|
|
#region Public Fields
|
2021-04-14 20:36:34 -03:00
|
|
|
|
2021-06-06 21:43:47 -07:00
|
|
|
/// <summary>
|
2021-06-29 21:16:43 -07:00
|
|
|
/// Indicate if the output is ready to be used
|
2021-06-06 21:43:47 -07:00
|
|
|
/// </summary>
|
2021-08-05 21:05:20 -07:00
|
|
|
public bool Initialized
|
|
|
|
|
{
|
|
|
|
|
get => _initialized;
|
|
|
|
|
private set => this.RaiseAndSetIfChanged(ref _initialized, value);
|
|
|
|
|
}
|
2021-06-06 20:28:36 +01:00
|
|
|
|
2021-06-29 12:08:08 -07:00
|
|
|
/// <summary>
|
2021-08-05 21:05:20 -07:00
|
|
|
/// Indicates the current player state
|
2021-06-29 12:08:08 -07:00
|
|
|
/// </summary>
|
2021-08-05 21:05:20 -07:00
|
|
|
public PlayerState PlayerState
|
2021-07-04 23:17:30 -07:00
|
|
|
{
|
2021-08-05 21:05:20 -07:00
|
|
|
get => _playerState;
|
|
|
|
|
private set => this.RaiseAndSetIfChanged(ref _playerState, value);
|
2021-07-04 23:17:30 -07:00
|
|
|
}
|
2021-06-29 12:08:08 -07:00
|
|
|
|
2021-07-03 16:04:18 -07:00
|
|
|
/// <summary>
|
|
|
|
|
/// Current playback volume
|
|
|
|
|
/// </summary>
|
|
|
|
|
public int Volume
|
|
|
|
|
{
|
|
|
|
|
get => _volume;
|
2021-07-05 16:23:50 -07:00
|
|
|
private set
|
2021-07-03 16:04:18 -07:00
|
|
|
{
|
2021-07-04 23:17:30 -07:00
|
|
|
int tempVolume = value;
|
2021-07-03 16:04:18 -07:00
|
|
|
if(value > 100)
|
2021-07-04 23:17:30 -07:00
|
|
|
tempVolume = 100;
|
2021-07-03 16:04:18 -07:00
|
|
|
else if(value < 0)
|
2021-07-04 23:17:30 -07:00
|
|
|
tempVolume = 0;
|
|
|
|
|
|
|
|
|
|
this.RaiseAndSetIfChanged(ref _volume, tempVolume);
|
2021-07-03 16:04:18 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-05 21:05:20 -07:00
|
|
|
private bool _initialized;
|
|
|
|
|
private PlayerState _playerState;
|
2021-07-04 23:17:30 -07:00
|
|
|
private int _volume;
|
|
|
|
|
|
2021-06-06 21:43:47 -07:00
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Private State Variables
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Data provider for sound output
|
|
|
|
|
/// </summary>
|
|
|
|
|
private PlayerSource _source;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sound output instance
|
|
|
|
|
/// </summary>
|
2021-10-04 21:50:44 -07:00
|
|
|
private IAudioBackend _soundOut;
|
2021-06-06 21:43:47 -07:00
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2021-08-05 21:05:20 -07:00
|
|
|
/// <summary>
|
|
|
|
|
/// Constructor
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="defaultVolume">Default volume between 0 and 100 to use when starting playback</param>
|
2021-10-05 21:40:41 -07:00
|
|
|
public SoundOutput(int defaultVolume = 100) => Volume = defaultVolume;
|
2021-08-05 21:05:20 -07:00
|
|
|
|
2021-06-06 21:43:47 -07:00
|
|
|
/// <summary>
|
2021-06-29 15:45:13 -07:00
|
|
|
/// Initialize the output with a given image
|
2021-06-06 21:43:47 -07:00
|
|
|
/// </summary>
|
2021-10-05 21:40:41 -07:00
|
|
|
/// <param name="read">ReadFunction to use during decoding</param>
|
2021-06-06 21:43:47 -07:00
|
|
|
/// <param name="autoPlay">True if playback should begin immediately, false otherwise</param>
|
2021-10-05 21:40:41 -07:00
|
|
|
public void Init(PlayerSource.ReadFunction read, bool autoPlay)
|
2021-03-19 17:07:27 -03:00
|
|
|
{
|
2021-10-05 21:40:41 -07:00
|
|
|
// Reset initialization
|
|
|
|
|
Initialized = false;
|
2021-04-08 21:41:31 -03:00
|
|
|
|
2021-06-06 21:43:47 -07:00
|
|
|
// Setup the audio output
|
2021-10-05 21:40:41 -07:00
|
|
|
SetupAudio(read);
|
2021-08-24 22:11:25 -07:00
|
|
|
|
2021-06-06 21:43:47 -07:00
|
|
|
// Initialize playback, if necessary
|
2021-06-06 20:28:36 +01:00
|
|
|
if(autoPlay)
|
2021-06-06 21:43:47 -07:00
|
|
|
_soundOut.Play();
|
2021-04-15 19:16:34 -03:00
|
|
|
|
2021-06-29 15:45:13 -07:00
|
|
|
// Mark the output as ready
|
2021-03-19 17:07:27 -03:00
|
|
|
Initialized = true;
|
2021-08-05 21:05:20 -07:00
|
|
|
PlayerState = PlayerState.Stopped;
|
2021-03-19 17:07:27 -03:00
|
|
|
|
2021-06-06 21:43:47 -07:00
|
|
|
// Begin loading data
|
|
|
|
|
_source.Start();
|
2021-03-19 17:07:27 -03:00
|
|
|
}
|
|
|
|
|
|
2021-08-24 22:11:25 -07:00
|
|
|
/// <summary>
|
|
|
|
|
/// Reset the current internal state
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Reset()
|
|
|
|
|
{
|
|
|
|
|
_soundOut.Stop();
|
|
|
|
|
Initialized = false;
|
|
|
|
|
PlayerState = PlayerState.NoDisc;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-21 21:35:09 -07:00
|
|
|
#region Playback
|
2021-03-19 17:07:27 -03:00
|
|
|
|
2021-06-06 21:43:47 -07:00
|
|
|
/// <summary>
|
2021-06-29 15:45:13 -07:00
|
|
|
/// Start audio playback
|
2021-06-29 12:08:08 -07:00
|
|
|
/// </summary>
|
2021-07-04 23:17:30 -07:00
|
|
|
public void Play()
|
|
|
|
|
{
|
2021-10-04 21:50:44 -07:00
|
|
|
if(_soundOut.GetPlayerState() != PlayerState.Playing)
|
2021-07-04 23:17:30 -07:00
|
|
|
_soundOut.Play();
|
|
|
|
|
|
2021-08-05 21:05:20 -07:00
|
|
|
PlayerState = PlayerState.Playing;
|
2021-07-04 23:17:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Pause audio playback
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Pause()
|
|
|
|
|
{
|
2021-10-04 21:50:44 -07:00
|
|
|
if(_soundOut.GetPlayerState() != PlayerState.Paused)
|
2021-07-04 23:17:30 -07:00
|
|
|
_soundOut.Pause();
|
|
|
|
|
|
2021-08-05 21:05:20 -07:00
|
|
|
PlayerState = PlayerState.Paused;
|
2021-07-04 23:17:30 -07:00
|
|
|
}
|
2021-06-29 12:08:08 -07:00
|
|
|
|
|
|
|
|
/// <summary>
|
2021-06-29 15:45:13 -07:00
|
|
|
/// Stop audio playback
|
2021-06-29 12:08:08 -07:00
|
|
|
/// </summary>
|
2021-07-04 23:17:30 -07:00
|
|
|
public void Stop()
|
|
|
|
|
{
|
2021-10-04 21:50:44 -07:00
|
|
|
if(_soundOut.GetPlayerState() != PlayerState.Stopped)
|
2021-07-04 23:17:30 -07:00
|
|
|
_soundOut.Stop();
|
|
|
|
|
|
2021-08-05 21:05:20 -07:00
|
|
|
PlayerState = PlayerState.Stopped;
|
2021-07-04 23:17:30 -07:00
|
|
|
}
|
2021-03-19 17:07:27 -03:00
|
|
|
|
2021-08-24 22:11:25 -07:00
|
|
|
/// <summary>
|
|
|
|
|
/// Eject the currently loaded disc
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Eject() => Reset();
|
|
|
|
|
|
2021-06-06 21:43:47 -07:00
|
|
|
#endregion
|
2021-03-19 17:07:27 -03:00
|
|
|
|
2021-06-06 21:43:47 -07:00
|
|
|
#region Helpers
|
|
|
|
|
|
2021-07-05 16:20:34 -07:00
|
|
|
/// <summary>
|
|
|
|
|
/// Set the value for the volume
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="volume">New volume value</param>
|
2021-10-05 21:40:41 -07:00
|
|
|
public void SetVolume(int volume)
|
2021-08-05 21:05:20 -07:00
|
|
|
{
|
2021-10-05 21:40:41 -07:00
|
|
|
Volume = volume;
|
|
|
|
|
_soundOut.SetVolume((float)Volume / 100);
|
2021-08-05 21:05:20 -07:00
|
|
|
}
|
|
|
|
|
|
2021-06-06 21:43:47 -07:00
|
|
|
/// <summary>
|
|
|
|
|
/// Sets or resets the audio playback objects
|
|
|
|
|
/// </summary>
|
2021-10-05 21:40:41 -07:00
|
|
|
/// <param name="read">ReadFunction to use during decoding</param>
|
|
|
|
|
private void SetupAudio(PlayerSource.ReadFunction read)
|
2021-06-06 21:43:47 -07:00
|
|
|
{
|
|
|
|
|
if(_source == null)
|
|
|
|
|
{
|
2021-10-05 21:40:41 -07:00
|
|
|
_source = new PlayerSource(read);
|
2021-10-05 09:54:02 -07:00
|
|
|
if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
|
|
|
_soundOut = new Linux.AudioBackend(_source);
|
|
|
|
|
else if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
|
|
|
_soundOut = new Windows.AudioBackend(_source);
|
2021-06-06 21:43:47 -07:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_soundOut.Stop();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-06 20:28:36 +01:00
|
|
|
|
2021-06-06 21:43:47 -07:00
|
|
|
#endregion
|
2021-03-19 17:07:27 -03:00
|
|
|
}
|
2021-08-05 21:05:20 -07:00
|
|
|
}
|