Instead, we use some traits and generics in an attempt to retain a
little readability. See the remaining TODOs in this section for required
future work.
Currently not compiling - still need to address some global items within
asio-sys, including the `set_callback` function and the double buffer
globals.
Now runs the beep and enumerate examples nicely! Time to do a proper
code review of the ASIO stuff and see how to best take advantage of the
new `Host` API.
This is a draft implementation of #294. I'll leave this open for
feedback and potentially better trait naming suggestions or better
solutions in general!
cc @ishitatsuyuki
This solution was originally posted by @HybridEidolon in #185. Sorry it
took so long! I thought it might be easier to open a new PR as half of
your implementation here has already been implemented in a following PR
(namely, the change from an unnecessary `Vec` of callbacks to a single
user callback).
Closes#185.
Re-exports host-specific types so that they are available within the
platform module if necessary (e.g. host::asla::Host as AlsaHost).
Allows for converting platform-specific host types (e.g. AlsaHost) into
the dynamically dispatched type generated for the target platform
(`Host`).
This is an implementation of the API described at #204. Please see that
issue for more details on the motivation.
-----
A **Host** provides access to the available audio devices on the system.
Some platforms have more than one host available, e.g.
wasapi/asio/dsound on windows, alsa/pulse/jack on linux and so on. As a
result, some audio devices are only available on certain hosts, while
others are only available on other hosts. Every platform supported by
CPAL has at least one **DefaultHost** that is guaranteed to be available
(alsa, wasapi and coreaudio). Currently, the default hosts are the only
hosts supported by CPAL, however this will change as of landing #221 (cc
@freesig). These changes should also accommodate support for other hosts
such as jack #250 (cc @derekdreery) and pulseaudio (cc @knappador) #259.
This introduces a suite of traits allowing for both compile time and
runtime dispatch of different hosts and their uniquely associated device
and event loop types.
A new private **host** module has been added containing the individual
host implementations, each in their own submodule gated to the platforms
on which they are available.
A new **platform** module has been added containing platform-specific
items, including a dynamically dispatched host type that allows for
easily switching between hosts at runtime.
The **ALL_HOSTS** slice contains a **HostId** for each host supported on
the current platform. The **available_hosts** function produces a
**HostId** for each host that is currently *available* on the platform.
The **host_from_id** function allows for initialising a host from its
associated ID, failing with a **HostUnavailable** error. The
**default_host** function returns the default host and should never
fail.
Please see the examples for a demonstration of the change in usage. For
the most part, things look the same at the surface level, however the
role of device enumeration and creating the event loop have been moved
from global functions to host methods. The enumerate.rs example has been
updated to enumerate all devices for each host, not just the default.
**TODO**
- [x] Add the new **Host** API
- [x] Update examples for the new API.
- [x] ALSA host
- [ ] WASAPI host
- [ ] CoreAudio host
- [ ] Emscripten host **Follow-up PR**
- [ ] ASIO host #221
cc @ishitatsuyuki more to review for you if you're interested, but it
might be easier after #288 lands and this gets rebased.
This commit significantly refactors the alsa backend's `EventLoop::run`
implementation in order to allow for better error handling throughout
the loop. This removes many cases that would previously `panic!` in
favour of calling the user callback with the necessary error and
removing the corrupt stream. Seeing as the method cannot return, a
catch-all `panic!` still exists at the end of the method, however this
refactor should make it much easier to remove this restriction in the
future.
This adds the following types:
- `StreamEvent`
- `CloseStreamCause`
- `StreamError`
These allow for notifying the user of the following events:
- A stream has been played.
- A stream has been paused.
- A stream has been closed due to user destroying stream.
- A stream has been closed due to an error.
This allows for properly handling potential failure on macOS. We should
also consider propagating the mutex/channel poison errors through these
new types, especially considering the potential removal of the event
loop in favour of switching over to high-priority audio threads on
windows and linux.
The coreaudio and wasapi backends may both potentially fail to produce
the name associated with a device. This changes the API to allow for
returning the errors in these cases.
See the documentation for both new errors for details.
The new `DevicesError` has been added to allow for returning errors when
enumerating devices. This has allowed to remove multiple potential
`panic!`s in each of the alsa, coreaudio and wasapi backends.
Since #269 this `panic!` is certainly unnecessary as `InputBuffer` and
`OutputBuffer` are a thin wrapper around a slice. That said, I'm
struggling to understand exactly why this `panic!` was necessary in the
first place.
This closes#228.
- ALSA backend: reuse the buffers
- Make `InputBuffer` and `OutputBuffer` types just a wrapper of slice
* Buffer is now submitted at the end of callback
The internal alsa, null and emscripten Device implementations already
implemented Debug; but the coreaudio and wasapi ones, and therefore
also the wrapper, did not.
I decided to eschew the `Device(…)` wrapping in the outer layer
(hence a custom implementation rather than `#[derive(Debug)]`),
because `Device(Device)`, `Device(Device { … })` and so forth all
look better without the extra `Device(…)` wrapping.
On the wasapi and coreaudio implementations I put both the pointer and
name. Name because it’s useful, pointer because on Windows at least
I believe duplicated names are possible. (e.g. two monitors that include
monitors, of the same type; I haven’t strictly confirmed this, because I
killed those off harshly on my machine and don’t want to reinstate
them.)
I do not have access to a macOS device to confirm that the coreaudio
implementation is sane, but I think it is.
Instead of taking the easy way out and killing the whole program by panicking, device enumeration and stream creation will now report the error variant 'Unknown'