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.