Skip to content

Commit

Permalink
[GoogleCast] Added dummy player impl
Browse files Browse the repository at this point in the history
  • Loading branch information
Efrain Bastidas Berrios committed Sep 18, 2023
1 parent bef2e73 commit 9903477
Show file tree
Hide file tree
Showing 3 changed files with 285 additions and 1 deletion.
5 changes: 5 additions & 0 deletions CastIt.GoogleCast/DependencyInjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,10 @@ public static IServiceCollection AddGoogleCast(this IServiceCollection services)
{
return services.AddSingleton<IPlayer>(provider => new Player(provider.GetRequiredService<ILogger<Player>>()));
}

public static IServiceCollection AddDummyGoogleCast(this IServiceCollection services)
{
return services.AddSingleton<IPlayer>(new DummyPlayer());
}
}
}
279 changes: 279 additions & 0 deletions CastIt.GoogleCast/DummyPlayer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
using CastIt.GoogleCast.Interfaces;
using CastIt.GoogleCast.Models;
using CastIt.GoogleCast.Models.Events;
using CastIt.GoogleCast.Models.Media;
using CastIt.GoogleCast.Models.Receiver;
using CastIt.GoogleCast.Shared.Device;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace CastIt.GoogleCast
{
internal class DummyPlayer : IPlayer
{
#region Members
private CancellationTokenSource _listenerToken;
private List<IReceiver> _devices = new List<IReceiver>
{
new Receiver
{
FriendlyName = "Dummy",
Host = "192.168.1.101",
IsConnected = true,
Id = "xxxxxx",
Port = 8080,
Type = "N/A"
}
};

#endregion

#region Events
public event EventHandler Disconnected;
public event EventHandler<DeviceAddedArgs> DeviceAdded;
public event EventHandler FileLoading;
public event EventHandler FileLoaded;
public event EventHandler<double> TimeChanged;
public event EventHandler<double> PositionChanged;
public event EventHandler Paused;
public event EventHandler EndReached;
public event EventHandler<double> VolumeLevelChanged;
public event EventHandler<bool> IsMutedChanged;
public event EventHandler LoadFailed;
#endregion


#region Properties
public bool IsPlaying { get; set; }
public bool IsPaused { get; set; }
public bool IsPlayingOrPaused
=> IsPlaying || IsPaused;
public string CurrentContentId { get; set; }
public double CurrentMediaDuration { get; set; }
public double ElapsedSeconds { get; set; }
public double PlayedPercentage
{
get
{
if (CurrentMediaDuration > 0)
return ElapsedSeconds * 100 / CurrentMediaDuration;
return 0;
}
}
public double CurrentVolumeLevel { get; set; }
public bool IsMuted { get; set; }

public PlayerStatus State => new PlayerStatus(this);
private SemaphoreSlim ListenMediaChangesSemaphoreSlim { get; } = new SemaphoreSlim(1, 1);
#endregion

public void ListenForDevices()
{
DeviceAdded?.Invoke(this, new DeviceAddedArgs(_devices.First()));
}

public Task ConnectAsync()
{
return Task.Delay(TimeSpan.FromSeconds(2));
}

public Task ConnectAsync(string host, int port)
{
return Task.Delay(TimeSpan.FromSeconds(2));
}

public Task ConnectAsync(IReceiver receiver)
{
return Task.Delay(TimeSpan.FromSeconds(2));
}

public void Dispose()
{
}

public async Task<MediaStatus> LoadAsync(MediaInformation media, bool autoPlay = true, double seekedSeconds = 0, params int[] activeTrackIds)
{
CleanLoadedFile();
CancelAndSetListenerToken();

FileLoading?.Invoke(this, EventArgs.Empty);
await Task.Delay(TimeSpan.FromSeconds(2));

CurrentContentId = media.ContentId;
CurrentMediaDuration = media.Duration ?? 0;
CurrentVolumeLevel = 1;
IsMuted = false;
ElapsedSeconds = 0;

TriggerTimeEvents();
IsPlaying = true;
IsPaused = false;

ListenForMediaChanges(_listenerToken.Token);

FileLoaded?.Invoke(this, EventArgs.Empty);
return new MediaStatus();
}

public Task<MediaStatus> GetMediaStatusAsync()
{
throw new NotImplementedException();
}

public async Task<MediaStatus> PlayAsync()
{
IsPlaying = true;
IsPaused = false;
await Task.Delay(TimeSpan.FromSeconds(2));
return new MediaStatus();
}

public async Task<MediaStatus> PauseAsync()
{
IsPlaying = false;
await Task.Delay(TimeSpan.FromSeconds(2));
Paused?.Invoke(this, EventArgs.Empty);
return new MediaStatus();
}

public async Task<MediaStatus> StopPlaybackAsync()
{
CleanLoadedFile();
CurrentContentId = null;
IsPlaying = false;
await Task.Delay(TimeSpan.FromSeconds(2));
CancelAndSetListenerToken(false);
EndReached?.Invoke(this, EventArgs.Empty);
return new MediaStatus();
}

public async Task<MediaStatus> SeekAsync(double seconds)
{
ElapsedSeconds += seconds;
await Task.Delay(TimeSpan.FromSeconds(2));
return new MediaStatus();
}

public async Task<List<IReceiver>> GetDevicesAsync(TimeSpan scanTime)
{
await Task.Delay(scanTime);
return _devices;
}

public async Task<ReceiverStatus> SetVolumeAsync(float level)
{
CurrentVolumeLevel = level;
await Task.Delay(TimeSpan.FromSeconds(2));
VolumeLevelChanged?.Invoke(this, CurrentVolumeLevel);
return new ReceiverStatus
{
Volume = new Volume
{
IsMuted = IsMuted,
Level = (float)CurrentVolumeLevel,
}
};
}

public async Task<ReceiverStatus> SetIsMutedAsync(bool isMuted)
{
IsMuted = isMuted;
await Task.Delay(TimeSpan.FromSeconds(2));
IsMutedChanged?.Invoke(this, IsMuted);
return new ReceiverStatus
{
Volume = new Volume
{
IsMuted = IsMuted,
Level = (float)CurrentVolumeLevel,
}
};
}

public Task DisconnectAsync()
{
CancelAndSetListenerToken(false);
CleanLoadedFile();
OnDisconnect(this, EventArgs.Empty);
return Task.Delay(TimeSpan.FromSeconds(2));
}

private void OnDisconnect(object sender, EventArgs e)
{
Disconnected?.Invoke(sender, e);
IsPlaying = false;
}

private void TriggerTimeEvents()
{
TimeChanged?.Invoke(this, ElapsedSeconds);
PositionChanged?.Invoke(this, PlayedPercentage);
}

private void CleanLoadedFile()
{
CurrentContentId = null;
CurrentMediaDuration = 0;
ElapsedSeconds = 0;
IsPlaying = false;
IsPaused = false;
}

private void CancelAndSetListenerToken(bool createNewToken = true)
{
if (_listenerToken?.IsCancellationRequested == false)
_listenerToken.Cancel();

if (createNewToken)
_listenerToken = new CancellationTokenSource();
}

private async void ListenForMediaChanges(CancellationToken token)
{
try
{
await ListenMediaChangesSemaphoreSlim.WaitAsync(token);
await Task.Run(async () =>
{
while (!token.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(2), token);
ElapsedSeconds++;
if (IsPaused)
{
IsPaused = true;
IsPlaying = false;
Paused?.Invoke(this, EventArgs.Empty);
continue;
}
IsPlaying = true;
IsPaused = false;
TriggerTimeEvents();
//If CurrentMediaDuration <= 0, that means that a live streaming is being played
if (CurrentMediaDuration > 0 && Math.Round(ElapsedSeconds, 4) >= Math.Round(CurrentMediaDuration, 4))
{
CleanLoadedFile();
CancelAndSetListenerToken(false);
EndReached?.Invoke(this, EventArgs.Empty);
break;
}
}
}, token).ConfigureAwait(false);
}
catch (Exception e)
{
if (e is TaskCanceledException or OperationCanceledException)
return;
}
finally
{
if (ListenMediaChangesSemaphoreSlim.CurrentCount == 0)
ListenMediaChangesSemaphoreSlim.Release();
}
}
}
}
2 changes: 1 addition & 1 deletion CastIt.GoogleCast/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,12 +158,12 @@ public PlayerStatus State
_sender.Disconnected += OnDisconnect;
_connectionChannel = new ConnectionChannel(destinationId);
_heartbeatChannel = new HeartbeatChannel(destinationId);
_receiverChannel = new ReceiverChannel(destinationId);
_mediaChannel = new MediaChannel(destinationId, async () =>
{
var app = await _receiverChannel.GetApplication(_sender, _connectionChannel, _mediaChannel.Namespace);
return app.SessionId;
});
_receiverChannel = new ReceiverChannel(destinationId);
}
#endregion

Expand Down

0 comments on commit 9903477

Please sign in to comment.