Compare commits

...

12 Commits

Author SHA1 Message Date
Lars Immisch
62e5515341 Document the release process. 2020-07-13 22:00:44 +02:00
Lars Immisch
ed027a6141 More output for playwav 2020-07-13 20:42:25 +01:00
Lars Immisch
5302dc524d Cleanup warnings 2020-07-13 20:59:49 +02:00
Lars Immisch
b17b36be50 Better error messages in tests 2020-07-13 20:51:59 +02:00
Lars Immisch
08bdce9ed9 Tests for Depreciations 2020-07-13 20:20:28 +02:00
Lars Immisch
0224c8a308 Inline documentation (and .gitignore) 2020-07-10 00:54:24 +02:00
Lars Immisch
f07627543c Update documentation 2020-07-10 00:45:57 +02:00
Lars Immisch
df889b94ef Don't use setrate etc. in samples. 2020-07-09 21:22:06 +02:00
Lars Immisch
2a21bf6c42 Support all essential parameters in alsapcm_new. 2020-07-08 22:39:46 +02:00
Lars Immisch
8084297926 Merge pull request #83 from stalkerg/master
fix generate switch capabilities
2020-05-25 12:58:03 +02:00
stalkerg
8fbc04e18d fix generate switch capabilities 2020-05-21 17:21:40 +09:00
Lars Immisch
8ed9f924cd Attempt to fix #45 2020-04-23 21:36:29 +01:00
10 changed files with 2151 additions and 2101 deletions

2
.gitignore vendored
View File

@@ -4,6 +4,8 @@ MANIFEST
doc/gh-pages/ doc/gh-pages/
doc/html/ doc/html/
doc/doctrees/ doc/doctrees/
doc/_build/
gh-pages/ gh-pages/
build/ build/
dist/ dist/
.vscode/

View File

@@ -1,4 +1,4 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: t -*- */
/* /*
* alsaaudio -- Python interface to ALSA (Advanced Linux Sound Architecture). * alsaaudio -- Python interface to ALSA (Advanced Linux Sound Architecture).
@@ -107,7 +107,7 @@ typedef struct {
// Configurable parameters // Configurable parameters
int channels; int channels;
int rate; unsigned int rate;
int format; int format;
snd_pcm_uframes_t periodsize; snd_pcm_uframes_t periodsize;
int framesize; int framesize;
@@ -370,8 +370,9 @@ static int alsapcm_setup(alsapcm_t *self)
and fill it with configuration space */ and fill it with configuration space */
snd_pcm_hw_params_alloca(&hwparams); snd_pcm_hw_params_alloca(&hwparams);
res = snd_pcm_hw_params_any(self->handle, hwparams); res = snd_pcm_hw_params_any(self->handle, hwparams);
if (res < 0) if (res < 0) {
return res; return res;
}
/* Fill it with default values. /* Fill it with default values.
@@ -386,10 +387,11 @@ static int alsapcm_setup(alsapcm_t *self)
self->channels); self->channels);
dir = 0; dir = 0;
snd_pcm_hw_params_set_rate(self->handle, hwparams, self->rate, dir); unsigned int periods = 4;
snd_pcm_hw_params_set_period_size(self->handle, hwparams, snd_pcm_hw_params_set_rate_near(self->handle, hwparams, &self->rate, &dir);
self->periodsize, dir); snd_pcm_hw_params_set_period_size_near(self->handle, hwparams,
snd_pcm_hw_params_set_periods(self->handle, hwparams, 4, 0); &self->periodsize, &dir);
snd_pcm_hw_params_set_periods_near(self->handle, hwparams, &periods, &dir);
/* Write it to the device */ /* Write it to the device */
res = snd_pcm_hw_params(self->handle, hwparams); res = snd_pcm_hw_params(self->handle, hwparams);
@@ -421,11 +423,16 @@ alsapcm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
char *card = NULL; char *card = NULL;
int cardidx = -1; int cardidx = -1;
char hw_device[128]; char hw_device[128];
char *kw[] = { "type", "mode", "device", "cardindex", "card", NULL }; int rate = 44100;
int channels = 2;
int format = SND_PCM_FORMAT_S16_LE;
int periodsize = 32;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oisiz", kw, char *kw[] = { "type", "mode", "device", "cardindex", "card", "rate", "channels", "format", "periodsize", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oisiziiii", kw,
&pcmtypeobj, &pcmmode, &device, &pcmtypeobj, &pcmmode, &device,
&cardidx, &card)) &cardidx, &card, &rate, &channels, &format, &periodsize))
return NULL; return NULL;
if (cardidx >= 0) { if (cardidx >= 0) {
@@ -469,10 +476,10 @@ alsapcm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self->handle = 0; self->handle = 0;
self->pcmtype = pcmtype; self->pcmtype = pcmtype;
self->pcmmode = pcmmode; self->pcmmode = pcmmode;
self->channels = 2; self->channels = channels;
self->rate = 44100; self->rate = rate;
self->format = SND_PCM_FORMAT_S16_LE; self->format = format;
self->periodsize = 32; self->periodsize = periodsize;
res = snd_pcm_open(&(self->handle), device, self->pcmtype, res = snd_pcm_open(&(self->handle), device, self->pcmtype,
self->pcmmode); self->pcmmode);
@@ -687,7 +694,7 @@ alsapcm_getratemaxmin(alsapcm_t *self, PyObject *args)
return NULL; return NULL;
} }
unsigned min,max; unsigned min, max;
if (snd_pcm_hw_params_get_rate_min(params, &min,NULL)<0) { if (snd_pcm_hw_params_get_rate_min(params, &min,NULL)<0) {
PyErr_SetString(ALSAAudioError, "Cannot get minimum supported bitrate"); PyErr_SetString(ALSAAudioError, "Cannot get minimum supported bitrate");
return NULL; return NULL;
@@ -887,6 +894,10 @@ alsapcm_setchannels(alsapcm_t *self, PyObject *args)
return NULL; return NULL;
} }
PyErr_WarnEx(PyExc_DeprecationWarning,
"This function is deprecated. "
"Please use the named parameter `channels` to `PCM()` instead", 1);
saved = self->channels; saved = self->channels;
self->channels = channels; self->channels = channels;
res = alsapcm_setup(self); res = alsapcm_setup(self);
@@ -903,6 +914,8 @@ alsapcm_setchannels(alsapcm_t *self, PyObject *args)
PyDoc_STRVAR(setchannels_doc, PyDoc_STRVAR(setchannels_doc,
"setchannels(numchannels)\n\ "setchannels(numchannels)\n\
\n\ \n\
Deprecated since 0.9\n\
\n\
Used to set the number of capture or playback channels. Common values\n\ Used to set the number of capture or playback channels. Common values\n\
are: 1 = mono, 2 = stereo, and 6 = full 6 channel audio.\n\ are: 1 = mono, 2 = stereo, and 6 = full 6 channel audio.\n\
\n\ \n\
@@ -914,6 +927,7 @@ alsapcm_setrate(alsapcm_t *self, PyObject *args)
{ {
int rate, saved; int rate, saved;
int res; int res;
if (!PyArg_ParseTuple(args,"i:setrate", &rate)) if (!PyArg_ParseTuple(args,"i:setrate", &rate))
return NULL; return NULL;
@@ -923,6 +937,10 @@ alsapcm_setrate(alsapcm_t *self, PyObject *args)
return NULL; return NULL;
} }
PyErr_WarnEx(PyExc_DeprecationWarning,
"This function is deprecated. "
"Please use the named parameter `rate` to `PCM()` instead", 1);
saved = self->rate; saved = self->rate;
self->rate = rate; self->rate = rate;
res = alsapcm_setup(self); res = alsapcm_setup(self);
@@ -939,6 +957,8 @@ alsapcm_setrate(alsapcm_t *self, PyObject *args)
PyDoc_STRVAR(setrate_doc, PyDoc_STRVAR(setrate_doc,
"setrate(rate)\n\ "setrate(rate)\n\
\n\ \n\
Deprecated since 0.9\n\
\n\
Set the sample rate in Hz for the device. Typical values are\n\ Set the sample rate in Hz for the device. Typical values are\n\
8000 (telephony), 11025, 44100 (CD), 48000 (DVD audio) and 96000"); 8000 (telephony), 11025, 44100 (CD), 48000 (DVD audio) and 96000");
@@ -948,6 +968,7 @@ alsapcm_setformat(alsapcm_t *self, PyObject *args)
{ {
int format, saved; int format, saved;
int res; int res;
if (!PyArg_ParseTuple(args,"i:setformat", &format)) if (!PyArg_ParseTuple(args,"i:setformat", &format))
return NULL; return NULL;
@@ -957,6 +978,10 @@ alsapcm_setformat(alsapcm_t *self, PyObject *args)
return NULL; return NULL;
} }
PyErr_WarnEx(PyExc_DeprecationWarning,
"This function is deprecated. "
"Please use the named parameter `format` to `PCM()` instead", 1);
saved = self->format; saved = self->format;
self->format = format; self->format = format;
res = alsapcm_setup(self); res = alsapcm_setup(self);
@@ -971,7 +996,9 @@ alsapcm_setformat(alsapcm_t *self, PyObject *args)
} }
PyDoc_STRVAR(setformat_doc, PyDoc_STRVAR(setformat_doc,
"setformat(rate)\n"); "setformat(rate)\n\
\n\
Deprecated since 0.9");
static PyObject * static PyObject *
alsapcm_setperiodsize(alsapcm_t *self, PyObject *args) alsapcm_setperiodsize(alsapcm_t *self, PyObject *args)
@@ -982,13 +1009,16 @@ alsapcm_setperiodsize(alsapcm_t *self, PyObject *args)
if (!PyArg_ParseTuple(args,"i:setperiodsize", &periodsize)) if (!PyArg_ParseTuple(args,"i:setperiodsize", &periodsize))
return NULL; return NULL;
if (!self->handle) if (!self->handle)
{ {
PyErr_SetString(ALSAAudioError, "PCM device is closed"); PyErr_SetString(ALSAAudioError, "PCM device is closed");
return NULL; return NULL;
} }
PyErr_WarnEx(PyExc_DeprecationWarning,
"This function is deprecated. "
"Please use the named parameter `periodsize` to `PCM()` instead", 1);
saved = self->periodsize; saved = self->periodsize;
self->periodsize = periodsize; self->periodsize = periodsize;
res = alsapcm_setup(self); res = alsapcm_setup(self);
@@ -1009,6 +1039,8 @@ alsapcm_setperiodsize(alsapcm_t *self, PyObject *args)
PyDoc_STRVAR(setperiodsize_doc, PyDoc_STRVAR(setperiodsize_doc,
"setperiodsize(period) -> int\n\ "setperiodsize(period) -> int\n\
\n\ \n\
Deprecated since 0.9\n\
\n\
Sets the actual period size in frames. Each write should consist of\n\ Sets the actual period size in frames. Each write should consist of\n\
exactly this number of frames, and each read will return this number of\n\ exactly this number of frames, and each read will return this number of\n\
frames (unless the device is in PCM_NONBLOCK mode, in which case it\n\ frames (unless the device is in PCM_NONBLOCK mode, in which case it\n\
@@ -1830,43 +1862,43 @@ alsamixer_switchcap(alsamixer_t *self, PyObject *args)
} }
result = PyList_New(0); result = PyList_New(0);
if (self->volume_cap & MIXER_CAP_SWITCH) if (self->switch_cap & MIXER_CAP_SWITCH)
{ {
item = PyUnicode_FromString("Mute"); item = PyUnicode_FromString("Mute");
PyList_Append(result, item); PyList_Append(result, item);
Py_DECREF(item); Py_DECREF(item);
} }
if (self->volume_cap & MIXER_CAP_SWITCH_JOINED) if (self->switch_cap & MIXER_CAP_SWITCH_JOINED)
{ {
item = PyUnicode_FromString("Joined Mute"); item = PyUnicode_FromString("Joined Mute");
PyList_Append(result, item); PyList_Append(result, item);
Py_DECREF(item); Py_DECREF(item);
} }
if (self->volume_cap & MIXER_CAP_PSWITCH) if (self->switch_cap & MIXER_CAP_PSWITCH)
{ {
item = PyUnicode_FromString("Playback Mute"); item = PyUnicode_FromString("Playback Mute");
PyList_Append(result, item); PyList_Append(result, item);
Py_DECREF(item); Py_DECREF(item);
} }
if (self->volume_cap & MIXER_CAP_PSWITCH_JOINED) if (self->switch_cap & MIXER_CAP_PSWITCH_JOINED)
{ {
item = PyUnicode_FromString("Joined Playback Mute"); item = PyUnicode_FromString("Joined Playback Mute");
PyList_Append(result, item); PyList_Append(result, item);
Py_DECREF(item); Py_DECREF(item);
} }
if (self->volume_cap & MIXER_CAP_CSWITCH) if (self->switch_cap & MIXER_CAP_CSWITCH)
{ {
item = PyUnicode_FromString("Capture Mute"); item = PyUnicode_FromString("Capture Mute");
PyList_Append(result, item); PyList_Append(result, item);
Py_DECREF(item); Py_DECREF(item);
} }
if (self->volume_cap & MIXER_CAP_CSWITCH_JOINED) if (self->switch_cap & MIXER_CAP_CSWITCH_JOINED)
{ {
item = PyUnicode_FromString("Joined Capture Mute"); item = PyUnicode_FromString("Joined Capture Mute");
PyList_Append(result, item); PyList_Append(result, item);
Py_DECREF(item); Py_DECREF(item);
} }
if (self->volume_cap & MIXER_CAP_CSWITCH_EXCLUSIVE) if (self->switch_cap & MIXER_CAP_CSWITCH_EXCLUSIVE)
{ {
item = PyUnicode_FromString("Capture Exclusive"); item = PyUnicode_FromString("Capture Exclusive");
PyList_Append(result, item); PyList_Append(result, item);

View File

@@ -1,3 +1,22 @@
# Make a new release
Update the version in setup.py
pyalsa_version = '0.9.0'
Commit and push the update.
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:
python3 setup.py sdist
Don't forget to update the documentation.
# Publish the documentation # Publish the documentation
The documentation is published through the `gh-pages` branch. The documentation is published through the `gh-pages` branch.

View File

@@ -63,7 +63,6 @@ The :mod:`alsaaudio` module defines functions and classes for using ALSA.
useful. If you want to see a list of available PCM devices, use :func:`pcms` useful. If you want to see a list of available PCM devices, use :func:`pcms`
instead. instead.
.. function:: mixers(cardindex=-1, device='default') .. function:: mixers(cardindex=-1, device='default')
List the available mixers. The arguments are: List the available mixers. The arguments are:
@@ -108,7 +107,7 @@ PCM objects in :mod:`alsaaudio` can play or capture (record) PCM
sound through speakers or a microphone. The PCM constructor takes the sound through speakers or a microphone. The PCM constructor takes the
following arguments: following arguments:
.. class:: PCM(type=PCM_PLAYBACK, mode=PCM_NORMAL, device='default', cardindex=-1) .. class:: PCM(type=PCM_PLAYBACK, mode=PCM_NORMAL, rate=44100, channels=2, format=PCM_FORMAT_S16_LE, periodsize=32, device='default', cardindex=-1)
This class is used to represent a PCM device (either for playback and This class is used to represent a PCM device (either for playback and
recording). The arguments are: recording). The arguments are:
@@ -117,72 +116,11 @@ following arguments:
(default). (default).
* *mode* - can be either :const:`PCM_NONBLOCK`, or :const:`PCM_NORMAL` * *mode* - can be either :const:`PCM_NONBLOCK`, or :const:`PCM_NORMAL`
(default). (default).
* *device* - the name of the PCM device that should be used (for example * *rate* - the sampling rate in Hz. Typical values are ``8000``
a value from the output of :func:`pcms`). The default value is (mainly used for telephony), ``16000``, ``44100`` (default), ``48000`` and ``96000``.
``'default'``. * *channels* - the number of channels. The default value is 2 (stereo).
* *cardindex* - the card index. If this argument is given, the device name * *format* - the data format. This controls how the PCM device interprets data for playback, and how data is encoded in captures.
is constructed as 'hw:*cardindex*' and The default value is :const:`PCM_FORMAT_S16_LE`.
the `device` keyword argument is ignored.
``0`` is the first hardware sound card.
This will construct a PCM object with these default settings:
* Sample format: :const:`PCM_FORMAT_S16_LE`
* Rate: 44100 Hz
* Channels: 2
* Period size: 32 frames
*Changed in 0.8:*
- The `card` keyword argument is still supported,
but deprecated. Please use `device` instead.
- The keyword argument `cardindex` was added.
The `card` keyword is deprecated because it guesses the real ALSA
name of the card. This was always fragile and broke some legitimate usecases.
PCM objects have the following methods:
.. method:: PCM.pcmtype()
Returns the type of PCM object. Either :const:`PCM_CAPTURE` or
:const:`PCM_PLAYBACK`.
.. method:: PCM.pcmmode()
Return the mode of the PCM object. One of :const:`PCM_NONBLOCK`,
:const:`PCM_ASYNC`, or :const:`PCM_NORMAL`
.. method:: PCM.cardname()
Return the name of the sound card used by this PCM object.
.. method:: PCM.setchannels(nchannels)
Used to set the number of capture or playback channels. Common
values are: ``1`` = mono, ``2`` = stereo, and ``6`` = full 6 channel audio.
Few sound cards support more than 2 channels
.. method:: PCM.setrate(rate)
Set the sample rate in Hz for the device. Typical values are ``8000``
(mainly used for telephony), ``16000``, ``44100`` (CD quality),
``48000`` and ``96000``.
.. method:: PCM.setformat(format)
The sound *format* of the device. Sound format controls how the PCM device
interpret data for playback, and how data is encoded in captures.
The following formats are provided by ALSA:
========================= =============== ========================= ===============
Format Description Format Description
@@ -216,14 +154,65 @@ PCM objects have the following methods:
``PCM_FORMAT_U24_3BE`` Unsigned 24 bit samples for each channel (Big Endian byte order in 3 bytes) ``PCM_FORMAT_U24_3BE`` Unsigned 24 bit samples for each channel (Big Endian byte order in 3 bytes)
========================= =============== ========================= ===============
* *periodsize* - the period size in frames. Each write should consist of *periodsize* frames. The default value is 32.
* *device* - the name of the PCM device that should be used (for example
a value from the output of :func:`pcms`). The default value is
``'default'``.
* *cardindex* - the card index. If this argument is given, the device name
is constructed as 'hw:*cardindex*' and
the `device` keyword argument is ignored.
``0`` is the first hardware sound card.
This will construct a PCM object with the given settings.
*Changed in 0.9:*
- Added the optional named parameters `rate`, `channels`, `format` and `periodsize`.
*Changed in 0.8:*
- The `card` keyword argument is still supported,
but deprecated. Please use `device` instead.
- The keyword argument `cardindex` was added.
The `card` keyword is deprecated because it guesses the real ALSA
name of the card. This was always fragile and broke some legitimate usecases.
PCM objects have the following methods:
.. method:: PCM.pcmtype()
Returns the type of PCM object. Either :const:`PCM_CAPTURE` or
:const:`PCM_PLAYBACK`.
.. method:: PCM.pcmmode()
Return the mode of the PCM object. One of :const:`PCM_NONBLOCK`,
:const:`PCM_ASYNC`, or :const:`PCM_NORMAL`
.. method:: PCM.cardname()
Return the name of the sound card used by this PCM object.
.. method:: PCM.setchannels(nchannels)
.. deprecated:: 0.9 Use the `channels` named argument to :func:`PCM`.
.. method:: PCM.setrate(rate)
.. deprecated:: 0.9 Use the `rate` named argument to :func:`PCM`.
.. method:: PCM.setformat(format)
.. deprecated:: 0.9 Use the `format` named argument to :func:`PCM`.
.. method:: PCM.setperiodsize(period) .. method:: PCM.setperiodsize(period)
Sets the actual period size in frames. Each write should consist of .. deprecated:: 0.9 Use the `periodsize` named argument to :func:`PCM`.
exactly this number of frames, and each read will return this
number of frames (unless the device is in :const:`PCM_NONBLOCK` mode, in
which case it may return nothing at all)
.. method:: PCM.read() .. method:: PCM.read()

View File

@@ -56,10 +56,7 @@ class SinePlayer(Thread):
def __init__(self, frequency = 440.0): def __init__(self, frequency = 440.0):
Thread.__init__(self) Thread.__init__(self)
self.setDaemon(True) self.setDaemon(True)
self.device = alsaaudio.PCM() self.device = alsaaudio.PCM(channels=channels, format=format, rate=sampling_rate)
self.device.setchannels(channels)
self.device.setformat(format)
self.device.setrate(sampling_rate)
self.queue = Queue() self.queue = Queue()
self.change(frequency) self.change(frequency)

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- mode: python; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
## playbacktest.py ## playbacktest.py
## ##
@@ -38,18 +39,11 @@ if __name__ == '__main__':
f = open(args[0], 'rb') f = open(args[0], 'rb')
# Open the device in playback mode. # Open the device in playback mode in Mono, 44100 Hz, 16 bit little endian frames
out = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK, device=device)
# Set attributes: Mono, 44100 Hz, 16 bit little endian frames
out.setchannels(1)
out.setrate(44100)
out.setformat(alsaaudio.PCM_FORMAT_S16_LE)
# The period size controls the internal number of frames per period. # The period size controls the internal number of frames per period.
# The significance of this parameter is documented in the ALSA api. # The significance of this parameter is documented in the ALSA api.
out.setperiodsize(160)
out = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK, channels=1, rate=44100, format=alsaaudio.PCM_FORMAT_S16_LE, periodsize=160, device=device)
# Read data from stdin # Read data from stdin
data = f.read(320) data = f.read(320)
while data: while data:

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- mode: python; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
# Simple test script that plays (some) wav files # Simple test script that plays (some) wav files
@@ -11,28 +12,29 @@ import alsaaudio
def play(device, f): def play(device, f):
print('%d channels, %d sampling rate\n' % (f.getnchannels(), format = None
f.getframerate()))
# Set attributes
device.setchannels(f.getnchannels())
device.setrate(f.getframerate())
# 8bit is unsigned in wav files # 8bit is unsigned in wav files
if f.getsampwidth() == 1: if f.getsampwidth() == 1:
device.setformat(alsaaudio.PCM_FORMAT_U8) format = alsaaudio.PCM_FORMAT_U8
# Otherwise we assume signed data, little endian # Otherwise we assume signed data, little endian
elif f.getsampwidth() == 2: elif f.getsampwidth() == 2:
device.setformat(alsaaudio.PCM_FORMAT_S16_LE) format = alsaaudio.PCM_FORMAT_S16_LE
elif f.getsampwidth() == 3: elif f.getsampwidth() == 3:
device.setformat(alsaaudio.PCM_FORMAT_S24_3LE) format = alsaaudio.PCM_FORMAT_S24_3LE
elif f.getsampwidth() == 4: elif f.getsampwidth() == 4:
device.setformat(alsaaudio.PCM_FORMAT_S32_LE) format = alsaaudio.PCM_FORMAT_S32_LE
else: else:
raise ValueError('Unsupported format') raise ValueError('Unsupported format')
periodsize = f.getframerate() // 8 periodsize = f.getframerate() // 8
device.setperiodsize(periodsize) print('%d channels, %d sampling rate, format %d, periodsize %d\n' % (f.getnchannels(),
f.getframerate(),
format,
periodsize))
device = alsaaudio.PCM(channels=f.getnchannels(), rate=f.getframerate(), format=format, periodsize=periodsize, device=device)
data = f.readframes(periodsize) data = f.readframes(periodsize)
while data: while data:
@@ -57,9 +59,5 @@ if __name__ == '__main__':
if not args: if not args:
usage() usage()
f = wave.open(args[0], 'rb') with wave.open(args[0], 'rb') as f:
device = alsaaudio.PCM(device=device)
play(device, f) play(device, f)
f.close()

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- mode: python; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
## recordtest.py ## recordtest.py
## ##
@@ -39,16 +40,8 @@ if __name__ == '__main__':
f = open(args[0], 'wb') f = open(args[0], 'wb')
# Open the device in nonblocking capture mode. The last argument could # Open the device in nonblocking capture mode in mono, with a sampling rate of 44100 Hz
# just as well have been zero for blocking mode. Then we could have # and 16 bit little endian samples
# left out the sleep call in the bottom of the loop
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NONBLOCK, device=device)
# Set attributes: Mono, 44100 Hz, 16 bit little endian samples
inp.setchannels(1)
inp.setrate(44100)
inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)
# The period size controls the internal number of frames per period. # The period size controls the internal number of frames per period.
# The significance of this parameter is documented in the ALSA api. # The significance of this parameter is documented in the ALSA api.
# For our purposes, it is suficcient to know that reads from the device # For our purposes, it is suficcient to know that reads from the device
@@ -56,7 +49,9 @@ if __name__ == '__main__':
# This means that the reads below will return either 320 bytes of data # This means that the reads below will return either 320 bytes of data
# or 0 bytes of data. The latter is possible because we are in nonblocking # or 0 bytes of data. The latter is possible because we are in nonblocking
# mode. # mode.
inp.setperiodsize(160) inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NONBLOCK,
channels=1, rate=44100, format=alsaaudio.PCM_FORMAT_S16_LE,
periodsize=160, device=device)
loops = 1000000 loops = 1000000
while loops > 0: while loops > 0:

View File

@@ -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.6' pyalsa_version = '0.9.0'
if __name__ == '__main__': if __name__ == '__main__':
setup( setup(

36
test.py
View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python3
# -*- mode: python; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-
# These are internal tests. They shouldn't fail, but they don't cover all # These are internal tests. They shouldn't fail, but they don't cover all
# of the ALSA API. Most importantly PCM.read and PCM.write are missing. # of the ALSA API. Most importantly PCM.read and PCM.write are missing.
@@ -12,13 +13,18 @@ import alsaaudio
import warnings import warnings
# we can't test read and write well - these are tested otherwise # we can't test read and write well - these are tested otherwise
PCMMethods = [('pcmtype', None), PCMMethods = [
('pcmtype', None),
('pcmmode', None), ('pcmmode', None),
('cardname', None), ('cardname', None)
]
PCMDeprecatedMethods = [
('setchannels', (2,)), ('setchannels', (2,)),
('setrate', (44100,)), ('setrate', (44100,)),
('setformat', (alsaaudio.PCM_FORMAT_S8,)), ('setformat', (alsaaudio.PCM_FORMAT_S8,)),
('setperiodsize', (320,))] ('setperiodsize', (320,))
]
# A clever test would look at the Mixer capabilities and selectively run the # A clever test would look at the Mixer capabilities and selectively run the
# omitted tests, but I am too tired for that. # omitted tests, but I am too tired for that.
@@ -129,8 +135,26 @@ class PCMTest(unittest.TestCase):
pass pass
# Verify we got a DepreciationWarning # Verify we got a DepreciationWarning
assert len(w) == 1 self.assertEqual(len(w), 1, "PCM(card='default') expected a warning" )
assert issubclass(w[-1].category, DeprecationWarning) self.assertTrue(issubclass(w[-1].category, DeprecationWarning), "PCM(card='default') expected a DeprecationWarning")
for m, a in PCMDeprecatedMethods:
with warnings.catch_warnings(record=True) as w:
# Cause all warnings to always be triggered.
warnings.simplefilter("always")
pcm = alsaaudio.PCM()
f = alsaaudio.PCM.__dict__[m]
if a is None:
f(pcm)
else:
f(pcm, *a)
# Verify we got a DepreciationWarning
method = "%s%s" % (m, str(a))
self.assertEqual(len(w), 1, method + " expected a warning")
self.assertTrue(issubclass(w[-1].category, DeprecationWarning), method + " expected a DeprecationWarning")
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()