private E <LocalStr> Start(PlayResource resource, string restoredLink) { Log.Trace("Starting resource..."); var playInfo = new PlayInfoEventArgs(resource.Meta.ResourceOwnerUid, resource, restoredLink); BeforeResourceStarted?.Invoke(this, playInfo); if (string.IsNullOrWhiteSpace(resource.PlayUri)) { Log.Error("Internal resource error: link is empty (resource:{0})", resource); return(new LocalStr(strings.error_playmgr_internal_error)); } var gain = resource.BaseData.Gain ?? 0; Log.Debug("AudioResource start: {0} with gain {1}", resource, gain); var result = player.Play(resource, gain); if (!result) { Log.Error("Error return from player: {0}", result.Error); return(new LocalStr(strings.error_playmgr_internal_error)); } player.Volume = Tools.Clamp(player.Volume, config.Audio.Volume.Min, config.Audio.Volume.Max); AfterResourceStarted?.Invoke(this, playInfo); return(R.Ok); }
/// <summary>Plays the passed <see cref="PlayResource"/></summary> /// <param name="invoker">The invoker of this resource. Used for responses and association.</param> /// <param name="play">The associated resource type string to a factory.</param> /// <param name="meta">Allows overriding certain settings for the resource.</param> /// <returns>Ok if successful, or an error message otherwise.</returns> public E <LocalStr> Play(InvokerData invoker, PlayResource play, MetaData meta) { if (!meta.FromPlaylist) { meta.ResourceOwnerUid = invoker.ClientUid; } var playInfo = new PlayInfoEventArgs(invoker, play, meta); BeforeResourceStarted?.Invoke(this, playInfo); // pass the song to the AF to start it var result = StartResource(play, meta); if (!result) { return(result); } // add it to our freelist for comfort if (!meta.FromPlaylist) { int index = PlaylistManager.InsertToFreelist(new PlaylistItem(play.BaseData, meta)); PlaylistManager.Index = index; } CurrentPlayData = playInfo; // TODO meta as readonly AfterResourceStarted?.Invoke(this, CurrentPlayData); return(R.Ok); }
/// <summary> /// <para>Do NOT call this method directly! Use the <see cref="PlayManager"/> instead.</para> /// <para>Stops the old resource and starts the new one.</para> /// <para>The volume gets resetted and the OnStartEvent gets triggered.</para> /// </summary> /// <param name="playData">The info struct containing the PlayResource to start.</param> internal R StartResource(PlayResource playResource, MetaData config) { if (playResource == null) { Log.Write(Log.Level.Debug, "AF audioResource is null"); return("No new resource"); } Stop(true); if (string.IsNullOrWhiteSpace(playResource.PlayUri)) { return("Internal resource error: link is empty"); } Log.Write(Log.Level.Debug, "AF ar start: {0}", playResource); var result = playerConnection.AudioStart(playResource.PlayUri); if (!result) { Log.Write(Log.Level.Error, "Error return from player: {0}", result.Message); return($"Internal player error ({result.Message})"); } Volume = config.Volume ?? audioFrameworkData.DefaultVolume; Log.Write(Log.Level.Debug, "AF set volume: {0}", Volume); return(R.OkR); }
private E <LocalStr> StartResource(InvokerData invoker, PlayResource play, MetaData meta = null) { play.Meta = meta ?? play.Meta ?? new MetaData(); var sourceLink = resourceResolver.RestoreLink(play.BaseData).OkOr(null); var playInfo = new PlayInfoEventArgs(invoker, play, sourceLink); BeforeResourceStarted?.Invoke(this, playInfo); if (string.IsNullOrWhiteSpace(play.PlayUri)) { Log.Error("Internal resource error: link is empty (resource:{0})", play); return(new LocalStr(strings.error_playmgr_internal_error)); } Log.Debug("AudioResource start: {0}", play); var result = playerConnection.Play(play); if (!result) { Log.Error("Error return from player: {0}", result.Error); return(new LocalStr(strings.error_playmgr_internal_error)); } playerConnection.Volume = Tools.Clamp(playerConnection.Volume, confBot.Audio.Volume.Min, confBot.Audio.Volume.Max); CurrentPlayData = playInfo; // TODO meta as readonly AfterResourceStarted?.Invoke(this, playInfo); return(R.Ok); }
public R Play(InvokerData invoker, PlayResource play, MetaData meta) { if (!meta.FromPlaylist) { meta.ResourceOwnerDbId = invoker.DatabaseId; } // add optional beforestart here. maybe for blocking/interrupting etc. BeforeResourceStarted?.Invoke(this, new EventArgs()); // pass the song to the AF to start it var result = AudioFramework.StartResource(play, meta); if (!result) { return(result); } // add it to our freelist for comfort if (!meta.FromPlaylist) { int index = PlaylistManager.InsertToFreelist(new PlaylistItem(play.BaseData, meta)); PlaylistManager.Index = index; } // Log our resource in the history ulong?owner = meta.ResourceOwnerDbId ?? invoker.DatabaseId; HistoryManager.LogAudioResource(new HistorySaveData(play.BaseData, owner)); CurrentPlayData = new PlayInfoEventArgs(invoker, play, meta); // TODO meta as readonly AfterResourceStarted?.Invoke(this, CurrentPlayData); return(R.OkR); }
private E <LocalStr> StartResource(InvokerData invoker, PlayResource play, MetaData meta) { if (meta.From != PlaySource.FromPlaylist) { meta.ResourceOwnerUid = invoker.ClientUid; } var sourceLink = resourceFactory.RestoreLink(play.BaseData).OkOr(null); var playInfo = new PlayInfoEventArgs(invoker, play, meta, sourceLink); BeforeResourceStarted?.Invoke(this, playInfo); if (string.IsNullOrWhiteSpace(play.PlayUri)) { Log.Error("Internal resource error: link is empty (resource:{0})", play); return(new LocalStr(strings.error_playmgr_internal_error)); } Log.Debug("AudioResource start: {0}", play); var result = playerConnection.AudioStart(play); if (!result) { Log.Error("Error return from player: {0}", result.Error); return(new LocalStr(strings.error_playmgr_internal_error)); } playerConnection.Volume = Util.Clamp(playerConnection.Volume, confBot.Audio.Volume.Min, confBot.Audio.Volume.Max); CurrentPlayData = playInfo; // TODO meta as readonly AfterResourceStarted?.Invoke(this, playInfo); return(R.Ok); }
public PlayInfoEventArgs(InvokerData invoker, PlayResource playResource, MetaData meta, string sourceLink) { Invoker = invoker; PlayResource = playResource; MetaData = meta; SourceLink = sourceLink; }
/// <summary>Plays the passed <see cref="PlayResource"/></summary> /// <param name="invoker">The invoker of this resource. Used for responses and association.</param> /// <param name="play">The associated resource type string to a factory.</param> /// <param name="meta">Allows overriding certain settings for the resource.</param> /// <returns>Ok if successful, or an error message otherwise.</returns> public E <LocalStr> Play(InvokerData invoker, PlayResource play, MetaData meta = null) { meta = meta ?? new MetaData(); playlistManager.Clear(); playlistManager.Queue(new PlaylistItem(play.BaseData, meta)); playlistManager.Index = 0; return(StartResource(invoker, play, meta)); }
public E <string> Play(PlayResource res) { E <string> result; if (res is MediaPlayResource mres && mres.IsIcyStream) { result = FfmpegProducer.AudioStartIcy(res.PlayUri); }
/// <summary>Plays the passed <see cref="PlayResource"/></summary> /// <param name="invoker">The invoker of this resource. Used for responses and association.</param> /// <param name="play">The associated resource type string to a factory.</param> /// <param name="meta">Allows overriding certain settings for the resource.</param> /// <returns>Ok if successful, or an error message otherwise.</returns> public Task Play(InvokerData invoker, PlayResource play) { playlistManager.Clear(); playlistManager.Queue(PlaylistItem.From(play)); playlistManager.Index = 0; stats.TrackSongLoad(play.AudioResource.AudioType, true, true); return(StartResource(invoker, play)); }
/// <summary>Plays the passed <see cref="PlayResource"/></summary> /// <param name="invoker">The invoker of this resource. Used for responses and association.</param> /// <param name="play">The associated resource type string to a factory.</param> /// <param name="meta">Allows overriding certain settings for the resource.</param> /// <returns>Ok if successful, or an error message otherwise.</returns> public E <LocalStr> Play(InvokerData invoker, PlayResource play, MetaData meta = null) { meta = meta ?? new MetaData(); playlistManager.Clear(); playlistManager.Queue(new PlaylistItem(play.BaseData, meta)); playlistManager.Index = 0; stats.TrackSongLoad(play.BaseData.AudioType, true, true); return(StartResource(invoker, play, meta)); }
public R <Stream, LocalStr> GetThumbnail(ResolveContext ctx, PlayResource playResource) { var urlOption = GetThumbnailUrl(ctx, playResource); if (!urlOption.Ok) { return(urlOption.Error); } return(WebWrapper.GetResponseUnsafe(urlOption.Value)); }
public Task GetThumbnail(ResolveContext _, PlayResource playResource, Func <Stream, Task> action) { // default : 120px/ 90px /default.jpg // medium : 320px/180px /mqdefault.jpg // high : 480px/360px /hqdefault.jpg // standard : 640px/480px /sddefault.jpg // maxres : 1280px/720px /maxresdefault.jpg return(WebWrapper .Request($"https://i.ytimg.com/vi/{playResource.AudioResource.ResourceId}/mqdefault.jpg") .ToStream(action)); }
public R <Stream, LocalStr> GetThumbnail(ResolveContext _, PlayResource playResource) { // default : 120px/ 90px /default.jpg // medium : 320px/180px /mqdefault.jpg // high : 480px/360px /hqdefault.jpg // standard : 640px/480px /sddefault.jpg // maxres : 1280px/720px /maxresdefault.jpg var imgurl = new Uri($"https://i.ytimg.com/vi/{playResource.BaseData.ResourceId}/mqdefault.jpg"); return(WebWrapper.GetResponseUnsafe(imgurl)); }
public E <LocalStr> StartResource(PlayResource resource) { if (string.IsNullOrWhiteSpace(resource.PlayUri)) { Log.Error($"{this}: Internal resource error: link is empty (resource:{resource})"); return(new LocalStr(strings.error_playmgr_internal_error)); } var gain = resource.BaseData.Gain ?? 0; Log.Debug($"{this}: Starting {resource} with gain {gain}"); var result = player.Play(resource, gain); if (!result) { Log.Error($"{this}: Error return from player: {result.Error}"); return(new LocalStr(strings.error_playmgr_internal_error)); } player.Volume = Tools.Clamp(player.Volume, volumeConfig.Min, volumeConfig.Max); return(R.Ok); }
private E <LocalStr> StartResource(PlayResource playResource, MetaData meta) { if (string.IsNullOrWhiteSpace(playResource.PlayUri)) { Log.Error("Internal resource error: link is empty (resource:{0})", playResource); return(new LocalStr(strings.error_playmgr_internal_error)); } Log.Debug("AudioResource start: {0}", playResource); var result = PlayerConnection.AudioStart(playResource.PlayUri); if (!result) { Log.Error("Error return from player: {0}", result.Error); return(new LocalStr(strings.error_playmgr_internal_error)); } PlayerConnection.Volume = meta.Volume ?? Math.Min(Math.Max(PlayerConnection.Volume, Config.Audio.Volume.Min), Config.Audio.Volume.Max); return(R.Ok); }
public R <Uri, LocalStr> GetThumbnailUrl(ResolveContext ctx, PlayResource playResource) { // default : 120px/ 90px /default.jpg // medium : 320px/180px /mqdefault.jpg // high : 480px/360px /hqdefault.jpg // standard : 640px/480px /sddefault.jpg // maxres : 1280px/720px /maxresdefault.jpg IList <string> names = new List <string> { "maxresdefault.jpg", "sddefault.jpg", "hqdefault.jpg", "mqdefault.jpg", "default.jpg" }; Uri workingUrl = null; foreach (var name in names) { var tentativeUrl = new Uri($"https://i.ytimg.com/vi/{playResource.BaseData.ResourceId}/{name}"); var request = WebRequest.CreateHttp(tentativeUrl); request.Method = "HEAD"; try { request.GetResponse(); workingUrl = tentativeUrl; break; } catch (WebException) { // Apparently offline. } } if (workingUrl == null) { return(new LocalStr("No working thumbnail URL found.")); } return(workingUrl); }
private R StartResource(PlayResource playResource, MetaData config) { //PlayerConnection.AudioStop(); if (string.IsNullOrWhiteSpace(playResource.PlayUri)) { return("Internal resource error: link is empty"); } Log.Write(Log.Level.Debug, "PM ar start: {0}", playResource); var result = PlayerConnection.AudioStart(playResource.PlayUri); if (!result) { Log.Write(Log.Level.Error, "Error return from player: {0}", result.Message); return($"Internal player error ({result.Message})"); } PlayerConnection.Volume = config.Volume ?? AudioValues.DefaultVolume; return(R.OkR); }
/// <summary>Plays the passed <see cref="PlayResource"/></summary> /// <param name="invoker">The invoker of this resource. Used for responses and association.</param> /// <param name="play">The associated resource type string to a factory.</param> /// <param name="meta">Allows overriding certain settings for the resource.</param> /// <returns>Ok if successful, or an error message otherwise.</returns> public E <LocalStr> Play(InvokerData invoker, PlayResource play, MetaData meta) { if (meta.From != PlaySource.FromPlaylist) { meta.ResourceOwnerUid = invoker.ClientUid; } var sourceLink = ResourceFactoryManager.RestoreLink(play.BaseData); var playInfo = new PlayInfoEventArgs(invoker, play, meta, sourceLink); BeforeResourceStarted?.Invoke(this, playInfo); var result = StartResource(play, meta); if (!result) { return(result); } CurrentPlayData = playInfo; // TODO meta as readonly AfterResourceStarted?.Invoke(this, playInfo); return(R.Ok); }
private async Task StartResource(InvokerData invoker, PlayResource play) { var sourceLink = resourceResolver.RestoreLink(play.AudioResource); var playInfo = new PlayInfoEventArgs(invoker, play, sourceLink); await BeforeResourceStarted.InvokeAsync(this, playInfo); if (string.IsNullOrWhiteSpace(play.PlayUri)) { Log.Error("Internal resource error: link is empty (resource:{0})", play); throw Error.LocalStr(strings.error_playmgr_internal_error); } Log.Debug("AudioResource start: {0}", play); try { await playerConnection.Play(play); } catch (AudioBotException ex) { Log.Error("Error return from player: {0}", ex.Message); throw Error.Exception(ex).LocalStr(strings.error_playmgr_internal_error); } playerConnection.Volume = Tools.Clamp(playerConnection.Volume, confBot.Audio.Volume.Min, confBot.Audio.Volume.Max); CurrentPlayData = playInfo; // TODO meta as readonly await AfterResourceStarted.InvokeAsync(this, playInfo); }
public async Task Play(PlayResource res) { if (res is MediaPlayResource mres && mres.IsIcyStream) { await FfmpegProducer.AudioStartIcy(res.PlayUri); }
public PlayInfoEventArgs(InvokerData invoker, PlayResource playResource, string?sourceLink) { Invoker = invoker; PlayResource = playResource; SourceLink = sourceLink; }
public PlayInfoEventArgs(InvokerData invoker, PlayResource playResource, MetaData meta) { Invoker = invoker; PlayResource = playResource; MetaData = meta; }
public PlayInfoEventArgs(ClientData invoker, PlayResource playResource, MetaData meta) : this(new InvokerData(invoker), playResource, meta) { }
public void RunStartSongTaskTest() { var lck = new object(); var queueItem = new QueueItem(Constants.Resource1AYoutube, new MetaData(Constants.TestUid, Constants.ListId)); var queueItemGain = new QueueItem(Constants.Resource1AYoutubeGain, new MetaData(Constants.TestUid, Constants.ListId)); var playResource = new PlayResource(queueItem.AudioResource.ResourceId, queueItem.AudioResource, queueItem.MetaData); var playResourceGain = new PlayResource(queueItemGain.AudioResource.ResourceId, queueItemGain.AudioResource, queueItemGain.MetaData); { // Queue item without gain gets it set and update gets invoked var loaderContext = new LoaderContextMock(); var player = new PlayerMock(); var task = new StartSongTask(loaderContext, player, Constants.VolumeConfig, lck, queueItem); AudioResource changedResource = null; QueueItem containingQueueItem = null; task.OnAudioResourceUpdated += (sender, args) => { changedResource = args.Resource; containingQueueItem = args.QueueItem; }; var waitHandle = new InformingEventWaitHandle(false, EventResetMode.AutoReset); var tokenSource = new CancellationTokenSource(); var t = Task.Run(() => task.RunInternal(waitHandle, tokenSource.Token)); // Wait that the task reached the first point, cancel waitHandle.OutputHandle.WaitOne(); tokenSource.Cancel(); waitHandle.Set(); // Check that it actually failed AssertThrowsInnerException <AggregateException, TaskCanceledException>(() => { var _ = t.Result; }); Assert.NotNull(changedResource); Assert.NotNull(containingQueueItem); Assert.AreSame(containingQueueItem, queueItem); var gain = changedResource.Gain; Assert.IsTrue(gain.HasValue); Assert.AreEqual(gain.Value, VolumeDetectorMock.VolumeSet); } { var loaderContext = new LoaderContextMock(); var player = new PlayerMock(); var task = new StartSongTask(loaderContext, player, Constants.VolumeConfig, lck, queueItem); var waitHandle = new InformingEventWaitHandle(false, EventResetMode.AutoReset); var tokenSource = new CancellationTokenSource(); var t = Task.Run(() => task.RunInternal(waitHandle, tokenSource.Token)); // Wait that the task reached the first point, cancel waitHandle.OutputHandle.WaitOne(); lock (lck) { waitHandle.Set(); Task.Delay(100); tokenSource.Cancel(); } AssertThrowsInnerException <AggregateException, TaskCanceledException>(() => { var _ = t.Result; }); } { var player = new PlayerMock(); var task = new StartSongTask(null, player, Constants.VolumeConfig, null, null); PlayInfoEventArgs argsBefore = null; PlayInfoEventArgs argsAfter = null; task.BeforeResourceStarted += (sender, args) => { Assert.IsNotNull(args); Assert.AreEqual(args.Invoker, Constants.TestUid); Assert.AreSame(args.MetaData, queueItemGain.MetaData); Assert.AreSame(args.ResourceData, queueItemGain.AudioResource); Assert.AreSame(args.SourceLink, LoaderContextMock.RestoredLink); argsBefore = args; }; task.AfterResourceStarted += (sender, args) => { Assert.IsNotNull(args); Assert.AreEqual(args.Invoker, Constants.TestUid); Assert.AreSame(args.MetaData, queueItemGain.MetaData); Assert.AreSame(args.ResourceData, queueItemGain.AudioResource); Assert.AreSame(args.SourceLink, LoaderContextMock.RestoredLink); argsAfter = args; }; var t = Task.Run(() => task.StartResource(new SongAnalyzerResult { Resource = playResourceGain, RestoredLink = LoaderContextMock.RestoredLink })); var res = t.Result; Assert.IsTrue(res.Ok); Assert.AreSame(argsBefore, argsAfter); Assert.NotNull(player.PlayArgs.res); Assert.NotNull(player.PlayArgs.gain); Assert.AreSame(player.PlayArgs.res, playResourceGain); Assert.AreEqual(player.PlayArgs.gain, queueItemGain.AudioResource.Gain); Assert.AreEqual(player.Volume, 10.0f); } { var player = new PlayerMock(); var task = new StartSongTask(null, player, Constants.VolumeConfig, null, null); var t = Task.Run(() => task.StartResource(new SongAnalyzerResult { Resource = playResource, RestoredLink = LoaderContextMock.RestoredLink })); var res = t.Result; Assert.IsTrue(res.Ok); Assert.NotNull(player.PlayArgs.res); Assert.NotNull(player.PlayArgs.gain); Assert.AreSame(player.PlayArgs.res, playResource); Assert.AreEqual(player.PlayArgs.gain, 0); Assert.AreEqual(player.Volume, 10.0f); } }
public static PlaylistItem From(PlayResource playResource) { return(new PlaylistItem(playResource.AudioResource, playResource.PlayInfo)); }