1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! libao sink

extern crate ao;

use std::mem;
use super::{SourceResult, Sample, Source, Sink};
use super::interleave::Interleave;

/// Sink writing to a libao device.
///
/// Consumes samples of format `F` from a `Source` `R`.
pub struct AOSink<'a, F, R> {
    device: ao::Device<'a, F>,
    interleave_buf: Vec<F>,
    source: R,
}

impl<'a, F, R> AOSink<'a, F, R>  where
        F: ao::Sample,
        R: Source<Output=F> {
    /// Construct a libao sink.
    pub fn new(source: R, driver: &ao::Driver<'a>) -> ao::AoResult<AOSink<'a, F, R>> {

        // TODO permit user to specify these parameters
        let format = ao::SampleFormat::<F, &str>::new(44100, 1, ao::Endianness::Native, None);

        Ok(AOSink {
            device: match driver.get_info().unwrap().flavor {
                ao::DriverType::Live => {
                    try!(driver.open_live(&format))
                },
                ao::DriverType::File => {
                    panic!("Can't do file output yet.")
                }
            },
            interleave_buf: Vec::new(),
            source: source,
        })
    }
}

impl<'a, F: ao::Sample + Interleave, R: Source<Output=F>> Sink for AOSink<'a, F, R> {
    fn run_once(&mut self) -> Option<()> {
        match self.source.next() {
            SourceResult::Buffer(channels) => {
                // Interleave channels
                let len = channels[0].len();
                self.interleave_buf.reserve(len);
                unsafe {
                    self.interleave_buf.set_len(len);
                    // Transmute hack to lose `mut` on each channel.
                    Interleave::interleave(mem::transmute(channels), self.interleave_buf.as_mut_slice());
                }

                self.device.play(self.interleave_buf.as_slice());
                // Drop all interleaved samples
                self.interleave_buf.truncate(0);
                Some(())
            }
            _ => None
        }
    }
}

/// Dynamic-format AO output.
#[warn(dead_code)]
pub struct AOAutoWriterSink<'a, R, W, _S> {
    /// Writer which receives data from libao
    dest: W,
    /// libao device handle
    device: ao::auto::AutoFormatDevice<'a, _S>,
    /// Source this receives data from.
    source: R
}

// TODO we really want dynamic format support for sinks here.
/*impl<'a, R, W, _S> AOAutoSink<'a, R, W, _S> where
        R: DynamicSource,
        W: Writer,
        _S: Str {

}*/