Example #1
0
        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);
        }
Example #2
0
        /// <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);
        }
Example #3
0
        /// <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);
        }
Example #4
0
        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);
        }
Example #5
0
        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);
        }
Example #6
0
        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;
 }
Example #8
0
 /// <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));
 }
Example #9
0
        public E <string> Play(PlayResource res)
        {
            E <string> result;

            if (res is MediaPlayResource mres && mres.IsIcyStream)
            {
                result = FfmpegProducer.AudioStartIcy(res.PlayUri);
            }
Example #10
0
 /// <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));
 }
Example #11
0
 /// <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));
 }
Example #12
0
        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));
        }
Example #13
0
 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));
 }
Example #14
0
        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));
        }
Example #15
0
        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);
        }
Example #17
0
        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);
        }
Example #18
0
        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);
        }
Example #20
0
        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);
        }
Example #21
0
 public async Task Play(PlayResource res)
 {
     if (res is MediaPlayResource mres && mres.IsIcyStream)
     {
         await FfmpegProducer.AudioStartIcy(res.PlayUri);
     }
Example #22
0
 public PlayInfoEventArgs(InvokerData invoker, PlayResource playResource, string?sourceLink)
 {
     Invoker      = invoker;
     PlayResource = playResource;
     SourceLink   = sourceLink;
 }
Example #23
0
 public PlayInfoEventArgs(InvokerData invoker, PlayResource playResource, MetaData meta)
 {
     Invoker      = invoker;
     PlayResource = playResource;
     MetaData     = meta;
 }
Example #24
0
 public PlayInfoEventArgs(ClientData invoker, PlayResource playResource, MetaData meta)
     : this(new InvokerData(invoker), playResource, meta)
 {
 }
Example #25
0
        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);
            }
        }
Example #26
0
 public static PlaylistItem From(PlayResource playResource)
 {
     return(new PlaylistItem(playResource.AudioResource, playResource.PlayInfo));
 }