1use std::sync::Arc;
9use std::time::Duration;
10
11use crate::consumer::MoqBroadcastConsumer;
12use crate::error::MoqError;
13use crate::ffi::Task;
14use crate::producer::MoqBroadcastProducer;
15
16#[derive(Clone, Copy, uniffi::Enum)]
20pub enum MoqAudioFormat {
21 U8,
22 S16,
23 S32,
24 F32,
25 U8Planar,
26 S16Planar,
27 S32Planar,
28 F32Planar,
29}
30
31impl From<MoqAudioFormat> for moq_audio::AudioFormat {
32 fn from(f: MoqAudioFormat) -> Self {
33 match f {
34 MoqAudioFormat::U8 => Self::U8,
35 MoqAudioFormat::S16 => Self::S16,
36 MoqAudioFormat::S32 => Self::S32,
37 MoqAudioFormat::F32 => Self::F32,
38 MoqAudioFormat::U8Planar => Self::U8Planar,
39 MoqAudioFormat::S16Planar => Self::S16Planar,
40 MoqAudioFormat::S32Planar => Self::S32Planar,
41 MoqAudioFormat::F32Planar => Self::F32Planar,
42 }
43 }
44}
45
46#[derive(Clone, Copy, uniffi::Enum)]
48pub enum MoqAudioCodec {
49 Opus,
50}
51
52impl From<MoqAudioCodec> for moq_audio::Codec {
53 fn from(c: MoqAudioCodec) -> Self {
54 match c {
55 MoqAudioCodec::Opus => Self::Opus,
56 }
57 }
58}
59
60#[derive(uniffi::Record)]
62pub struct MoqAudioEncoderInput {
63 pub format: MoqAudioFormat,
64 pub sample_rate: u32,
65 pub channels: u32,
66}
67
68#[derive(uniffi::Record)]
72pub struct MoqAudioEncoderOutput {
73 pub codec: MoqAudioCodec,
74 pub sample_rate: Option<u32>,
75 pub channels: Option<u32>,
76 pub bitrate: Option<u32>,
77 pub frame_duration_ms: u32,
80}
81
82#[derive(uniffi::Record)]
84pub struct MoqAudioDecoderOutput {
85 pub format: MoqAudioFormat,
86 pub sample_rate: Option<u32>,
88 pub channels: Option<u32>,
90 pub latency_max_ms: Option<u64>,
98}
99
100#[derive(uniffi::Record)]
107pub struct MoqAudioFrame {
108 pub timestamp_us: u64,
109 pub data: Vec<u8>,
110}
111
112impl From<moq_audio::Frame> for MoqAudioFrame {
113 fn from(f: moq_audio::Frame) -> Self {
114 Self {
115 timestamp_us: f.timestamp_us,
116 data: f.data.to_vec(),
117 }
118 }
119}
120
121impl From<MoqAudioFrame> for moq_audio::Frame {
122 fn from(f: MoqAudioFrame) -> Self {
123 Self {
124 timestamp_us: f.timestamp_us,
125 data: f.data.into(),
126 }
127 }
128}
129
130#[derive(uniffi::Object)]
139pub struct MoqAudioProducer {
140 inner: std::sync::Mutex<Option<moq_audio::AudioProducer>>,
141}
142
143#[uniffi::export]
144impl MoqAudioProducer {
145 pub fn write(&self, frame: MoqAudioFrame) -> Result<(), MoqError> {
146 let _guard = crate::ffi::RUNTIME.enter();
147 let mut guard = self.inner.lock().unwrap();
148 let producer = guard.as_mut().ok_or(MoqError::Closed)?;
149 producer.write(&frame.into())?;
150 Ok(())
151 }
152
153 pub fn finish(&self) -> Result<(), MoqError> {
154 let _guard = crate::ffi::RUNTIME.enter();
155 let producer = self.inner.lock().unwrap().take().ok_or(MoqError::Closed)?;
156 producer.finish()?;
157 Ok(())
158 }
159}
160
161#[uniffi::export]
162impl MoqBroadcastProducer {
163 pub fn publish_audio(
167 &self,
168 name: String,
169 input: MoqAudioEncoderInput,
170 output: MoqAudioEncoderOutput,
171 ) -> Result<Arc<MoqAudioProducer>, MoqError> {
172 let _guard = crate::ffi::RUNTIME.enter();
173
174 let producer = self.with_state(|state| {
175 moq_audio::AudioProducer::new(
176 &mut state.broadcast,
177 state.catalog.clone(),
178 name,
179 moq_audio::EncoderInput {
180 format: input.format.into(),
181 sample_rate: input.sample_rate,
182 channels: input.channels,
183 },
184 moq_audio::EncoderOutput {
185 codec: output.codec.into(),
186 sample_rate: output.sample_rate,
187 channels: output.channels,
188 bitrate: output.bitrate,
189 frame_duration: Duration::from_millis(output.frame_duration_ms.into()),
190 },
191 )
192 .map_err(Into::into)
193 })?;
194
195 Ok(Arc::new(MoqAudioProducer {
196 inner: std::sync::Mutex::new(Some(producer)),
197 }))
198 }
199}
200
201struct ConsumerInner {
204 consumer: moq_audio::AudioConsumer,
205}
206
207impl ConsumerInner {
208 async fn next(&mut self) -> Result<Option<MoqAudioFrame>, MoqError> {
209 Ok(self.consumer.read().await?.map(Into::into))
210 }
211}
212
213#[derive(uniffi::Object)]
215pub struct MoqAudioConsumer {
216 task: Task<ConsumerInner>,
217}
218
219#[uniffi::export]
220impl MoqAudioConsumer {
221 pub async fn next(&self) -> Result<Option<MoqAudioFrame>, MoqError> {
222 self.task.run(|mut state| async move { state.next().await }).await
223 }
224
225 pub fn cancel(&self) {
226 self.task.cancel();
227 }
228}
229
230#[uniffi::export]
231impl MoqBroadcastConsumer {
232 pub fn subscribe_audio(
237 &self,
238 name: String,
239 catalog_audio: crate::media::MoqAudio,
240 output: MoqAudioDecoderOutput,
241 ) -> Result<Arc<MoqAudioConsumer>, MoqError> {
242 let _guard = crate::ffi::RUNTIME.enter();
243
244 let mut cfg = hang::catalog::AudioConfig::new(
245 hang::catalog::AudioCodec::Opus,
246 catalog_audio.sample_rate,
247 catalog_audio.channel_count,
248 );
249 cfg.bitrate = catalog_audio.bitrate;
250 cfg.description = catalog_audio.description.map(Into::into);
251 cfg.container = catalog_audio.container.into();
252
253 let consumer = moq_audio::AudioConsumer::new(
254 self.inner(),
255 &cfg,
256 name,
257 moq_audio::DecoderOutput {
258 format: output.format.into(),
259 sample_rate: output.sample_rate,
260 channels: output.channels,
261 latency_max: output.latency_max_ms.map(Duration::from_millis),
262 },
263 )?;
264
265 Ok(Arc::new(MoqAudioConsumer {
266 task: Task::new(ConsumerInner { consumer }),
267 }))
268 }
269}