diff --git a/.gitignore b/.gitignore index 2adcf2b..bdd931d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ doc/_build/ gh-pages/ build/ dist/ -.vscode/ \ No newline at end of file +.vscode/ +/__pycache__/ +/pyalsaaudio.egg-info/ +*.raw diff --git a/alsaaudio.c b/alsaaudio.c index 61f68ac..ce9b610 100644 --- a/alsaaudio.c +++ b/alsaaudio.c @@ -651,7 +651,7 @@ alsapcm_info(alsapcm_t *self, PyObject *args) snd_pcm_hw_params_alloca(&hwparams); snd_pcm_hw_params_current(self->handle,hwparams); - if (!PyArg_ParseTuple(args,":dumpinfo")) + if (!PyArg_ParseTuple(args,":info")) return NULL; if (!self->handle) { @@ -827,6 +827,21 @@ they represent values stored by pyalsaaudio and they are prefixed with ' (call v "); +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) { @@ -845,13 +860,167 @@ alsapcm_htimestamp(alsapcm_t *self, PyObject *args) } -PyDoc_STRVAR(pcm_htimestamp_doc, +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 @@ -1588,8 +1757,11 @@ 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, - pcm_htimestamp_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}, @@ -1606,6 +1778,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) { @@ -3033,6 +3211,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); @@ -3069,6 +3249,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 diff --git a/doc/libalsaaudio.rst b/doc/libalsaaudio.rst index c9b9c5e..4e9a4e9 100644 --- a/doc/libalsaaudio.rst +++ b/doc/libalsaaudio.rst @@ -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: @@ -260,6 +263,56 @@ PCM objects have the following methods: 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** diff --git a/recordtest.py b/recordtest.py index c77646b..62d13ff 100755 --- a/recordtest.py +++ b/recordtest.py @@ -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)