Ok, well ive written some code, but it doesnt work, any help guys?
Its supposed to take a wave file in the correct format piped to it from stdin. The soundcard gets configured right (seemingly) but it just doesnt play.
/*
This program opens an audio interface for playback, configures it for
"CD" audio - 2ch Stereo, 16 bit at 44.1 khz
It reads from stdin and writes 5secs of data.to the default PCM device
Compile with g++ (filename) -lasound
http://www.linuxjournal.com/article/6735?page=0,1 http://www.equalarea.com/paul/alsa-audio.html http://soundprogramming.net/programming_apis/alsa_tutorial_1_initialization
*/
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <alsa/asoundlib.h>
#include <sys/ioctl.h>
using namespace std;
// Use the newer ALSA API
#define ALSA_PCM_NEW_HW_PARAMS_API
// Globals are bad but oh well, keeps it simple.
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
// Runs ALSA sound plackback tests
void testSound()
{
long loops;
int rc;
int size;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
int err;
// Try to open the default device
err = snd_pcm_open( &handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, 0 );
// Check for error on open.
if( err < 0 )
{
cout << "ERROR: Cannot open audio device! " << snd_strerror (err)
<< ")" << endl;
return;
}
else
{
cout << "SUCCESS: Audio device opened successfully!" << endl;
}
// Allocate the hardware parameter structure.
if ((err = snd_pcm_hw_params_malloc (¶ms)) < 0) // malloc vs alloca ?
{
cout << "ERROR: Error encountered while allocating hardware parameter structure! (" << snd_strerror
(err) << ")" << endl;
return;
}
//Fill it in with default values.
if ((err = snd_pcm_hw_params_any (handle, params)) < 0)
{
cout << "ERROR: Error encountered while initializing hardware parameter structure! (" << snd_strerror
(err) << ")" << endl;
return;
}
// Enable resampling.
unsigned int resample = 1;
err = snd_pcm_hw_params_set_rate_resample(handle, params, resample);
if (err < 0)
{
cout << "ERROR: Setting up resampling for playback failed! " << snd_strerror(err) <<
endl;
return;
}
// Set access to RW interleaved.
if ((err = snd_pcm_hw_params_set_access (handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
cout << "ERROR: Cannot set RW-Interleaved access type (" << snd_strerror (err) << ")" << endl;
return;
}
// Signed 16-bit little-endian format
if ((err = snd_pcm_hw_params_set_format (handle, params,
SND_PCM_FORMAT_S16_LE)) < 0)
{
cout << "ERROR: Cannot set 16-Bit PCM Sample format (" << snd_strerror (err) << ")" << endl;
return;
}
// Set to 2channel (Stereo)
if ((err = snd_pcm_hw_params_set_channels (handle, params, 2)) < 0)
{
cout << "ERROR: Cannot set channel count to 2 (Stereo) (" << snd_strerror (err) << ")" << endl;
return;
}
// Set sample rate to 44.1 khz (CD quality).
unsigned int actualRate = 44100;
if ((err = snd_pcm_hw_params_set_rate_near (handle, params, &actualRate,
0)) < 0)
{
cout << "ERROR: Cannot set sample rate to 44100 (44.1khz)! (" << snd_strerror (err) << ")"
<< endl;
return;
}
if( actualRate < 44100 )
{
cout << "ERROR: Sample rate does not match that requested? (" << "44100 requested, " << actualRate << " acquired)" << endl;
}
// Set period size to 32 frames.
frames = 32;
snd_pcm_hw_params_set_period_size_near(handle,
params, &frames, &dir);
// Write the hardware parameters that we've just set to the driver.
if ((err = snd_pcm_hw_params (handle, params)) < 0)
{
cout << "ERROR: Cannot set HW parameters (" << snd_strerror (err) << ")" << endl;
return;
}
else
{
cout << "SUCCESS: Audio device HW parameters have been set successfully!" << endl;
}
// Get the buffer size.
snd_pcm_uframes_t bufferSize;
snd_pcm_hw_params_get_buffer_size( params, &bufferSize );
// If we were going to do more with our sound device we would want to store
// the buffer size so we know how much data we will need to fill it with.
cout << "Buffer size: " << bufferSize << " frames." << endl;
// Display the bit size of samples.
cout << "Significant bits (For linear samples): " <<
snd_pcm_hw_params_get_sbits(params) << endl;
// Free the hardware parameters now that we're done with them.
snd_pcm_hw_params_free (params);
// Prepare interface for use.
if ((err = snd_pcm_prepare (handle)) < 0)
{
cout << "ERROR: Unable to prepare audio interface for use! (" << snd_strerror (err)
<< ")" << endl;
return;
}
else
{
cout << "SUCCESS: Audio device has been prepared for use." << endl;
}
// Done, now play back file
// Open PCM device for playback.
rc = snd_pcm_open(&handle, "default",
SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0) {
fprintf(stderr,
"ERROR: Unable to open PCM device: %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 (microseconds / period time)
snd_pcm_hw_params_get_period_time(params,
&val, &dir);
loops = 5000000 / val;
while (loops > 0) {
loops--;
rc = read(0, buffer, size); // Read from file descriptor/handle 0 - stdin
if (rc == 0) {
fprintf(stderr, "SUCCESS: Reached EOF\n");
break;
} else if (rc != size) {
fprintf(stderr,
"ERROR: Short read! - Read %d bytes\n", rc);
}
rc = snd_pcm_writei(handle, buffer, frames);
if (rc == -EPIPE) {
// EPIPE means underrun
fprintf(stderr, "ERROR: Underrun occurred!\n");
snd_pcm_prepare(handle);
} else if (rc < 0) {
fprintf(stderr,
"ERROR: Writei: %s\n",
snd_strerror(rc));
} else if (rc != (int)frames) {
fprintf(stderr,
"ERROR: Short write, wrote %d frames!\n", rc);
}
}
// Tidy up
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
cout << "SUCCESS: Audio device has been uninitialized." << endl;
}
int main(int argc, char *argv[])
{
testSound();
return 0;
}