skua_voice/input/sources/
file.rs

1use crate::input::{AudioStream, AudioStreamError, Compose, Input};
2use std::{error::Error, ffi::OsStr, path::Path};
3use symphonia_core::{io::MediaSource, probe::Hint};
4
5/// A lazily instantiated local file.
6#[derive(Clone, Debug)]
7pub struct File<P: AsRef<Path>> {
8    path: P,
9}
10
11impl<P: AsRef<Path>> File<P> {
12    /// Creates a lazy file object, which will open the target path.
13    ///
14    /// This is infallible as the path is only checked during creation.
15    pub fn new(path: P) -> Self {
16        Self { path }
17    }
18}
19
20impl<P: AsRef<Path> + Send + Sync + 'static> From<File<P>> for Input {
21    fn from(val: File<P>) -> Self {
22        Input::Lazy(Box::new(val))
23    }
24}
25
26#[async_trait::async_trait]
27impl<P: AsRef<Path> + Send + Sync> Compose for File<P> {
28    fn create(&mut self) -> Result<AudioStream<Box<dyn MediaSource>>, AudioStreamError> {
29        let err: Box<dyn Error + Send + Sync> =
30            "Files should be created asynchronously.".to_string().into();
31        Err(AudioStreamError::Fail(err))
32    }
33
34    async fn create_async(
35        &mut self,
36    ) -> Result<AudioStream<Box<dyn MediaSource>>, AudioStreamError> {
37        let file = tokio::fs::File::open(&self.path)
38            .await
39            .map_err(|io| AudioStreamError::Fail(Box::new(io)))?;
40
41        let input = Box::new(file.into_std().await);
42
43        let mut hint = Hint::default();
44        if let Some(ext) = self.path.as_ref().extension().and_then(OsStr::to_str) {
45            hint.with_extension(ext);
46        }
47
48        Ok(AudioStream {
49            input,
50            hint: Some(hint),
51        })
52    }
53
54    fn should_create_async(&self) -> bool {
55        true
56    }
57
58    // SEE: issue #186
59    // Below is removed due to issues with:
60    // 1) deadlocks on small files.
61    // 2) serde_aux poorly handles missing field names.
62    //
63
64    // Probes for metadata about this audio file using `ffprobe`.
65    // async fn aux_metadata(&mut self) -> Result<AuxMetadata, AudioStreamError> {
66    //     let args = [
67    //         "-v",
68    //         "quiet",
69    //         "-of",
70    //         "json",
71    //         "-show_format",
72    //         "-show_streams",
73    //         "-i",
74    //     ];
75
76    //     let mut output = Command::new("ffprobe")
77    //         .args(args)
78    //         .arg(self.path.as_ref().as_os_str())
79    //         .output()
80    //         .await
81    //         .map_err(|e| AudioStreamError::Fail(Box::new(e)))?;
82
83    //     AuxMetadata::from_ffprobe_json(&mut output.stdout[..])
84    //         .map_err(|e| AudioStreamError::Fail(Box::new(e)))
85    // }
86}