diff options
| author | salmonik <salmonik@tuta.io> | 2026-09-09 12:50:56 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-09-09 12:50:56 +0200 |
| commit | 5eea9f2fef1a840f9c9e6ec6d471fe4f87f1d1fd (patch) | |
| tree | 8172563321f0737df9426bbd577c0a18bef9471f /src/voice/mod.rs | |
| parent | feat: piper now not a subprocess, cache system for TTS (diff) | |
| download | senator-sperma-5eea9f2fef1a840f9c9e6ec6d471fe4f87f1d1fd.tar.gz senator-sperma-5eea9f2fef1a840f9c9e6ec6d471fe4f87f1d1fd.zip | |
make /grajcuj w\ compress finally work as compressing a file and then
/grajcuj'ing
Signed-off-by: salmonik <salmonik@tuta.io>
Diffstat (limited to 'src/voice/mod.rs')
| -rw-r--r-- | src/voice/mod.rs | 80 |
1 files changed, 40 insertions, 40 deletions
diff --git a/src/voice/mod.rs b/src/voice/mod.rs index 4087eba..9c92202 100644 --- a/src/voice/mod.rs +++ b/src/voice/mod.rs | |||
| @@ -188,46 +188,6 @@ pub async fn download_url(client: &reqwest::Client, url: &str) -> Result<Vec<u8> | |||
| 188 | Ok(bytes.to_vec()) | 188 | Ok(bytes.to_vec()) |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | /// DEBUG: bypass encode/decode — just pipe through ffmpeg as PCM. | ||
| 192 | /// If this plays, the streaming pipeline works; bug is in Opus roundtrip. | ||
| 193 | pub async fn degrade_audio(input: &[u8]) -> Result<songbird::input::Input> { | ||
| 194 | use std::process::Stdio; | ||
| 195 | |||
| 196 | let mut child = tokio::process::Command::new("ffmpeg") | ||
| 197 | .args([ | ||
| 198 | "-y", "-i", "pipe:0", "-vn", "-f", "f32le", "-ac", "2", "-ar", "8000", "-b:a", "500", | ||
| 199 | "pipe:1", | ||
| 200 | ]) | ||
| 201 | .stdin(Stdio::piped()) | ||
| 202 | .stdout(Stdio::piped()) | ||
| 203 | .stderr(Stdio::null()) | ||
| 204 | .kill_on_drop(true) | ||
| 205 | .spawn() | ||
| 206 | .map_err(|e| Error::Custom(format!("ffmpeg passthrough spawn: {e}")))?; | ||
| 207 | |||
| 208 | let mut stdin = child.stdin.take().unwrap(); | ||
| 209 | let stdout = child | ||
| 210 | .stdout | ||
| 211 | .take() | ||
| 212 | .ok_or_else(|| Error::Custom("stdout not captured".into()))?; | ||
| 213 | |||
| 214 | let owned_input = input.to_vec(); | ||
| 215 | tokio::spawn(async move { | ||
| 216 | use tokio::io::AsyncWriteExt; | ||
| 217 | let _ = stdin.write_all(&owned_input).await; | ||
| 218 | }); | ||
| 219 | |||
| 220 | let ffmpeg_child = FfmpegChild { | ||
| 221 | _child: child, | ||
| 222 | stdout, | ||
| 223 | }; | ||
| 224 | |||
| 225 | let async_source = AsyncReadOnlySource::new(ffmpeg_child); | ||
| 226 | let adapter = AsyncAdapterStream::new(Box::new(async_source), 64 * 1024); | ||
| 227 | let raw = RawAdapter::new(adapter, 48000, 2); | ||
| 228 | Ok(raw.into()) | ||
| 229 | } | ||
| 230 | |||
| 231 | // ── HTTP streaming via songbird's built-in HttpRequest (legacy) ───── | 191 | // ── HTTP streaming via songbird's built-in HttpRequest (legacy) ───── |
| 232 | 192 | ||
| 233 | /// Create a songbird `Input` that streams audio directly from an HTTP(S) URL. | 193 | /// Create a songbird `Input` that streams audio directly from an HTTP(S) URL. |
| @@ -268,6 +228,46 @@ impl tokio::io::AsyncRead for FfmpegChild { | |||
| 268 | } | 228 | } |
| 269 | } | 229 | } |
| 270 | 230 | ||
| 231 | /// Decode a local audio file via ffmpeg to raw f32 PCM at 48 kHz stereo. | ||
| 232 | /// No reconnect flags (those are for HTTP streams only). | ||
| 233 | pub async fn ffmpeg_decode_file(path: &str) -> Result<songbird::input::Input> { | ||
| 234 | use std::process::Stdio; | ||
| 235 | |||
| 236 | let mut child = tokio::process::Command::new("ffmpeg") | ||
| 237 | .args([ | ||
| 238 | "-i", | ||
| 239 | path, | ||
| 240 | "-vn", | ||
| 241 | "-f", | ||
| 242 | "f32le", | ||
| 243 | "-ar", | ||
| 244 | "48000", | ||
| 245 | "-ac", | ||
| 246 | "2", | ||
| 247 | "pipe:1", | ||
| 248 | ]) | ||
| 249 | .stdout(Stdio::piped()) | ||
| 250 | .stderr(Stdio::piped()) | ||
| 251 | .kill_on_drop(true) | ||
| 252 | .spawn() | ||
| 253 | .map_err(|e| Error::Custom(format!("ffmpeg decode spawn: {e}")))?; | ||
| 254 | |||
| 255 | let stdout = child | ||
| 256 | .stdout | ||
| 257 | .take() | ||
| 258 | .ok_or_else(|| Error::Custom("ffmpeg stdout not captured".into()))?; | ||
| 259 | |||
| 260 | let ffmpeg_child = FfmpegChild { | ||
| 261 | _child: child, | ||
| 262 | stdout, | ||
| 263 | }; | ||
| 264 | |||
| 265 | let async_source = AsyncReadOnlySource::new(ffmpeg_child); | ||
| 266 | let adapter = AsyncAdapterStream::new(Box::new(async_source), 64 * 1024); | ||
| 267 | let raw = RawAdapter::new(adapter, 48000, 2); | ||
| 268 | Ok(raw.into()) | ||
| 269 | } | ||
| 270 | |||
| 271 | /// Stream an HTTP(S) URL live via an ffmpeg subprocess, producing a songbird | 271 | /// Stream an HTTP(S) URL live via an ffmpeg subprocess, producing a songbird |
| 272 | /// `Input` of raw f32 PCM at 48 kHz stereo — NO full download. | 272 | /// `Input` of raw f32 PCM at 48 kHz stereo — NO full download. |
| 273 | /// | 273 | /// |
