Невозможно применить настроенные параметры для звукового устройства - PullRequest
0 голосов
/ 03 декабря 2018

Я написал следующий простой пример с 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 здесь?

...