无法为声音设备应用已配置的参数

时间:2018-12-03 08:43:28

标签: c undefined-behavior alsa

我用asoundlib.h写了以下简单示例:

#include <alsa/asoundlib.h>
#include <sys/fcntl.h>
#include <unistd.h>

typedef struct sound_device_config_t sound_device_config_t;

struct sound_device_config_t{
        unsigned int rate;
        unsigned int periods;
        snd_pcm_uframes_t period_size;
        unsigned int channels;
        snd_pcm_format_t sample_format;
};

static void _configure_device(snd_pcm_t **pcm_handle_ptr, const char *sd);

int main(int argc, char * argv[]){
    sound_device_config_t *cfg_ptr = malloc(sizeof(sound_device_config_t));
    cfg_ptr -> channels = 2;
    cfg_ptr -> period_size = 2048;
    cfg_ptr -> periods = 2;
    cfg_ptr -> rate = 44100;
    cfg_ptr -> sample_format = SND_PCM_FORMAT_S16_LE;
    snd_pcm_t *pcm_handle;

    _configure_device(&pcm_handle, "plughw:1,0");
    return 0;
}

_configure_device文件末尾实现main.c的位置,如下所示:

static void _configure_device(snd_pcm_t **pcm_handle_ptr, const char *sd_name){ 
    snd_pcm_hw_params_t *hwparams;
    snd_pcm_stream_t stream = SND_PCM_STREAM_CAPTURE;
    snd_pcm_t *pcm_handle = *pcm_handle_ptr;
    snd_pcm_hw_params_alloca(&hwparams);
    const char * device_name = strdup(sd_name);

    int err;

    if((err = snd_pcm_open(&pcm_handle, device_name, stream, 0)) < 0){
        fprintf(stderr, "Something went wrong. Result code = %d\n", err);
        fprintf(stderr, "Error details: %s\n", snd_strerror(err));
        return;
    }


    if((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0){
        fprintf(stderr, "Initialization failed wit error %d\n", err);
        fprintf(stderr, "Error details: %s\n", snd_strerror(err));
        return;
    }
    int rate = 44100;
    int exact_rate;

    int direction;

    int periods = 2;
    snd_pcm_uframes_t period_size = 8192;

    if((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
       fprintf(stderr, "Error setting access. Details: %s\n", snd_strerror(err));
       return;
    } else {
        printf("Setting access to SND_PCM_ACCESS_RW_INTERLEAVED: %s\n", snd_strerror(err));
    }

    if((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0){
        fprintf(stderr, "Error setting format. Details: %s\n", snd_strerror(err));
        return;
    } else {
        printf("Setting format to SND_PCM_FORMAT_S16_LE: %s\n", snd_strerror(err));
    }

    exact_rate = rate;
    if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, &direction)) < 0){
        fprintf(stderr, "Error setting sample rate to %d. Details: %s\n", exact_rate, snd_strerror(err));
        return;
    } else if(rate != exact_rate){ 
        fprintf(stderr, "The rate %d is not supported by your hardware.\n\
        Setting rate to the nearest supported %d instead.\n", rate, exact_rate);
    } else {
        printf("Setting rate to %d: %s\n", rate, snd_strerror(err));
    }

    if((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2))){
        fprintf(stderr, "Error setting number of channels. Details: %s\n", snd_strerror(err));
        return;
    } else {
        printf("Setting channels to 2: %s\n", snd_strerror(err));
    }

    if((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, direction))){
        fprintf(stderr, "Error setting periods to %d. Details: %s\n", periods, snd_strerror(err));
        return; 
    } else {
        printf("Setting periods to %d: %s\n", periods, snd_strerror(err));
    }

    if((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (period_size * periods) >> 2)) < 0){
        fprintf(stderr, "Error setting buffer size. Details: %s\n", snd_strerror(err));
        return;
    } else {
        printf("Setting buffer size status: %s\n", snd_strerror(err));
    }

    if((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0){
        fprintf(stderr, "Cannot set the configured params. Details: %s\n", snd_strerror(err));
        return;
    } else {
        printf("Params are successfully applied to the pcm device\n");
    }
}

它不起作用。当我运行此代码时,将显示以下内容:

Setting access to SND_PCM_ACCESS_RW_INTERLEAVED: Success
Setting format to SND_PCM_FORMAT_S16_LE: Success
Setting rate to 44100: Success
Setting channels to 2: Success
Setting periods to 2: Success
Error setting buffer size. Details: Invalid argument

但是,当我删除sound_device_config_t的配置分配和初始化(我打算用来配置声音设备,目前不使用)时,它可以正常工作:

int main(int argc, char * argv[]){
    snd_pcm_t *pcm_handle;

    _configure_device(&pcm_handle, "plughw:1,0");
}

打印

Setting access to SND_PCM_ACCESS_RW_INTERLEAVED: Success
Setting format to SND_PCM_FORMAT_S16_LE: Success
Setting rate to 44100: Success
Setting channels to 2: Success
Setting periods to 2: Success
Setting buffer size status: Success
Params are successfully applied to the pcm device

这看起来有些神奇。我删除了一个在任何地方都不使用的对象的分配,它会影响程序的行为。

也许我在这里错过了一些UB?

0 个答案:

没有答案