we *really* should not paper over underruns, as they require attention.
however, the previous attempt (c2a6b6e) caused an exception to be thrown
(see #130), which was a bit excessive, and was consequently reverted
(438e52e).
so instead we make the handling consistent with what we do in read():
return the verbatim -EPIPE in this case. this can be simply ignored, and
the next write will resume the stream, so this is mostly backwards-
compatible (the failing write will be discarded and would need
repeating, but that will just cause a skip after the interruption,
which does not seem particularly relevant).
as a drive-by, again stop using snd_pcm_recover(), as it still just
obfuscates the snd_pcm_prepare() call it does in the end.
the `else` branch of the return value handling cascade got lost in
commit 438e52e, leading to us returning None on success.
rather than restoring the old code exactly, delay the construction
of the final return code object. this is more consistent with
alsapcm_read() and overall nicer.
this came from 438e52e, which tried to partially revert c2a6b6e, but
inserted a chunk that actually belonged to alsapcm_drop(). the latter
does not need to be restored, as we now handle SND_PCM_STATE_SETUP prior
to reading/writing.
my commit c2a6b6e broke it big time; we'd now just paper over overruns.
:}
the previous handling was fundamentally correct, needing only two
adjustments:
- to recover from drop()/drain(), we need to call snd_pcm_prepare() when
the stream state is SND_PCM_STATE_SETUP. notably, we must not do this
when the state is SND_PCM_STATE_XRUN.
- we should error-check the unlikely case that the recovery from an xrun
fails.
that way we now have two snd_pcm_prepare() call sites in read(), which
looks a bit messy, but it's actually correct.
as a drive-by, simplify the return value check of snd_pcm_prepare() -
values higher than zero are impossible.
[Revisionist Note] This is a squashed commit formed from commits
f374adb, 3743cf5, and cd44517, still found in the main-pre-rewrite
branch. It incorporates a suggestion from PR #134.
This issue can be worked around by calling mixer.handleevents() before
calling mixer.getvolume(), but it makes more sense to handle all events
before returning the volume.
in principle, the state is already available from info(), but that's a
rather heavy function for something one might want to query often.
a practical use case might be checking whether a playback stream is done
draining, for example.
for playback, this allows making sure that all written frames are
played, without using an external delay.
in principle, it's also usable for capture, but there isn't really a
practical reason to do so, as simply discarding excess captured frames
has no real cost.
the period count is just as important for playback latency as the period
size, so it makes no sense to have only one of them configurable.
as a drive-by, fix up the handling of periods in info() & dumpinfo().
perform it prior to invoking read()/write() if necessary, not right
after a failure event. this makes things more uniform and predictable.
we don't use snd_pcm_recover() any more, as we used it only for the
EPIPE case anyway, which boils down to snd_pcm_prepare() exactly.
handling ESTRPIPE as well might be desirable, but that's a separate
consideration.
this removes lots of casts around snd_pcm_hw_params_get_*() calls
we could go further with that to make the code clean if we enabled all
the warnings, but it doesn't seem worth the effort.
it's been obsolete for a *long* time, and having it redundantly to the
rst sources is bad hygiene. it still contained some useful info, which
has been transplanted to the rst source in the previous commit.
in case of error, alsamixer_new() would leak the object, while
alsamixer_list() might crash due to a null pointer.
as a drive-by, make alsamixer_gethandle() `static`.
commit 8abf06be introduced a pause() prior to draining, in an attempt
to work around clearly broken pulseaudio client behavior for capture
streams (drain() is supposed to imply a stop).
but as the workaround was also applied to playback streams, it would
cause nasty "clicks", as the stream would (obviously) stop before being
resumed for draining.
but draining is actually pointless for capture streams, as we're closing
right afterwards, so the samples are lost anyway.
what's more, destructors are not supposed to wait for anything, so
draining in alsapcm_dealloc() was wrong to start with. so we remove it.
note that this is a minor behavior change, which is reflected by the
adjustment of the playback test to have an explicit close() at the end.
finally, close() was also affected by the pulseaudio bug (which was not
addressed before), so there we make draining exclusive to playback
streams.
* First version documentation PCM.info() method.
* Add reference to documentation to docstring for PCM.info() method.
* Add extra fields to info dict:
card_no *index of card* integer (negative indicates device not associable with a card)
device_no *index of PCM device* integer
subdevice_no *index of PCM subdevice* integer
and update documentation accordingly.
Co-authored-by: Ronald van Elburg <Ronald@SoundAppraisal.eu>
* alsamixer_getvolume: Fix incorrect parenthesis
The pcmtypeobj check is overriding the pcmtype if the object is not NULL
or Py_None, making it impossible to get the playback volume. Fix the
paranthesis so that pcmtype is only overwritten when pcmtypeobj is not
set.
* Fix indentation format
Fix the indentation format to match the rest of the project.1
Co-authored-by: Portia <portia.stephens@biamp.com>
* Use `pcmtype` keyword for range
Update methods that accept a `direction` argument (i.e.
capture/playback) to get this via positional _or_ keyword arguments.
Code using keyword arguments can be more robust; however the main reason
for this change is to prepare the way for an extra `units` argument to
many of these methods.
Update documentation to consistently use `pcmtype` instead of
a mixture of that and `direction`.
* Support units