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

Update to a more general Device and Stream API. Add support for input streams (E.g. microphone). Add default format methods. #201

Merged
merged 27 commits into from
Feb 12, 2018

Conversation

mitchmindtree
Copy link
Member

@mitchmindtree mitchmindtree commented Feb 4, 2018

This update prepares for adding input stream support by removing the
Endpoint type (which only supports output streams) in favour of a more
general Device type which may support any number of input or output
streams. Previously discussed at #117.

The name Voice has been replaced with the more ubiquitous name
stream. See #118 for discussion on this.

Also introduces a new StreamData type which is now passed to the
EventLoop::run callback rather than the UnknownTypeBuffer.
StreamData allows for passing either Input data to be read, or
Output data to be written. As of this PR, the Input variant is just
a unit type and is not yet implemented.

All backends have been updated for the API changes, however input
stream functionality remains unimplemented across each backend.
That is, most backend implementations of default_input_device,
supported_input_formats and default_input_format are currently
unimplemented!(); and panic if called. The main aim was to update
to the new API while retaining existing functionality across all backends.

The beep.rs and enumerate.rs examples and the crate-root
documentation have also been updated for the API changes.

Closes #117.
Closes #118.

cc @tomaka (or anyone following CPAL) this is a pretty big change, it would
be great to get your thoughts/feedback on this! I'm totally open to alternative
approaches, this is my attempt at keeping functionality familiar and similar to
the current API while also allowing for input support. I've began implementing
the input API for the coreaudio backend and will be trying to get the remaining
backends implemented over the next couple days too. I don't mind whether
they are a part of this PR or a follow up PR.

EDIT: The new API is now implemented fully across all backends! Emscripten
still needs updating to handle input streams - I'm hoping someone more
familiar with the emscripten tool-chain can do this in a follow-up PR.

@mitchmindtree mitchmindtree force-pushed the device_api branch 2 times, most recently from 9a54a5f to d8e4efb Compare February 4, 2018 12:09
examples/beep.rs Outdated
match data {
cpal::StreamData::Output { buffer } => {
match buffer {
cpal::UnknownTypeBuffer::U16(mut buffer) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style: this could be merged with the above match (even if that means duplicating the StreamData::Output variant).

/// ALSA implementation for `EndpointsIterator`.
pub struct EndpointsIterator {
/// ALSA implementation for `Devices`.
pub struct Devices {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be DevicesIter IMO.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm I tend to avoid adding the Iter suffix unless I'm trying to avoid ambiguity between a collection and its iterator. IMO Devices is fine in the same way that std::str::Chars is OK.

@tomaka
Copy link
Collaborator

tomaka commented Feb 4, 2018

Thanks! The change is positive. We should probably make sure that the various backends have a working implementation before we ship a version on crates.io.

Please also add entries in CHANGELOG.md!

mitchmindtree added a commit to mitchmindtree/cpal that referenced this pull request Feb 5, 2018
The enumerate.rs example now also displays:

- Supported input stream formats.
- Default input stream format.
- Default output stream format.

This should also be useful for testing the progress of RustAudio#201.
mitchmindtree added a commit to mitchmindtree/cpal that referenced this pull request Feb 7, 2018
Adds only the necessary cargo features to reduce compile time and reduce
the chance of linking errors occurring for unused libraries (e.g.
d3d12.dll fails to link on my win10 VM).

I thought I'd try and land this before before working on the wasapi
backend implementation for RustAudio#201.

Tested both beep.rs and enumerate.rs and they work fine with the update.
tomaka pushed a commit that referenced this pull request Feb 7, 2018
Adds only the necessary cargo features to reduce compile time and reduce
the chance of linking errors occurring for unused libraries (e.g.
d3d12.dll fails to link on my win10 VM).

I thought I'd try and land this before before working on the wasapi
backend implementation for #201.

Tested both beep.rs and enumerate.rs and they work fine with the update.
mitchmindtree added a commit to mitchmindtree/cpal that referenced this pull request Feb 8, 2018
The enumerate.rs example now also displays:

- Supported input stream formats.
- Default input stream format.
- Default output stream format.

This should also be useful for testing the progress of RustAudio#201.
mitchmindtree added a commit to mitchmindtree/cpal that referenced this pull request Feb 10, 2018
The enumerate.rs example now also displays:

- Supported input stream formats.
- Default input stream format.
- Default output stream format.

This should also be useful for testing the progress of RustAudio#201.
This update prepares for adding input stream support by removing the
`Endpoint` type (which only supports output streams) in favour of a more
general `Device` type which may support any number of input or output
streams. Previously discussed at RustAudio#117.

The name `Voice` has been replaced with the more ubiquitous name
`Stream`. See RustAudio#118 for justification.

Also introduces a new `StreamData` which is now passed to the
`EventLoop::run` callback rather than the `UnknownTypeBuffer`.
`StreamData` allows for passing either `Input` data to be read, or
`Output` data to be written.

The `beep.rs` example has been updated for the API changes.

None of the backends have been updated for this API change yet. Backends
will be updated in the following commits.

Closes RustAudio#117.
Closes RustAudio#118.
UnknownTypeBuffer and Buffer have been renamed to
UnknownTypeOutputBuffer and OutputBuffer respectively.

No backends have yet been updated for this name change or the addition
of the InputBuffer.
The enumerate.rs example now also displays:

- Supported input stream formats.
- Default input stream format.
- Default output stream format.

This should also be useful for testing the progress of RustAudio#201.
Records a ~3 second WAV file to `$CARGO_MANIFEST_DIR/recorded.wav` using
the default input device and default input format.

Uses hound 3.0 to create and write to the WAV file.

This should also be useful for testing the input stream implementations
for each different cpal backend.
This implements the following for the coreaudio backend:

- Device::supported_input_formats
- Device::default_input_format
- Device::default_output_format
- EventLoop::build_input_stream

The `enumerate.rs` and `record_wav.rs` examples now work successfully on
macos.
This adds a comparison function which compares two `SupportedFormat`s in
terms of their priority of use as a default stream format.

Some backends (such as ALSA) do not provide a default stream format for
their audio devices. In these cases, CPAL attempts to decide on a
reasonable default format for the user. To do this we use the "greatest"
of all supported stream formats when compared with this method.
This implements the following for the ALSA backend:

- Device::supported_input_formats
- Device::default_input_format
- Device::default_output_format
- EventLoop::build_input_stream

Note that ALSA itself does not give default stream formats for its
devices. Thus the newly added `SupportedFormat::cmp_default_heuristics`
method is used to determine the most suitable, supported stream format
to use as the default.

The `enumerate.rs` and `record_wav.rs` examples now work successfully on
my linux machine.
This implements the following for the wasapi backend:

- Device::supported_input_formats
- Device::default_input_format
- Device::default_output_format
- EventLoop::build_input_stream

Note that wasapi does not enumerate supported input/output stream
formats for its devices. Instead, we query the `IsFormatSupported`
method for supported formats ourselves.
@mitchmindtree
Copy link
Member Author

mitchmindtree commented Feb 10, 2018

OK, input streams are now be supported across coreaudio, alsa and wasapi! This includes the Device::default_{input/output}_format, Device::supported_input_formats and Endpoint::build_input_stream methods.

I've fixed the Device::name method on windows (it now uses FriendlyName rather than the GUID). I also updated the run_inner method to handle non-f32 sample formats properly.

I've updated the enumerate example to display both default input/output devices as well as default input/output formats and supported input/output formats for all devices.

I've also added a new record_wav.rs example that records three seconds of audio from the system's default input device and writes this audio to a wav at $CARGO_MANIFEST_DIR/recorded.wav. I used this for testing across all of the main backends.

All three examples work on the macos (10.10), linux and two separate windows 10 systems I've been using for testing, but more testing is welcome of course!

I've also updated the CHANGELOG to account for all changes in this PR.

This PR should now be ready for review!

@mitchmindtree mitchmindtree changed the title Update to a more general Device and Stream API (preparing for Input stream support) Update to a more general Device and Stream API. Add support for input streams (E.g. microphone). Add default format methods. Feb 10, 2018
@mitchmindtree
Copy link
Member Author

@freesig could you test this branch (run each of the examples) on your mac and the windows machine while you have it? Also maybe let us know what mac version you're running (i've only tested on 10.10).

@mitchmindtree mitchmindtree force-pushed the device_api branch 2 times, most recently from a1b6b25 to edb040d Compare February 11, 2018 03:12
@freesig
Copy link
Contributor

freesig commented Feb 11, 2018

@mitchmindtree It ran fine on the mac(10.13.3)
Everything worked fine on the windows except record_wav

thread 'main' panicked at 'Failed to get default input device', src\libcore\option.rs:874:4
note: Run with RUST_BACKTRACE=1 for a backtrace.
error: process didn't exit successfully: target\release\examples\record_wav.exe (exit code: 101)

@mitchmindtree
Copy link
Member Author

Ahh right, I guess you just don't have any input audio devices on the windows machine then (you can check this with the enumerate example - it should show None for default input device)? Do you have a mic or audio interface that you could use to test it with? All good if not, that behaviour is expected for that example if there's no inputs to record with.

@freesig
Copy link
Contributor

freesig commented Feb 11, 2018

Yep record_wav works if I just plug a lead into the computers input.

@mitchmindtree
Copy link
Member Author

Nice one, thanks for that!

Copy link
Collaborator

@tomaka tomaka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will merge after nit.
I don't see any obvious mistake, so let's merge.

format_attempt.Format
};

/*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove

@mitchmindtree
Copy link
Member Author

Good spot! Fixed.

@tomaka tomaka merged commit c38bbb2 into RustAudio:master Feb 12, 2018
@mitchmindtree mitchmindtree deleted the device_api branch February 12, 2018 14:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants