public void PlayFile(IAudioClient ac, string path) { var process = Process.Start(new ProcessStartInfo { // FFmpeg requires us to spawn a process and hook into its stdout, so we will create a Process FileName = "ffmpeg", Arguments = $"-i {path} " + "-f s16le -ar 48000 -ac 2 pipe:1", UseShellExecute = false, RedirectStandardOutput = true }); Thread.Sleep(200); // Sleep for a few seconds to FFmpeg can start processing data. int blockSize = 3840; byte[] buffer = new byte[blockSize]; int byteCount; while (true) { byteCount = process.StandardOutput.BaseStream .Read(buffer, 0, blockSize); if (byteCount == 0) // FFmpeg did not output anything { break; // Break out of the while(true) loop, since there was nothing to read. } ac.Send(buffer, 0, byteCount); } ac.Wait(); // Wait for the Voice Client to finish sending data }
/// <summary> /// Send audio to the current _vClient channel /// </summary> /// <param name="path">Path of the .wav file to send</param> private void send(string path, Command current, IAudioClient _vClient) { int blockSize = 3840; // The size of bytes to read per frame; 1920 for mono try { using (FileStream f = File.Open(path, FileMode.Open)) { byte[] buffer = new byte[blockSize]; while (f.Read(buffer, 0, buffer.Length) > 0) { try { _vClient.Send(buffer, 0, buffer.Length); } catch (Discord.Net.TimeoutException e) { log.Error("Error sending audio data: " + e.Message); } } _vClient.Wait(); log.Info("Sent audio: " + path); } } catch (FileNotFoundException e) { log.Error(string.Format("Could not find file; ensure {0} is correct path", path)); } catch (Exception e) { log.Error(e); } }
public static async Task PlayMusic(IAudioClient voiceClient, string file) { var ffmpegProcess = new ProcessStartInfo(); ffmpegProcess.FileName = @"C:\FFMPEG\bin\ffmpeg.exe"; ffmpegProcess.Arguments = $"-i {file} -f s16le -ar 48000 -ac 2 pipe:1 -loglevel quiet"; ffmpegProcess.UseShellExecute = false; ffmpegProcess.RedirectStandardOutput = true; var p = Process.Start(ffmpegProcess); await Task.Delay(1000); //give it 2 seconds to get some dataz int blockSize = 3840; // 1920 for mono byte[] buffer = new byte[blockSize]; int read; while (!MilliaBot.IsSkipSong) { read = p.StandardOutput.BaseStream.Read(buffer, 0, blockSize); if (read == 0 || MilliaBot.IsSkipSong) { MilliaBot.IsSkipSong = false; await Task.Delay(1000); break; //nothing to read } voiceClient.Send(buffer, 0, read); } voiceClient.Wait(); }
/// <summary> /// Plays an mp3 file in the current voiceChannel /// </summary> /// <param name="filePath">Path for mp3 file</param> private void SendAudio(string filePath) { voiceClient.Wait(); var channelCount = client.GetService <AudioService>().Config.Channels; // Get the number of AudioChannels our AudioService has been configured to use. var OutFormat = new WaveFormat(48000, 16, channelCount); // Create a new Output Format, using the spec that Discord will accept, and with the number of channels that our client supports. using (var MP3Reader = new Mp3FileReader(filePath)) // Create a new Disposable MP3FileReader, to read audio from the filePath parameter using (var resampler = new MediaFoundationResampler(MP3Reader, OutFormat)) // Create a Disposable Resampler, which will convert the read MP3 data to PCM, using our Output Format { resampler.ResamplerQuality = 60; // Set the quality of the resampler to 60, the highest quality int blockSize = OutFormat.AverageBytesPerSecond / 50; // Establish the size of our AudioBuffer byte[] buffer = new byte[blockSize]; int byteCount; while ((byteCount = resampler.Read(buffer, 0, blockSize)) > 0) // Read audio into our buffer, and keep a loop open while data is present { if (byteCount < blockSize) { // Incomplete Frame for (int i = byteCount; i < blockSize; i++) { buffer[i] = 0; } } voiceClient.Send(buffer, 0, blockSize); // Send the buffer to Discord } } }
private void SendAudioData(IAudioClient audioClient, PlayRequest request) { try { var file = request.File; var cancellationToken = request.TokenSource.Token; using (var reader = File.OpenRead(file)) { byte[] buffer = new byte[BLOCK_SIZE]; int byteCount; while ((byteCount = reader.Read(buffer, 0, BLOCK_SIZE)) > 0) { if (cancellationToken.IsCancellationRequested) { audioClient.Clear(); return; } audioClient.Send(buffer, 0, byteCount); } } audioClient.Wait(); } catch (Exception ex) { Logger.Error(ex.Message, ex); } }
private async Task SendSound(string song) { if (!_playing) { _vclient = await _client.GetService <AudioService>().Join(channel); _playing = true; } _skipThis = false; await Task.Run(() => { int channelCount = _client.GetService <AudioService>().Config.Channels; WaveFormat outFormat = new WaveFormat(48000, 16, channelCount); AudioFileReader r = new AudioFileReader(song); using (MediaFoundationResampler resampler = new MediaFoundationResampler(r, outFormat)) { resampler.ResamplerQuality = 60; int blockSize = outFormat.AverageBytesPerSecond / 50; byte[] buffer = new byte[blockSize]; int byteCount; while ((byteCount = resampler.Read(buffer, 0, blockSize)) > 0 && _playing == true) { r.Volume = volume; if (byteCount < blockSize) { // Incomplete Frame for (int i = byteCount; i < blockSize; i++) { buffer[i] = 0; if (_skipThis) { _vclient.Clear(); break; } } } _vclient.Send(buffer, 0, blockSize); _vclient.Wait(); } GetNextSong(); } }); }
internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken) { var bufferTask = BufferSong(cancelToken).ConfigureAwait(false); var bufferAttempts = 0; const int waitPerAttempt = 500; var toAttemptTimes = SongInfo.ProviderType != MusicType.Normal ? 5 : 9; while (!prebufferingComplete && bufferAttempts++ < toAttemptTimes) { await Task.Delay(waitPerAttempt, cancelToken).ConfigureAwait(false); } cancelToken.ThrowIfCancellationRequested(); Console.WriteLine($"Prebuffering done? in {waitPerAttempt * bufferAttempts}"); const int blockSize = 3840; var attempt = 0; while (!cancelToken.IsCancellationRequested) { //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); byte[] buffer = new byte[blockSize]; var read = songBuffer.Read(buffer, blockSize); unchecked { bytesSent += (ulong)read; } if (read == 0) { if (attempt++ == 20) { voiceClient.Wait(); Console.WriteLine($"Song finished. [{songBuffer.ContentLength}]"); break; } else { await Task.Delay(100, cancelToken).ConfigureAwait(false); } } else { attempt = 0; } while (this.MusicPlayer.Paused) { await Task.Delay(200, cancelToken).ConfigureAwait(false); } buffer = AdjustVolume(buffer, MusicPlayer.Volume); voiceClient.Send(buffer, 0, read); } Console.WriteLine("Awiting buffer task"); await bufferTask; Console.WriteLine("Buffer task done."); voiceClient.Clear(); cancelToken.ThrowIfCancellationRequested(); }
public async Task StartPlaylist() { if (IsPlaying) { return; } if (await IsPlaylistEmpty()) { return; } if (PlaybackChannel == null) { await ChatChannel.SafeSendMessage("Audio playback channel has not been set."); return; } if (!await DiscordUtils.CanJoinAndTalkInVoiceChannel(PlaybackChannel, ChatChannel)) { return; } _voiceClient = await _client.Audio().Join(PlaybackChannel); while (true) { if (_stopPlaylistFlag) { _stopPlaylistFlag = false; break; } if (await IsPlaylistEmpty()) { return; } await StartCurrentTrackPlayback(); if (_prevFlag) { _prevFlag = false; TrackIndex--; } else if (!_skipToFlag) { TrackIndex++; } } _voiceClient.Wait(); await _voiceClient.Disconnect(); }
internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken) { var t = BufferSong(cancelToken).ConfigureAwait(false); int bufferAttempts = 0; int waitPerAttempt = 500; int toAttemptTimes = SongInfo.ProviderType != MusicType.Normal ? 5 : 9; while (!prebufferingComplete && bufferAttempts++ < toAttemptTimes) { await Task.Delay(waitPerAttempt); } Console.WriteLine($"Prebuffering done? in {waitPerAttempt * bufferAttempts}"); int blockSize = 3840; byte[] buffer = new byte[blockSize]; int attempt = 0; while (!cancelToken.IsCancellationRequested) { //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); int read = songBuffer.Read(buffer, blockSize); if (read == 0) { if (attempt++ == 10) { voiceClient.Wait(); Console.WriteLine("Playing done."); return; } else { await Task.Delay(50); } } else { attempt = 0; } while (this.MusicPlayer.Paused) { await Task.Delay(200); } buffer = adjustVolume(buffer, MusicPlayer.Volume); voiceClient.Send(buffer, 0, read); } //try { // voiceClient.Clear(); // Console.WriteLine("CLEARED"); //} //catch { // Console.WriteLine("CLEAR FAILED!!!"); //} }
private void PlayYouTube(IAudioClient audioClient, string youtubeURL) { IEnumerable <VideoInfo> downloadUrls = DownloadUrlResolver.GetDownloadUrls(youtubeURL); VideoInfo targetVideoInfo = downloadUrls.First(info => info.VideoType == VideoType.Mp4 && info.Resolution == 720); if (targetVideoInfo.RequiresDecryption) { DownloadUrlResolver.DecryptDownloadUrl(targetVideoInfo); } Console.WriteLine("Found download url {0}", targetVideoInfo.DownloadUrl); Process process = Process.Start(new ProcessStartInfo { FileName = "ffmpeg", Arguments = $"-i {targetVideoInfo.DownloadUrl} -f s16le -ar 48000 -ac 2 pipe:1", UseShellExecute = false, RedirectStandardOutput = true }); Console.WriteLine("Started ffmpeg"); Thread.Sleep(5000); int blockSize = 3840; byte[] buffer = new byte[blockSize]; int byteCount; while (!shouldStop) { byteCount = process.StandardOutput.BaseStream.Read(buffer, 0, blockSize); if (byteCount == 0) { break; } audioClient.Send(buffer, 0, byteCount); } audioClient.Wait(); if (shouldStop) { process.Kill(); shouldStop = false; audioClient.Disconnect(); } }
// Streaming service for youtube audio stream public async Task YoutubeStream(string pathOrUrl, CommandEventArgs e) { Process process = Process.Start(new ProcessStartInfo { // FFmpeg requires us to spawn a process and hook into its stdout, so we will create a Process FileName = "ffmpeg", Arguments = $"-i {pathOrUrl} " + // Here we provide a list of arguments to feed into FFmpeg. -i means the location of the file/URL it will read from "-f s16le -ar 48000 -ac 2 pipe:1", // Next, we tell it to output 16-bit 48000Hz PCM, over 2 channels, to stdout. UseShellExecute = false, RedirectStandardOutput = true // Capture the stdout of the process }); Thread.Sleep(2000); // Sleep for a few seconds to FFmpeg can start processing data. int blockSize = 3840; // The size of bytes to read per frame; 1920 for mono byte[] buffer = new byte[blockSize]; int byteCount; while (true) // Loop forever, so data will always be read { byteCount = process.StandardOutput.BaseStream // Access the underlying MemoryStream from the stdout of FFmpeg .Read(buffer, 0, blockSize); // Read stdout into the buffer int breaklimit = 0; while (byteCount == 0 /*&& breaklimit != 5*/) // counter for failed attempts and sleeps so ffmpeg can read more audio { Thread.Sleep(2500); breaklimit++; } _audio.Send(buffer, 0, byteCount); // Send our data to Discord if (breaklimit == 6) // when the breaklimit reaches 6 failed attempts its fair to say that ffmpeg has either crashed or is finished with the song { break; // breaks the audio stream } } _audio.Wait(); // Wait for the Voice Client to finish sending data, as ffMPEG may have already finished buffering out a song, and it is unsafe to return now. await NextSong(e); // starts the stream for the next song }
public static void Play(Music MusicToPlay) { int channelCount = Program._client.GetService <AudioService>().Config.Channels; // Get the number of AudioChannels our AudioService has been configured to use. WaveFormat OutFormat = new WaveFormat(SampleRate, 16, channelCount); // Create a new Output Format, using the spec that Discord will accept, and with the number of channels that our client supports. try { mediaStream = new WaveChannel32(new MediaFoundationReader(MusicToPlay.FilePath), Volume, 0F); using (mediaStream) using (resampler = new MediaFoundationResampler(mediaStream, OutFormat)) // Create a Disposable Resampler, which will convert the read MP3 data to PCM, using our Output Format { resampler.ResamplerQuality = 60; // Set the quality of the resampler to 60, the highest quality int blockSize = OutFormat.AverageBytesPerSecond / 50; // Establish the size of our AudioBuffer byte[] buffer = new byte[blockSize]; int byteCount; while ((byteCount = resampler.Read(buffer, 0, blockSize)) > 0) // Read audio into our buffer, and keep a loop open while data is present { if (byteCount < blockSize) { // Incomplete Frame for (int i = byteCount; i < blockSize; i++) { buffer[i] = 0; } } _vClient.Send(buffer, 0, blockSize); // Send the buffer to Discord } } } catch (Exception ReaderException) { Console.WriteLine(ReaderException.Message); // Prints any errors to console } _vClient.Wait(); // Waits for the currently playing sound file to end. }
internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken) { var filename = Path.Combine(MusicModule.MusicDataPath, DateTime.Now.UnixTimestamp().ToString()); SongBuffer sb = new SongBuffer(filename, SongInfo, skipTo); var bufferTask = sb.BufferSong(cancelToken).ConfigureAwait(false); var inStream = new FileStream(sb.GetNextFile(), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write);; bytesSent = 0; try { var attempt = 0; var prebufferingTask = CheckPrebufferingAsync(inStream, sb, cancelToken); var sw = new Stopwatch(); sw.Start(); var t = await Task.WhenAny(prebufferingTask, Task.Delay(5000, cancelToken)); if (t != prebufferingTask) { Console.WriteLine("Prebuffering timed out or canceled. Cannot get any data from the stream."); return; } else if (prebufferingTask.IsCanceled) { Console.WriteLine("Prebuffering timed out. Cannot get any data from the stream."); return; } sw.Stop(); Console.WriteLine("Prebuffering successfully completed in " + sw.Elapsed); const int blockSize = 3840; byte[] buffer = new byte[blockSize]; while (!cancelToken.IsCancellationRequested) { //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); var read = inStream.Read(buffer, 0, buffer.Length); //await inStream.CopyToAsync(voiceClient.OutputStream); unchecked { bytesSent += (ulong)read; } if (read < blockSize) { if (sb.IsNextFileReady()) { inStream.Dispose(); inStream = new FileStream(sb.GetNextFile(), FileMode.Open, FileAccess.Read, FileShare.Write); read += inStream.Read(buffer, read, buffer.Length - read); attempt = 0; } if (read == 0) { if (sb.BufferingCompleted) { break; } if (attempt++ == 20) { voiceClient.Wait(); MusicPlayer.SongCancelSource.Cancel(); break; } else { await Task.Delay(100, cancelToken).ConfigureAwait(false); } } else { attempt = 0; } } else { attempt = 0; } while (this.MusicPlayer.Paused) { await Task.Delay(200, cancelToken).ConfigureAwait(false); } buffer = AdjustVolume(buffer, MusicPlayer.Volume); voiceClient.Send(buffer, 0, read); } } finally { await bufferTask; await Task.Run(() => voiceClient.Clear()); if (inStream != null) { inStream.Dispose(); } Console.WriteLine("l"); sb.CleanFiles(); } }
internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken) { var bufferTask = BufferSong(cancelToken).ConfigureAwait(false); var bufferAttempts = 0; const int waitPerAttempt = 500; var toAttemptTimes = SongInfo.ProviderType != MusicType.Normal ? 5 : 9; while (!prebufferingComplete && bufferAttempts++ < toAttemptTimes) { await Task.Delay(waitPerAttempt, cancelToken); } cancelToken.ThrowIfCancellationRequested(); Console.WriteLine($"Prebuffering done? in {waitPerAttempt * bufferAttempts}"); const int blockSize = 3840; var attempt = 0; while (!cancelToken.IsCancellationRequested) { //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); byte[] buffer = new byte[blockSize]; var read = songBuffer.Read(buffer, blockSize); unchecked { bytesSent += (ulong)read; } if (read == 0) if (attempt++ == 20) { voiceClient.Wait(); Console.WriteLine($"Song finished. [{songBuffer.ContentLength}]"); break; } else await Task.Delay(100, cancelToken); else attempt = 0; while (this.MusicPlayer.Paused) await Task.Delay(200, cancelToken); buffer = AdjustVolume(buffer, MusicPlayer.Volume); voiceClient.Send(buffer, 0, read); } Console.WriteLine("Awiting buffer task"); await bufferTask; Console.WriteLine("Buffer task done."); voiceClient.Clear(); cancelToken.ThrowIfCancellationRequested(); }
//m r,radio - init //m n,next - next in que //m p,pause - pauses, call again to unpause //m yq [key_words] - queue from yt by keywords //m s,stop - stop //m sh - shuffle songs //m pl - current playlist public override void Install(ModuleManager manager) { var client = NadekoBot.client; manager.CreateCommands("!m", cgb => { //queue all more complex commands commands.ForEach(cmd => cmd.Init(cgb)); cgb.CreateCommand("n") .Alias("next") .Description("Goes to the next song in the queue.") .Do(e => { if (Voice != null && Exit == false) { NextSong = true; } }); cgb.CreateCommand("s") .Alias("stop") .Description("Completely stops the music and unbinds the bot from the channel.") .Do(e => { if (Voice != null && Exit == false) { Exit = true; SongQueue = new List <YouTubeVideo>(); } }); cgb.CreateCommand("p") .Alias("pause") .Description("Pauses the song") .Do(async e => { if (Voice != null && Exit == false && CurrentSong != null) { Pause = !Pause; if (Pause) { await e.Send("Pausing. Run the command again to resume."); } else { await e.Send("Resuming..."); } } }); cgb.CreateCommand("q") .Alias("yq") .Description("Queue a song using a multi/single word name.\n**Usage**: `!m q Dream Of Venice`") .Parameter("Query", ParameterType.Unparsed) .Do(async e => { var youtube = YouTube.Default; var video = youtube.GetAllVideos(Searches.FindYoutubeUrlByKeywords(e.Args[0])) .Where(v => v.AdaptiveKind == AdaptiveKind.Audio) .OrderByDescending(v => v.AudioBitrate).FirstOrDefault(); if (video?.Uri != "" && video.Uri != null) { SongQueue.Add(video); if (SongQueue.Count > 1) { await e.Send("**Queued** " + video.FullName); } } }); cgb.CreateCommand("lq") .Alias("ls").Alias("lp") .Description("Lists up to 10 currently queued songs.") .Do(async e => { await e.Send(SongQueue.Count + " videos currently queued."); await e.Send(string.Join("\n", SongQueue.Select(v => v.FullName).Take(10))); }); cgb.CreateCommand("sh") .Description("Shuffles the current playlist.") .Do(async e => { if (SongQueue.Count < 2) { await e.Send("Not enough songs in order to perform the shuffle."); return; } SongQueue.Shuffle(); await e.Send("Songs shuffled!"); }); cgb.CreateCommand("radio") .Alias("music") .Description("Binds to a voice and text channel in order to play music.") .Parameter("ChannelName", ParameterType.Unparsed) .Do(async e => { if (Voice != null) { return; } VoiceChannel = e.Server.FindChannels(e.GetArg("ChannelName").Trim(), ChannelType.Voice).FirstOrDefault(); Voice = await client.Audio().Join(VoiceChannel); Exit = false; NextSong = false; Pause = false; try { while (true) { if (Exit) { break; } if (SongQueue.Count == 0 || Pause) { Thread.Sleep(100); continue; } if (!LoadNextSong()) { break; } await Task.Run(async() => { if (Exit) { Voice = null; Exit = false; await e.Send("Exiting..."); return; } var streamer = new AudioStreamer(Music.CurrentSong.Uri); streamer.Start(); while (streamer.BytesSentToTranscoder < 100 * 0x1000 || streamer.NetworkDone) { await Task.Delay(500); } int blockSize = 1920 * client.Audio().Config.Channels; byte[] buffer = new byte[blockSize]; var msg = await e.Send("Playing " + Music.CurrentSong.FullName + " [00:00]"); int counter = 0; int byteCount; while ((byteCount = streamer.PCMOutput.Read(buffer, 0, blockSize)) > 0) { Voice.Send(buffer, byteCount); counter += blockSize; if (NextSong) { NextSong = false; break; } if (Exit) { Exit = false; return; } while (Pause) { Thread.Sleep(100); } } }); } Voice.Wait(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } await Voice.Disconnect(); Voice = null; VoiceChannel = null; }); }); }
public async void SendOnlineAudio(CommandEventArgs e, string pathOrUrl) { try { await joinVoiceChannel(e); } catch (Exception ex) { Console.WriteLine("WARNING: Bot failed!"); e.Channel.SendMessage("ERROR: Bot failed"); return; } if (!isInSameVoice(e)) { e.Channel.SendMessage("You are not in the same voice as me!"); return; } YouTubeVideo ytVideo = new YouTubeVideo(pathOrUrl, e.User.Name); //Couldn't find a video so do not add if (ytVideo.title == "") { e.Channel.SendMessage("Could not find video!"); return; } if (playingSong) { queue.Enqueue(ytVideo); sendMessage(ytVideo.requester + " added `" + ytVideo.title + "` **" + ytVideo.duration + "** to the queue! **[" + queue.Count + "]**"); return; } currentSong = ytVideo; if (_vClient == null) { e.Channel.SendMessage("You are not in a voice channel!"); return; } playingSong = true; sendMessage("Playing `" + currentSong.title + "` **" + currentSong.duration + "**"); var process = Process.Start(new ProcessStartInfo { // FFmpeg requires us to spawn a process and hook into its stdout, so we will create a Process FileName = "cmd.exe", Arguments = "/C youtube-dl.exe -f 140 -o - " + pathOrUrl + " -q -i | ffmpeg.exe -i pipe:0 -f s16le -ar 48000 -ac 2 pipe:1 -af \"volume=" + volume + "\" -loglevel quiet", // Next, we tell it to output 16-bit 48000Hz PCM, over 2 channels, to stdout. UseShellExecute = false, RedirectStandardOutput = true, // Capture the stdout of the process RedirectStandardError = false, }); //Thread.Sleep(1500); // Sleep for a few seconds to FFmpeg can start processing data. int blockSize = 3840; // The size of bytes to read per frame; 1920 for mono byte[] buffer = new byte[blockSize]; int byteCount; while (playingSong) // Loop forever, so data will always be read { if (!playingSong || process.HasExited) { Console.WriteLine("task canceled"); break; } byteCount = process.StandardOutput.BaseStream // Access the underlying MemoryStream from the stdout of FFmpeg .Read(buffer, 0, blockSize); // Read stdout into the buffer if (byteCount == 0) // FFmpeg did not output anything { break; // Break out of the while(true) loop, since there was nothing to read. } try { _vClient.Send(buffer, 0, byteCount); // Send our data to Discord } catch (OperationCanceledException ex) { Console.WriteLine("Operation cancelled!"); break; } } _vClient.Clear(); try { _vClient.Wait(); // Wait for the Voice Client to finish sending data, as ffMPEG may have already finished buffering out a song, and it is unsafe to return now. }catch (OperationCanceledException ex) { Console.WriteLine("Operation canceled"); } if (!process.HasExited) { process.Kill(); process.Dispose(); Console.WriteLine("Killed process"); } //set current votes to 0, if a vote was underway, but not enough voted to skip votes.Clear(); playingSong = false; if (!queue.Any()) { sendMessage("No songs in queue! Disconnecting..."); leaveVoiceChannel(); return; } string video = queue.First().url; queue.Dequeue(); //Thread.Sleep(1000); //Sleep for a sec so it can stop music //Play next song //await Task.Run(() => SendOnlineAudio(e, video), ct); SendOnlineAudio(e, video); }
public void PlaySound(AudioService audioService, IAudioClient audioClient, TrackRequest trackRequest) { var channels = audioService.Config.Channels; var timePlayed = 0; var outFormat = new WaveFormat(48000, 16, channels); SetVolumeOfCurrentTrack(trackRequest.Volume); using (var audioFileStream = new MediaFoundationReader(trackRequest.Track.Path)) using (var waveChannel32 = new WaveChannel32(audioFileStream, (_volumeOverride > 0 ? _volumeOverride : _volume) * 0.2f, 0f) { PadWithZeroes = false }) using (var effectStream = new EffectStream(waveChannel32)) using (var blockAlignmentStream = new BlockAlignReductionStream(effectStream)) using (var resampler = new MediaFoundationResampler(blockAlignmentStream, outFormat)) { resampler.ResamplerQuality = 60; ApplyEffects(waveChannel32, effectStream, trackRequest); // Establish the size of our AudioBuffer var blockSize = outFormat.AverageBytesPerSecond / 50; var buffer = new byte[blockSize]; int byteCount; // Read audio into our buffer, and keep a loop open while data is present while ((byteCount = resampler.Read(buffer, 0, blockSize)) > 0) { waveChannel32.Volume = (_volumeOverride > 0 ? _volumeOverride : _volume) * 0.2f; // Limit play length (--length) timePlayed += byteCount * 1000 / outFormat.AverageBytesPerSecond; if (trackRequest.TimeLimit > 0 && timePlayed > trackRequest.TimeLimit) { break; } if (byteCount < blockSize) { // Incomplete Frame for (var i = byteCount; i < blockSize; i++) { buffer[i] = 0; } } if (audioClient.State == ConnectionState.Disconnected || Stop) { break; } // Send the buffer to Discord try { audioClient.Send(buffer, 0, blockSize); } catch (Exception) { break; } } MyLogger.WriteLine("Voice finished enqueuing", ConsoleColor.Green); } if (Stop) { audioClient.Clear(); Stop = false; } audioClient.Wait(); }
internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken) { var filename = Path.Combine(MusicModule.MusicDataPath, DateTime.Now.UnixTimestamp().ToString()); SongBuffer sb = new SongBuffer(filename, SongInfo, skipTo); var bufferTask = sb.BufferSong(cancelToken).ConfigureAwait(false); var inStream = new FileStream(sb.GetNextFile(), FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write); ; bytesSent = 0; try { var attempt = 0; var prebufferingTask = CheckPrebufferingAsync(inStream, sb, cancelToken); var sw = new Stopwatch(); sw.Start(); var t = await Task.WhenAny(prebufferingTask, Task.Delay(5000, cancelToken)); if (t != prebufferingTask) { Console.WriteLine("Prebuffering timed out or canceled. Cannot get any data from the stream."); return; } else if(prebufferingTask.IsCanceled) { Console.WriteLine("Prebuffering timed out. Cannot get any data from the stream."); return; } sw.Stop(); Console.WriteLine("Prebuffering successfully completed in "+ sw.Elapsed); const int blockSize = 3840; byte[] buffer = new byte[blockSize]; while (!cancelToken.IsCancellationRequested) { //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); var read = inStream.Read(buffer, 0, buffer.Length); //await inStream.CopyToAsync(voiceClient.OutputStream); unchecked { bytesSent += (ulong)read; } if (read < blockSize) { if (sb.IsNextFileReady()) { inStream.Dispose(); inStream = new FileStream(sb.GetNextFile(), FileMode.Open, FileAccess.Read, FileShare.Write); read += inStream.Read(buffer, read, buffer.Length - read); attempt = 0; } if (read == 0) { if (sb.BufferingCompleted) break; if (attempt++ == 20) { voiceClient.Wait(); MusicPlayer.SongCancelSource.Cancel(); break; } else await Task.Delay(100, cancelToken).ConfigureAwait(false); } else attempt = 0; } else attempt = 0; while (this.MusicPlayer.Paused) await Task.Delay(200, cancelToken).ConfigureAwait(false); buffer = AdjustVolume(buffer, MusicPlayer.Volume); voiceClient.Send(buffer, 0, read); } } finally { await bufferTask; await Task.Run(() => voiceClient.Clear()); if(inStream != null) inStream.Dispose(); Console.WriteLine("l"); sb.CleanFiles(); } }
public async Task StartPlaylist() { if (IsPlaying) return; if (await IsPlaylistEmpty()) return; if (PlaybackChannel == null) { await ChatChannel.SafeSendMessage("Audio playback channel has not been set."); return; } if (!await DiscordUtils.CanJoinAndTalkInVoiceChannel(PlaybackChannel, ChatChannel)) return; _voiceClient = await _client.Audio().Join(PlaybackChannel); while (true) { if (_stopPlaylistFlag) { _stopPlaylistFlag = false; break; } if (await IsPlaylistEmpty()) return; await StartCurrentTrackPlayback(); if (_prevFlag) { _prevFlag = false; TrackIndex--; } else if (!_skipToFlag) TrackIndex++; } _voiceClient.Wait(); await _voiceClient.Disconnect(); }
async Task StreamFunc() { CancellationToken cancellationToken = tokenSource.Token; IAudioClient voiceClient = null; TranscodingTask streamer = null; try { uint byteCounter = 0; // Download and read audio from the url streamer = new TranscodingTask(streamRequest, bufferingStream); streamer.Start(); // Wait until we have at least a few kb transcoded or network stream done while (true) { if (streamRequest.NetworkDone) { await Task.Delay(600); break; } if (streamer.ReadyBytesLeft > 5 * 1024) { break; } await Task.Delay(200); } if (cancellationToken.IsCancellationRequested) { return; } // Start streaming to voice await streamRequest.Channel.SendMessage($"Playing **{streamRequest.Title}** [{streamRequest.Length}]"); var audioService = client.Audio(); voiceClient = await audioService.Join(streamRequest.VoiceChannel); int blockSize = 1920 * audioService.Config.Channels; byte[] voiceBuffer = new byte[blockSize]; var ringBuffer = streamer.PCMOutput; Stopwatch timeout = Stopwatch.StartNew(); while (true) { var readCount = ringBuffer.Read(voiceBuffer, 0, voiceBuffer.Length); if (readCount == 0) { if (timeout.ElapsedMilliseconds > 1500) { Console.WriteLine("Audio stream timed out. Disconnecting."); break; } await Task.Delay(200); continue; } if (cancellationToken.IsCancellationRequested) { return; } timeout.Restart(); byteCounter += (uint)voiceBuffer.Length; voiceClient.Send(voiceBuffer, 0, voiceBuffer.Length); } streamer.Cancel(); voiceClient.Wait(); } catch (Exception ex) { await streamRequest.Channel.SendMessage($":musical_note: {streamRequest.User.Mention} Something went wrong, please report this. :angry: :anger:"); Console.WriteLine("Exception while playing music: " + ex); } finally { if (voiceClient != null) { await streamRequest.Channel.SendMessage($"Finished playing **{streamRequest.Title}**"); State = StreamTaskState.Completed; streamer?.Cancel(); await voiceClient.Disconnect(); await Task.Delay(500); } } }
internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken) { var bufferTask = new ConfiguredTaskAwaitable(); try { bufferTask = BufferSong(cancelToken).ConfigureAwait(false); } catch (Exception ex) { var clr = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"ERR BUFFER START : {ex.Message}\n{ex}"); Console.ForegroundColor = clr; } var bufferAttempts = 0; const int waitPerAttempt = 500; var toAttemptTimes = SongInfo.ProviderType != MusicType.Normal ? 5 : 9; while (!prebufferingComplete && bufferAttempts++ < toAttemptTimes) { await Task.Delay(waitPerAttempt, cancelToken); } cancelToken.ThrowIfCancellationRequested(); Console.WriteLine($"Prebuffering done? in {waitPerAttempt * bufferAttempts}"); const int blockSize = 3840; var attempt = 0; while (!cancelToken.IsCancellationRequested) { //Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------"); byte[] buffer = new byte[blockSize]; var read = songBuffer.Read(buffer, blockSize); if (read == 0) { if (attempt++ == 20) { Console.WriteLine("Waiting to empty out buffer."); voiceClient.Wait(); Console.WriteLine($"Song finished. [{songBuffer.ContentLength}]"); break; } else { await Task.Delay(100, cancelToken); } } else { attempt = 0; } while (this.MusicPlayer.Paused) { await Task.Delay(200, cancelToken); } buffer = AdjustVolume(buffer, MusicPlayer.Volume); voiceClient.Send(buffer, 0, read); } await bufferTask; voiceClient.Clear(); cancelToken.ThrowIfCancellationRequested(); }
public void PlaySoundEffect(User user, Channel ch, string name) { if (string.IsNullOrWhiteSpace(name)) { return; } // Ensure voice channel is connected ConnectToVoice(); // Play the sound effect Task.Run(() => { try { sending.WaitOne(); var effect = SoundEffectRepository.FindByName(name); if (audio != null && effect != null) { if (effect.Duration.TotalMilliseconds == 0) { return; } SoundboardLoggingService.Instance.Info( string.Format("[{0}] playing <{1}>", user.Name, name)); // Change "playing" to the sound effect name SetStatusMessage(name); // Records play statistics Statistics.Play(user, effect); // Notify users soundbot will begin playing SendMessage(ch, string.Format(Properties.Resources.MessagePlayingSound, name)); // Resample and stream sound effect over the configured voice channel var format = new WaveFormat(48000, 16, 2); var length = Convert.ToInt32(format.AverageBytesPerSecond / 60.0 * 1000.0); var buffer = new byte[length]; using (var reader = new WaveFileReader(effect.Path)) using (var resampler = new WaveFormatConversionStream(format, reader)) { int count = 0; while ((count = resampler.Read(buffer, 0, length)) > 0) { audio.Send(buffer, 0, count); } } audio.Wait(); SetStatusMessage(Configuration.Status); } } catch (Exception ex) { SoundboardLoggingService.Instance.Error( string.Format(Properties.Resources.MessagePlayingFailed, name), ex); } finally { sending.Set(); } }); }
// Subtask for async operation of above function public void SendAudioTask(string filePath) { // Flag to prevent multiple simultaneous audio sendingAudio = true; try { // Get the number of AudioChannels our AudioService has been configured to use. var channelCount = client.GetService <AudioService>().Config.Channels; // Create a new Output Format, using the spec that Discord will accept, and with the number of channels that our client supports. var OutFormat = new WaveFormat(48000, 16, channelCount); // Select the right type of reader, based on the file extension. MediaFoundationResampler resampler = null; if (filePath.ToLower().Contains(".mp3")) { // MP3 file // Create a new Disposable MP3FileReader, to read audio from the filePath parameter var Reader = new Mp3FileReader(filePath); resampler = new MediaFoundationResampler(Reader, OutFormat); } if (filePath.ToLower().Contains(".wav")) { // WAV file // Create a new Disposable WaveFileReader, to read audio from the filePath parameter var Reader = new WaveFileReader(filePath); resampler = new MediaFoundationResampler(Reader, OutFormat); } // Only attempt output if we have a good file type if (resampler != null) { // Set the quality of the resampler to 60, the highest quality resampler.ResamplerQuality = 60; // Establish the size of our AudioBuffer int blockSize = OutFormat.AverageBytesPerSecond / 50; byte[] buffer = new byte[blockSize]; int byteCount; try { // Read audio into our buffer, and keep a loop open while data is present while ((byteCount = resampler.Read(buffer, 0, blockSize)) > 0) { if (byteCount < blockSize) { // Incomplete Frame, pad it for (int i = byteCount; i < blockSize; i++) { buffer[i] = 0; } } // Send the buffer to Discord vClient.Send(buffer, 0, blockSize); } vClient.Wait(); } catch (Exception ex) { // Do nothing, just absorb the exception- likely as not we were cancelled. } } } catch (Exception ex) { // Set a flag so we can annunciate a bad file badfile = true; } //Set flag to say we're no longer sending audio. sendingAudio = false; }