forked from auracaster/pyalsaaudio
* fix draining/closing, take 2 commit8abf06beintroduced 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. * fix memory leaks in *_polldescriptors() the calloc'd pollfd arrays were not freed. * fix memory handling in mixer access error paths 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`. * fix crashes when accessing already closed devices PCM.htimestamp() gets the usual exception emission, Mixer.close() gets a "double invocation" check like PCM.close() has. * fix deprecation warning about PyEval_InitThreads() PyEval_InitThreads is a no-op in since python 3.9. * fix deprecation warning about PyUnicode_AsUnicode() converting to ascii for the purpose of comparison is inefficient. * remove redundant snd_pcm_hw_params_any() call we just called it (and even error-checked it) a few lines above. * add new high-speed samples rates closes #89 (but alsa doesn't support 768khz yet). * drop some pointless comments from the tex => sphinx conversion amends5c2a00655. * remove bogus markup from the documentation the poll objects are linked properly in a different way, and the footnote appears outdated. * unify line spacing in .rst files one empty line, except for high-level sections, which get two. while at it, trim whitespace on otherwise empty lines. * formatting/language fixes in introduction document * improve terminology document mention xruns, and rework the definition of periods: concentrate on relevant information, and remove the misinformation about period size reduction being not that bad (pedantically, an application could run somewhat asynchronously to the interrupts by using some timer, and therefore actually save some of the overhead, but why would one use a small period size in the first place then?). also, language and formatting fixes. * add missing and update incorrect/outdated documentation for clarity, this includes docs which were previously omitted (presumably) intentionally, but mark them as comments. the getrec() and getmute() functions' docs are moved around, so they appear in pairs with their set*() counterparts, like the *volume() ones already did. notably, this also fixes the docu of PCM_FORMAT_U8, which closes #104. * add some best practices to the docu addresses #110, among other things. * purge pydoc from the source 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. * use data types closer to those of ALSA 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. * reduce scope of GIL releases it's pointless to enclose snd_pcm_close() and snd_pcm_pause(), as these calls don't sleep. * reshuffle XRUN recovery somewhat 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. * bump (minor) version we're about to add new features. * make period count configurable 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(). * add PCM.drain() 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. * add PCM.state() and associated enum values 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.
92 lines
3.7 KiB
ReStructuredText
92 lines
3.7 KiB
ReStructuredText
****************************
|
|
PCM Terminology and Concepts
|
|
****************************
|
|
|
|
In order to use PCM devices it is useful to be familiar with some concepts and
|
|
terminology.
|
|
|
|
Sample
|
|
PCM audio, whether it is input or output, consists of *samples*.
|
|
A single sample represents the amplitude of one channel of sound
|
|
at a certain point in time. A lot of individual samples are
|
|
necessary to represent actual sound; for CD audio, 44100 samples
|
|
are taken every second.
|
|
|
|
Samples can be of many different sizes, ranging from 8 bit to 64
|
|
bit precision. The specific format of each sample can also vary -
|
|
they can be big endian byte integers, little endian byte integers, or
|
|
floating point numbers.
|
|
|
|
Musically, the sample size determines the dynamic range. The
|
|
dynamic range is the difference between the quietest and the
|
|
loudest signal that can be reproduced.
|
|
|
|
Frame
|
|
A frame consists of exactly one sample per channel. If there is only one
|
|
channel (Mono sound) a frame is simply a single sample. If the sound is
|
|
stereo, each frame consists of two samples, etc.
|
|
|
|
Frame size
|
|
This is the size in bytes of each frame. This can vary a lot: if each sample
|
|
is 8 bits, and we're handling mono sound, the frame size is one byte.
|
|
For six channel audio with 64 bit floating point samples, the frame size
|
|
is 48 bytes.
|
|
|
|
Rate
|
|
PCM sound consists of a flow of sound frames. The sound rate controls how
|
|
often the current frame is replaced. For example, a rate of 8000 Hz
|
|
means that a new frame is played or captured 8000 times per second.
|
|
|
|
Data rate
|
|
This is the number of bytes which must be consumed or provided per
|
|
second at a certain frame size and rate.
|
|
|
|
8000 Hz mono sound with 8 bit (1 byte) samples has a data rate of
|
|
8000 \* 1 \* 1 = 8 kb/s or 64kbit/s. This is typically used for telephony.
|
|
|
|
At the other end of the scale, 96000 Hz, 6 channel sound with 64
|
|
bit (8 bytes) samples has a data rate of 96000 \* 6 \* 8 = 4608
|
|
kb/s (almost 5 MB sound data per second).
|
|
|
|
If the data rate requirement is not met, an overrun (on capture) or
|
|
underrun (on playback) occurs; the term "xrun" is used to refer to
|
|
either event.
|
|
|
|
.. _term-period:
|
|
|
|
Period
|
|
The CPU processes sample data in chunks of frames, so-called periods
|
|
(also called fragments by some systems). The operating system kernel's
|
|
sample buffer must hold at least two periods (at any given time, one
|
|
is processed by the sound hardware, and one by the CPU).
|
|
|
|
The completion of a *period* triggers a CPU interrupt, which causes
|
|
processing and context switching overhead. Therefore, a smaller period
|
|
size causes higher CPU resource usage at a given data rate.
|
|
|
|
A bigger size of the *buffer* improves the system's resilience to xruns.
|
|
The buffer being split into a bigger number of smaller periods also does
|
|
that, as it allows it to be drained / topped up sooner.
|
|
|
|
On the other hand, a bigger size of the *buffer* also increases the
|
|
playback latency, that is, the time it takes for a frame from being
|
|
sent out by the application to being actually audible.
|
|
|
|
Similarly, a bigger *period* size increases the capture latency.
|
|
|
|
The trade-off between latency, xrun resilience, and resource usage
|
|
must be made depending on the application.
|
|
|
|
Period size
|
|
This is the size of each period in frames. *Not bytes, but frames!*
|
|
In :mod:`alsaaudio` the period size is set directly, and it is
|
|
therefore important to understand the significance of this
|
|
number. If the period size is configured to for example 32,
|
|
each write should contain exactly 32 frames of sound data, and each
|
|
read will return either 32 frames of data or nothing at all.
|
|
|
|
Once you understand these concepts, you will be ready to use the PCM API. Read
|
|
on.
|
|
|
|
|