sapi_lite/audio/
stream.rs1use std::path::Path;
2use std::ptr::null;
3
4use windows as Windows;
5use Windows::core::{GUID, HRESULT};
6use Windows::Win32::Foundation::E_OUTOFMEMORY;
7use Windows::Win32::Media::Speech::{
8 ISpStream, SpStream, SPFILEMODE, SPFM_CREATE_ALWAYS, SPFM_OPEN_READONLY,
9};
10use Windows::Win32::System::Com::{CoCreateInstance, IStream, CLSCTX_ALL};
11use Windows::Win32::UI::Shell::SHCreateMemStream;
12
13use crate::com_util::Intf;
14use crate::Result;
15
16use super::AudioFormat;
17
18pub struct AudioStream {
20 intf: Intf<ISpStream>,
21}
22
23#[allow(non_upper_case_globals)]
24const SPDFID_WaveFormatEx: GUID = GUID::from_u128(0xc31adbae_527f_4ff5_a230_f62bb61ff70c);
25
26impl AudioStream {
27 pub fn open_file<P: AsRef<Path>>(path: P, format: &AudioFormat) -> Result<Self> {
30 Self::from_file(path, format, SPFM_OPEN_READONLY)
31 }
32
33 pub fn create_file<P: AsRef<Path>>(path: P, format: &AudioFormat) -> Result<Self> {
36 Self::from_file(path, format, SPFM_CREATE_ALWAYS)
37 }
38
39 pub fn from_stream<S: Into<IStream>>(stream: S, format: &AudioFormat) -> Result<Self> {
41 let intf: ISpStream = unsafe { CoCreateInstance(&SpStream, None, CLSCTX_ALL) }?;
42 unsafe { intf.SetBaseStream(stream.into(), &SPDFID_WaveFormatEx, &format.to_sapi()) }?;
43 Ok(Self { intf: Intf(intf) })
44 }
45
46 fn from_file<P: AsRef<Path>>(path: P, format: &AudioFormat, mode: SPFILEMODE) -> Result<Self> {
47 let intf: ISpStream = unsafe { CoCreateInstance(&SpStream, None, CLSCTX_ALL) }?;
48 unsafe {
49 intf.BindToFile(
50 path.as_ref().as_os_str(),
51 mode,
52 &SPDFID_WaveFormatEx,
53 &format.to_sapi(),
54 0,
55 )
56 }?;
57 Ok(AudioStream { intf: Intf(intf) })
58 }
59
60 pub(crate) fn to_sapi(&self) -> ISpStream {
61 self.intf.0.clone()
62 }
63}
64
65pub struct MemoryStream {
67 intf: Intf<IStream>,
68}
69
70impl MemoryStream {
71 pub fn new(init_data: Option<&[u8]>) -> Result<Self> {
73 Ok(Self {
74 intf: Intf(Self::create_stream(init_data)?),
75 })
76 }
77
78 pub fn try_clone(&self) -> Result<Self> {
81 unsafe { self.intf.Clone() }.map(|intf| Self { intf: Intf(intf) })
82 }
83
84 fn create_stream(init_data: Option<&[u8]>) -> std::result::Result<IStream, HRESULT> {
85 let size = init_data
86 .map(|buf| buf.len())
87 .unwrap_or(0)
88 .try_into()
89 .map_err(|_| E_OUTOFMEMORY)?;
90 unsafe { SHCreateMemStream(init_data.map(|buf| buf.as_ptr()).unwrap_or(null()), size) }
91 .ok_or(E_OUTOFMEMORY)
92 }
93}
94
95impl From<MemoryStream> for IStream {
96 fn from(source: MemoryStream) -> Self {
97 source.intf.0
98 }
99}