Compare commits

...

32 Commits
0.9.0 ... 0.9.2

Author SHA1 Message Date
Lars Immisch
279760add5 Prepare release 0.9.2 2022-05-06 21:33:41 +02:00
Portia Stephens
59a712c486 alsamixer_getvolume: Fix incorrect parenthesis (#112)
* 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>
2022-05-06 21:28:36 +02:00
Lars Immisch
dfda54642d Prepare 0.9.1 2022-05-03 20:04:26 +01:00
Chris Diamand
3f6fb9844d Support decibel, percentage, and raw volumes in getvolume, setvolume, and getrange (#109)
* 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
2022-03-28 21:46:40 +02:00
Lars Immisch
4d9f6e5b50 Merge pull request #108 from st8ed/fix-polldescriptors
Fix polldescriptors() data types
2022-01-25 15:17:39 +01:00
Kirill Konstantinov
40a4a36b1d Fix polldescriptors() data types 2022-01-25 14:23:21 +03:00
Lars Immisch
38ea69bbaa Merge pull request #100 from soundappraisal/feature_timestamp_mode_and_type
Feature timestamp mode and type
2021-04-12 12:30:23 +02:00
Ronald van Elburg
c8f3916337 On phys_from_sound: Small memory management fixes and code simplification. And add documentation on new functionality. 2021-04-11 15:16:03 +02:00
Ronald van Elburg
f19af8eba0 Remove recordtestchanges. 2021-04-07 12:12:10 +02:00
Ronald van Elburg
b8980d992b Remove recordtestchanges. 2021-04-07 12:10:21 +02:00
Ronald van Elburg
ebd2b5359d Add function to set timestamp mode and type. Add a function to get the alsa version. 2021-04-07 11:59:16 +02:00
Ronald van Elburg
c5f22fd7e0 Second version enable timestamps 2021-04-06 22:48:17 +02:00
Ronald van Elburg
3c3f0af74a First version enable timestamps 2021-04-06 14:31:45 +02:00
Ronald van Elburg
17f3b440cc Show new functions in recordtest.py 2021-04-06 09:09:49 +02:00
Lars Immisch
b2a303121a Merge pull request #98 from soundappraisal/add_timestamp_function
Add timestamp_raw function
2021-04-04 16:27:26 +02:00
Ronald van Elburg
3168833b4e Merge remote-tracking branch 'upstream/master' into add_timestamp_function
# Conflicts:
#	alsaaudio.c
2021-04-02 22:54:18 +02:00
Lars Immisch
c74669850b Merge pull request #92 from soundappraisal/pcm_info_function
Add an PCM.info function: returns pcm properties as a dict
2021-04-02 20:57:15 +02:00
Ronald van Elburg
1a4c0541d7 Change name timestamp_raw fuinction to htimestamp to follow the convention used in the rest of the library: that's the current convention (prefix the name with alsapcm_ for PCM methods). 2021-04-02 13:42:51 +02:00
Ronald van Elburg
e6a6445375 Move creation of dictionary to a point after error handling, when it is relatively certain that the function will succeed.
(cherry picked from commit 1820716a4bc018bb903b95bcf5d7cf83a5ebda9c)
2021-04-02 13:24:55 +02:00
Ronald van Elburg
97f2abcb30 Remove debugging print statement.
(cherry picked from commit dcc43f3da7bf4d083cc6cab18ae464261fadc53f)
2021-04-02 13:24:55 +02:00
Ronald van Elburg
a53ffd0d4f Fix potential memory leaks on new info function.
(cherry picked from commit ade9dd5923edd65c1fcdf2298e8ad024daf66e2a)
2021-04-02 13:24:55 +02:00
Ronald van Elburg
da71e01f9c Remove unused code from timestamp_raw function. 2021-03-31 16:27:55 +02:00
Ronald van Elburg
f6736ec43a first version timestamp function
(cherry picked from commit 21d0527c7b91723b3bfc87ea889bd599dff12576)

# Conflicts:
#	alsaaudio.c
2020-11-02 19:32:34 +01:00
Ronald van Elburg
e48b294b84 PCM.info function: added format, mode and type fields. Also added a doc string describing the info function. 2020-10-28 22:01:04 +01:00
Lars Immisch
d037297632 Merge pull request #91 from soundappraisal/master
Fix #51: Only return valid part of the buffer in the read function
2020-10-27 12:47:36 +01:00
Ronald van Elburg
c8e7261e94 Add an PCM.info function returning the information now printed by dumpinfo as a dictionary. Removed double entry from dumpinfo. 2020-10-27 12:41:59 +01:00
Ronald van Elburg
5c481b4094 Fix #51: Only return valid part of the buffer in the read function; avoid unnecesssary work by only changing size when needed 2020-09-30 15:58:19 +02:00
Ronald van Elburg
1e3c7f3fd0 Fix #51: Only return valid part of the buffer in the read function 2020-09-30 15:11:10 +02:00
Lars Immisch
0ae60f80f3 Better pcm_type deduction in alsamixer_getvolume
Closes #87
2020-07-16 23:36:50 +02:00
Lars Immisch
4018ab4f6c Fix copypasta. 2020-07-16 23:36:12 +02:00
Lars Immisch
07f84a8e95 Move CHANGES to markdown, remove NOTES.md (doc/README.md replaces it) 2020-07-13 22:27:06 +02:00
Lars Immisch
d83e829de1 Formatting and fixed upload description. 2020-07-13 22:18:32 +02:00
9 changed files with 747 additions and 118 deletions

5
.gitignore vendored
View File

@@ -8,4 +8,7 @@ doc/_build/
gh-pages/
build/
dist/
.vscode/
.vscode/
/__pycache__/
/pyalsaaudio.egg-info/
*.raw

View File

@@ -1,99 +1,103 @@
Version 0.8.6:
- Added four methods to the 'PCM' class to allow users to get detailed information about the device:
# Version 0.9.2
- Fix alsamixer_getvolume (#112 from @stephensp)
- 'getformats()' returns a dictionary of name / value pairs, one for each of the card's
supported formats - e.g. '{"U8": 1, "S16_LE": 2}',
- 'getchannels()' returns a list of the supported channel numbers, e.g. '[1, 2]',
- 'getrates()' returns supported sample rates for the device, e.g. '[48000]',
- 'getratebounds()' returns the device's official minimum and maximum supported
sample rates as a tuple, e.g. '(4000, 48000)'.
# Version 0.9.1:
- Support decibel, percentage, and raw volumes in getvolume, setvolume, and getrange (#109 from @chrisdiamand)
# Version 0.9.0:
- Added keyword arguments for channels, format, rate and periodsize
- Deprecated `setchannel`, `setformat`, `setrate` and `setperiodsize`
# Version 0.8.6:
- Added four methods to the `PCM` class to allow users to get detailed information about the device:
- `getformats()` returns a dictionary of name / value pairs, one for each of the card's
supported formats - e.g. `{"U8": 1, "S16_LE": 2}`,
- `getchannels()` returns a list of the supported channel numbers, e.g. `[1, 2]`,
- `getrates()` returns supported sample rates for the device, e.g. `[48000]`,
- `getratebounds()` returns the device's official minimum and maximum supported
sample rates as a tuple, e.g. `(4000, 48000)`.
(#82 contributed by @jdstmporter)
- Prevent hang on close after capturing audio (#80 contributed by @daym)
Version 0.8.5:
- Return an empty string/bytestring when 'read()' detects an
# Version 0.8.5:
- Return an empty string/bytestring when `read()` detects an
overrun. Previously the returned data was undefined (contributed by @jcea)
- Unlimited setperiod buffer size when reading frames (contributed by @jcea)
Version 0.8.4:
# Version 0.8.4:
- Fix Python3 API usage broken in 0.8.3
Version 0.8.3:
# Version 0.8.3:
- Add DSD sample formats (contributed by @lintweaker)
- Add Mixer.handleevents() to acknowledge events identified by select.poll (contributed by @PaulSD)
- Add functions for listing cards and their names (contributed by @chrisdiamand)
- Add a method for setting enums (contributed by @chrisdiamand)
Version 0.8.2:
# Version 0.8.2:
- fix #3 (we cannot get the revision from git for pip installs)
Version 0.8.1:
# Version 0.8.1:
- document changes (this file)
Version 0.8:
- 'PCM()' has new 'device' and 'cardindex' keyword arguments.
# Version 0.8:
- `PCM()` has new `device` and `cardindex` keyword arguments.
The keyword 'device' allows to select virtual devices, 'cardindex' can be
used to select hardware cards by index (as with 'mixers()' and 'Mixer()').
The keyword `device` allows to select virtual devices, `cardindex` can be
used to select hardware cards by index (as with `mixers()` and `Mixer()`).
The 'card' keyword argument is still supported, but deprecated.
The `card` keyword argument is still supported, but deprecated.
The reason for this change is that the 'card' keyword argument guessed
The reason for this change is that the `card` keyword argument guessed
a device name from the card name, but this only works sometimes, and breaks
opening virtual devices.
- new function 'pcms()' to list available PCM devices.
- new function `pcms()` to list available PCM devices.
- mixers() and Mixer() take an additional 'device' keyword argument.
- `mixers()` and `Mixer()` take an additional `device` keyword argument.
This allows to list or open virtual devices.
- The default behaviour of Mixer() without any arguments has changed.
Now Mixer() will try to open the 'default' Mixer instead of the Mixer
- The default behaviour of `Mixer()` without any arguments has changed.
Now Mixer() will try to open the `default` Mixer instead of the Mixer
that is associated with card 0.
- fix a memory leak under Python 3.x
- some more memory leaks in error conditions fixed.
Version 0.7:
# Version 0.7:
- fixed several memory leaks (patch 3372909), contributed by Erik Kulyk)
Version 0.6:
# Version 0.6:
- mostly reverted patch 2594366: alsapcm_setup did not do complete error
checking for good reasons; some ALSA functions in alsapcm_setup may fail without
rendering the device unusable
Version 0.5:
# Version 0.5:
- applied patch 2777035: Fixed setrec method in alsaaudio.c
This included a mixertest with more features
- fixed/applied patch 2594366: alsapcm_setup does not do any error checking
Version 0.4:
# Version 0.4:
- API changes: mixers() and Mixer() now take a card index instead of a
card name as optional parameter.
- Support for Python 3.0
- Documentation converted to reStructuredText; use Sphinx instead of LaTeX.
- added cards()
- added PCM.close()
- added Mixer.close()
- added mixer.getenum()
- added `cards()`
- added `PCM.close()`
- added `Mixer.close()`
- added `mixer.getenum()`
Version 0.3:
- wrapped blocking calls with Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS
# Version 0.3:
- wrapped blocking calls with `Py_BEGIN_ALLOW_THREADS`/`Py_END_ALLOW_THREADS`
- added pause
Version 0.2:
# Version 0.2:
- Many bugfixes related to playback in particular
- Module documentation in the doc subdirectory
Version 0.1:
# Version 0.1:
- Initial version

View File

@@ -1,11 +0,0 @@
# Publishing the documentation
- Install Sphinx; `sudo pip install sphinx`
- Clone gh-pages branch: `cd doc; git clone -b gh-pages git@github.com:larsimmisch/pyalsaaudio.git gh-pages`
- `cd doc; make publish`
# Release procedure
- Update version number in setup.py
- Create tag and push it, i.e. `git tag x.y.z; git push origin x.y.z`
- `python setup.py sdist upload -r pypi`

View File

@@ -28,6 +28,7 @@
#include <alsa/asoundlib.h>
#include <alsa/version.h>
#include <stdio.h>
#include <stdbool.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof *(a))
static const snd_pcm_format_t ALSAFormats[] = {
@@ -88,6 +89,12 @@ static const unsigned ALSARates[] = {
192000
};
typedef enum volume_units_t {
VOLUME_UNITS_PERCENTAGE,
VOLUME_UNITS_RAW,
VOLUME_UNITS_DB,
} volume_units_t;
PyDoc_STRVAR(alsaaudio_module_doc,
"This modules provides support for the ALSA audio API.\n"
"\n"
@@ -129,10 +136,13 @@ typedef struct {
unsigned int cchannels;
/* min and max values for playback and capture volumes */
long pmin;
long pmax;
long cmin;
long cmax;
long pmin, pmax;
long cmin, cmax;
/* min and max values for playback and capture volumes, in dB * 100 as
* reported by ALSA */
long pmin_dB, pmax_dB;
long cmin_dB, cmax_dB;
snd_mixer_t *handle;
} alsamixer_t;
@@ -181,6 +191,16 @@ get_pcmtype(PyObject *obj)
return -1;
}
static bool is_value_volume_unit(long unit)
{
if (unit == VOLUME_UNITS_PERCENTAGE ||
unit == VOLUME_UNITS_RAW ||
unit == VOLUME_UNITS_DB) {
return true;
}
return false;
}
static PyObject *
alsacard_list(PyObject *self, PyObject *args)
{
@@ -306,7 +326,7 @@ Return the card name and long name for card 'card_index'.");
static PyObject *
alsapcm_list(PyObject *self, PyObject *args)
alsapcm_list(PyObject *self, PyObject *args, PyObject *kwds)
{
PyObject *pcmtypeobj = NULL;
long pcmtype;
@@ -316,8 +336,11 @@ alsapcm_list(PyObject *self, PyObject *args)
char *name, *io;
const char *filter;
if (!PyArg_ParseTuple(args,"|O:pcms", &pcmtypeobj))
char *kw[] = { "pcmtype", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:pcms", kw, &pcmtypeobj)) {
return NULL;
}
pcmtype = get_pcmtype(pcmtypeobj);
if (pcmtype < 0) {
@@ -602,9 +625,6 @@ alsapcm_dumpinfo(alsapcm_t *self, PyObject *args)
val = snd_pcm_hw_params_get_sbits(hwparams);
printf("significant bits = %d\n", val);
snd_pcm_hw_params_get_period_time(hwparams, &val, &dir);
printf("period time = %d us\n", val);
val = snd_pcm_hw_params_is_batch(hwparams);
printf("is batch = %d\n", val);
@@ -639,6 +659,391 @@ alsapcm_dumpinfo(alsapcm_t *self, PyObject *args)
return Py_None;
}
static PyObject *
alsapcm_info(alsapcm_t *self, PyObject *args)
{
PyObject *info;
PyObject *value;
unsigned int val,val2;
snd_pcm_format_t fmt;
int dir;
snd_pcm_uframes_t frames;
snd_pcm_hw_params_t *hwparams;
snd_pcm_hw_params_alloca(&hwparams);
snd_pcm_hw_params_current(self->handle,hwparams);
if (!PyArg_ParseTuple(args,":info"))
return NULL;
if (!self->handle) {
PyErr_SetString(ALSAAudioError, "PCM device is closed");
return NULL;
}
info = PyDict_New();
value=PyUnicode_FromString(snd_pcm_name(self->handle));
PyDict_SetItemString(info,"name",value);
Py_DECREF(value);
value=PyUnicode_FromString(snd_pcm_state_name(snd_pcm_state(self->handle)));
PyDict_SetItemString(info,"state",value);
Py_DECREF(value);
snd_pcm_hw_params_get_access(hwparams, (snd_pcm_access_t *) &val);
value=PyUnicode_FromString(snd_pcm_access_name((snd_pcm_access_t)val));
PyDict_SetItemString(info,"access_type",value);
Py_DECREF(value);
value = PyLong_FromUnsignedLong((unsigned long) self->pcmtype);
PyDict_SetItemString(info," (call value) type",value);
Py_DECREF(value);
value=PyUnicode_FromString(snd_pcm_stream_name((snd_pcm_stream_t) self->pcmtype));
PyDict_SetItemString(info," (call value) type_name",value);
Py_DECREF(value);
value = PyLong_FromUnsignedLong((unsigned long) self->pcmmode);
PyDict_SetItemString(info," (call value) mode",value);
Py_DECREF(value);
switch(self->pcmmode){
case 0:
value = PyUnicode_FromString("PCM_NORMAL");
break;
case SND_PCM_NONBLOCK:
value = PyUnicode_FromString("PCM_NONBLOCK");
break;
case SND_PCM_ASYNC:
value = PyUnicode_FromString("PCM_ASYNC");
break;
}
PyDict_SetItemString(info," (call value) mode_name",value);
Py_DECREF(value);
snd_pcm_hw_params_get_format(hwparams, &fmt);
value=PyLong_FromUnsignedLong((unsigned long)fmt);
PyDict_SetItemString(info,"format",value);
Py_DECREF(value);
value=PyUnicode_FromString(snd_pcm_format_name(fmt));
PyDict_SetItemString(info,"format_name",value);
Py_DECREF(value);
value=PyUnicode_FromString(snd_pcm_format_description(fmt));
PyDict_SetItemString(info,"format_description",value);
Py_DECREF(value);
snd_pcm_hw_params_get_subformat(hwparams, (snd_pcm_subformat_t *)&val);
value=PyUnicode_FromString(snd_pcm_subformat_name((snd_pcm_subformat_t)val));
PyDict_SetItemString(info,"subformat_name",value);
Py_DECREF(value);
value=PyUnicode_FromString(snd_pcm_subformat_description((snd_pcm_subformat_t)val));
PyDict_SetItemString(info,"subformat_description",value);
Py_DECREF(value);
snd_pcm_hw_params_get_channels(hwparams, &val);
value=PyLong_FromUnsignedLong((unsigned long) val);
PyDict_SetItemString(info,"channels", value);
Py_DECREF(value);
snd_pcm_hw_params_get_rate(hwparams, &val, &dir);
value=PyLong_FromUnsignedLong((unsigned long) val);
PyDict_SetItemString(info,"rate", value);
Py_DECREF(value);
snd_pcm_hw_params_get_period_time(hwparams, &val, &dir);
value=PyLong_FromUnsignedLong((unsigned long) val);
PyDict_SetItemString(info,"period_time", value);
Py_DECREF(value);
snd_pcm_hw_params_get_period_size(hwparams, &frames, &dir);
value=PyLong_FromUnsignedLong((unsigned long) frames);
PyDict_SetItemString(info,"period_size", value);
Py_DECREF(value);
snd_pcm_hw_params_get_buffer_time(hwparams, &val, &dir);
value=PyLong_FromUnsignedLong((unsigned long) val);
PyDict_SetItemString(info,"buffer_time", value);
Py_DECREF(value);
snd_pcm_hw_params_get_buffer_size(hwparams, (snd_pcm_uframes_t *) &val);
value=PyLong_FromUnsignedLong((unsigned long) val);
PyDict_SetItemString(info,"buffer_size", value);
Py_DECREF(value);
snd_pcm_hw_params_get_periods(hwparams, &val, &dir);
value=PyLong_FromUnsignedLong((unsigned long) val);
PyDict_SetItemString(info,"get_periods", value);
Py_DECREF(value);
snd_pcm_hw_params_get_rate_numden(hwparams, &val, &val2);
value=PyTuple_Pack(2,PyLong_FromUnsignedLong((unsigned long) val) \
,PyLong_FromUnsignedLong((unsigned long) val2));
PyDict_SetItemString(info,"rate_numden", value);
Py_DECREF(value);
val = snd_pcm_hw_params_get_sbits(hwparams);
value=PyLong_FromUnsignedLong((unsigned long) val);
PyDict_SetItemString(info,"significant_bits", value);
Py_DECREF(value);
val = snd_pcm_hw_params_is_batch(hwparams);
value=PyBool_FromLong((unsigned long) val);
PyDict_SetItemString(info,"is_batch", value);
Py_DECREF(value);
val = snd_pcm_hw_params_is_block_transfer(hwparams);
value=PyBool_FromLong((unsigned long) val);
PyDict_SetItemString(info,"is_block_transfer", value);
Py_DECREF(value);
val = snd_pcm_hw_params_is_double(hwparams);
value=PyBool_FromLong((unsigned long) val);
PyDict_SetItemString(info,"is_double", value);
Py_DECREF(value);
val = snd_pcm_hw_params_is_half_duplex(hwparams);
value=PyBool_FromLong((unsigned long) val);
PyDict_SetItemString(info,"is_half_duplex", value);
Py_DECREF(value);
val = snd_pcm_hw_params_is_joint_duplex(hwparams);
value=PyBool_FromLong((unsigned long) val);
PyDict_SetItemString(info,"is_joint_duplex", value);
Py_DECREF(value);
val = snd_pcm_hw_params_can_overrange(hwparams);
value=PyBool_FromLong((unsigned long) val);
PyDict_SetItemString(info,"can_overrange", value);
Py_DECREF(value);
val = snd_pcm_hw_params_can_mmap_sample_resolution(hwparams);
value=PyBool_FromLong((unsigned long) val);
PyDict_SetItemString(info,"can_mmap_sample_resolution", value);
Py_DECREF(value);
val = snd_pcm_hw_params_can_pause(hwparams);
value=PyBool_FromLong((unsigned long) val);
PyDict_SetItemString(info,"can_pause", value);
Py_DECREF(value);
val = snd_pcm_hw_params_can_resume(hwparams);
value=PyBool_FromLong((unsigned long) val);
PyDict_SetItemString(info,"can_resume", value);
Py_DECREF(value);
val = snd_pcm_hw_params_can_sync_start(hwparams);
value=PyBool_FromLong((unsigned long) val);
PyDict_SetItemString(info,"can_sync_start", value);
Py_DECREF(value);
return info;
}
PyDoc_STRVAR(pcm_info_doc,
"info() -> dict\n\
\n\
Returns a dictionary with the alsa device parameters as it is realized. \n\
Keys are retrieved from the alsa library if they can be accessed, if not \n\
they represent values stored by pyalsaaudio and they are prefixed with ' (call value) '. \n\
");
static PyObject *
alsa_asoundlib_version(PyObject * module, PyObject *args)
{
if (!PyArg_ParseTuple(args,":asoundlib_version"))
return NULL;
return PyUnicode_FromString(snd_asoundlib_version());
}
PyDoc_STRVAR(asoundlib_version_doc,
"asoundlib_version() -> string\n\
\n\
Returns ALSA version string. \n\
");
static PyObject *
alsapcm_htimestamp(alsapcm_t *self, PyObject *args)
{
snd_htimestamp_t tstamp;
snd_pcm_uframes_t avail;
PyObject *result = NULL;
snd_pcm_htimestamp(self->handle , &avail, &tstamp);
result = PyTuple_New(3);
PyTuple_SetItem(result, 0, PyLong_FromLongLong(tstamp.tv_sec));
PyTuple_SetItem(result, 1, PyLong_FromLong(tstamp.tv_nsec));
PyTuple_SetItem(result, 2, PyLong_FromLong(avail));
return result;
}
PyDoc_STRVAR(htimestamp_doc,
"htimestamp() -> tuple\n\
\n\
Returns a tuple containing the seconds since epoch in the first element \n\
, nanoseconds in the second element, and number of frames available in \n\
the buffer at the time of the time stamp. \n");
static PyObject *
alsapcm_set_tstamp_mode(alsapcm_t *self, PyObject *args)
{
snd_pcm_tstamp_t mode = SND_PCM_TSTAMP_ENABLE;
int err;
if (!PyArg_ParseTuple(args,"|i:set_tstamp_mode", &mode))
return NULL;
if (!self->handle)
{
PyErr_SetString(ALSAAudioError, "PCM device is closed");
return NULL;
}
snd_pcm_sw_params_t* swParams;
snd_pcm_sw_params_alloca( &swParams);
snd_pcm_sw_params_current(self->handle, swParams);
snd_pcm_sw_params_set_tstamp_mode(self->handle, swParams, mode);
err = snd_pcm_sw_params(self->handle, swParams);
if (err < 0) {
PyErr_SetString(PyExc_RuntimeError, "Unable to set pcm tstamp mode!");
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyDoc_STRVAR(set_tstamp_mode_doc,
"set_tstamp_mode() -> None\n\
\n\
Set the timestamp mode of the device. \n");
static PyObject *
alsapcm_get_tstamp_mode(alsapcm_t *self, PyObject *args)
{
snd_pcm_tstamp_t mode;
int err;
if (!PyArg_ParseTuple(args,":get_tstamp_mode"))
return NULL;
if (!self->handle)
{
PyErr_SetString(ALSAAudioError, "PCM device is closed");
return NULL;
}
snd_pcm_sw_params_t* swParams;
snd_pcm_sw_params_alloca( &swParams);
snd_pcm_sw_params_current(self->handle, swParams);
err = snd_pcm_sw_params_get_tstamp_mode(swParams, &mode);
if (err < 0) {
PyErr_SetString(PyExc_RuntimeError, "Unable to get pcm tstamp mode!");
return NULL;
}
return PyLong_FromUnsignedLong((unsigned long) mode);
}
PyDoc_STRVAR(get_tstamp_mode_doc,
"get_tstamp_mode() -> integer \n\
\n\
Get the timestamp mode of the device. \n");
static PyObject *
alsapcm_set_tstamp_type(alsapcm_t *self, PyObject *args)
{
snd_pcm_tstamp_type_t type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
int err;
if (!PyArg_ParseTuple(args,"|i:set_tstamp_type", &type))
return NULL;
if (!self->handle)
{
PyErr_SetString(ALSAAudioError, "PCM device is closed");
return NULL;
}
snd_pcm_sw_params_t* swParams;
snd_pcm_sw_params_alloca( &swParams);
snd_pcm_sw_params_current(self->handle, swParams);
snd_pcm_sw_params_set_tstamp_type(self->handle, swParams, type);
err = snd_pcm_sw_params(self->handle, swParams);
if (err < 0) {
PyErr_SetString(PyExc_RuntimeError, "Unable to set pcm tstamp type!");
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyDoc_STRVAR(set_tstamp_type_doc,
"set_tstamp_type() -> None\n\
\n\
Set the timestamp type of the device. \n");
static PyObject *
alsapcm_get_tstamp_type(alsapcm_t *self, PyObject *args)
{
snd_pcm_tstamp_type_t type;
int err;
if (!PyArg_ParseTuple(args,":get_tstamp_type"))
return NULL;
if (!self->handle)
{
PyErr_SetString(ALSAAudioError, "PCM device is closed");
return NULL;
}
snd_pcm_sw_params_t* swParams;
snd_pcm_sw_params_alloca( &swParams);
snd_pcm_sw_params_current(self->handle, swParams);
err = snd_pcm_sw_params_get_tstamp_type(swParams, &type);
if (err < 0) {
PyErr_SetString(PyExc_RuntimeError, "Unable to get pcm tstamp type!");
return NULL;
}
return PyLong_FromUnsignedLong((unsigned long) type);
}
PyDoc_STRVAR(get_tstamp_type_doc,
"get_tstamp_type() -> int \n\
\n\
Get the timestamp type of the device. \n");
// auxiliary function
@@ -1051,6 +1456,7 @@ alsapcm_read(alsapcm_t *self, PyObject *args)
{
int res;
int size = self->framesize * self->periodsize;
int sizeout = 0;
PyObject *buffer_obj, *tuple_obj, *res_obj;
char *buffer;
@@ -1105,18 +1511,22 @@ alsapcm_read(alsapcm_t *self, PyObject *args)
}
}
if (res <= 0) {
if (res > 0 ) {
sizeout = res * self->framesize;
}
if (size != sizeout) {
#if PY_MAJOR_VERSION < 3
/* If the following fails, it will free the object */
if (_PyString_Resize(&buffer_obj, 0))
if (_PyString_Resize(&buffer_obj, sizeout))
return NULL;
#else
/* If the following fails, it will free the object */
if (_PyBytes_Resize(&buffer_obj, 0))
if (_PyBytes_Resize(&buffer_obj, sizeout))
return NULL;
#endif
}
res_obj = PyLong_FromLong(res);
if (!res_obj) {
Py_DECREF(buffer_obj);
@@ -1345,7 +1755,7 @@ alsapcm_polldescriptors(alsapcm_t *self, PyObject *args)
for (i = 0; i < count; ++i)
{
PyList_SetItem(result, i,
Py_BuildValue("II", fds[i].fd, fds[i].events));
Py_BuildValue("ih", fds[i].fd, fds[i].events));
}
return result;
@@ -1370,7 +1780,13 @@ static PyMethodDef alsapcm_methods[] = {
{"setformat", (PyCFunction)alsapcm_setformat, METH_VARARGS, setformat_doc},
{"setperiodsize", (PyCFunction)alsapcm_setperiodsize, METH_VARARGS,
setperiodsize_doc},
{"htimestamp", (PyCFunction) alsapcm_htimestamp, METH_VARARGS, htimestamp_doc},
{"set_tstamp_type", (PyCFunction) alsapcm_set_tstamp_type, METH_VARARGS, set_tstamp_type_doc},
{"set_tstamp_mode", (PyCFunction) alsapcm_set_tstamp_mode, METH_VARARGS, set_tstamp_mode_doc},
{"get_tstamp_type", (PyCFunction) alsapcm_get_tstamp_type, METH_VARARGS, get_tstamp_type_doc},
{"get_tstamp_mode", (PyCFunction) alsapcm_get_tstamp_mode, METH_VARARGS, get_tstamp_mode_doc},
{"dumpinfo", (PyCFunction)alsapcm_dumpinfo, METH_VARARGS},
{"info", (PyCFunction)alsapcm_info, METH_VARARGS, pcm_info_doc},
{"getformats", (PyCFunction)alsapcm_getformats, METH_VARARGS, getformats_doc},
{"getratebounds", (PyCFunction)alsapcm_getratemaxmin, METH_VARARGS, getratebounds_doc},
{"getrates", (PyCFunction)alsapcm_getrates, METH_VARARGS, getrates_doc},
@@ -1385,6 +1801,12 @@ static PyMethodDef alsapcm_methods[] = {
{NULL, NULL}
};
static PyMethodDef alsa_methods[] = {
{"asoundlib_version", (PyCFunction) alsa_asoundlib_version, METH_VARARGS, asoundlib_version_doc},
{NULL, NULL}
};
#if PY_VERSION_HEX < 0x02020000
static PyObject *
alsapcm_getattr(alsapcm_t *self, char *name) {
@@ -1680,6 +2102,8 @@ alsamixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
snd_mixer_selem_get_playback_volume_range(elem, &self->pmin, &self->pmax);
snd_mixer_selem_get_capture_volume_range(elem, &self->cmin, &self->cmax);
snd_mixer_selem_get_playback_dB_range(elem, &self->pmin_dB, &self->pmax_dB);
snd_mixer_selem_get_capture_dB_range(elem, &self->cmin_dB, &self->cmax_dB);
return (PyObject *)self;
}
@@ -1951,18 +2375,22 @@ static long alsamixer_getphysvolume(long min, long max, int percentage)
}
static PyObject *
alsamixer_getvolume(alsamixer_t *self, PyObject *args)
alsamixer_getvolume(alsamixer_t *self, PyObject *args, PyObject *kwds)
{
snd_mixer_elem_t *elem;
int channel;
long ival;
PyObject *pcmtypeobj = NULL;
long pcmtype;
int iunits = VOLUME_UNITS_PERCENTAGE;
PyObject *result;
PyObject *item;
if (!PyArg_ParseTuple(args,"|O:getvolume", &pcmtypeobj))
char *kw[] = { "pcmtype", "units", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:getvolume", kw, &pcmtypeobj, &iunits)) {
return NULL;
}
if (!self->handle)
{
@@ -1975,28 +2403,65 @@ alsamixer_getvolume(alsamixer_t *self, PyObject *args)
return NULL;
}
if (!is_value_volume_unit(iunits)) {
PyErr_SetString(ALSAAudioError, "Invalid volume units");
return NULL;
}
volume_units_t units = iunits;
elem = alsamixer_find_elem(self->handle,self->controlname,self->controlid);
if (!pcmtypeobj || (pcmtypeobj == Py_None)) {
if (self->pchannels) {
pcmtype = SND_PCM_STREAM_PLAYBACK;
}
else {
pcmtype = SND_PCM_STREAM_CAPTURE;
}
}
result = PyList_New(0);
for (channel = 0; channel <= SND_MIXER_SCHN_LAST; channel++) {
if (pcmtype == SND_PCM_STREAM_PLAYBACK &&
snd_mixer_selem_has_playback_channel(elem, channel))
{
snd_mixer_selem_get_playback_volume(elem, channel, &ival);
item = PyLong_FromLong(alsamixer_getpercentage(self->pmin,
self->pmax,
ival));
switch (units)
{
case VOLUME_UNITS_PERCENTAGE:
snd_mixer_selem_get_playback_volume(elem, channel, &ival);
ival = alsamixer_getpercentage(self->pmin, self->pmax, ival);
break;
case VOLUME_UNITS_RAW:
snd_mixer_selem_get_playback_volume(elem, channel, &ival);
break;
case VOLUME_UNITS_DB:
snd_mixer_selem_get_playback_dB(elem, channel, &ival);
break;
}
item = PyLong_FromLong(ival);
PyList_Append(result, item);
Py_DECREF(item);
}
else if (pcmtype == SND_PCM_STREAM_CAPTURE
&& snd_mixer_selem_has_capture_channel(elem, channel)
&& snd_mixer_selem_has_capture_volume(elem)) {
snd_mixer_selem_get_capture_volume(elem, channel, &ival);
item = PyLong_FromLong(alsamixer_getpercentage(self->cmin,
self->cmax,
ival));
switch (units)
{
case VOLUME_UNITS_PERCENTAGE:
snd_mixer_selem_get_capture_volume(elem, channel, &ival);
ival = alsamixer_getpercentage(self->cmin, self->cmax, ival);
break;
case VOLUME_UNITS_RAW:
snd_mixer_selem_get_capture_volume(elem, channel, &ival);
break;
case VOLUME_UNITS_DB:
snd_mixer_selem_get_capture_dB(elem, channel, &ival);
break;
}
item = PyLong_FromLong(ival);
PyList_Append(result, item);
Py_DECREF(item);
}
@@ -2018,13 +2483,17 @@ if the mixer has this capability, otherwise PCM_CAPTURE");
static PyObject *
alsamixer_getrange(alsamixer_t *self, PyObject *args)
alsamixer_getrange(alsamixer_t *self, PyObject *args, PyObject *kwds)
{
snd_mixer_elem_t *elem;
PyObject *pcmtypeobj = NULL;
int iunits = VOLUME_UNITS_RAW;
long pcmtype;
long min = -1, max = -1;
if (!PyArg_ParseTuple(args,"|O:getrange", &pcmtypeobj)) {
char *kw[] = { "pcmtype", "units", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:getrange", kw, &pcmtypeobj, &iunits)) {
return NULL;
}
@@ -2039,6 +2508,12 @@ alsamixer_getrange(alsamixer_t *self, PyObject *args)
return NULL;
}
if (!is_value_volume_unit(iunits)) {
PyErr_SetString(ALSAAudioError, "Invalid volume units");
return NULL;
}
volume_units_t units = iunits;
elem = alsamixer_find_elem(self->handle, self->controlname,
self->controlid);
@@ -2056,7 +2531,22 @@ alsamixer_getrange(alsamixer_t *self, PyObject *args)
{
if (snd_mixer_selem_has_playback_channel(elem, 0))
{
return Py_BuildValue("[ii]", self->pmin, self->pmax);
switch (units)
{
case VOLUME_UNITS_PERCENTAGE:
min = 0;
max = 100;
break;
case VOLUME_UNITS_RAW:
min = self->pmin;
max = self->pmax;
break;
case VOLUME_UNITS_DB:
min = self->pmin_dB;
max = self->pmax_dB;
break;
}
return Py_BuildValue("[ii]", min, max);
}
PyErr_Format(ALSAAudioError, "Mixer %s,%d has no playback channel [%s]",
@@ -2067,7 +2557,22 @@ alsamixer_getrange(alsamixer_t *self, PyObject *args)
{
if (snd_mixer_selem_has_capture_channel(elem, 0)
&& snd_mixer_selem_has_capture_volume(elem)) {
return Py_BuildValue("[ii]", self->cmin, self->cmax);
switch (units)
{
case VOLUME_UNITS_PERCENTAGE:
min = 0;
max = 100;
break;
case VOLUME_UNITS_RAW:
min = self->cmin;
max = self->cmax;
break;
case VOLUME_UNITS_DB:
min = self->cmin_dB;
max = self->cmax_dB;
break;
}
return Py_BuildValue("[ii]", min, max);
}
PyErr_Format(ALSAAudioError, "Mixer %s,%d has no capture channel "
@@ -2086,7 +2591,7 @@ PyDoc_STRVAR(getrange_doc,
\n\
Returns a list of tuples with the volume range (ints).\n\
\n\
The optional 'direction' argument can be either PCM_PLAYBACK or\n\
The optional 'pcmtype' argument can be either PCM_PLAYBACK or\n\
PCM_CAPTURE, which is relevant if the mixer can control both\n\
playback and capture volume. The default value is 'playback'\n\
if the mixer has this capability, otherwise 'capture'");
@@ -2340,7 +2845,7 @@ This method will fail if the mixer has no capture switch capabilities.");
static PyObject *
alsamixer_setvolume(alsamixer_t *self, PyObject *args)
alsamixer_setvolume(alsamixer_t *self, PyObject *args, PyObject *kwds)
{
snd_mixer_elem_t *elem;
int i;
@@ -2348,16 +2853,14 @@ alsamixer_setvolume(alsamixer_t *self, PyObject *args)
int physvolume;
PyObject *pcmtypeobj = NULL;
long pcmtype;
int iunits = VOLUME_UNITS_PERCENTAGE;
int channel = MIXER_CHANNEL_ALL;
int done = 0;
if (!PyArg_ParseTuple(args,"l|iO:setvolume", &volume, &channel,
&pcmtypeobj))
return NULL;
char *kw[] = { "volume", "channel", "pcmtype", "units", NULL };
if (volume < 0 || volume > 100)
{
PyErr_SetString(ALSAAudioError, "Volume must be between 0 and 100");
if (!PyArg_ParseTupleAndKeywords(args, kwds, "l|iOi:setvolume", kw, &volume,
&channel, &pcmtypeobj, &iunits)) {
return NULL;
}
@@ -2366,6 +2869,18 @@ alsamixer_setvolume(alsamixer_t *self, PyObject *args)
return NULL;
}
if (!is_value_volume_unit(iunits)) {
PyErr_SetString(ALSAAudioError, "Invalid volume units");
return NULL;
}
volume_units_t units = iunits;
if (units == VOLUME_UNITS_PERCENTAGE && (volume < 0 || volume > 100))
{
PyErr_SetString(ALSAAudioError, "Volume out of range");
return NULL;
}
if (!self->handle)
{
PyErr_SetString(ALSAAudioError, "Mixer is closed");
@@ -2388,18 +2903,40 @@ alsamixer_setvolume(alsamixer_t *self, PyObject *args)
{
if (pcmtype == SND_PCM_STREAM_PLAYBACK &&
snd_mixer_selem_has_playback_channel(elem, i)) {
physvolume = alsamixer_getphysvolume(self->pmin,
self->pmax, volume);
snd_mixer_selem_set_playback_volume(elem, i, physvolume);
switch (units)
{
case VOLUME_UNITS_PERCENTAGE:
physvolume = alsamixer_getphysvolume(self->pmin,
self->pmax, volume);
snd_mixer_selem_set_playback_volume(elem, i, physvolume);
break;
case VOLUME_UNITS_RAW:
snd_mixer_selem_set_playback_volume(elem, i, volume);
break;
case VOLUME_UNITS_DB:
snd_mixer_selem_set_playback_dB(elem, i, volume, 0);
break;
}
done++;
}
else if (pcmtype == SND_PCM_STREAM_CAPTURE
&& snd_mixer_selem_has_capture_channel(elem, i)
&& snd_mixer_selem_has_capture_volume(elem))
{
physvolume = alsamixer_getphysvolume(self->cmin, self->cmax,
volume);
snd_mixer_selem_set_capture_volume(elem, i, physvolume);
switch (units)
{
case VOLUME_UNITS_PERCENTAGE:
physvolume = alsamixer_getphysvolume(self->cmin, self->cmax,
volume);
snd_mixer_selem_set_capture_volume(elem, i, physvolume);
break;
case VOLUME_UNITS_RAW:
snd_mixer_selem_set_capture_volume(elem, i, volume);
break;
case VOLUME_UNITS_DB:
snd_mixer_selem_set_capture_dB(elem, i, volume, 0);
break;
}
done++;
}
}
@@ -2425,7 +2962,7 @@ If the optional argument channel is present, the volume is set only for\n\
this channel. This assumes that the mixer can control the volume for the\n\
channels independently.\n\
\n\
The optional direction argument can be either PCM_PLAYBACK or PCM_CAPTURE.\n\
The optional 'pcmtype' argument can be either PCM_PLAYBACK or PCM_CAPTURE.\n\
It is relevant if the mixer has independent playback and capture volume\n\
capabilities, and controls which of the volumes will be changed.\n\
The default is 'playback' if the mixer has this capability, otherwise\n\
@@ -2593,7 +3130,7 @@ alsamixer_polldescriptors(alsamixer_t *self, PyObject *args)
for (i = 0; i < count; ++i)
{
PyList_SetItem(result, i,
Py_BuildValue("II", fds[i].fd, fds[i].events));
Py_BuildValue("ih", fds[i].fd, fds[i].events));
}
return result;
@@ -2647,13 +3184,13 @@ static PyMethodDef alsamixer_methods[] = {
switchcap_doc},
{"volumecap", (PyCFunction)alsamixer_volumecap, METH_VARARGS,
volumecap_doc},
{"getvolume", (PyCFunction)alsamixer_getvolume, METH_VARARGS,
{"getvolume", (PyCFunction)alsamixer_getvolume, METH_VARARGS | METH_KEYWORDS,
getvolume_doc},
{"getrange", (PyCFunction)alsamixer_getrange, METH_VARARGS, getrange_doc},
{"getrange", (PyCFunction)alsamixer_getrange, METH_VARARGS | METH_KEYWORDS, getrange_doc},
{"getenum", (PyCFunction)alsamixer_getenum, METH_VARARGS, getenum_doc},
{"getmute", (PyCFunction)alsamixer_getmute, METH_VARARGS, getmute_doc},
{"getrec", (PyCFunction)alsamixer_getrec, METH_VARARGS, getrec_doc},
{"setvolume", (PyCFunction)alsamixer_setvolume, METH_VARARGS,
{"setvolume", (PyCFunction)alsamixer_setvolume, METH_VARARGS | METH_KEYWORDS,
setvolume_doc},
{"setenum", (PyCFunction)alsamixer_setenum, METH_VARARGS, setenum_doc},
{"setmute", (PyCFunction)alsamixer_setmute, METH_VARARGS, setmute_doc},
@@ -2729,7 +3266,7 @@ static PyMethodDef alsaaudio_methods[] = {
{ "card_indexes", (PyCFunction)alsacard_list_indexes, METH_VARARGS, card_indexes_doc},
{ "card_name", (PyCFunction)alsacard_name, METH_VARARGS, card_name_doc},
{ "cards", (PyCFunction)alsacard_list, METH_VARARGS, cards_doc},
{ "pcms", (PyCFunction)alsapcm_list, METH_VARARGS, pcms_doc},
{ "pcms", (PyCFunction)alsapcm_list, METH_VARARGS|METH_KEYWORDS, pcms_doc},
{ "mixers", (PyCFunction)alsamixer_list, METH_VARARGS|METH_KEYWORDS, mixers_doc},
{ 0, 0 },
};
@@ -2803,6 +3340,8 @@ PyObject *PyInit_alsaaudio(void)
Py_INCREF(ALSAAudioError);
PyModule_AddObject(m, "ALSAAudioError", ALSAAudioError);
PyModule_AddFunctions(m, alsa_methods);
_EXPORT_INT(m, "PCM_PLAYBACK",SND_PCM_STREAM_PLAYBACK);
_EXPORT_INT(m, "PCM_CAPTURE",SND_PCM_STREAM_CAPTURE);
@@ -2839,6 +3378,15 @@ PyObject *PyInit_alsaaudio(void)
_EXPORT_INT(m, "PCM_FORMAT_U24_3LE",SND_PCM_FORMAT_U24_3LE);
_EXPORT_INT(m, "PCM_FORMAT_U24_3BE",SND_PCM_FORMAT_U24_3BE);
/* PCM tstamp modes */
_EXPORT_INT(m, "PCM_TSTAMP_NONE",SND_PCM_TSTAMP_NONE);
_EXPORT_INT(m, "PCM_TSTAMP_ENABLE",SND_PCM_TSTAMP_ENABLE);
/* PCM tstamp types */
_EXPORT_INT(m, "PCM_TSTAMP_TYPE_GETTIMEOFDAY",SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY);
_EXPORT_INT(m, "PCM_TSTAMP_TYPE_MONOTONIC",SND_PCM_TSTAMP_TYPE_MONOTONIC);
_EXPORT_INT(m, "PCM_TSTAMP_TYPE_MONOTONIC_RAW",SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW);
/* DSD sample formats are included in ALSA 1.0.29 and higher
* define OVERRIDE_DSD_COMPILE to include DSD sample support
* if you use a patched ALSA lib version
@@ -2868,6 +3416,10 @@ PyObject *PyInit_alsaaudio(void)
_EXPORT_INT(m, "MIXER_SCHN_MONO", SND_MIXER_SCHN_MONO);
#endif
_EXPORT_INT(m, "VOLUME_UNITS_PERCENTAGE", VOLUME_UNITS_PERCENTAGE)
_EXPORT_INT(m, "VOLUME_UNITS_RAW", VOLUME_UNITS_RAW)
_EXPORT_INT(m, "VOLUME_UNITS_DB", VOLUME_UNITS_DB)
#if PY_MAJOR_VERSION >= 3
return m;
#endif

View File

@@ -11,10 +11,14 @@ Create and push a tag naming the version (i.e. 0.9.0):
git tag 0.9.0
git push origin 0.9.0
Upload the package:
Create the package:
python3 setup.py sdist
Upload the package
twine upload dist/*
Don't forget to update the documentation.
# Publish the documentation

View File

@@ -33,13 +33,13 @@ The :mod:`alsaaudio` module defines functions and classes for using ALSA.
.. % should be enclosed in \var{...}.
.. function:: pcms([type=PCM_PLAYBACK])
.. function:: pcms(pcmtype=PCM_PLAYBACK)
List available PCM devices by name.
Arguments are:
* *type* - can be either :const:`PCM_CAPTURE` or :const:`PCM_PLAYBACK`
* *pcmtype* - can be either :const:`PCM_CAPTURE` or :const:`PCM_PLAYBACK`
(default).
**Note:**
@@ -97,6 +97,9 @@ The :mod:`alsaaudio` module defines functions and classes for using ALSA.
changed. Since 0.8, this functions returns the mixers for the default
device, not the mixers for the first card.
.. function:: asoundlib_version()
Return a Python string containing the ALSA version found.
.. _pcm-objects:
@@ -116,8 +119,7 @@ following arguments:
(default).
* *mode* - can be either :const:`PCM_NONBLOCK`, or :const:`PCM_NORMAL`
(default).
* *rate* - the sampling rate in Hz. Typical values are ``8000``
(mainly used for telephony), ``16000``, ``44100`` (default), ``48000`` and ``96000``.
* *rate* - the sampling rate in Hz. Typical values are ``8000`` (mainly used for telephony), ``16000``, ``44100`` (default), ``48000`` and ``96000``.
* *channels* - the number of channels. The default value is 2 (stereo).
* *format* - the data format. This controls how the PCM device interprets data for playback, and how data is encoded in captures.
The default value is :const:`PCM_FORMAT_S16_LE`.
@@ -256,11 +258,61 @@ PCM objects have the following methods:
.. method:: PCM.polldescriptors()
Returns a tuple of *(file descriptor, eventmask)* that can be used to
wait for changes on the mixer with *select.poll*.
wait for changes on the PCM with *select.poll*.
The *eventmask* value is compatible with `poll.register`__ in the Python
:const:`select` module.
.. method:: PCM.set_tstamp_mode([mode=PCM_TSTAMP_ENABLE])
Set the ALSA timestamp mode on the device. The mode argument can be set to
either :const:`PCM_TSTAMP_NONE` or :const:`PCM_TSTAMP_ENABLE`.
.. method:: PCM.get_tstamp_mode()
Return the integer value corresponding to the ALSA timestamp mode. The
return value can be either :const:`PCM_TSTAMP_NONE` or :const:`PCM_TSTAMP_ENABLE`.
.. method:: PCM.set_tstamp_type([type=PCM_TSTAMP_TYPE_GETTIMEOFDAY])
Set the ALSA timestamp mode on the device. The type argument
can be set to either :const:`PCM_TSTAMP_TYPE_GETTIMEOFDAY`,
:const:`PCM_TSTAMP_TYPE_MONOTONIC` or :const:`PCM_TSTAMP_TYPE_MONOTONIC_RAW`.
.. method:: PCM.get_tstamp_type()
Return the integer value corresponding to the ALSA timestamp type. The
return value can be either :const:`PCM_TSTAMP_TYPE_GETTIMEOFDAY`,
:const:`PCM_TSTAMP_TYPE_MONOTONIC` or :const:`PCM_TSTAMP_TYPE_MONOTONIC_RAW`.
.. method:: PCM.htimestamp()
Return a Python tuple *(seconds, nanoseconds, frames_available_in_buffer)*.
The type of output is controlled by the tstamp_type, as described in the table below.
================================= ===========================================
Timestamp Type Description
================================= ===========================================
``PCM_TSTAMP_TYPE_GETTIMEOFDAY`` System-wide realtime clock with seconds
since epoch.
``PCM_TSTAMP_TYPE_MONOTONIC`` Monotonic time from an unspecified starting
time. Progress is NTP synchronized.
``PCM_TSTAMP_TYPE_MONOTONIC_RAW`` Monotonic time from an unspecified starting
time using only the system clock.
================================= ===========================================
The timestamp mode is controlled by the tstamp_mode, as described in the table below.
================================= ===========================================
Timestamp Mode Description
================================= ===========================================
``PCM_TSTAMP_NONE`` No timestamp.
``PCM_TSTAMP_ENABLE`` Update timestamp at every hardware position
update.
================================= ===========================================
__ poll_objects_
**A few hints on using PCM devices for playback**
@@ -414,11 +466,11 @@ Mixer objects have the following methods:
This method will fail if the mixer has no playback switch capabilities.
.. method:: Mixer.getrange([direction])
.. method:: Mixer.getrange(pcmtype=PCM_PLAYBACK)
Return the volume range of the ALSA mixer controlled by this object.
The optional *direction* argument can be either :const:`PCM_PLAYBACK` or
The optional *pcmtype* argument can be either :const:`PCM_PLAYBACK` or
:const:`PCM_CAPTURE`, which is relevant if the mixer can control both
playback and capture volume. The default value is :const:`PCM_PLAYBACK`
if the mixer has playback channels, otherwise it is :const:`PCM_CAPTURE`.
@@ -432,18 +484,18 @@ Mixer objects have the following methods:
This method will fail if the mixer has no capture switch capabilities.
.. method:: Mixer.getvolume([direction])
.. method:: Mixer.getvolume(pcmtype=PCM_PLAYBACK)
Returns a list with the current volume settings for each channel. The list
elements are integer percentages.
The optional *direction* argument can be either :const:`PCM_PLAYBACK` or
The optional *pcmtype* argument can be either :const:`PCM_PLAYBACK` or
:const:`PCM_CAPTURE`, which is relevant if the mixer can control both
playback and capture volume. The default value is :const:`PCM_PLAYBACK`
if the mixer has playback channels, otherwise it is :const:`PCM_CAPTURE`.
.. method:: Mixer.setvolume(volume, [channel], [direction])
.. method:: Mixer.setvolume(volume, channel=None, pcmtype=PCM_PLAYBACK)
Change the current volume settings for this mixer. The *volume* argument
controls the new volume setting as an integer percentage.
@@ -452,7 +504,7 @@ Mixer objects have the following methods:
only for this channel. This assumes that the mixer can control the
volume for the channels independently.
The optional *direction* argument can be either :const:`PCM_PLAYBACK` or
The optional *pcmtype* argument can be either :const:`PCM_PLAYBACK` or
:const:`PCM_CAPTURE`, which is relevant if the mixer can control both
playback and capture volume. The default value is :const:`PCM_PLAYBACK`
if the mixer has playback channels, otherwise it is :const:`PCM_CAPTURE`.

View File

@@ -43,11 +43,36 @@ def show_mixer(name, kwargs):
sys.exit(1)
print("Mixer name: '%s'" % mixer.mixer())
print("Capabilities: %s %s" % (' '.join(mixer.volumecap()),
volcap = mixer.volumecap()
print("Capabilities: %s %s" % (' '.join(volcap),
' '.join(mixer.switchcap())))
if "Volume" in volcap or "Joined Volume" in volcap or "Playback Volume" in volcap:
pmin, pmax = mixer.getrange(alsaaudio.PCM_PLAYBACK)
pmin_keyword, pmax_keyword = mixer.getrange(pcmtype=alsaaudio.PCM_PLAYBACK, units=alsaaudio.VOLUME_UNITS_RAW)
pmin_default, pmax_default = mixer.getrange()
assert pmin == pmin_keyword
assert pmax == pmax_keyword
assert pmin == pmin_default
assert pmax == pmax_default
print("Raw playback volume range {}-{}".format(pmin, pmax))
pmin_dB, pmax_dB = mixer.getrange(units=alsaaudio.VOLUME_UNITS_DB)
print("dB playback volume range {}-{}".format(pmin_dB / 100.0, pmax_dB / 100.0))
if "Capture Volume" in volcap or "Joined Capture Volume" in volcap:
# Check that `getrange` works with keyword and positional arguments
cmin, cmax = mixer.getrange(alsaaudio.PCM_CAPTURE)
cmin_keyword, cmax_keyword = mixer.getrange(pcmtype=alsaaudio.PCM_CAPTURE, units=alsaaudio.VOLUME_UNITS_RAW)
assert cmin == cmin_keyword
assert cmax == cmax_keyword
print("Raw capture volume range {}-{}".format(cmin, cmax))
cmin_dB, cmax_dB = mixer.getrange(pcmtype=alsaaudio.PCM_CAPTURE, units=alsaaudio.VOLUME_UNITS_DB)
print("dB capture volume range {}-{}".format(cmin_dB / 100.0, cmax_dB / 100.0))
volumes = mixer.getvolume()
volumes_dB = mixer.getvolume(units=alsaaudio.VOLUME_UNITS_DB)
for i in range(len(volumes)):
print("Channel %i volume: %i%%" % (i,volumes[i]))
print("Channel %i volume: %i%% (%.1f dB)" % (i, volumes[i], volumes_dB[i] / 100.0))
try:
mutes = mixer.getmute()

View File

@@ -58,7 +58,7 @@ if __name__ == '__main__':
loops -= 1
# Read data from device
l, data = inp.read()
if l:
f.write(data)
time.sleep(.001)

View File

@@ -8,7 +8,7 @@ from setuptools import setup
from setuptools.extension import Extension
from sys import version
pyalsa_version = '0.9.0'
pyalsa_version = '0.9.2'
if __name__ == '__main__':
setup(