Example #1
0
 private async Task CheckPrebufferingAsync(MusicBuffer inStream, CancellationToken cancelToken, long size)
 {
     while (!inStream.BufferingCompleted && inStream.Length < size)
     {
         await Task.Delay(100, cancelToken);
     }
     Log.Message(LogSeverity.Debug, "Buffering successfull.");
 }
Example #2
0
        private async Task StreamAsync(Track currentTrack)
        {
            try
            {
                var response = await new HttpClient().GetStringAsync(string.Format("https://www.googleapis.com/youtube/v3/videos?part=contentDetails&id={0}&key={1}", currentTrack.Id, LumpiBot.Configuration.Bot.GoogleAPIKey));
                var json     = JsonConvert.DeserializeObject <YTRootObject>(response);
                if (json != null)
                {
                    foreach (var o in json.items)
                    {
                        TotalTime = XmlConvert.ToTimeSpan(o.contentDetails.duration);
                    }

                    CurrentTrack = currentTrack.SourceVideo.Title;
                    await currentTrack.sourceTextChannel.SendMessageAsync(string.Format("🎶 Now Playing **{0}** *({1})*", currentTrack.SourceVideo.Title, TotalTime));
                }
            }
            catch (Exception ex) { Log.Message(LogSeverity.Error, ex.Message); }

            Music.isPlaying = true;
            bytesSent       = (ulong)currentTrack.SkipTo * 3840 * 50;

            if (!Directory.Exists(LumpiBot.CacheFolder + Path.DirectorySeparatorChar + MusicCacheFolder + Path.DirectorySeparatorChar))
            {
                Directory.CreateDirectory(LumpiBot.CacheFolder + Path.DirectorySeparatorChar + MusicCacheFolder + Path.DirectorySeparatorChar);
            }

            var filename   = LumpiBot.CacheFolder + Path.DirectorySeparatorChar + MusicCacheFolder + Path.DirectorySeparatorChar + DateTime.Now.Ticks.ToString();
            var inStream   = new MusicBuffer(currentTrack, filename, _frameBytes * 100);
            var bufferTask = inStream.BufferSong(currentTrack.CancelTokenSource.Token).ConfigureAwait(false);

            try
            {
                var attempt = 0;

                var prebufferingTask = CheckPrebufferingAsync(inStream, currentTrack.CancelTokenSource.Token, 1.MiB()); //Fast connection can do this easy
                var finished         = false;
                var count            = 0;
                var sw             = new Stopwatch();
                var slowconnection = false;
                sw.Start();
                while (!finished)
                {
                    var t = await Task.WhenAny(prebufferingTask, Task.Delay(2000, currentTrack.CancelTokenSource.Token));

                    if (t != prebufferingTask)
                    {
                        count++;
                        if (count == 10)
                        {
                            slowconnection   = true;
                            prebufferingTask = CheckPrebufferingAsync(inStream, currentTrack.CancelTokenSource.Token, 20.MiB());
                            Log.Message(LogSeverity.Warning, "Slow connection buffering more to ensure no disruption, consider hosting in cloud");
                            continue;
                        }

                        if (inStream.BufferingCompleted && count == 1)
                        {
                            Log.Message(LogSeverity.Warning, "Prebuffering canceled. Cannot get any data from the stream.");
                            Music.isPlaying = false;
                            return;
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else if (prebufferingTask.IsCanceled)
                    {
                        Log.Message(LogSeverity.Warning, "Prebuffering canceled. Cannot get any data from the stream.");
                        Music.isPlaying = false;
                        return;
                    }
                    finished = true;
                }
                sw.Stop();
                Log.Message(LogSeverity.Debug, "Prebuffering successfully completed in " + sw.Elapsed);

                var outStream = audioClient.CreatePCMStream(AudioApplication.Music);

                int nextTime = Environment.TickCount + _milliseconds;

                byte[] buffer = new byte[_frameBytes];
                while (!currentTrack.CancelTokenSource.Token.IsCancellationRequested)
                {
                    var read = await inStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);

                    if (read < _frameBytes)
                    {
                        Log.Message(LogSeverity.Debug, $"read {read}");
                    }
                    unchecked
                    {
                        bytesSent += (ulong)read;
                    }

                    CurrentTime = TimeSpan.FromSeconds(bytesSent / (float)_frameBytes / (1000 / (float)_milliseconds));

                    if (read < _frameBytes)
                    {
                        if (read == 0)
                        {
                            if (inStream.BufferingCompleted)
                            {
                                break;
                            }
                            if (attempt++ == 20)
                            {
                                currentTrack.CancelTokenSource.Cancel();
                                break;
                            }
                            if (slowconnection)
                            {
                                Log.Message(LogSeverity.Warning, "Slow connection has disrupted music, waiting a bit for buffer...");

                                await Task.Delay(1000, currentTrack.CancelTokenSource.Token).ConfigureAwait(false);

                                nextTime = Environment.TickCount + _milliseconds;
                            }
                            else
                            {
                                await Task.Delay(100, currentTrack.CancelTokenSource.Token).ConfigureAwait(false);

                                nextTime = Environment.TickCount + _milliseconds;
                            }
                        }
                        else
                        {
                            attempt = 0;
                        }
                    }
                    else
                    {
                        attempt = 0;
                    }

                    while (currentTrack.isPaused)
                    {
                        await Task.Delay(200, currentTrack.CancelTokenSource.Token).ConfigureAwait(false);

                        nextTime = Environment.TickCount + _milliseconds;
                    }

                    float calcvol = Volume / 100;
                    buffer = ScaleVolumeSafeAllocateBuffers(buffer, calcvol);
                    if (read != _frameBytes)
                    {
                        continue;
                    }
                    nextTime = unchecked (nextTime + _milliseconds);
                    int delayMillis = unchecked (nextTime - Environment.TickCount);
                    if (delayMillis > 0)
                    {
                        await Task.Delay(delayMillis, currentTrack.CancelTokenSource.Token).ConfigureAwait(false);
                    }
                    await outStream.WriteAsync(buffer, 0, read).ConfigureAwait(false);
                }
            }
            finally
            {
                await bufferTask;
                inStream.Dispose();
                Music.isPlaying = false;
                await LumpiBot.Client.SetGameAsync(string.Empty);
            }
        }