Audio Fix

This commit is contained in:
Brad Stein 2025-06-30 02:42:20 -05:00
parent 4522367a64
commit f8528897de
3 changed files with 33 additions and 15 deletions

View File

@ -30,8 +30,26 @@ impl AudioOut {
.expect("no src element")
.downcast::<gst_app::AppSrc>()
.expect("src not an AppSrc");
src.set_caps(Some(&gst::Caps::builder("audio/mpeg") // mpeg4 AAC
.field("mpegversion", &4i32)
.field("stream-format", &"adts")
.build()));
src.set_format(gst::Format::Time);
{
let bus = pipeline.bus().expect("bus");
std::thread::spawn(move || {
use gst::MessageView::*;
for msg in bus.iter_timed(gst::ClockTime::NONE) {
if let Error(e) = msg.view() {
error!("💥 clientaudio: {} ({})",
e.error(), e.debug().unwrap_or_default());
}
}
});
}
pipeline.set_state(gst::State::Playing)?;
Ok(Self { src })

View File

@ -7,6 +7,7 @@ use gstreamer as gst;
use gstreamer_app as gst_app;
use gst::prelude::*;
use gst::ElementFactory;
use gst::MessageView::*;
use lesavka_common::lesavka::AudioPacket;
use tokio_stream::wrappers::ReceiverStream;
use tonic::Status;
@ -36,10 +37,10 @@ impl Drop for AudioStream {
}
/*───────────────────────────────────────────────────────────────────────────*/
/* eye_ear() capture from ALSA (“speaker”) and push AAC AUs via gRPC */
/* ear() capture from ALSA (“speaker”) and push AAC AUs via gRPC */
/*───────────────────────────────────────────────────────────────────────────*/
pub async fn eye_ear(alsa_dev: &str, id: u32) -> anyhow::Result<AudioStream> {
pub async fn ear(alsa_dev: &str, id: u32) -> anyhow::Result<AudioStream> {
// NB: one *logical* speaker → id==0. A 2nd logical stream could be
// added later (for multichannel) without changing the client.
gst::init().context("gst init")?;
@ -65,15 +66,14 @@ pub async fn eye_ear(alsa_dev: &str, id: u32) -> anyhow::Result<AudioStream> {
let (tx, rx) = tokio::sync::mpsc::channel(8192);
let bus = pipeline.bus().expect("no bus");
let bus = pipeline.bus().expect("bus");
std::thread::spawn(move || {
for msg in bus.iter_timed(gst::ClockTime::NONE) {
use gst::MessageView::*;
match msg.view() {
Error(e) => error!("💥 audio pipeline: {} ({})",
e.error(), e.debug().unwrap_or_default()),
e.error(), e.debug().unwrap_or_default()),
Warning(w) => warn!("⚠️ audio pipeline: {} ({})",
w.error(), w.debug().unwrap_or_default()),
w.error(), w.debug().unwrap_or_default()),
StateChanged(s) if s.current() == gst::State::Playing =>
debug!("🎶 audio pipeline PLAYING"),
_ => {}
@ -93,7 +93,7 @@ pub async fn eye_ear(alsa_dev: &str, id: u32) -> anyhow::Result<AudioStream> {
std::sync::atomic::AtomicU64::new(0);
let n = CNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
if n < 10 || n % 300 == 0 {
debug!("🔊 eyeear #{n}: {}bytes", map.len());
debug!("🎧 ear #{n}: {}bytes", map.len());
}
let pts_us = buffer
@ -111,7 +111,7 @@ pub async fn eye_ear(alsa_dev: &str, id: u32) -> anyhow::Result<AudioStream> {
std::sync::atomic::AtomicU64::new(0);
let d = DROPS.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
if d % 300 == 0 {
warn!("🔊💔 dropped {d} audio AUs (client too slow)");
warn!("🎧💔 dropped {d} audio AUs (client too slow)");
}
}
Ok(gst::FlowSuccess::Ok)
@ -129,17 +129,17 @@ pub async fn eye_ear(alsa_dev: &str, id: u32) -> anyhow::Result<AudioStream> {
}
fn build_pipeline_desc(dev: &str) -> anyhow::Result<String> {
use gst::ElementFactory; // <- simpler probe
// choose the first encoder that exists on the system
let enc = ["voaacenc", "avenc_aac", "fdkaacenc"]
.into_iter()
.find(|&e| ElementFactory::find(e).is_some())
.find(|e| ElementFactory::find(e).is_some()) // cheap runtime probe
.ok_or_else(|| anyhow::anyhow!("no AAC encoder plugin available"))?;
Ok(format!(
// ➊ provide-clock=false lets the USB gadget be master
// ➋ audioconvert+audioresample make sure caps match encoder
// 48kHz stereo, floats, gadget is master → provideclock=false
"alsasrc device=\"{dev}\" provide-clock=false do-timestamp=true ! \
audioconvert ! audioresample ! audio/x-raw,channels=2,rate=48000,format=F32LE ! \
audioconvert ! audioresample ! \
audio/x-raw,format=F32LE,channels=2,rate=48000 ! \
{enc} bitrate=192000 ! aacparse ! queue ! \
appsink name=asink emit-signals=true max-buffers=64 drop=true"
))

View File

@ -192,7 +192,7 @@ impl Relay for Handler {
let dev = std::env::var("LESAVKA_ALSA_DEV")
.unwrap_or_else(|_| "hw:UAC2Gadget,0".into());
let s = audio::eye_ear(&dev, 0)
let s = audio::ear(&dev, 0)
.await
.map_err(|e| Status::internal(format!("{e:#}")))?;