diff options
| author | Nathan Perry <avaglir@gmail.com> | 2019-02-18 18:30:13 -0500 |
|---|---|---|
| committer | Nathan Perry <avaglir@gmail.com> | 2019-02-18 18:30:13 -0500 |
| commit | 372f09c41034899dfa307501296a2822b70680eb (patch) | |
| tree | a3b88e7578b8a70fff979e6a1799ff4d88befca1 /src | |
| parent | db09977b0891c5aab20dd1888bc962f74a78a642 (diff) | |
pad audio startup and trail with silence
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio/play_queue.rs | 141 |
1 files changed, 92 insertions, 49 deletions
diff --git a/src/audio/play_queue.rs b/src/audio/play_queue.rs index 6849797..77cb252 100644 --- a/src/audio/play_queue.rs +++ b/src/audio/play_queue.rs @@ -1,6 +1,6 @@ use std::{ collections::VecDeque, - io::{self, BufRead, BufReader, Cursor}, + io::{self, BufRead, BufReader, Cursor, Read}, process, sync::{Arc, RwLock}, thread, @@ -19,7 +19,7 @@ use crate::{ audio::{ CurrentItem, PlayArgs, - ytdl, + ytdl_url, }, commands::{ send, @@ -30,6 +30,14 @@ use crate::{ TARGET_GUILD_ID, }; +const SECONDS_LEAD_TIME: f32 = 0.75; +const SECONDS_TRAIL_TIME: f32 = 0.1; +const SAMPLE_RATE: usize = 48000; +const CHANNELS: usize = 2; +const BYTES_PER_SAMPLE: usize = 2; +const PRE_SILENCE_BYTES: usize = (SECONDS_LEAD_TIME * (SAMPLE_RATE * CHANNELS * BYTES_PER_SAMPLE) as f32) as usize; +const POST_SILENCE_BYTES: usize = (SECONDS_TRAIL_TIME * (SAMPLE_RATE * CHANNELS * BYTES_PER_SAMPLE) as f32) as usize; + #[derive(Clone)] pub struct PlayQueue { pub queue: VecDeque<PlayArgs>, @@ -106,64 +114,99 @@ impl PlayQueue { let mut item = queue.queue.pop_front().unwrap(); let src = match &mut item.data { - Left(ref url) => { - match ytdl(url, item.start, item.end) { - Ok(src) => src, - Err(e) => { - error!("bad link: {}; {:?}", url, e); - let _ = send(item.sender_channel, "what the fuck", false)?; + Left(ref url) => { + let youtube_url = ytdl_url(url.as_str())?; - return Ok(()); - } - } + let duration_opts = if let Some(e) = item.end { + vec! [ + "-ss".to_owned(), item.start.map_or_else( + || "00:00:00".to_owned(), + |s| format!("{:02}:{:02}:{:02}", s.num_hours(), s.num_minutes() % 60, s.num_seconds() % 60) + ), + + "-to".to_owned(), format!("{:02}:{:02}:{:02}", e.num_hours(), e.num_minutes() % 60, e.num_seconds() % 60), + ] + } else { + vec! [] + }; + + let ffmpeg_command = process::Command::new("ffmpeg") + .arg("-i") + .arg(youtube_url) + .args(duration_opts) + .args(&[ + "-ac", "2", + "-ar", "48000", + "-f", "s16le", + "-acodec", "pcm_s16le", + "-", + ]) + .stdout(process::Stdio::piped()) + .stderr(process::Stdio::null()) + .stdin(process::Stdio::null()) + .spawn()?; + + let mut audio_reader = ffmpeg_command.stdout.unwrap(); + + let mut pre_silence = vec![0u8; PRE_SILENCE_BYTES]; + let mut post_silence = vec![0u8; POST_SILENCE_BYTES]; + + let reader = Cursor::new(pre_silence).chain(audio_reader).chain(Cursor::new(post_silence)); + + voice::pcm(true, reader) }, Right(ref vec) => { let mut transcoder = process::Command::new("ffmpeg") - .args(&[ - "-format", "opus", - "-i", "pipe:0", - "-acodec", "pcm_s16le", - "-f", "s16le", - "-" - ]) - .stdin(process::Stdio::piped()) - .stdout(process::Stdio::piped()) - .stderr(process::Stdio::piped()) - .spawn() - .expect("unable to call ffmpeg"); + .args(&[ + "-format", "opus", + "-i", "pipe:0", + "-acodec", "pcm_s16le", + "-f", "s16le", + "-" + ]) + .stdin(process::Stdio::piped()) + .stdout(process::Stdio::piped()) + .stderr(process::Stdio::piped()) + .spawn() + .expect("unable to call ffmpeg"); - let process::Child { - stdin, - stderr, - stdout, - .. - } = transcoder; + let process::Child { + stdin, + stderr, + stdout, + .. + } = transcoder; - thread::spawn(move || { - let stderr = BufReader::new(stderr.unwrap()); + thread::spawn(move || { + let stderr = BufReader::new(stderr.unwrap()); - for line in stderr.lines() { - let line = line.unwrap(); + for line in stderr.lines() { + let line = line.unwrap(); - trace!("{}", line); - } - }); + trace!("{}", line); + } + }); + + let v = vec.clone(); + thread::spawn(move || { + if let Err(e) = io::copy(&mut Cursor::new(v), &mut stdin.unwrap()) { + use std::io::ErrorKind; + if e.kind() == ErrorKind::BrokenPipe { + debug!("ffmpeg closed unexpectedly"); + } else { + error!("copying audio to ffmpeg {}", e); + } + } + }); - let v = vec.clone(); - thread::spawn(move || { - if let Err(e) = io::copy(&mut Cursor::new(v), &mut stdin.unwrap()) { - use std::io::ErrorKind; - if e.kind() == ErrorKind::BrokenPipe { - debug!("ffmpeg closed unexpectedly"); - } else { - error!("copying audio to ffmpeg {}", e); - } - } - }); + let mut pre_silence = vec![0u8; PRE_SILENCE_BYTES]; + let mut post_silence = vec![0u8; POST_SILENCE_BYTES]; - let result = voice::pcm(true, stdout.unwrap()); + let reader = Cursor::new(pre_silence) + .chain(stdout.unwrap()) + .chain(Cursor::new(post_silence)); - result + voice::pcm(true, reader) } }; |
