using System; using System.Threading.Tasks; using System.Collections.Generic; using Aurora.Proto.Party; using Aurora.Models.Media; using Aurora.Proto.General; using Aurora.Services.Library; using Aurora.Services.Player; using Autofac; namespace Aurora.Services.Server.Controllers { public partial class RemotePartyController : RemotePartyService.RemotePartyServiceBase { private SortedList _mediaList; public override Task ListMedia(ListMediaRequest request, Grpc.Core.ServerCallContext context) { ListMediaResponse resp = new ListMediaResponse(); int startIdx = 0; if (!string.IsNullOrEmpty(request.PageToken)) { startIdx = _memberList.IndexOfKey(request.PageToken) + 1; } int pageSize = request.PageSize; if (pageSize > _mediaList.Count) { pageSize = _mediaList.Count; } //Gather page List mediaList = new List(_mediaList.Values); resp.Media.AddRange(mediaList.GetRange(startIdx, pageSize)); resp.NextPageToken = resp.Media[resp.Media.Count - 1].Name; return Task.FromResult(resp); } public override Task GetMedia(GetMediaRequest request, Grpc.Core.ServerCallContext context) { _mediaList.TryGetValue(request.Name, out Media baseMedia); if (baseMedia == null) { throw new KeyNotFoundException(); } return Task.FromResult(baseMedia); } public override Task CreateMedia(CreateMediaRequest request, Grpc.Core.ServerCallContext context) { throw new NotImplementedException(); } public override Task DeleteMedia(DeleteMediaRequest request, Grpc.Core.ServerCallContext context) { throw new NotImplementedException(); } public override async Task StreamMedia(StreamMediaRequest request, Grpc.Core.IServerStreamWriter responseStream, Grpc.Core.ServerCallContext context) { using (var scope = App.Container.BeginLifetimeScope()) { ILibraryService library = scope.Resolve(); string mediaName = request.Name.Split('/')[1]; BaseMedia originalSong = library.GetSong(mediaName); if (!(originalSong is LocalAudio)) { return; } //Copy media object to not interfere with other threads LocalAudio songCopy = new LocalAudio((LocalAudio)originalSong); try { //Load only if not already loaded. (Multiple clients may be requesting media) if (!songCopy.IsLoaded) { await songCopy.Load(); } //Send stream Console.WriteLine("Begin sending file"); byte[] buffer = new byte[2048]; // read in chunks of 2KB int bytesRead; while ((bytesRead = songCopy.DataStream.Read(buffer, 0, buffer.Length)) > 0) { Google.Protobuf.ByteString bufferByteString = Google.Protobuf.ByteString.CopyFrom(buffer); await responseStream.WriteAsync(new Chunk { Content = bufferByteString }); } Console.WriteLine("Done sending file"); } catch (Exception ex) { Console.WriteLine("Exception caught while sending audio file: " + ex.Message); } } } public override async Task SyncMedia(SyncMediaRequest request, Grpc.Core.IServerStreamWriter responseStream, Grpc.Core.ServerCallContext context) { bool continueSync = true; using (var scope = App.Container.BeginLifetimeScope()) { try { IPlayer player = scope.Resolve(); string currentId = player.CurrentMedia.Id; while (continueSync) { float length = player.CurrentMediaLength; Sync sync = new Sync() { TrackPosition = player.CurrentMediaPosition, ServerTimeTicks = Utils.TimeUtils.GetNetworkTime().DateTime.Ticks }; await responseStream.WriteAsync(sync); Console.WriteLine("Sent Sync"); await Task.Delay(5000); } } catch (Exception ex) { Console.WriteLine("Error sending sync: " + ex.Message); } } } } }