How to configure a pcm to write to it periodically?
Hi all,
hope this is the right list. [1] stated that it's also intended for "application developers", so I ask here.
I've got a program that uses timers to periodically read samples from a microphone and write to a sound device. The timer's period is, for example, 20ms. So I have a sample rate of r = 16000, frame sizes of 20ms, a bit depth of 16 and therefore 320 samples per 20ms. I try to write those 320 samples timer-controled every 20ms to the pcm device.
That works fine when reading samples. When writing, however, it seems that snd_pcm_writei() blocks longer than the 20ms. Which it shouldn't do, as far as I understand snd_pcm_set_params() delay-parameter. I'll attach the example below.
So, I'd have a number of questions: 1. Am I even using ALSA as it's intended? As far as I saw in the API, there's the possiblity to get poll()able file descriptors from the API. So should I, instead of using my own timers, configure the ALSA interface to become readable every 20ms? 2. Why does my example not work as I intended? What does the "latency" parameter in snd_pcm_set_params() actually do? 3. Is the 'size' parameter in the write functions [2] the size in bytes or in samples? So if I configured SND_PCM_S16_LE and pass size = 10, will it read 10 bytes or 160 bit? It seems to be that it's the number of samples, whose type has been set with snd_pcm_set_params(). The docu isn't super clear to me, though.
It seems that the size parameter has changed a bit. At least the examples here [3] are faulting when I build them with -fsanitize=address
Thx a lot! Philipp
[1] https://www.alsa-project.org/wiki/Mailing-lists [2] https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html#gabc748a50... [3] http://equalarea.com/paul/alsa-audio.html
Example: /* * This is a mini-example of the code I took for my draft ofa broader application. * The main difference is that I call snd_pcm_writei() when my timer fires. */ #include <alsa/asoundlib.h> static char *device = "default"; /* playback device */ unsigned char buffer[16*1024]; /* some random data */ int main(void) { int err; unsigned int i; snd_pcm_t *handle; snd_pcm_sframes_t frames; for (i = 0; i < sizeof(buffer); i++) buffer[i] = random() & 0xff; if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } if ((err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 1, 16000, 1, 20000)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } for (i = 0; i < 16; i++) { frames = snd_pcm_writei(handle, buffer, sizeof(buffer) / sizeof(short)); if (frames < 0) frames = snd_pcm_recover(handle, frames, 0); if (frames < 0) { printf("snd_pcm_writei failed: %s\n", snd_strerror(frames)); break; } if (frames > 0 && frames < (long)(sizeof(buffer) / sizeof(short))) printf("Short write (expected %li, wrote %li)\n", (long)(sizeof(buffer) / sizeof(short)), frames); } /* pass the remaining samples, otherwise they're dropped in close */ err = snd_pcm_drain(handle); if (err < 0) printf("snd_pcm_drain failed: %s\n", snd_strerror(err)); snd_pcm_close(handle); return 0; }
PS: Seems the formatting for my example broke.
Here's a paste: https://paste.debian.net/1304802/
Am Sonntag, dem 21.01.2024 um 11:47 +0000 schrieb Philipp Stanner:
Hi all,
hope this is the right list. [1] stated that it's also intended for "application developers", so I ask here.
I've got a program that uses timers to periodically read samples from a microphone and write to a sound device. The timer's period is, for example, 20ms. So I have a sample rate of r = 16000, frame sizes of 20ms, a bit depth of 16 and therefore 320 samples per 20ms. I try to write those 320 samples timer-controled every 20ms to the pcm device.
That works fine when reading samples. When writing, however, it seems that snd_pcm_writei() blocks longer than the 20ms. Which it shouldn't do, as far as I understand snd_pcm_set_params() delay-parameter. I'll attach the example below.
So, I'd have a number of questions: 1. Am I even using ALSA as it's intended? As far as I saw in the API, there's the possiblity to get poll()able file descriptors from the API. So should I, instead of using my own timers, configure the ALSA interface to become readable every 20ms? 2. Why does my example not work as I intended? What does the "latency" parameter in snd_pcm_set_params() actually do? 3. Is the 'size' parameter in the write functions [2] the size in bytes or in samples? So if I configured SND_PCM_S16_LE and pass size = 10, will it read 10 bytes or 160 bit? It seems to be that it's the number of samples, whose type has been set with snd_pcm_set_params(). The docu isn't super clear to me, though.
It seems that the size parameter has changed a bit. At least the examples here [3] are faulting when I build them with -fsanitize=address
Thx a lot! Philipp
[1] https://www.alsa-project.org/wiki/Mailing-lists [2] https://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html#gabc748a50... [3] http://equalarea.com/paul/alsa-audio.html
Example: /* * This is a mini-example of the code I took for my draft ofa broader application. * The main difference is that I call snd_pcm_writei() when my timer fires. */ #include <alsa/asoundlib.h> static char *device = "default"; /* playback device */ unsigned char buffer[16*1024]; /* some random data */ int main(void) { int err; unsigned int i; snd_pcm_t *handle; snd_pcm_sframes_t frames; for (i = 0; i < sizeof(buffer); i++) buffer[i] = random() & 0xff; if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } if ((err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 1, 16000, 1, 20000)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } for (i = 0; i < 16; i++) { frames = snd_pcm_writei(handle, buffer, sizeof(buffer) / sizeof(short)); if (frames < 0) frames = snd_pcm_recover(handle, frames, 0); if (frames < 0) { printf("snd_pcm_writei failed: %s\n", snd_strerror(frames)); break; } if (frames > 0 && frames < (long)(sizeof(buffer) / sizeof(short))) printf("Short write (expected %li, wrote %li)\n", (long)(sizeof(buffer) / sizeof(short)), frames); } /* pass the remaining samples, otherwise they're dropped in close */ err = snd_pcm_drain(handle); if (err < 0) printf("snd_pcm_drain failed: %s\n", snd_strerror(err)); snd_pcm_close(handle); return 0; }
participants (1)
-
Philipp Stanner