воспроизводить несколько файлов WAV одновременно, используя Alsa C API - PullRequest
0 голосов
/ 25 июня 2018

Я хочу реализовать определенную функциональность в моем проекте, которая включает в себя непрерывное воспроизведение sample-default.wav в фоновом режиме и воспроизведение файла sample-specific.wav при совпадении некоторых конкретных условий. Что я действительно хочу, так это то, что при работе файла sample-specific.wav объем файла sample-default.wav становится равным 0 (или просто я хочу отключить файл sample-default.wav при работе sample-specific.wav).

Я пытаюсь реализовать эту функцию, используя alsa-library для c. Я испробовал почти все подходы для достижения этой цели, но мне кажется, что ничего не работает.


Мой нынешний подход

Я пытаюсь добавить два виртуальных звуковых устройства, используя dmix плагин alsa, оставляя default для системных звуков. Я искал в Google и обнаружил, что мне нужно отредактировать файл /etc/asound.conf для создания различных звуковых устройств.

Я добавил два звуковых устройства с именами notification и sample-sound. Мой текущий /etc/asound.conf файл выглядит примерно так, как показано ниже: -

pcm.notification {
    type dmix
    ipc_key 1024
    slave {
        pcm "hw:1,0"
    }
}

ctl.notification {
     type hw
     card 2
}

pcm.sample-sound {
     type dmix
     ipc_key 1025
    slave {
         pcm "hw:1,0"
    }
}

ctl.sample-sound {
     type hw
    card 3
}

Это прекрасно работает с aplay, т.е. когда я играю файл sample-default.wav, используя aplay, с помощью следующей команды: -

aplay -D plug:notification sample-default.wav

Это работает, но когда я пытаюсь запустить следующий код для воспроизведения sample-default.wav, используя alsa library на моем notification устройстве: -

#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <pthread.h>

void default_sound (char * str) {
    snd_pcm_t *handle;
    snd_pcm_hw_params_t *params;
    snd_pcm_uframes_t frames;

    /* Open PCM device for playback */
    int status = snd_pcm_open(&handle, "notification", SND_PCM_STREAM_PLAYBACK, 0);
    if (status < 0) {
        printf("Unable to open pcm deveice%s\n", snd_strerror(status));
        return;
    }

    /* Allocate a hardware parameter obejct */
    snd_pcm_hw_params_alloca(&params);

    /* Fill it with default values */
    snd_pcm_hw_params_any(handle, params);

    /* Set the desired hardware parameters */

    /* Interleaved mode */
    snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);

    /* Signed 16-bit little-endian format */
    snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);

    /* Single Channel (mono) */
    snd_pcm_hw_params_set_channels(handle, params, 1);

    /* sampling rate */
    unsigned int sample_rate = 16000;
    int dir;
    snd_pcm_hw_params_set_rate_near(handle, params, &sample_rate, &dir);

    /* set period size to 32 frames */
    frames = 32;
    snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);

    /* Write the parameters to the driver */
    status = snd_pcm_hw_params(handle, params);
    if(status < 0) {
        printf("Unable to set hw params: %s\n", snd_strerror(status));
        return;
    }

    /* Use a buffer large enough to hold one period */
    snd_pcm_hw_params_get_period_size(params, &frames, &dir);

    int size = frames * 2;
    char *buffer = (char *)malloc(size);

    int readfd = open("sample-call.wav", O_RDONLY);
    if(readfd < 0) {
        printf("Error in opening wav file\n");
        exit(1);
    }


    int readval;
    while(readval = read(readfd, buffer, size) > 0) {
        status = snd_pcm_writei(handle, buffer, frames);
        if(status == -EPIPE) {
            printf("underrun occured\n");
            snd_pcm_prepare(handle);
        }
        else if(status < 0) {
            printf("Error from writei: %s\n", snd_strerror(status));
        }
    }

    snd_pcm_drain(handle);
    snd_pcm_close(handle);
    free(buffer);
}

int main() {
    pthread_t pthread_id;
    int status = pthread_create(&pthread_id, NULL, default_sound, "running");
    if (status != 0) {
        printf("Error in creating thread\n");
    }
    pthread_join(pthread_id, NULL);

    return 0;
}

Он успешно компилируется, но выдает ошибку времени выполнения: -

8211 segmentation fault (core dumped)  ./play-multiple-sound

Я не знаю, что не так с приведенным выше кодом.

Если приведенный выше код работает нормально, тогда я буду воспроизводить два звуковых файла на двух устройствах (notification и sample-sound) и управлять громкостью этих устройств с помощью библиотеки alsa-mixer, которую я уже внедрил.

Я пытаюсь добиться этого за последние несколько недель, и ни одно из решений, похоже, не работает для меня, поэтому, пожалуйста, помогите мне с этим, и если вы знаете лучший подход, то, пожалуйста, предложите.


...