Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added example of opening an input stream and output stream separately #162

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 150 additions & 0 deletions examples/record.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
//! A demonstration of recording input
//!
//! Audio from the default input device is recorded into memory until
//! the user presses Enter. They are then played back to the default
//! output device.

extern crate portaudio;

use portaudio as pa;
use std::io;
use std::thread;
use std::time::Duration;

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 = try!(pa::PortAudio::new());

println!("PortAudio:");
println!("version: {}", pa.version());
println!("version text: {:?}", pa.version_text());
println!("host count: {}", try!(pa.host_api_count()));

let default_host = try!(pa.default_host_api());
println!("default host: {:#?}", pa.host_api_info(default_host));

let def_input = try!(pa.default_input_device());
let input_info = try!(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);

// Check that the stream format is supported.
try!(pa.is_input_format_supported(input_params, SAMPLE_RATE));

// Construct the settings with which we'll open our input stream.
let input_settings = pa::InputStreamSettings::new(input_params, SAMPLE_RATE, FRAMES);

// We'll use this channel to send the samples back to the main thread.
let (sender, receiver) = ::std::sync::mpsc::channel();

// A callback to pass to the non-blocking input stream.
let input_callback = move |pa::InputStreamCallbackArgs { buffer, frames, .. }| {
assert!(frames == FRAMES as usize);

// We'll construct a copy of the input buffer and send that
// onto the channel. This doesn't block, even though nothing
// is waiting on the receiver yet.
let vec_buffer = Vec::from(buffer);
// There are actually 512 samples here. 256 for the left, 256 for the right.
assert!(vec_buffer.len() == FRAMES as usize * CHANNELS as usize);

// If sending fails (the receiver has been dropped), stop recording
match sender.send(vec_buffer) {
Ok(_) => pa::Continue,
Err(_) => pa::Complete
}
};

// Construct a stream with input sample types of f32.
let mut input_stream = try!(pa.open_non_blocking_stream(input_settings, input_callback));

try!(input_stream.start());

println!("Recording has started. Press Enter to stop.");

// Wait for enter to be pressed
let mut buffer = String::new();
io::stdin().read_line(&mut buffer).ok();

try!(input_stream.stop());


// We now have a channel filled with the samples from the input
// device. Let's pipe it all to the output device.


let def_output = try!(pa.default_output_device());
let output_info = try!(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.
try!(pa.is_output_format_supported(output_params, SAMPLE_RATE));

// Construct the settings with which we'll open our output stream.
let output_settings = pa::OutputStreamSettings::new(output_params, SAMPLE_RATE, FRAMES);

// A callback to pass to the non-blocking output stream.
let output_callback = move |pa::OutputStreamCallbackArgs { buffer, frames, .. }| {
// like with the input, frames is the number of samples that
// buffer expects per channel
assert!(frames == FRAMES as usize);

// try_recv will return immediately, with an error if there
// isn't any data waiting. This is reading in the data that we
// sent from the input callback.
match receiver.try_recv() {
Ok(samples) => {
assert!(samples.len() == FRAMES as usize * CHANNELS as usize);

// Pass the previous input over to the output. No
// feedback issues in this example, since we aren't
// recording anymore at this point.
for (output_sample, input_sample) in buffer.iter_mut().zip(samples.iter()) {
*output_sample = *input_sample;
}
pa::Continue
},
Err(_) => pa::Complete
}
};

// Construct a stream with output sample types of f32.
let mut output_stream = try!(pa.open_non_blocking_stream(output_settings, output_callback));

try!(output_stream.start());

// wait until the output stream reaches the end
while let true = try!(output_stream.is_active()) {
// This thread doesn't need to do anything while it waits. If
// we don't make the thread sleep, we max out the CPU usage
// doing nothing but checking if the output stream is still
// active.
thread::sleep(Duration::from_millis(100));
}

try!(output_stream.stop());

Ok(())
}