orinium_browser/platform/audio/
mod.rs

1//! 音声データの管理と再生を行う
2
3use crate::platform::io as platform_io;
4use anyhow::{Context, Result};
5use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
6use cpal::{SampleFormat, StreamConfig};
7use std::io::Cursor;
8use std::sync::{Arc, Mutex};
9use std::time::Duration;
10use symphonia::core::audio::{AudioBufferRef, Signal};
11use symphonia::core::codecs::DecoderOptions;
12use symphonia::core::formats::FormatOptions;
13use symphonia::core::io::MediaSourceStream;
14use symphonia::core::meta::MetadataOptions;
15use symphonia::core::probe::Hint;
16use symphonia::default::{get_codecs, get_probe};
17
18/// 音声の管理を行う構造体
19pub struct SoundManager {
20    /// f32のインタリーブドサンプルバッファ
21    samples: Arc<Mutex<Vec<f32>>>,
22    /// 現在の再生位置(フレーム単位)
23    play_pos: Arc<Mutex<usize>>,
24    /// ソースのチャンネル数
25    src_channels: usize,
26    /// ソースのサンプルレート
27    // TODO: Hzを考慮したコンバーターを実装する
28    src_sample_rate: u32,
29    /// cpalのストリーム
30    stream: Option<cpal::Stream>,
31}
32
33impl SoundManager {
34    /// 初期化
35    pub fn init() -> Result<Arc<Mutex<Self>>> {
36        let manager = SoundManager {
37            samples: Arc::new(Mutex::new(Vec::new())),
38            play_pos: Arc::new(Mutex::new(0)),
39            src_channels: 0,
40            src_sample_rate: 0,
41            stream: None,
42        };
43        Ok(Arc::new(Mutex::new(manager)))
44    }
45
46    /// cpalストリームを確保する
47    fn ensure_stream(&mut self) -> Result<()> {
48        if self.stream.is_some() {
49            return Ok(());
50        }
51
52        let host = cpal::default_host();
53        let device = host
54            .default_output_device()
55            .context("No default output device available")?;
56        let supported_cfg = device
57            .default_output_config()
58            .context("Failed to get default output config")?;
59        let config: StreamConfig = supported_cfg.clone().into();
60        let sample_format = supported_cfg.sample_format();
61        let output_channels = config.channels as usize;
62
63        let samples = self.samples.clone();
64        let play_pos = self.play_pos.clone();
65        let src_channels = self.src_channels;
66
67        let err_fn = |err| log::error!("cpal stream error: {}", err);
68
69        let latency = Some(Duration::from_millis(100));
70
71        let stream = match sample_format {
72            SampleFormat::F32 => device.build_output_stream(
73                &config,
74                move |data: &mut [f32], _| {
75                    write_output_f32(data, src_channels, output_channels, &samples, &play_pos)
76                },
77                err_fn,
78                latency,
79            )?,
80            SampleFormat::I16 => device.build_output_stream(
81                &config,
82                move |data: &mut [i16], _| {
83                    write_output_i16(data, src_channels, output_channels, &samples, &play_pos)
84                },
85                err_fn,
86                latency,
87            )?,
88            SampleFormat::U16 => device.build_output_stream(
89                &config,
90                move |data: &mut [u16], _| {
91                    write_output_u16(data, src_channels, output_channels, &samples, &play_pos)
92                },
93                err_fn,
94                latency,
95            )?,
96            _ => {
97                return Err(anyhow::anyhow!(
98                    "Unsupported sample format from output device"
99                ));
100            }
101        };
102
103        stream.play()?;
104        self.stream = Some(stream);
105        Ok(())
106    }
107
108    /// バイト列から音声を再生する
109    pub fn play_from_bytes(&mut self, data: &[u8]) -> Result<()> {
110        let (samples, channels, sample_rate) = decode(data)?;
111        // replace buffer
112        {
113            let mut buf = match self.samples.lock() {
114                Ok(x) => x,
115                Err(_) => todo!(),
116            };
117            *buf = samples;
118        }
119        // reset position
120        {
121            let mut pos = match self.play_pos.lock() {
122                Ok(x) => x,
123                Err(_) => todo!(),
124            };
125            *pos = 0;
126        }
127        self.src_channels = channels;
128        self.src_sample_rate = sample_rate;
129
130        self.ensure_stream()?;
131
132        Ok(())
133    }
134
135    /// ローカルファイルから音声を再生する
136    pub fn play_from_file(&mut self, path: &str) -> Result<()> {
137        let data = platform_io::load_local_file(path)
138            .with_context(|| format!("Failed to read local file: {}", path))?;
139        self.play_from_bytes(&data)
140    }
141
142    /// URIから音声を再生する(resourceまたはfileスキームに対応)
143    ///
144    /// 通常の再生には `play_from_bytes` を使用してください。
145    /// これはテスト用メソッドです
146    pub fn play_from_local_uri(&mut self, uri: &str) -> Result<()> {
147        if uri.starts_with("resource:") {
148            let rel = uri
149                .trim_start_matches("resource:///")
150                .trim_start_matches("resource://")
151                .trim_start_matches("resource:/")
152                .trim_start_matches("resource:");
153            let rel = rel.trim_start_matches('/');
154            let data = platform_io::load_resource(rel)
155                .with_context(|| format!("Failed to load resource: {}", rel))?;
156            return self.play_from_bytes(&data);
157        }
158        if uri.starts_with("file://") {
159            let p = uri.trim_start_matches("file://");
160            let data = platform_io::load_local_file(p)
161                .with_context(|| format!("Failed to read local file from URI: {}", p))?;
162            return self.play_from_bytes(&data);
163        }
164        let data = platform_io::load_local_file(uri)
165            .with_context(|| format!("Failed to read local file: {}", uri))?;
166        self.play_from_bytes(&data)
167    }
168}
169
170/// 音声をデコードする
171fn decode(data: &[u8]) -> Result<(Vec<f32>, usize, u32)> {
172    let cursor = Cursor::new(data.to_vec());
173    let mss = MediaSourceStream::new(Box::new(cursor), Default::default());
174
175    let hint = Hint::new();
176    let probed = get_probe()
177        .format(
178            &hint,
179            mss,
180            &FormatOptions::default(),
181            &MetadataOptions::default(),
182        )
183        .context("Failed to probe media format")?;
184
185    let mut format = probed.format;
186    let track = format
187        .default_track()
188        .ok_or_else(|| anyhow::anyhow!("No default audio track found"))?;
189    let codec_params = &track.codec_params;
190    let mut decoder = get_codecs()
191        .make(codec_params, &DecoderOptions::default())
192        .context("Failed to create decoder")?;
193
194    let mut samples: Vec<f32> = Vec::new();
195    let mut channels: usize = codec_params.channels.map(|c| c.count()).unwrap_or(1);
196    let mut sample_rate: u32 = codec_params.sample_rate.unwrap_or(44100);
197
198    loop {
199        match format.next_packet() {
200            Ok(packet) => match decoder.decode(&packet) {
201                Ok(audio_buf) => match audio_buf {
202                    AudioBufferRef::U8(buf) => {
203                        let ab = buf.as_ref();
204                        channels = ab.spec().channels.count();
205                        sample_rate = ab.spec().rate;
206                        let frames = ab.frames();
207                        for f in 0..frames {
208                            for ch in 0..channels {
209                                let v = ab.chan(ch)[f] as f32;
210                                samples.push((v - 128.0) / 128.0);
211                            }
212                        }
213                    }
214                    AudioBufferRef::U16(buf) => {
215                        let ab = buf.as_ref();
216                        channels = ab.spec().channels.count();
217                        sample_rate = ab.spec().rate;
218                        let frames = ab.frames();
219                        for f in 0..frames {
220                            for ch in 0..channels {
221                                let v = ab.chan(ch)[f] as f32;
222                                samples.push((v - 32768.0) / 32768.0);
223                            }
224                        }
225                    }
226                    AudioBufferRef::S16(buf) => {
227                        let ab = buf.as_ref();
228                        channels = ab.spec().channels.count();
229                        sample_rate = ab.spec().rate;
230                        let frames = ab.frames();
231                        for f in 0..frames {
232                            for ch in 0..channels {
233                                let v = ab.chan(ch)[f] as f32;
234                                samples.push(v / i16::MAX as f32);
235                            }
236                        }
237                    }
238                    AudioBufferRef::F32(buf) => {
239                        let ab = buf.as_ref();
240                        channels = ab.spec().channels.count();
241                        sample_rate = ab.spec().rate;
242                        let frames = ab.frames();
243                        for f in 0..frames {
244                            for ch in 0..channels {
245                                let v = ab.chan(ch)[f];
246                                samples.push(v);
247                            }
248                        }
249                    }
250                    AudioBufferRef::F64(buf) => {
251                        let ab = buf.as_ref();
252                        channels = ab.spec().channels.count();
253                        sample_rate = ab.spec().rate;
254                        let frames = ab.frames();
255                        for f in 0..frames {
256                            for ch in 0..channels {
257                                let v = ab.chan(ch)[f];
258                                samples.push(v as f32);
259                            }
260                        }
261                    }
262                    _ => {
263                        // Unsupported format
264                    }
265                },
266                Err(_) => { /* ignore */ }
267            },
268            Err(_) => break,
269        }
270    }
271
272    Ok((samples, channels, sample_rate))
273}
274
275/// 出力バッファに音声データを書き込む(f32)
276fn write_output_f32(
277    output: &mut [f32],
278    src_channels: usize,
279    out_channels: usize,
280    samples: &Arc<Mutex<Vec<f32>>>,
281    pos: &Arc<Mutex<usize>>,
282) {
283    let mut p = pos.lock().unwrap();
284    let buf = samples.lock().unwrap();
285    let total_frames = if src_channels > 0 {
286        buf.len() / src_channels
287    } else {
288        0
289    };
290
291    if out_channels == 0 {
292        return;
293    }
294    let frames_to_write = output.len() / out_channels;
295
296    for frame in 0..frames_to_write {
297        if total_frames == 0 || *p >= total_frames {
298            // zero out remaining
299            for ch in 0..out_channels {
300                output[frame * out_channels + ch] = 0.0;
301            }
302            continue;
303        }
304        for ch in 0..out_channels {
305            let src_index = (*p * src_channels) + (ch % src_channels);
306            if src_index < buf.len() {
307                output[frame * out_channels + ch] = buf[src_index];
308            } else {
309                output[frame * out_channels + ch] = 0.0;
310            }
311        }
312        *p += 1;
313    }
314}
315
316/// 出力バッファに音声データを書き込む(i16)
317fn write_output_i16(
318    output: &mut [i16],
319    src_channels: usize,
320    out_channels: usize,
321    samples: &Arc<Mutex<Vec<f32>>>,
322    pos: &Arc<Mutex<usize>>,
323) {
324    let mut p = pos.lock().unwrap();
325    let buf = samples.lock().unwrap();
326    let total_frames = if src_channels > 0 {
327        buf.len() / src_channels
328    } else {
329        0
330    };
331
332    if out_channels == 0 {
333        return;
334    }
335    let frames_to_write = output.len() / out_channels;
336
337    for frame in 0..frames_to_write {
338        if total_frames == 0 || *p >= total_frames {
339            for ch in 0..out_channels {
340                output[frame * out_channels + ch] = 0;
341            }
342            continue;
343        }
344        for ch in 0..out_channels {
345            let src_index = (*p * src_channels) + (ch % src_channels);
346            if src_index < buf.len() {
347                let v = buf[src_index].clamp(-1.0, 1.0);
348                output[frame * out_channels + ch] = (v * i16::MAX as f32) as i16;
349            } else {
350                output[frame * out_channels + ch] = 0;
351            }
352        }
353        *p += 1;
354    }
355}
356
357/// 出力バッファに音声データを書き込む(u16)
358fn write_output_u16(
359    output: &mut [u16],
360    src_channels: usize,
361    out_channels: usize,
362    samples: &Arc<Mutex<Vec<f32>>>,
363    pos: &Arc<Mutex<usize>>,
364) {
365    let mut p = pos.lock().unwrap();
366    let buf = samples.lock().unwrap();
367    let total_frames = if src_channels > 0 {
368        buf.len() / src_channels
369    } else {
370        0
371    };
372
373    if out_channels == 0 {
374        return;
375    }
376    let frames_to_write = output.len() / out_channels;
377
378    for frame in 0..frames_to_write {
379        if total_frames == 0 || *p >= total_frames {
380            for ch in 0..out_channels {
381                output[frame * out_channels + ch] = 0;
382            }
383            continue;
384        }
385        for ch in 0..out_channels {
386            let src_index = (*p * src_channels) + (ch % src_channels);
387            if src_index < buf.len() {
388                let v = buf[src_index].clamp(-1.0, 1.0);
389                output[frame * out_channels + ch] = ((v * 0.5 + 0.5) * u16::MAX as f32) as u16;
390            } else {
391                output[frame * out_channels + ch] = 0;
392            }
393        }
394        *p += 1;
395    }
396}