aboutsummaryrefslogtreecommitdiffstats
path: root/src/voice/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/voice/mod.rs36
1 files changed, 32 insertions, 4 deletions
diff --git a/src/voice/mod.rs b/src/voice/mod.rs
index d8308eb..2866f54 100644
--- a/src/voice/mod.rs
+++ b/src/voice/mod.rs
@@ -342,15 +342,17 @@ impl tokio::io::AsyncRead for FfmpegChild {
342 } 342 }
343} 343}
344 344
345/// Decode a local audio file via ffmpeg to raw f32 PCM at 48 kHz stereo. 345/// Decode an in-memory audio file via ffmpeg to raw f32 PCM at 48 kHz stereo.
346/// No reconnect flags (those are for HTTP streams only). 346///
347pub async fn ffmpeg_decode_file(path: &str) -> Result<songbird::input::Input> { 347/// Used for compressed playback so the intermediate file never has to touch
348/// disk (and therefore cannot leak into `TEMP_PATH`).
349pub async fn ffmpeg_decode_bytes(data: Vec<u8>) -> Result<songbird::input::Input> {
348 use std::process::Stdio; 350 use std::process::Stdio;
349 351
350 let mut child = tokio::process::Command::new("ffmpeg") 352 let mut child = tokio::process::Command::new("ffmpeg")
351 .args([ 353 .args([
352 "-i", 354 "-i",
353 path, 355 "pipe:0",
354 "-vn", 356 "-vn",
355 "-f", 357 "-f",
356 "f32le", 358 "f32le",
@@ -360,17 +362,43 @@ pub async fn ffmpeg_decode_file(path: &str) -> Result<songbird::input::Input> {
360 "2", 362 "2",
361 "pipe:1", 363 "pipe:1",
362 ]) 364 ])
365 .stdin(Stdio::piped())
363 .stdout(Stdio::piped()) 366 .stdout(Stdio::piped())
364 .stderr(Stdio::piped()) 367 .stderr(Stdio::piped())
365 .kill_on_drop(true) 368 .kill_on_drop(true)
366 .spawn() 369 .spawn()
367 .map_err(|e| Error::Custom(format!("ffmpeg decode spawn: {e}")))?; 370 .map_err(|e| Error::Custom(format!("ffmpeg decode spawn: {e}")))?;
368 371
372 let mut stdin = child
373 .stdin
374 .take()
375 .ok_or_else(|| Error::Custom("ffmpeg stdin not captured".into()))?;
369 let stdout = child 376 let stdout = child
370 .stdout 377 .stdout
371 .take() 378 .take()
372 .ok_or_else(|| Error::Custom("ffmpeg stdout not captured".into()))?; 379 .ok_or_else(|| Error::Custom("ffmpeg stdout not captured".into()))?;
373 380
381 tokio::spawn(async move {
382 use tokio::io::AsyncWriteExt;
383 let _ = stdin.write_all(&data).await;
384 // Dropping stdin gives ffmpeg EOF.
385 });
386
387 if let Some(stderr) = child.stderr.take() {
388 tokio::spawn(async move {
389 use tokio::io::AsyncReadExt;
390 let mut buf = Vec::with_capacity(4096);
391 let mut reader = tokio::io::BufReader::new(stderr);
392 let _ = reader.read_to_end(&mut buf).await;
393 if !buf.is_empty() {
394 warn!(
395 "ffmpeg (decode) stderr: {}",
396 String::from_utf8_lossy(&buf).trim_end()
397 );
398 }
399 });
400 }
401
374 let ffmpeg_child = FfmpegChild { 402 let ffmpeg_child = FfmpegChild {
375 _child: child, 403 _child: child,
376 stdout, 404 stdout,