/
non_blocking.rs
111 lines (86 loc) · 3.6 KB
/
non_blocking.rs
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! A demonstration of constructing and using a non-blocking stream.
//!
//! Audio from the default input device is passed directly to the default output device in a duplex
//! stream, so beware of feedback!
extern crate portaudio;
use portaudio as pa;
const SAMPLE_RATE: f64 = 44_100.0;
const FRAMES: u32 = 256;
const CHANNELS: i32 = 2;
const INTERLEAVED: bool = true;
fn main() {
match run() {
Ok(_) => {}
e => {
eprintln!("Example failed with the following: {:?}", e);
}
}
}
fn run() -> Result<(), pa::Error> {
let pa = pa::PortAudio::new()?;
println!("PortAudio:");
println!("version: {}", pa.version());
println!("version text: {:?}", pa.version_text());
println!("host count: {}", pa.host_api_count()?);
let default_host = pa.default_host_api()?;
println!("default host: {:#?}", pa.host_api_info(default_host));
let def_input = pa.default_input_device()?;
let input_info = pa.device_info(def_input)?;
println!("Default input device info: {:#?}", &input_info);
// Construct the input stream parameters.
let latency = input_info.default_low_input_latency;
let input_params = pa::StreamParameters::<f32>::new(def_input, CHANNELS, INTERLEAVED, latency);
let def_output = pa.default_output_device()?;
let output_info = pa.device_info(def_output)?;
println!("Default output device info: {:#?}", &output_info);
// Construct the output stream parameters.
let latency = output_info.default_low_output_latency;
let output_params = pa::StreamParameters::new(def_output, CHANNELS, INTERLEAVED, latency);
// Check that the stream format is supported.
pa.is_duplex_format_supported(input_params, output_params, SAMPLE_RATE)?;
// Construct the settings with which we'll open our duplex stream.
let settings = pa::DuplexStreamSettings::new(input_params, output_params, SAMPLE_RATE, FRAMES);
// Once the countdown reaches 0 we'll close the stream.
let mut count_down = 3.0;
// Keep track of the last `current_time` so we can calculate the delta time.
let mut maybe_last_time = None;
// We'll use this channel to send the count_down to the main thread for fun.
let (sender, receiver) = ::std::sync::mpsc::channel();
// A callback to pass to the non-blocking stream.
let callback = move |pa::DuplexStreamCallbackArgs {
in_buffer,
out_buffer,
frames,
time,
..
}| {
let current_time = time.current;
let prev_time = maybe_last_time.unwrap_or(current_time);
let dt = current_time - prev_time;
count_down -= dt;
maybe_last_time = Some(current_time);
assert!(frames == FRAMES as usize);
sender.send(count_down).ok();
// Pass the input straight to the output - BEWARE OF FEEDBACK!
for (output_sample, input_sample) in out_buffer.iter_mut().zip(in_buffer.iter()) {
*output_sample = *input_sample;
}
if count_down > 0.0 {
pa::Continue
} else {
pa::Complete
}
};
// Construct a stream with input and output sample types of f32.
let mut stream = pa.open_non_blocking_stream(settings, callback)?;
stream.start()?;
// Loop while the non-blocking stream is active.
while let true = stream.is_active()? {
// Do some stuff!
while let Ok(count_down) = receiver.try_recv() {
println!("count_down: {:?}", count_down);
}
}
stream.stop()?;
Ok(())
}