forked from auracaster/pyalsaaudio
modified version of pyalsaaudio module
This commit is contained in:
12
py/CHANGES
12
py/CHANGES
@@ -1,3 +1,15 @@
|
|||||||
|
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)'.
|
||||||
|
|
||||||
|
(contributed by @jdstmporter)
|
||||||
|
|
||||||
Version 0.8.5:
|
Version 0.8.5:
|
||||||
- Return an empty string/bytestring when 'read()' detects an
|
- Return an empty string/bytestring when 'read()' detects an
|
||||||
overrun. Previously the returned data was undefined (contributed by @jcea)
|
overrun. Previously the returned data was undefined (contributed by @jcea)
|
||||||
|
|||||||
225
py/alsaaudio.c
225
py/alsaaudio.c
@@ -29,6 +29,64 @@
|
|||||||
#include <alsa/version.h>
|
#include <alsa/version.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof *(a))
|
||||||
|
static const snd_pcm_format_t ALSAFormats[] = {
|
||||||
|
SND_PCM_FORMAT_S8,
|
||||||
|
SND_PCM_FORMAT_U8,
|
||||||
|
SND_PCM_FORMAT_S16_LE,
|
||||||
|
SND_PCM_FORMAT_S16_BE,
|
||||||
|
SND_PCM_FORMAT_U16_LE,
|
||||||
|
SND_PCM_FORMAT_U16_BE,
|
||||||
|
SND_PCM_FORMAT_S24_LE,
|
||||||
|
SND_PCM_FORMAT_S24_BE,
|
||||||
|
SND_PCM_FORMAT_U24_LE,
|
||||||
|
SND_PCM_FORMAT_U24_BE,
|
||||||
|
SND_PCM_FORMAT_S32_LE,
|
||||||
|
SND_PCM_FORMAT_S32_BE,
|
||||||
|
SND_PCM_FORMAT_U32_LE,
|
||||||
|
SND_PCM_FORMAT_U32_BE,
|
||||||
|
SND_PCM_FORMAT_FLOAT_LE,
|
||||||
|
SND_PCM_FORMAT_FLOAT_BE,
|
||||||
|
SND_PCM_FORMAT_FLOAT64_LE,
|
||||||
|
SND_PCM_FORMAT_FLOAT64_BE,
|
||||||
|
SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
|
||||||
|
SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
|
||||||
|
SND_PCM_FORMAT_MU_LAW,
|
||||||
|
SND_PCM_FORMAT_A_LAW,
|
||||||
|
SND_PCM_FORMAT_IMA_ADPCM,
|
||||||
|
SND_PCM_FORMAT_MPEG,
|
||||||
|
SND_PCM_FORMAT_GSM,
|
||||||
|
SND_PCM_FORMAT_SPECIAL,
|
||||||
|
SND_PCM_FORMAT_S24_3LE,
|
||||||
|
SND_PCM_FORMAT_S24_3BE,
|
||||||
|
SND_PCM_FORMAT_U24_3LE,
|
||||||
|
SND_PCM_FORMAT_U24_3BE,
|
||||||
|
SND_PCM_FORMAT_S20_3LE,
|
||||||
|
SND_PCM_FORMAT_S20_3BE,
|
||||||
|
SND_PCM_FORMAT_U20_3LE,
|
||||||
|
SND_PCM_FORMAT_U20_3BE,
|
||||||
|
SND_PCM_FORMAT_S18_3LE,
|
||||||
|
SND_PCM_FORMAT_S18_3BE,
|
||||||
|
SND_PCM_FORMAT_U18_3LE,
|
||||||
|
SND_PCM_FORMAT_U18_3BE
|
||||||
|
};
|
||||||
|
static const unsigned ALSARates[] = {
|
||||||
|
4000,
|
||||||
|
5512,
|
||||||
|
8000,
|
||||||
|
11025,
|
||||||
|
16000,
|
||||||
|
22050,
|
||||||
|
32000,
|
||||||
|
44100,
|
||||||
|
48000,
|
||||||
|
64000,
|
||||||
|
88200,
|
||||||
|
96000,
|
||||||
|
176400,
|
||||||
|
192000
|
||||||
|
};
|
||||||
|
|
||||||
PyDoc_STRVAR(alsaaudio_module_doc,
|
PyDoc_STRVAR(alsaaudio_module_doc,
|
||||||
"This modules provides support for the ALSA audio API.\n"
|
"This modules provides support for the ALSA audio API.\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -572,6 +630,169 @@ alsapcm_dumpinfo(alsapcm_t *self, PyObject *args)
|
|||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// auxiliary function
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
alsapcm_getformats(alsapcm_t *self, PyObject *args) {
|
||||||
|
snd_pcm_t *pcm = self->handle;
|
||||||
|
if (!pcm) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "PCM device is closed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
snd_pcm_hw_params_t *params;
|
||||||
|
snd_pcm_hw_params_alloca(¶ms);
|
||||||
|
int err = snd_pcm_hw_params_any(pcm, params);
|
||||||
|
if (err < 0) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "Cannot get hardware parameters");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *fmts = PyDict_New();
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(ALSAFormats); ++i) {
|
||||||
|
snd_pcm_format_t format = ALSAFormats[i];
|
||||||
|
if (!snd_pcm_hw_params_test_format(pcm, params, format)) {
|
||||||
|
const char *name = snd_pcm_format_name(format);
|
||||||
|
PyObject *pname=PyUnicode_FromString(name);
|
||||||
|
PyObject *value=PyLong_FromLong((long)format);
|
||||||
|
PyDict_SetItem(fmts,pname,value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmts;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(getformats_doc,
|
||||||
|
"getformats() -> [str:int]\n\
|
||||||
|
\n\
|
||||||
|
Returns dictionary of supported format codes keyed by their standard ALSA names.");
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
alsapcm_getratemaxmin(alsapcm_t *self, PyObject *args) {
|
||||||
|
snd_pcm_t *pcm = self->handle;
|
||||||
|
if (!pcm) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "PCM device is closed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
snd_pcm_hw_params_t *params;
|
||||||
|
snd_pcm_hw_params_alloca(¶ms);
|
||||||
|
int err = snd_pcm_hw_params_any(pcm, params);
|
||||||
|
if (err < 0) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "Cannot get hardware parameters");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
unsigned min,max;
|
||||||
|
if(snd_pcm_hw_params_get_rate_min(params, &min,NULL)<0) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "Cannot get minimum supported bitrate");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(snd_pcm_hw_params_get_rate_max(params, &max,NULL)<0) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "Cannot get maximum supported bitrate");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *minp=PyLong_FromLong(min);
|
||||||
|
PyObject *maxp=PyLong_FromLong(max);
|
||||||
|
return PyTuple_Pack(2,minp,maxp);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(getratebounds_doc,
|
||||||
|
"getratebounds() -> (int,int)\n\
|
||||||
|
\n\
|
||||||
|
Returns the card's minimum and maximum supported sample rates as a tuple.");
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
alsapcm_getrates(alsapcm_t *self, PyObject *args) {
|
||||||
|
snd_pcm_t *pcm = self->handle;
|
||||||
|
if (!pcm) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "PCM device is closed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
snd_pcm_hw_params_t *params;
|
||||||
|
snd_pcm_hw_params_alloca(¶ms);
|
||||||
|
int err = snd_pcm_hw_params_any(pcm, params);
|
||||||
|
if (err < 0) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "Cannot get hardware parameters");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
unsigned min,max;
|
||||||
|
if(snd_pcm_hw_params_get_rate_min(params, &min,NULL)<0) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "Cannot get minimum supported bitrate");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(snd_pcm_hw_params_get_rate_max(params, &max,NULL)<0) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "Cannot get maximum supported bitrate");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(min==max) {
|
||||||
|
return PyLong_FromLong(min);
|
||||||
|
}
|
||||||
|
else if(!snd_pcm_hw_params_test_rate(pcm, params, min + 1, 0)) {
|
||||||
|
PyObject *minp=PyLong_FromLong(min);
|
||||||
|
PyObject *maxp=PyLong_FromLong(max);
|
||||||
|
return PyTuple_Pack(2,minp,maxp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyObject *rates=PyList_New(0);
|
||||||
|
for(int i=0;i<ARRAY_SIZE(ALSARates);i++) {
|
||||||
|
unsigned rate=ALSARates[i];
|
||||||
|
if(!snd_pcm_hw_params_test_rate(pcm, params, rate,0)) {
|
||||||
|
PyObject *prate=PyLong_FromLong(rate);
|
||||||
|
PyList_Append(rates,prate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(getrates_doc,
|
||||||
|
"getrates() -> obj\n\
|
||||||
|
\n\
|
||||||
|
Returns the sample rates supported by the device.\
|
||||||
|
Returned value can be one of three types, depending on the card's properties.\
|
||||||
|
There are three cases:\n\
|
||||||
|
\n\
|
||||||
|
- Card supports only a single rate: returns the rate\n\
|
||||||
|
- Card supports a continuous range of rates: returns a tuple of the range's lower and upper bounds (inclusive)\n\
|
||||||
|
- Card supports a collection of well-known rates: returns a list of the supported rates");
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
alsapcm_getchannels(alsapcm_t *self,PyObject *args) {
|
||||||
|
snd_pcm_t *pcm = self->handle;
|
||||||
|
if (!pcm) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "PCM device is closed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
snd_pcm_hw_params_t *params;
|
||||||
|
snd_pcm_hw_params_alloca(¶ms);
|
||||||
|
int err = snd_pcm_hw_params_any(pcm, params);
|
||||||
|
if (err < 0) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "Cannot get hardware parameters");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
unsigned min,max;
|
||||||
|
if(snd_pcm_hw_params_get_channels_min(params, &min)<0) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "Cannot get minimum supported number of channels");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(snd_pcm_hw_params_get_channels_max(params, &max)<0) {
|
||||||
|
PyErr_SetString(ALSAAudioError, "Cannot get maximum supported number of channels");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *out=PyList_New(0);
|
||||||
|
|
||||||
|
for(unsigned ch=min;ch<=max;++ch) {
|
||||||
|
if (!snd_pcm_hw_params_test_channels(pcm, params, ch)) {
|
||||||
|
PyObject *pch=PyLong_FromLong(ch);
|
||||||
|
PyList_Append(out,pch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
PyDoc_STRVAR(getchannels_doc,
|
||||||
|
"getchannels() -> [int]\n\
|
||||||
|
\n\
|
||||||
|
Returns list of supported channel numbers.");
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
alsapcm_pcmtype(alsapcm_t *self, PyObject *args)
|
alsapcm_pcmtype(alsapcm_t *self, PyObject *args)
|
||||||
{
|
{
|
||||||
@@ -1101,6 +1322,10 @@ static PyMethodDef alsapcm_methods[] = {
|
|||||||
{"setperiodsize", (PyCFunction)alsapcm_setperiodsize, METH_VARARGS,
|
{"setperiodsize", (PyCFunction)alsapcm_setperiodsize, METH_VARARGS,
|
||||||
setperiodsize_doc},
|
setperiodsize_doc},
|
||||||
{"dumpinfo", (PyCFunction)alsapcm_dumpinfo, METH_VARARGS},
|
{"dumpinfo", (PyCFunction)alsapcm_dumpinfo, METH_VARARGS},
|
||||||
|
{"getformats", (PyCFunction)alsapcm_getformats, METH_VARARGS, getformats_doc},
|
||||||
|
{"getratebounds", (PyCFunction)alsapcm_getratemaxmin, METH_VARARGS, getratebounds_doc},
|
||||||
|
{"getrates", (PyCFunction)alsapcm_getrates, METH_VARARGS, getrates_doc},
|
||||||
|
{"getchannels", (PyCFunction)alsapcm_getchannels, METH_VARARGS, getchannels_doc},
|
||||||
{"read", (PyCFunction)alsapcm_read, METH_VARARGS, read_doc},
|
{"read", (PyCFunction)alsapcm_read, METH_VARARGS, read_doc},
|
||||||
{"write", (PyCFunction)alsapcm_write, METH_VARARGS, write_doc},
|
{"write", (PyCFunction)alsapcm_write, METH_VARARGS, write_doc},
|
||||||
{"pause", (PyCFunction)alsapcm_pause, METH_VARARGS, pause_doc},
|
{"pause", (PyCFunction)alsapcm_pause, METH_VARARGS, pause_doc},
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from setuptools import setup
|
|||||||
from setuptools.extension import Extension
|
from setuptools.extension import Extension
|
||||||
from sys import version
|
from sys import version
|
||||||
|
|
||||||
pyalsa_version = '0.8.5'
|
pyalsa_version = '0.8.6'
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
setup(
|
setup(
|
||||||
|
|||||||
BIN
tests/params
BIN
tests/params
Binary file not shown.
@@ -59,6 +59,7 @@ static const snd_pcm_format_t formats[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int rates[] = {
|
static const unsigned int rates[] = {
|
||||||
|
4000,
|
||||||
5512,
|
5512,
|
||||||
8000,
|
8000,
|
||||||
11025,
|
11025,
|
||||||
@@ -164,7 +165,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
printf("Formats:");
|
printf("Formats:");
|
||||||
for (int i = 0; i < info.nFormats; ++i) {
|
for (int i = 0; i < info.nFormats; ++i) {
|
||||||
printf(" %s", snd_pcm_format_name(formats[i]));
|
printf("%s ", snd_pcm_format_name(info.formats[i]));
|
||||||
}
|
}
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
printf("Rates:");
|
printf("Rates:");
|
||||||
@@ -178,7 +179,7 @@ int main(int argc, char *argv[])
|
|||||||
printf(" %u", info.channels[i]);
|
printf(" %u", info.channels[i]);
|
||||||
}
|
}
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
/*
|
|
||||||
|
|
||||||
err = snd_pcm_open(&pcm, device_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
err = snd_pcm_open(&pcm, device_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
@@ -205,8 +206,10 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
printf("Formats:");
|
printf("Formats:");
|
||||||
for (i = 0; i < ARRAY_SIZE(formats); ++i) {
|
for (i = 0; i < ARRAY_SIZE(formats); ++i) {
|
||||||
if (!snd_pcm_hw_params_test_format(pcm, hw_params, formats[i]))
|
if (!snd_pcm_hw_params_test_format(pcm, hw_params, formats[i])) {
|
||||||
printf(" %s", snd_pcm_format_name(formats[i]));
|
printf(" %s", snd_pcm_format_name(formats[i]));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
|
|
||||||
@@ -289,7 +292,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
snd_pcm_close(pcm);
|
snd_pcm_close(pcm);
|
||||||
|
|
||||||
*/
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user