Skip to main content

sim_lib_stream_audio/
spine.rs

1use 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
8/// Drains a [`PcmSource`] into a pull-mode `sim-lib-stream-core` `StreamValue`.
9///
10/// Each source buffer becomes one PCM stream packet carried on `metadata`.
11/// Returns an error when `metadata` is not PCM media or is marked sink-only, or
12/// when a buffer fails to encode.
13pub 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
25/// Drains a `sim-lib-stream-core` `StreamValue` into a [`PcmSink`].
26///
27/// Each PCM stream packet is decoded into a [`PcmBuffer`] matching the sink's
28/// spec, written, and counted in the returned [`PcmPumpSummary`]; the sink is
29/// flushed at the end. Returns an error on a non-PCM packet or a spec mismatch.
30pub 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}