使用 poll() 使用 ALSA 捕获样本不起作用

问题描述 投票:0回答:1

我想编写一个只有一个 ALSA 线程的应用程序,该线程使用

poll()
来处理混音器、播放和捕获的所有事件。我已经成功实现了一个用于播放的小程序。目前我在使用
poll()
捕获样本时遇到问题。我没有收到来自
poll()
的任何捕获事件。这是我的代码:

#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;
}

我的控制台输出是:

Starting alsa thread
Capturing ...
Status: 1
CONFIG

欢迎任何想法!

audio libalsa
1个回答
0
投票

终于找到问题所在了。在函数中

start_capture
我在指令后添加了

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 ...");`.

这将开始捕获,并通过轮询正确生成事件。这是该函数的完整代码:

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");
}
© www.soinside.com 2019 - 2024. All rights reserved.