web_codecs/audio/
decoder.rs1use bytes::{Bytes, BytesMut};
2use tokio::sync::{mpsc, watch};
3use wasm_bindgen::prelude::*;
4
5use super::AudioData;
6use crate::{EncodedFrame, Error};
7
8#[derive(Debug, Default, Clone)]
9pub struct AudioDecoderConfig {
10 pub codec: String,
12
13 pub description: Option<Bytes>,
15
16 pub channel_count: u32,
18
19 pub sample_rate: u32,
21}
22
23impl AudioDecoderConfig {
24 pub fn new<T: Into<String>>(codec: T, channel_count: u32, sample_rate: u32) -> Self {
25 Self {
26 codec: codec.into(),
27 channel_count,
28 sample_rate,
29 ..Default::default()
30 }
31 }
32
33 pub async fn is_supported(&self) -> Result<bool, Error> {
36 let res =
37 wasm_bindgen_futures::JsFuture::from(web_sys::AudioDecoder::is_config_supported(&self.into())).await?;
38
39 let supported = js_sys::Reflect::get(&res, &JsValue::from_str("supported"))
40 .unwrap()
41 .as_bool()
42 .unwrap();
43
44 Ok(supported)
45 }
46
47 pub fn build(self) -> Result<(AudioDecoder, AudioDecoded), Error> {
48 let (frames_tx, frames_rx) = mpsc::unbounded_channel();
49 let (closed_tx, closed_rx) = watch::channel(Ok(()));
50 let closed_tx2 = closed_tx.clone();
51
52 let on_error = Closure::wrap(Box::new(move |e: JsValue| {
53 closed_tx.send_replace(Err(Error::from(e))).ok();
54 }) as Box<dyn FnMut(_)>);
55
56 let on_frame = Closure::wrap(Box::new(move |e: JsValue| {
57 let frame: web_sys::AudioData = e.unchecked_into();
58 let frame = AudioData::from(frame);
59
60 if frames_tx.send(frame).is_err() {
61 closed_tx2.send_replace(Err(Error::Dropped)).ok();
62 }
63 }) as Box<dyn FnMut(_)>);
64
65 let init = web_sys::AudioDecoderInit::new(on_error.as_ref().unchecked_ref(), on_frame.as_ref().unchecked_ref());
66 let inner: web_sys::AudioDecoder = web_sys::AudioDecoder::new(&init).unwrap();
67 inner.configure(&(&self).into())?;
68
69 let decoder = AudioDecoder {
70 inner,
71 on_error,
72 on_frame,
73 };
74
75 let decoded = AudioDecoded {
76 frames: frames_rx,
77 closed: closed_rx,
78 };
79
80 Ok((decoder, decoded))
81 }
82}
83
84impl From<&AudioDecoderConfig> for web_sys::AudioDecoderConfig {
85 fn from(this: &AudioDecoderConfig) -> Self {
86 let config = web_sys::AudioDecoderConfig::new(&this.codec, this.channel_count, this.sample_rate);
87
88 if let Some(description) = &this.description {
89 config.set_description(&js_sys::Uint8Array::from(description.as_ref()));
90 }
91
92 config
93 }
94}
95
96impl From<web_sys::AudioDecoderConfig> for AudioDecoderConfig {
97 fn from(this: web_sys::AudioDecoderConfig) -> Self {
98 let description = this.get_description().map(|d| {
99 let buffer = js_sys::Uint8Array::new(&d);
101 let size = buffer.byte_length() as usize;
102
103 let mut payload = BytesMut::with_capacity(size);
104 payload.resize(size, 0);
105 buffer.copy_to(&mut payload);
106
107 payload.freeze()
108 });
109
110 let channels = this.get_number_of_channels();
111 let sample_rate = this.get_sample_rate();
112
113 Self {
114 codec: this.get_codec(),
115 description,
116 channel_count: channels,
117 sample_rate,
118 }
119 }
120}
121
122pub struct AudioDecoder {
123 inner: web_sys::AudioDecoder,
124
125 #[allow(dead_code)]
127 on_error: Closure<dyn FnMut(JsValue)>,
128 #[allow(dead_code)]
129 on_frame: Closure<dyn FnMut(JsValue)>,
130}
131
132impl AudioDecoder {
133 pub fn decode(&self, frame: EncodedFrame) -> Result<(), Error> {
134 let chunk_type = match frame.keyframe {
135 true => web_sys::EncodedAudioChunkType::Key,
136 false => web_sys::EncodedAudioChunkType::Delta,
137 };
138
139 let chunk = web_sys::EncodedAudioChunkInit::new(
140 &js_sys::Uint8Array::from(frame.payload.as_ref()),
141 frame.timestamp.as_micros() as _,
142 chunk_type,
143 );
144
145 let chunk = web_sys::EncodedAudioChunk::new(&chunk)?;
146 self.inner.decode(&chunk)?;
147
148 Ok(())
149 }
150
151 pub async fn flush(&self) -> Result<(), Error> {
152 wasm_bindgen_futures::JsFuture::from(self.inner.flush()).await?;
153 Ok(())
154 }
155
156 pub fn queue_size(&self) -> u32 {
157 self.inner.decode_queue_size()
158 }
159}
160
161impl Drop for AudioDecoder {
162 fn drop(&mut self) {
163 let _ = self.inner.close();
164 }
165}
166
167pub struct AudioDecoded {
168 frames: mpsc::UnboundedReceiver<AudioData>,
169 closed: watch::Receiver<Result<(), Error>>,
170}
171
172impl AudioDecoded {
173 pub async fn next(&mut self) -> Result<Option<AudioData>, Error> {
174 tokio::select! {
175 biased;
176 frame = self.frames.recv() => Ok(frame),
177 Ok(()) = self.closed.changed() => Err(self.closed.borrow().clone().err().unwrap()),
178 }
179 }
180}