play multiple wav files simultaneously using alsa c api - c

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(&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;
}
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.

Related

Sound Recording & Play on Raspberry Pi Using ALSA in C

I am trying to record sound and play it in a C program.
just like using those terminal lines:
arecord -D plughw:0 -r 16000 sample.wav
for record, and later on
aplay sample.wav
to play the sound.
I used this code:
/*
This example reads from the default PCM device
and writes to standard output for 5 seconds of data.
*/
/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
int main() {
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
/* Open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, "default",
SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) {
fprintf(stderr,
"unable to open pcm device: %s\n",
snd_strerror(rc));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(&params);
/* Fill it in 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);
/* Two channels (stereo) */
snd_pcm_hw_params_set_channels(handle, params, 2);
/* 44100 bits/second sampling rate (CD quality) */
val = 44100;
snd_pcm_hw_params_set_rate_near(handle, params,
&val, &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 */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
fprintf(stderr,
"unable to set hw parameters: %s\n",
snd_strerror(rc));
exit(1);
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params,
&frames, &dir);
size = frames * 4; /* 2 bytes/sample, 2 channels */
buffer = (char *) malloc(size);
/* We want to loop for 5 seconds */
snd_pcm_hw_params_get_period_time(params,
&val, &dir);
loops = 5000000 / val;
while (loops > 0) {
loops--;
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE) {
/* EPIPE means overrun */
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(handle);
} else if (rc < 0) {
fprintf(stderr,
"error from read: %s\n",
snd_strerror(rc));
} else if (rc != (int)frames) {
fprintf(stderr, "short read, read %d frames\n", rc);
}
rc = write(1, buffer, size);
if (rc != size)
fprintf(stderr,
"short write: wrote %d bytes\n", rc);
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}
I compile this file this way:
gcc -o recorder -lasound recorder.c
and run it:
./recorder < sample.wav
if I try to play this with "aplay sample.wav" it's making a terrible noisy sound.
but if I use "aplay -t raw -f S16_LE -c2 -r44100 sample.wav"
it works good.
what I do wrong and if there is an easy way to capture audio and play it on Raspberry Pi?
Thank You for Your time.
Its just a basic thing, when you are trying aplay sample.wav" "aplay" will look for wave header and its not there in your file. So its playing with some other format (Sampling frequency,Channels, etc ..). That why your audio become noisy.
But in aplay -t raw -f S16_LE -c2 -r44100 sample.wav you are providing all information needed and its working fine.

How to record sound in buffer using ALSA [duplicate]

I'm begining to learn linux and ALSA and I was wondering if there is a way to store the sound I record from a microphone a directly to the buffer. I read here http://www.linuxjournal.com/article/6735?page=0,2 how to make my recording program. But what I need is a little more complex. I need to record sound untill I hit a key. The reason I need this is because I'm messing with a RaspberryPI(debian on it) and to see if I could turn it into a sound monitoring/detecting device.
My main problem is now that when I try to use it to record (./Rec >name.raw ) it does nothing. It just ouputs an empty .raw file.
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <termios.h>
#include <alsa/asoundlib.h>
struct termios stdin_orig; // Structure to save parameters
void term_reset() {
tcsetattr(STDIN_FILENO,TCSANOW,&stdin_orig);
tcsetattr(STDIN_FILENO,TCSAFLUSH,&stdin_orig);
}
void term_nonblocking() {
struct termios newt;
tcgetattr(STDIN_FILENO, &stdin_orig);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // non-blocking
newt = stdin_orig;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
atexit(term_reset);
}
int main() {
int key=0;
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
/* Open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) {
fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(&params);
/* Fill it in 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);
/* One channel (mono) */
snd_pcm_hw_params_set_channels(handle, params, 1);
/* 16000 bits/second sampling rate */
val = 16000;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
/* Set period size to 2048 frames. */
frames = 2048;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
exit(1);
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
size = frames * 2; /* 2 bytes/sample, 1 channels */
buffer = (char *) malloc(size);
while (key == 0)
{
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE)
{
/* EPIPE means overrun */
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(handle);
}
else if (rc < 0)
{
fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
}
else if (rc != (int)frames)
{
fprintf(stderr, "short read, read %d frames\n", rc);
}
rc = write(1, buffer, size);
if (rc != size)
fprintf(stderr, "short write: wrote %d bytes\n", rc);
key = getchar();
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}
Here is how I did that with python. Tested to work on my desktop Debian with USB Plantronics headphones. You need to install python-qt4 and python-pyaudio packages for this to work.
Also, you'll need to set your input device to microphone. In GNOME I switched both input and output devices via System Tools -> System Settings -> Sound. If you have Raspbian, not Debian on your Raspberry, as I do, it's gonna be tougher, cause there's LXDE instead of GNOME. You can use alsamixer and F6 button there to set audio cards, but the problem is that ALSA is low-level interface, while most Linuxes use some sound server on top of it, such as PulseAudio or JACK. You'll need some luck/spent time to make sure you switched input/output device to your mic/headphones.
If you use Jack microphone, plugged in through Jack input of your Raspberry Pi, note that Raspberry's Jack is input only, so you won't be able to play back your recordings and need some USB headphones to listen to your wav.
Personally, I feel that ALSA is very poorly documented (I suppose it's intentional job security) and I don't like to deal with it.
import pyaudio
import wave
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
# This is Qt part: we create a window, which has a "stop" flag.
# Stop flag defaults to False, but is set to True, when you press a key.
# Value of that flag is checked in main loop and loop exits when flag is True.
app = QApplication(sys.argv)
class MyWindow(QWidget):
def __init__(self):
super(QWidget, self).__init__()
self.stop = False
def keyPressEvent(self, event):
print "keyPressedEvent caught!"
self.stop = True
window = MyWindow()
window.show()
# This is sound processing part: we create an input stream to read from microphone.
p = pyaudio.PyAudio()
stream = p.open(format = p.get_format_from_width(2),
channels = 2,
rate=44100,
input=True,
output=False,
frames_per_buffer=1024)
# This is main loop: we iteratively poll audio and gui: audio data are stored in output_buffer,
# whereas gui is checked for stop flag value (if keyPressedEvent happened, flag will be set
# to True and break our main loop).
output_buffer = ""
while True:
app.processEvents()
data = stream.read(1024)
output_buffer += data
if window.stop: break
stream.stop_stream()
stream.close()
# Here we output contents of output_buffer as .wav file
output_wav = wave.open("output.wav", 'w')
output_wav.setparams((2, 2, 44100, len(output_buffer),"NONE","not compressed"))
output_wav.writeframesraw(output_buffer)
p.terminate()
This code shows you how to capture from ALSA in C++ in a while loop :
https://github.com/flatmax/gtkiostream/blob/master/test/ALSACaptureTest.C#L95
You can alter the loop there to record forever, replace :
while (N>0){
with
while (1){
Now you'll need some extra code. Firstly to read a character non-blocking add this to the top of the file :
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define ngetc(c) (read (0, (c), 1))
ngetc is a non-blocking read from stdin. It returns -1 when nothing is read. It returns > 1 when you press the enter key.
So finally putting this all together, change :
while (N>0){
with
while (1){
int enter=ngetc(&ch);
if (enter>0)
break;

How to record sound in buffer using ALSA

I'm begining to learn linux and ALSA and I was wondering if there is a way to store the sound I record from a microphone a directly to the buffer. I read here http://www.linuxjournal.com/article/6735?page=0,2 how to make my recording program. But what I need is a little more complex. I need to record sound untill I hit a key. The reason I need this is because I'm messing with a RaspberryPI(debian on it) and to see if I could turn it into a sound monitoring/detecting device.
My main problem is now that when I try to use it to record (./Rec >name.raw ) it does nothing. It just ouputs an empty .raw file.
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <termios.h>
#include <alsa/asoundlib.h>
struct termios stdin_orig; // Structure to save parameters
void term_reset() {
tcsetattr(STDIN_FILENO,TCSANOW,&stdin_orig);
tcsetattr(STDIN_FILENO,TCSAFLUSH,&stdin_orig);
}
void term_nonblocking() {
struct termios newt;
tcgetattr(STDIN_FILENO, &stdin_orig);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // non-blocking
newt = stdin_orig;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
atexit(term_reset);
}
int main() {
int key=0;
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
/* Open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) {
fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(&params);
/* Fill it in 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);
/* One channel (mono) */
snd_pcm_hw_params_set_channels(handle, params, 1);
/* 16000 bits/second sampling rate */
val = 16000;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
/* Set period size to 2048 frames. */
frames = 2048;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
exit(1);
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
size = frames * 2; /* 2 bytes/sample, 1 channels */
buffer = (char *) malloc(size);
while (key == 0)
{
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE)
{
/* EPIPE means overrun */
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(handle);
}
else if (rc < 0)
{
fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
}
else if (rc != (int)frames)
{
fprintf(stderr, "short read, read %d frames\n", rc);
}
rc = write(1, buffer, size);
if (rc != size)
fprintf(stderr, "short write: wrote %d bytes\n", rc);
key = getchar();
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}
Here is how I did that with python. Tested to work on my desktop Debian with USB Plantronics headphones. You need to install python-qt4 and python-pyaudio packages for this to work.
Also, you'll need to set your input device to microphone. In GNOME I switched both input and output devices via System Tools -> System Settings -> Sound. If you have Raspbian, not Debian on your Raspberry, as I do, it's gonna be tougher, cause there's LXDE instead of GNOME. You can use alsamixer and F6 button there to set audio cards, but the problem is that ALSA is low-level interface, while most Linuxes use some sound server on top of it, such as PulseAudio or JACK. You'll need some luck/spent time to make sure you switched input/output device to your mic/headphones.
If you use Jack microphone, plugged in through Jack input of your Raspberry Pi, note that Raspberry's Jack is input only, so you won't be able to play back your recordings and need some USB headphones to listen to your wav.
Personally, I feel that ALSA is very poorly documented (I suppose it's intentional job security) and I don't like to deal with it.
import pyaudio
import wave
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
# This is Qt part: we create a window, which has a "stop" flag.
# Stop flag defaults to False, but is set to True, when you press a key.
# Value of that flag is checked in main loop and loop exits when flag is True.
app = QApplication(sys.argv)
class MyWindow(QWidget):
def __init__(self):
super(QWidget, self).__init__()
self.stop = False
def keyPressEvent(self, event):
print "keyPressedEvent caught!"
self.stop = True
window = MyWindow()
window.show()
# This is sound processing part: we create an input stream to read from microphone.
p = pyaudio.PyAudio()
stream = p.open(format = p.get_format_from_width(2),
channels = 2,
rate=44100,
input=True,
output=False,
frames_per_buffer=1024)
# This is main loop: we iteratively poll audio and gui: audio data are stored in output_buffer,
# whereas gui is checked for stop flag value (if keyPressedEvent happened, flag will be set
# to True and break our main loop).
output_buffer = ""
while True:
app.processEvents()
data = stream.read(1024)
output_buffer += data
if window.stop: break
stream.stop_stream()
stream.close()
# Here we output contents of output_buffer as .wav file
output_wav = wave.open("output.wav", 'w')
output_wav.setparams((2, 2, 44100, len(output_buffer),"NONE","not compressed"))
output_wav.writeframesraw(output_buffer)
p.terminate()
This code shows you how to capture from ALSA in C++ in a while loop :
https://github.com/flatmax/gtkiostream/blob/master/test/ALSACaptureTest.C#L95
You can alter the loop there to record forever, replace :
while (N>0){
with
while (1){
Now you'll need some extra code. Firstly to read a character non-blocking add this to the top of the file :
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define ngetc(c) (read (0, (c), 1))
ngetc is a non-blocking read from stdin. It returns -1 when nothing is read. It returns > 1 when you press the enter key.
So finally putting this all together, change :
while (N>0){
with
while (1){
int enter=ngetc(&ch);
if (enter>0)
break;

Cannot open /dev/dsp

I am trying to learn audio recording, so I compiled The following code that I found online , but for some reason I cannot open /dev/dsp. I tried killing pulseaudio, but it re-opens as soon as I killall it. I really don't know what I am doing; I've been struggling for the latter part of the week. Please help.
I also tried chmod o+rw /dev/dsp
/*
* parrot.c
* Program to illustrate /dev/dsp device
* Records several seconds of sound, then echoes it back.
* Runs until Control-C is pressed.
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/soundcard.h>
#define LENGTH 3 /* how many seconds of speech to store */
#define RATE 8000 /* the sampling rate */
#define SIZE 8 /* sample size: 8 or 16 bits */
#define CHANNELS 1 /* 1 = mono 2 = stereo */
/* this buffer holds the digitized audio */
unsigned char buf[LENGTH*RATE*SIZE*CHANNELS/8];
int main()
{
int fd; /* sound device file descriptor */
int arg; /* argument for ioctl calls */
int status; /* return status of system calls */
/* open sound device */
fd = open("/dev/dsp", O_RDWR);
if (fd < 0) {
perror("open of /dev/dsp failed");
exit(1);
}
/* set sampling parameters */
arg = SIZE; /* sample size */
status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
if (status == -1)
perror("SOUND_PCM_WRITE_BITS ioctl failed");
if (arg != SIZE)
perror("unable to set sample size");
arg = CHANNELS; /* mono or stereo */
status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
if (status == -1)
perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");
if (arg != CHANNELS)
perror("unable to set number of channels");
arg = RATE; /* sampling rate */
status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
if (status == -1)
perror("SOUND_PCM_WRITE_WRITE ioctl failed");
while (1) { /* loop until Control-C */
printf("Say something:\n");
status = read(fd, buf, sizeof(buf)); /* record some sound */
if (status != sizeof(buf))
perror("read wrong number of bytes");
printf("You said:\n");
status = write(fd, buf, sizeof(buf)); /* play it back */
if (status != sizeof(buf))
perror("wrote wrong number of bytes");
/* wait for playback to complete before recording again */
status = ioctl(fd, SOUND_PCM_SYNC, 0);
if (status == -1)
perror("SOUND_PCM_SYNC ioctl failed");
}
}
See, /dev/dsp was used on older versions of ubuntu linux. It's no longer available in newer versions of ubuntu. I think it was gone with 10.04. Things changed from 10.10.
From one of the websites:
10.10 Maverick finally disabled the very old OSS drivers (which provided /dev/dsp, so the padsp wrapper is the easiest way to handle if it you can't select ALSA or PulseAudio directly.
See this http://manpages.ubuntu.com/manpages/hardy/man1/padsp.1.html

ALSA tutorial required

I am New to audio programming.I want to create small application which is capable of playing and gives volume control . I am using alsa-lib.
I want to know what is the purpose of switch (ex.Master Playback switch), enum in mixer elements and what value should i set to those switchs .
Please suggest me some tutorial for mixer settings as well as alsa programming .
Just collecting some here, that have example code:
ALSA Programming HOWTO v.1.0.0 [alsamodular.sourceforge.net]
A tutorial on using the ALSA Audio API [equalarea.com] 2002
A close look at ALSA [volkerschatz.com]
ALSA API - Sample Programs With Source Code By Aquiles Yanez 2005
Introduction to Sound Programming with ALSA | Linux Journal (pg3 with example code) 2004
Note that some of these are old, and API may have changed in the meantime... you can also look up aplay.c (the source for the command line arecord and aplay), but that one is not the easiest to read for starters...
You'll have a tough time finding anything concrete on ALSA, as I have have found from just starting learning it too. The best place to begin is the ALSA project homepage where they link to a number of tutorials, the best one being Dr Nagorni's one IMO.
From what it sounds like you're trying to do, JACK would most likely be a quicker and easier solution, though.
Check out the docs. There are some good examples.
http://www.alsa-project.org/alsa-doc/alsa-lib/examples.html
Be aware of the safe alsa subset.
https://www.winehq.org/pipermail/wine-bugs/2009-June/179698.html
Here's something small I put together using the various sources I could find. It miiiiiiiiiight be a good starting point.
/* Compile with gcc -lasound -pthread threadaudio.c */
#include <alsa/asoundlib.h>
#include <pthread.h>
#include <stdio.h>
unsigned char audiobuffer[0x400];
pthread_mutex_t audiomutex = PTHREAD_MUTEX_INITIALIZER;
void changeaudio (int volume) {
int i;
pthread_mutex_lock(&audiomutex);
for (i = 0; i < sizeof(audiobuffer); i++)
audiobuffer[i] = (random() & 0xff) * volume / 10;
pthread_mutex_unlock(&audiomutex);
}
void *startaudio (void *param)
{
static char *device = "default";
snd_output_t *output = NULL;
int *audiostop = (int*)param;
int err;
snd_pcm_t *handle;
snd_pcm_sframes_t frames;
changeaudio(5);
if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf("Playback open error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
if ((err = snd_pcm_set_params(handle,
SND_PCM_FORMAT_U8,
SND_PCM_ACCESS_RW_INTERLEAVED,
1,
48000,
1,
100000)) < 0) { /* 0.1sec */
printf("Playback open error: %s\n", snd_strerror(err));
exit(EXIT_FAILURE);
}
while (!*audiostop) {
err = snd_pcm_wait(handle, 1000);
if (err < 0) {
fprintf (stderr, "poll failed (%d)\n", err);
break;
}
pthread_mutex_lock(&audiomutex);
frames = snd_pcm_writei(handle, audiobuffer, sizeof(audiobuffer));
pthread_mutex_unlock(&audiomutex);
if (frames < 0)
err = snd_pcm_recover(handle, frames, 0);
if (err < 0) {
printf("snd_pcm_writei failed: %s\n", snd_strerror(err));
break;
}
if (frames > 0 && frames < (long)sizeof(audiobuffer))
printf("Short write (expected %li, wrote %li)\n", (long)sizeof(audiobuffer), frames);
}
snd_pcm_close(handle);
}
int main(void)
{
pthread_t audiothread;
int audiostop = 0;
int volume;
pthread_create(&audiothread, NULL, startaudio, &audiostop);
while (1) {
printf("Enter volume 1 through 10. [0 to quit.]: ");
scanf("%d", &volume);
if (volume == 0) break;
changeaudio(volume);
}
audiostop = 1;
pthread_join(audiothread, NULL);
return 0;
}
And after reading the code above you'll probably want to read this article regarding (among other things) not using locks.
http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing

Resources