diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio/play_queue.rs | 90 | ||||
| -rw-r--r-- | src/audio/ytdl.rs | 47 | ||||
| -rw-r--r-- | src/commands/meme.rs | 98 | ||||
| -rw-r--r-- | src/main.rs | 3 |
4 files changed, 89 insertions, 149 deletions
diff --git a/src/audio/play_queue.rs b/src/audio/play_queue.rs index 4bb6ade..fcbb4f9 100644 --- a/src/audio/play_queue.rs +++ b/src/audio/play_queue.rs @@ -1,20 +1,13 @@ use std::{ collections::VecDeque, - io::{self, Cursor}, - iter, - process::{ - Command, - Stdio, - }, + io::{self, BufRead, BufReader, Cursor}, + process, sync::{Arc, RwLock}, thread, time::Duration, }; -use byteorder::{ByteOrder, NativeEndian}; use either::{Left, Right}; -use itertools::Itertools; -use lame_sys; use serenity::{ prelude::*, voice, @@ -114,52 +107,51 @@ impl PlayQueue { } } }, - Right(ref mut v) => { - -// let out = unsafe { -// let hip_t = lame_sys::hip_decode_init(); -// -// let mut pcm_l = vec![0; 5 * 1024 * 1024 / 2]; -// let mut pcm_r = vec![0; 5 * 1024 * 1024 / 2]; -// -// let count = lame_sys::hip_decode(hip_t, -// v.as_mut_ptr(), -// v.len(), -// pcm_l.as_mut_ptr(), -// pcm_r.as_mut_ptr()); -// -// lame_sys::hip_decode_exit(hip_t); -// -// pcm_l.into_iter() -// .interleave(pcm_r.into_iter()) -// .flat_map(|x| { -// let mut b = vec![0u8; 2]; -// NativeEndian::write_i16(&mut b, x); -// -// b.into_iter() -// }) -// .collect::<Vec<u8>>() -// }; - - let mut out = Command::new("lame") + Right(ref vec) => { + let mut transcoder = process::Command::new("ffmpeg") .args(&[ - "--decode", "-t", - "-", "-", + "-format", "opus", + "-i", "pipe:0", + "-acodec", "pcm_s16le", + "-f", "s16le", + "-" ]) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) + .stdin(process::Stdio::piped()) + .stdout(process::Stdio::piped()) + .stderr(process::Stdio::piped()) .spawn() - .unwrap(); + .expect("unable to call ffmpeg"); + + let process::Child { + stdin, + stderr, + stdout, + .. + } = transcoder; + + thread::spawn(move || { + let stderr = BufReader::new(stderr.unwrap()); - io::copy(&mut Cursor::new(v), &mut out.stdin.as_mut().unwrap()); - let result = voice::pcm(true, Cursor::new("abc")); + for line in stderr.lines() { + let line = line.unwrap(); -// out.stdout.as_mut().unwrap() + 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 status = out.wait_with_output().unwrap(); - println!("{}", status.status); - println!("{}", String::from_utf8(status.stderr).unwrap()); + let result = voice::pcm(true, stdout.unwrap()); result } diff --git a/src/audio/ytdl.rs b/src/audio/ytdl.rs index 7333c18..8239683 100644 --- a/src/audio/ytdl.rs +++ b/src/audio/ytdl.rs @@ -45,8 +45,9 @@ pub(crate) trait CodecInfo { } pub(crate) struct Pcm {} + +#[allow(dead_code)] pub(crate) struct Opus {} -pub(crate) struct Mp3 {} impl CodecInfo for Pcm { #[inline] @@ -67,28 +68,9 @@ impl CodecInfo for Opus { fn ffmpeg_opts() -> &'static[&'static str] { lazy_static! { static ref OPTS: Vec<&'static str> = vec! [ -// "-f", "s16le", + "-f", "opus", "-acodec", "libopus", - "-sample_fmt", "s16", - "-vbr", "off", -// "-b:a 96k", -// "-vn", - ]; - } - - &*OPTS - } -} - -impl CodecInfo for Mp3 { - #[inline] - fn ffmpeg_opts() -> &'static[&'static str] { - lazy_static! { - static ref OPTS: Vec<&'static str> = vec! [ - "-f", "aac", - "-acodec", "libfdk_aac", - "-b:a", "96k", - "-sample_fmt", "s16", + "-b:a 96k", ]; } @@ -130,7 +112,7 @@ pub fn ytdl_url(uri: &str) -> Result<String> { } } -pub(crate) fn ffmpeg_dl<T: CodecInfo>(uri: &str, start: Option<Duration>, end: Option<Duration>, size_limit: Option<usize>) -> Result<Child> { +pub(crate) fn ffmpeg_dl<T: CodecInfo>(uri: &str, start: Option<Duration>, end: Option<Duration>, size_limit: Option<usize>) -> Result<Box<dyn Read + Send>> { let start = start.unwrap_or(Duration::zero()); let start_str = format!("{:02}:{:02}:{:02}", start.num_hours(), start.num_minutes() % 60, start.num_seconds() % 60); @@ -146,6 +128,11 @@ pub(crate) fn ffmpeg_dl<T: CodecInfo>(uri: &str, start: Option<Duration>, end: O .map(|s| s.to_owned()) .collect::<Vec<_>>(); + if let Some(e) = end { + opts.push("-to".to_owned()); + opts.push(format!("{:02}:{:02}:{:02}", e.num_hours(), e.num_minutes() % 60, e.num_seconds() % 60)); + } + let codec_opts = T::ffmpeg_opts().into_iter().map(|&s| s.to_owned()).collect::<Vec<_>>(); opts.extend(codec_opts); @@ -154,28 +141,24 @@ pub(crate) fn ffmpeg_dl<T: CodecInfo>(uri: &str, start: Option<Duration>, end: O opts.push(format!("{}", limit)); } - if let Some(e) = end { - opts.push("-to".to_owned()); - opts.push(format!("{:02}:{:02}:{:02}", e.num_hours(), e.num_minutes() % 60, e.num_seconds() % 60)); - } - opts.push("-".to_owned()); debug!("ffmpeg -i \"{}\" {}", uri, opts.join(" ")); - Command::new("ffmpeg") + let command = Command::new("ffmpeg") .arg("-i") .arg(uri) .args(opts) .stderr(Stdio::piped()) .stdin(Stdio::null()) .stdout(Stdio::piped()) - .spawn() - .map_err(|e| e.into()) + .spawn()?; + + Ok(Box::new(ChildContainer(command))) } pub fn ytdl(uri: &str, start: Option<Duration>, end: Option<Duration>) -> Result<Box<AudioSource>> { let youtube_uri = ytdl_url(uri)?; let command = ffmpeg_dl::<Pcm>(&youtube_uri, start, end, None)?; - Ok(pcm(true, command.stdout.unwrap())) + Ok(pcm(true, command)) } diff --git a/src/commands/meme.rs b/src/commands/meme.rs index a8ac417..913be00 100644 --- a/src/commands/meme.rs +++ b/src/commands/meme.rs @@ -1,5 +1,5 @@ use std::{ - io::{BufReader, Read}, + io::Read, process::{ Command, Stdio, @@ -7,14 +7,8 @@ use std::{ sync::RwLock, }; -use byteorder::{ - ByteOrder, - NativeEndian, -}; use diesel::PgConnection; use failure::Error; -use lame_sys; -use lame_sys::lame_set_brate; use lazy_static::lazy_static; use rand::{Rng, thread_rng}; use serenity::{ @@ -31,11 +25,7 @@ use audio::ytdl_url; use crate::{ audio::{ CtxExt, - ffmpeg_dl, - Mp3, - Opus, parse_times, - Pcm, PlayArgs, PlayQueue, }, @@ -162,22 +152,39 @@ pub fn addaudiomeme(_: &mut Context, msg: &Message, mut args: Args) -> Result<() let (start, end) = parse_times(opts); let youtube_url = ytdl_url(audio_link.as_str())?; - let ffmpeg_command = ffmpeg_dl::<Pcm>(&youtube_url, start, end, None)?; - let lame = Command::new("lame") + let duration_opts = if let Some(e) = end { + vec! [ + "-ss".to_owned(), 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 = Command::new("ffmpeg") + .arg("-i") + .arg(youtube_url) + .args(duration_opts) .args(&[ - "-r", - "-m", "s", - "-s", "48", - "-V", "2", - "-b", "96", - "-", "-", + "-ac", "2", + "-ar", "48000", + "-f", "opus", + "-acodec", "libopus", + "-b:a", "96k", + "-", ]) - .stdin(ffmpeg_command.stdout.unwrap()) .stdout(Stdio::piped()) .stderr(Stdio::null()) + .stdin(Stdio::null()) .spawn()?; + let mut audio_reader = ffmpeg_command.stdout.unwrap(); + let text = match args.multiple_quoted::<String>() { Ok(text) => text.join(" "), Err(_) => "".to_owned(), @@ -196,53 +203,12 @@ pub fn addaudiomeme(_: &mut Context, msg: &Message, mut args: Args) -> Result<() .ok(); let mut audio_data = Vec::new(); - lame.stdout.unwrap().read_to_end(&mut audio_data)?; - -// let mut i16_data: Vec<i16> = { -// let mut audio_data = Vec::new(); -// let bytes = audio_reader.read_to_end(&mut audio_data)?; -// -// let mut i16_data = Vec::with_capacity(bytes / 2); -// i16_data.resize(bytes / 2, 0); -// -// NativeEndian::read_i16_into(&audio_data, &mut i16_data); -// -// i16_data -// }; -// -// if i16_data.len() == 0 { -// debug!("read 0 bytes from audio reader"); -// return send(msg.channel_id, "🔇🔇🔇🔕🔕🔕🔕🔕🔇🔕🔕🔇🔕🔕📣📢📣📢📣", msg.tts); -// } -// -// let audio_data = unsafe { -// let lame_flags = lame_sys::lame_init(); -// -// lame_sys::lame_set_brate(lame_flags, 96000); -// lame_sys::lame_set_num_channels(lame_flags, 2); -// lame_sys::lame_set_num_samples(lame_flags, 48000); -// -// let mut out = Vec::<u8>::with_capacity(i16_data.len() * 2); -// out.resize(i16_data.len() * 2, 0); -// -// let result = lame_sys::lame_encode_buffer_interleaved( -// lame_flags, -// i16_data.as_mut_ptr(), -// (i16_data.len() / 2) as i32, -// out.as_mut_ptr(), -// out.len() as i32, -// ); -// -// if result <= 0 { -// debug!("return code {} from lame", result); -// return send(msg.channel_id, "wat", msg.tts); -// } -// -// out.truncate(result as usize); -// -// out -// }; + let bytes = audio_reader.read_to_end(&mut audio_data)?; + if bytes == 0 { + debug!("read 0 bytes from audio reader"); + return send(msg.channel_id, "🔇🔇🔇🔕🔕🔕🔕🔕🔇🔕🔕🔇🔕🔕📣📢📣📢📣", msg.tts); + } let audio_id = Audio::create(&conn, audio_data, msg.author.id.0)?; diff --git a/src/main.rs b/src/main.rs index 5bfc36e..5637ecd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ #![feature(impl_trait_in_bindings)] +#![feature(try_trait)] -extern crate byteorder; extern crate chrono; #[cfg(feature = "diesel")] #[macro_use] extern crate diesel; @@ -10,7 +10,6 @@ extern crate either; #[macro_use] extern crate failure; extern crate fern; #[cfg_attr(test, macro_use)] extern crate itertools; -extern crate lame_sys; #[macro_use] extern crate lazy_static; #[macro_use] extern crate log; extern crate rand; |
