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