使用alsa c api同时播放多个wav文件

时间:2018-06-25 11:13:50

标签: c audio alsa mixer libalsa

我想为我的项目实现特定的功能,包括在后台连续播放sample-default.wav并在某些特定条件匹配时播放sample-specific.wav文件。我真正想要的是,当sample-specific.wav文件运行时,sample-default.wav文件的容量变为0(或者简单地,我想在sample-default.wav运行时使sample-specific.wav文件静音)

我正在尝试使用alsa-library for c来实现此功能。我几乎尝试了所有方法来实现这一目标,但似乎没有任何效果。


我目前的做法

我正在尝试使用dmix的{​​{1}}插件添加两个虚拟声音设备,而将alsa用作系统声音。我搜索了google,发现需要编辑default文件来创建其他声音设备。

我添加了两个声音设备,分别名为/etc/asound.confnotification。我当前的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库控制这些设备的音量已经实施。

过去几周我一直在努力实现这一目标,但似乎没有一种解决方案适合我,因此请帮我解决这个问题,如果您知道更好的方法,请提出建议。


0 个答案:

没有答案