Reputation: 11
I want to write an application with exactly one ALSA thread that uses poll()
to handle all the events of the mixer, playback, and capture. I have successfully implemented a little program for playback. Currently I have problems capturing samples using poll()
. I don't receive any capture events from poll()
. This is my code:
#include <stdio.h>
#include <alsa/asoundlib.h>
#include <sys/eventfd.h>
#include <pthread.h>
#define COUNT_SAMPLES 1024
#define COUNT_CHANNELS 2
#define DEVICE "plughw:CARD=DSC8,DEV=0"
#define SAMPLE_RATE 48000
#define FD_IGNORE -1
enum ALSA_FD {
FD_CONFIG,
FD_PLAYBACK,
FD_CAPTURE,
FD_MIXER,
FD_COUNT
};
static snd_pcm_t *capture_handle = NULL;
static struct pollfd fds[FD_COUNT];
static int fds_initialized = 0;
#define exit_on_fail(result, msg) { \
int error = result; \
if (error < 0) { \
printf("ERROR: %s (%s)\n", msg, snd_strerror(error)); \
exit(0); \
} \
}
void set_parameters(snd_pcm_t *handle, unsigned sample_rate, snd_pcm_format_t format, unsigned int count_channels) {
unsigned long period_size = COUNT_SAMPLES;
snd_pcm_sw_params_t *sw_params = NULL;
snd_pcm_hw_params_t *hw_params = NULL;
snd_pcm_sw_params_malloc(&sw_params);
snd_pcm_sw_params_current(handle, sw_params);
snd_pcm_hw_params_alloca(&hw_params);
exit_on_fail(snd_pcm_hw_params_any(handle, hw_params), "Failed to retrieve HW params");
exit_on_fail(snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED), "Can't set interleaved mode.");
exit_on_fail(snd_pcm_hw_params_set_format(handle, hw_params, format), "Can't set format.");
exit_on_fail(snd_pcm_hw_params_set_channels(handle, hw_params, count_channels), "Can't set channels number.");
exit_on_fail(snd_pcm_hw_params_set_rate_near(handle, hw_params, &sample_rate, 0), "Can't set rate.");
exit_on_fail(snd_pcm_hw_params_set_period_size_near(handle, hw_params, &period_size, 0), "Can't set period size");
exit_on_fail(snd_pcm_hw_params(handle, hw_params), "Failed to set HW params");
}
void * alsa_thread(void * arg) {
int status;
int terminated = 0;
printf("Starting alsa thread\n");
fds[FD_CONFIG].fd = FD_IGNORE; // EFD_NONBLOCK
fds[FD_CONFIG].fd = eventfd(0, EFD_NONBLOCK); // EFD_NONBLOCK
fds[FD_CONFIG].events = POLLIN;
fds[FD_CAPTURE].fd = FD_IGNORE;
fds[FD_CAPTURE].events = POLLIN;
fds[FD_PLAYBACK].fd = FD_IGNORE;
fds[FD_PLAYBACK].events = POLLOUT;
fds[FD_MIXER].fd = FD_IGNORE;
fds[FD_MIXER].events = POLLIN;
fds_initialized = 1;
while (!terminated) {
status = poll(fds, FD_COUNT, -1);
if (status > 0) {
printf("Status: %d\n", status);
if (fds[FD_PLAYBACK].revents & POLLOUT) {
printf("PLAYBACK\n");
}
if (fds[FD_CAPTURE].revents & POLLIN) {
printf("CAPTURE\n");
}
if (fds[FD_MIXER].revents & POLLOUT) {
printf("MIXER\n");
}
if (fds[FD_CONFIG].revents & POLLIN) {
eventfd_t value;
eventfd_read(fds[FD_CONFIG].fd, &value);
printf("CONFIG\n");
}
} else if (status < 0) {
printf("Error: %d", status);
}
}
close(fds[FD_CONFIG].fd);
return NULL;
}
void notify_config_changed() {
while (!fds_initialized);
eventfd_write(fds[FD_CONFIG].fd, 1);
}
void start_capture(const char *device, unsigned sample_rate, unsigned count_channels) {
exit_on_fail(snd_pcm_open(&capture_handle, device, SND_PCM_STREAM_CAPTURE, 0), "Failed to open PCM device");
set_parameters(capture_handle, sample_rate, SND_PCM_FORMAT_S32_LE, count_channels);
exit_on_fail(snd_pcm_poll_descriptors(capture_handle, &fds[FD_CAPTURE], 1), "Failed to set file descriptor");
notify_config_changed();
printf("Capturing ...\n");
}
int main(int argc, char **argv) {
pthread_t tid_alsa;
pthread_create(&tid_alsa, NULL, alsa_thread, NULL);
start_capture(DEVICE, SAMPLE_RATE, COUNT_CHANNELS);
for(;;);
return 0;
}
My console output is:
Starting alsa thread
Capturing ...
Status: 1
CONFIG
Any ideas are welcome!
Upvotes: 0
Views: 99
Reputation: 11
Finally, I have found the problem. In the function start_capture
I have added after the instruction
exit_on_fail(snd_pcm_poll_descriptors(capture_handle, &fds[FD_CAPTURE], 1), "Failed to set file descriptor");
this line:
exit_on_fail(snd_pcm_start(capture_handle), "Starting capturing ...");`
This starts the capturing and the events are correctly generated with poll. Here is the complete code of the function:
void start_capture(const char *device, unsigned sample_rate, unsigned count_channels) {
exit_on_fail(snd_pcm_open(&capture_handle, device, SND_PCM_STREAM_CAPTURE, 0), "Failed to open PCM device");
set_parameters(capture_handle, sample_rate, SND_PCM_FORMAT_S32_LE, count_channels);
exit_on_fail(snd_pcm_poll_descriptors(capture_handle, &fds[FD_CAPTURE], 1), "Failed to set file descriptor");
exit_on_fail(snd_pcm_start(capture_handle), "Starting capturing ...");
notify_config_changed();
printf("Capturing ...\n");
}
Upvotes: 1