I want to implement a specific functionality to my project which includes continuously playing a sample-default.wav
in the background and play a sample-specific.wav
file when some specific condition matches. What I really want is that, when sample-specific.wav
file is running, volume of sample-default.wav
file becomes 0 (or simply, I want to mute sample-default.wav
file when sample-specific.wav
is running).
I am trying to implement this functionality using alsa-library
for c. I have tried almost every approach to achieve this but nothing seems to works for me.
My current approach
I am trying to add two virtual sound devices using dmix
plugin of alsa
leaving default
for system sounds. I searched google and find that I need to edit /etc/asound.conf
file for creating different sound devices.
I added two sound devices, named notification
and sample-sound
. My current /etc/asound.conf
file looks something like the one below:-
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
}
This works perfectly fine with aplay
i.e. when I am playing sample-default.wav
file using aplay
by the following command:-
aplay -D plug:notification sample-default.wav
It works, but when i am trying to run the following code to play sample-default.wav
using alsa library
on my notification
device:-
#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(¶ms);
/* 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;
}
It compiles successfully but throws run-time error :-
8211 segmentation fault (core dumped) ./play-multiple-sound
I don't know what's going wrong with the above code.
If the above code works fine then I will play two sound files on two devices (notification
and sample-sound
) and control the volume of these devices using the alsa-mixer
library which I have already implemented.
I am trying to achieve this from the past few weeks and none of the solution seems to work for me, so please help me out with this and if you know a better approach then please suggest.