sim_lib_stream_audio/
spine.rs1use sim_kernel::{Error, Result};
2use sim_lib_stream_core::{
3 StreamDirection, StreamItem, StreamMedia, StreamMetadata, StreamPacket, StreamValue,
4};
5
6use crate::{PcmBuffer, PcmPumpSummary, PcmSink, PcmSource};
7
8pub fn pcm_source_to_stream(
14 source: &mut impl PcmSource,
15 metadata: StreamMetadata,
16) -> Result<StreamValue> {
17 ensure_source_metadata(&metadata)?;
18 let mut items = Vec::new();
19 while let Some(buffer) = source.read_buffer()? {
20 items.push(StreamItem::new(StreamPacket::Pcm(buffer.to_packet()?)));
21 }
22 Ok(StreamValue::pull(metadata, items))
23}
24
25pub fn stream_to_pcm_sink(stream: &StreamValue, sink: &mut impl PcmSink) -> Result<PcmPumpSummary> {
31 let mut summary = PcmPumpSummary::default();
32 while let Some(item) = stream.next_packet()? {
33 let StreamPacket::Pcm(packet) = item.packet() else {
34 return Err(Error::Eval(
35 "PCM sink adapter received a non-PCM stream packet".to_owned(),
36 ));
37 };
38 let buffer = PcmBuffer::from_packet(*sink.spec(), packet)?;
39 summary.record(&buffer);
40 sink.write_buffer(buffer)?;
41 }
42 sink.flush()?;
43 Ok(summary)
44}
45
46fn ensure_source_metadata(metadata: &StreamMetadata) -> Result<()> {
47 if metadata.media() != StreamMedia::Pcm {
48 return Err(Error::Eval(
49 "PCM source stream metadata must use PCM media".to_owned(),
50 ));
51 }
52 if metadata.direction() == StreamDirection::Sink {
53 return Err(Error::Eval(
54 "PCM source stream metadata must not be sink-only".to_owned(),
55 ));
56 }
57 Ok(())
58}