simpleaudio: generalized simpleaudio_open_stream

This commit is contained in:
Kamal Mostafa 2012-08-12 14:24:55 -07:00
parent 5dddc1445a
commit 4d326a8c82
7 changed files with 214 additions and 151 deletions

View File

@ -284,17 +284,13 @@ main( int argc, char*argv[] )
float carrier_autodetect_threshold = 0.0; float carrier_autodetect_threshold = 0.0;
float bfsk_confidence_threshold = 0.6; float bfsk_confidence_threshold = 0.6;
simpleaudio * (*simpleaudio_open_system_audio)() = NULL; sa_backend_t sa_backend = SA_BACKEND_SYSDEFAULT;
unsigned int sample_rate = 48000; unsigned int sample_rate = 48000;
unsigned int nchannels = 1; // FIXME: only works with one channel unsigned int nchannels = 1; // FIXME: only works with one channel
/* configure the default system audio mechanism */ /* validate the default system audio mechanism */
#if USE_PULSEAUDIO #if !(USE_PULSEAUDIO || USE_ALSA)
simpleaudio_open_system_audio = simpleaudio_open_stream_pulseaudio;
#elif USE_ALSA
simpleaudio_open_system_audio = simpleaudio_open_stream_alsa;
#else
# define _MINIMODEM_NO_SYSTEM_AUDIO # define _MINIMODEM_NO_SYSTEM_AUDIO
# if !USE_SNDFILE # if !USE_SNDFILE
# error At least one of {USE_PULSEAUDIO,USE_ALSA,USE_SNDFILE} must be enabled! # error At least one of {USE_PULSEAUDIO,USE_ALSA,USE_SNDFILE} must be enabled!
@ -391,7 +387,7 @@ main( int argc, char*argv[] )
break; break;
case 'A': case 'A':
#if USE_ALSA #if USE_ALSA
simpleaudio_open_system_audio = simpleaudio_open_stream_alsa; sa_backend = SA_BACKEND_ALSA;
#else #else
fprintf(stderr, "E: This build of minimodem was configured without alsa support.\n"); fprintf(stderr, "E: This build of minimodem was configured without alsa support.\n");
exit(1); exit(1);
@ -508,31 +504,29 @@ main( int argc, char*argv[] )
band_width = bfsk_data_rate; band_width = bfsk_data_rate;
char *stream_name = NULL;;
if ( filename ) {
sa_backend = SA_BACKEND_FILE;
stream_name = filename;
}
/* /*
* Handle transmit mode * Handle transmit mode
*/ */
if ( TX_mode ) { if ( TX_mode ) {
simpleaudio *sa_out = NULL; int tx_interactive = 0;
int tx_interactive = 1; if ( ! stream_name ) {
tx_interactive = 1;
if ( filename ) { stream_name = "output audio";
tx_interactive = 0;
#if USE_SNDFILE
sa_out = simpleaudio_open_stream_sndfile(SA_STREAM_PLAYBACK,
SA_SAMPLE_FORMAT_FLOAT,
sample_rate, nchannels,
filename);
#endif
if ( ! sa_out )
return 1;
} }
if ( ! sa_out ) simpleaudio *sa_out;
sa_out = simpleaudio_open_system_audio(SA_STREAM_PLAYBACK, sa_out = simpleaudio_open_stream(sa_backend, SA_STREAM_PLAYBACK,
SA_SAMPLE_FORMAT_FLOAT, SA_SAMPLE_FORMAT_FLOAT,
sample_rate, nchannels, sample_rate, nchannels,
program_name, "output audio"); program_name, stream_name);
if ( ! sa_out ) if ( ! sa_out )
return 1; return 1;
@ -543,6 +537,9 @@ main( int argc, char*argv[] )
bfsk_txstopbits, bfsk_txstopbits,
bfsk_framebits_encode bfsk_framebits_encode
); );
simpleaudio_close(sa_out);
return 0; return 0;
} }
@ -550,24 +547,16 @@ main( int argc, char*argv[] )
/* /*
* Open the input audio stream * Open the input audio stream
*/ */
simpleaudio *sa = NULL;
if ( filename ) {
#if USE_SNDFILE
sa = simpleaudio_open_stream_sndfile(SA_STREAM_RECORD,
SA_SAMPLE_FORMAT_FLOAT,
sample_rate, nchannels,
filename);
#endif
if ( ! sa )
return 1;
}
if ( ! sa ) if ( ! stream_name )
sa = simpleaudio_open_system_audio(SA_STREAM_RECORD, stream_name = "input audio";
simpleaudio *sa;
sa = simpleaudio_open_stream(sa_backend, SA_STREAM_RECORD,
SA_SAMPLE_FORMAT_FLOAT, SA_SAMPLE_FORMAT_FLOAT,
sample_rate, nchannels, sample_rate, nchannels,
program_name, "input audio"); program_name, stream_name);
if ( !sa ) if ( ! sa )
return 1; return 1;

View File

@ -95,17 +95,11 @@ sa_alsa_close( simpleaudio *sa )
snd_pcm_close(sa->backend_handle); snd_pcm_close(sa->backend_handle);
} }
static int
static const struct simpleaudio_backend simpleaudio_backend_alsa = { sa_alsa_open_stream(
sa_alsa_read, simpleaudio *sa,
sa_alsa_write, sa_direction_t sa_stream_direction,
sa_alsa_close, sa_format_t sa_format,
};
simpleaudio *
simpleaudio_open_stream_alsa(
int sa_stream_direction,
sa_sample_format_t sa_sample_format,
unsigned int rate, unsigned int channels, unsigned int rate, unsigned int channels,
char *app_name, char *stream_name ) char *app_name, char *stream_name )
{ {
@ -118,10 +112,10 @@ simpleaudio_open_stream_alsa(
0 /*mode*/); 0 /*mode*/);
if (error) { if (error) {
fprintf(stderr, "E: Cannot create ALSA stream: %s\n", snd_strerror(error)); fprintf(stderr, "E: Cannot create ALSA stream: %s\n", snd_strerror(error));
return NULL; return 0;
} }
assert( sa_sample_format == SA_SAMPLE_FORMAT_FLOAT ); assert( sa_format == SA_SAMPLE_FORMAT_FLOAT );
/* set up ALSA hardware params */ /* set up ALSA hardware params */
error = snd_pcm_set_params(pcm, error = snd_pcm_set_params(pcm,
@ -134,7 +128,7 @@ simpleaudio_open_stream_alsa(
if (error) { if (error) {
fprintf(stderr, "E: %s\n", snd_strerror(error)); fprintf(stderr, "E: %s\n", snd_strerror(error));
snd_pcm_close(pcm); snd_pcm_close(pcm);
return NULL; return 0;
} }
#if 0 #if 0
@ -157,21 +151,18 @@ simpleaudio_open_stream_alsa(
} }
#endif #endif
simpleaudio *sa = malloc(sizeof(simpleaudio));
if ( !sa ) {
perror("malloc");
snd_pcm_close(pcm);
return NULL;
}
sa->format = sa_sample_format;
sa->rate = rate;
sa->channels = channels;
sa->samplesize = sizeof(float);
sa->backend = &simpleaudio_backend_alsa;
sa->backend_handle = pcm; sa->backend_handle = pcm;
sa->backend_framesize = sa->channels * sa->samplesize; sa->backend_framesize = sa->channels * sa->samplesize;
return sa; return 1;
} }
#endif /* USE_PULSEAUDIO */
const struct simpleaudio_backend simpleaudio_backend_alsa = {
sa_alsa_open_stream,
sa_alsa_read,
sa_alsa_write,
sa_alsa_close,
};
#endif /* USE_ALSA */

View File

@ -79,17 +79,11 @@ sa_pulse_close( simpleaudio *sa )
pa_simple_free(sa->backend_handle); pa_simple_free(sa->backend_handle);
} }
static int
static const struct simpleaudio_backend simpleaudio_backend_pulse = { sa_pulse_open_stream(
sa_pulse_read, simpleaudio *sa,
sa_pulse_write, sa_direction_t sa_stream_direction,
sa_pulse_close, sa_format_t sa_format,
};
simpleaudio *
simpleaudio_open_stream_pulseaudio(
int sa_stream_direction,
sa_sample_format_t sa_sample_format,
unsigned int rate, unsigned int channels, unsigned int rate, unsigned int channels,
char *app_name, char *stream_name ) char *app_name, char *stream_name )
{ {
@ -98,7 +92,7 @@ simpleaudio_open_stream_pulseaudio(
// FIXME - use source for something // FIXME - use source for something
// just take the default pulseaudio source for now // just take the default pulseaudio source for now
assert( sa_sample_format == SA_SAMPLE_FORMAT_FLOAT ); assert( sa_format == SA_SAMPLE_FORMAT_FLOAT );
/* The sample type to use */ /* The sample type to use */
pa_sample_spec ss = { pa_sample_spec ss = {
@ -128,26 +122,25 @@ simpleaudio_open_stream_pulseaudio(
&ss, NULL, &attr, &error); &ss, NULL, &attr, &error);
if ( !s ) { if ( !s ) {
fprintf(stderr, "E: Cannot create PulseAudio stream: %s\n ", pa_strerror(error)); fprintf(stderr, "E: Cannot create PulseAudio stream: %s\n ", pa_strerror(error));
return NULL; return 0;
} }
simpleaudio *sa = malloc(sizeof(simpleaudio)); /* good or bad to override these? */
if ( !sa ) {
perror("malloc");
pa_simple_free(s);
return NULL;
}
sa->format = sa_sample_format;
sa->rate = ss.rate; sa->rate = ss.rate;
sa->channels = ss.channels; sa->channels = ss.channels;
sa->samplesize = sizeof(float);
sa->backend = &simpleaudio_backend_pulse;
sa->backend_handle = s; sa->backend_handle = s;
sa->backend_framesize = pa_frame_size(&ss); sa->backend_framesize = pa_frame_size(&ss);
assert( sa->backend_framesize == sa->channels * sa->samplesize ); return 1;
return sa;
} }
const struct simpleaudio_backend simpleaudio_backend_pulseaudio = {
sa_pulse_open_stream,
sa_pulse_read,
sa_pulse_write,
sa_pulse_close,
};
#endif /* USE_PULSEAUDIO */ #endif /* USE_PULSEAUDIO */

View File

@ -76,13 +76,6 @@ sa_sndfile_close( simpleaudio *sa )
} }
static const struct simpleaudio_backend simpleaudio_backend_sndfile = {
sa_sndfile_read,
sa_sndfile_write,
sa_sndfile_close,
};
/* (Why) doesn't libsndfile provide an API for this?... */ /* (Why) doesn't libsndfile provide an API for this?... */
static const struct sndfile_format { static const struct sndfile_format {
unsigned int major_format; unsigned int major_format;
@ -132,14 +125,17 @@ sndfile_format_from_path( const char *path )
return SF_FORMAT_WAV; return SF_FORMAT_WAV;
} }
simpleaudio * static int
simpleaudio_open_stream_sndfile( sa_sndfile_open_stream(
int sa_stream_direction, simpleaudio *sa,
sa_sample_format_t sa_sample_format, sa_direction_t sa_stream_direction,
sa_format_t sa_format,
unsigned int rate, unsigned int channels, unsigned int rate, unsigned int channels,
char *path ) char *app_name, char *stream_name )
{ {
assert( sa_sample_format == SA_SAMPLE_FORMAT_FLOAT ); const char *path = stream_name;
assert( sa_format == SA_SAMPLE_FORMAT_FLOAT );
/* setting for SA_STREAM_PLAYBACK (file write) */ /* setting for SA_STREAM_PLAYBACK (file write) */
SF_INFO sfinfo = { SF_INFO sfinfo = {
@ -159,24 +155,25 @@ simpleaudio_open_stream_sndfile(
if ( !s ) { if ( !s ) {
fprintf(stderr, "%s: ", path); fprintf(stderr, "%s: ", path);
sf_perror(s); sf_perror(s);
return NULL; return 0;
} }
simpleaudio *sa = malloc(sizeof(simpleaudio)); /* good or bad to override these? */
if ( !sa ) {
perror("malloc");
sf_close(s);
return NULL;
}
sa->format = sa_sample_format;
sa->rate = sfinfo.samplerate; sa->rate = sfinfo.samplerate;
sa->channels = sfinfo.channels; sa->channels = sfinfo.channels;
sa->samplesize = sizeof(float);
sa->backend = &simpleaudio_backend_sndfile;
sa->backend_handle = s; sa->backend_handle = s;
sa->backend_framesize = sa->channels * sa->samplesize; sa->backend_framesize = sa->channels * sa->samplesize;
return sa; return 1;
} }
const struct simpleaudio_backend simpleaudio_backend_sndfile = {
sa_sndfile_open_stream,
sa_sndfile_read,
sa_sndfile_write,
sa_sndfile_close,
};
#endif /* USE_SNDFILE */ #endif /* USE_SNDFILE */

View File

@ -19,9 +19,101 @@
#include "simpleaudio.h" #include "simpleaudio.h"
#include "simpleaudio_internal.h" #include "simpleaudio_internal.h"
#include "malloc.h"
sa_sample_format_t #include <malloc.h>
#include <assert.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#else
# define USE_PULSEAUDIO 1
# define USE_ALSA 1
#endif
simpleaudio *
simpleaudio_open_stream(
sa_backend_t sa_backend,
sa_direction_t sa_stream_direction,
sa_format_t sa_format,
unsigned int rate, unsigned int channels,
char *app_name, char *stream_name )
{
simpleaudio *sa = calloc(1, sizeof(simpleaudio));
if ( !sa ) {
perror("malloc");
return NULL;
}
sa->format = sa_format;
sa->rate = rate;
sa->channels = channels;
switch ( sa_format ) {
case SA_SAMPLE_FORMAT_FLOAT:
assert( sizeof(float) == 4 );
sa->samplesize = sizeof(float);
break;
case SA_SAMPLE_FORMAT_S16:
assert( sizeof(short) == 2 );
sa->samplesize = sizeof(short);
break;
default:
fprintf(stderr, "simpleaudio_open_stream: no such sa_format (%d)\n", sa_format);
goto err_out;
break;
}
switch ( sa_backend ) {
#if USE_SNDFILE
case SA_BACKEND_FILE:
sa->backend = &simpleaudio_backend_sndfile;
break;
#endif
case SA_BACKEND_SYSDEFAULT:
#if USE_PULSEAUDIO
sa->backend = &simpleaudio_backend_pulseaudio;
#elif USE_ALSA
sa->backend = &simpleaudio_backend_alsa;
#else
fprintf(stderr, "simpleaudio_open_stream: no SA_BACKEND_SYSDEFAULT was configured\n");
goto err_out;
#endif
break;
#if USE_ALSA
case SA_BACKEND_ALSA:
sa->backend = &simpleaudio_backend_alsa;
break;
#endif
#if USE_PULSEAUDIO
case SA_BACKEND_PULSEAUDIO:
sa->backend = &simpleaudio_backend_pulseaudio;
break;
#endif
default:
fprintf(stderr, "simpleaudio_open_stream: no such sa_backend (%d). not configured at build?\n", sa_backend);
goto err_out;
}
int ok = sa->backend->simpleaudio_open_stream(sa,
sa_stream_direction, sa_format,
rate, channels, app_name, stream_name);
if ( ok ) {
assert( sa->backend_framesize == sa->channels * sa->samplesize );
return sa;
}
err_out:
free(sa);
return NULL;
}
sa_format_t
simpleaudio_get_format( simpleaudio *sa ) simpleaudio_get_format( simpleaudio *sa )
{ {
return sa->format; return sa->format;

View File

@ -31,43 +31,34 @@ typedef struct simpleaudio simpleaudio;
* *
*/ */
/* sa_backend */
typedef enum {
SA_BACKEND_SYSDEFAULT=0,
SA_BACKEND_FILE,
SA_BACKEND_ALSA,
SA_BACKEND_PULSEAUDIO,
} sa_backend_t;
/* sa_stream_direction */ /* sa_stream_direction */
enum { typedef enum {
SA_STREAM_PLAYBACK, SA_STREAM_PLAYBACK,
SA_STREAM_RECORD, SA_STREAM_RECORD,
}; } sa_direction_t;
/* sa_stream_format */ /* sa_stream_format */
typedef enum { typedef enum {
SA_SAMPLE_FORMAT_S16, SA_SAMPLE_FORMAT_S16,
SA_SAMPLE_FORMAT_FLOAT, SA_SAMPLE_FORMAT_FLOAT,
} sa_sample_format_t; } sa_format_t;
simpleaudio * simpleaudio *
simpleaudio_open_stream_pulseaudio( simpleaudio_open_stream(
int sa_stream_direction, sa_backend_t sa_backend,
sa_sample_format_t sa_sample_format, sa_direction_t sa_stream_direction,
sa_format_t sa_format,
unsigned int rate, unsigned int channels, unsigned int rate, unsigned int channels,
char *app_name, char *stream_name ); char *app_name, char *stream_name );
simpleaudio *
simpleaudio_open_stream_alsa(
int sa_stream_direction,
sa_sample_format_t sa_sample_format,
unsigned int rate, unsigned int channels,
char *app_name, char *stream_name );
simpleaudio *
simpleaudio_open_stream_sndfile(
int sa_stream_direction,
sa_sample_format_t sa_sample_format,
unsigned int rate, unsigned int channels,
char *path );
/*
* common simpleaudio_ API routines available to any backend:
*/
unsigned int unsigned int
simpleaudio_get_rate( simpleaudio *sa ); simpleaudio_get_rate( simpleaudio *sa );
@ -77,7 +68,7 @@ simpleaudio_get_channels( simpleaudio *sa );
unsigned int unsigned int
simpleaudio_get_framesize( simpleaudio *sa ); simpleaudio_get_framesize( simpleaudio *sa );
sa_sample_format_t sa_format_t
simpleaudio_get_format( simpleaudio *sa ); simpleaudio_get_format( simpleaudio *sa );
unsigned int unsigned int

View File

@ -23,17 +23,13 @@
#include "simpleaudio.h" #include "simpleaudio.h"
/*
* Backend modules must provide an "open" routine which returns a
* (simpleaudio *) to the caller.
*/
struct simpleaudio_backend; struct simpleaudio_backend;
typedef struct simpleaudio_backend simpleaudio_backend; typedef struct simpleaudio_backend simpleaudio_backend;
struct simpleaudio { struct simpleaudio {
const struct simpleaudio_backend *backend; const struct simpleaudio_backend *backend;
sa_sample_format_t format; sa_format_t format;
unsigned int rate; unsigned int rate;
unsigned int channels; unsigned int channels;
void * backend_handle; void * backend_handle;
@ -42,13 +38,27 @@ struct simpleaudio {
}; };
struct simpleaudio_backend { struct simpleaudio_backend {
int /* boolean 'ok' value */
(*simpleaudio_open_stream)(
simpleaudio * sa,
sa_direction_t sa_stream_direction,
sa_format_t sa_format,
unsigned int rate, unsigned int channels,
char *app_name, char *stream_name );
ssize_t ssize_t
(*simpleaudio_read)( simpleaudio *sa, float *buf, size_t nframes ); (*simpleaudio_read)( simpleaudio *sa, float *buf, size_t nframes );
ssize_t ssize_t
(*simpleaudio_write)( simpleaudio *sa, float *buf, size_t nframes ); (*simpleaudio_write)( simpleaudio *sa, float *buf, size_t nframes );
void void
(*simpleaudio_close)( simpleaudio *sa ); (*simpleaudio_close)( simpleaudio *sa );
}; };
extern const struct simpleaudio_backend simpleaudio_backend_sndfile;
extern const struct simpleaudio_backend simpleaudio_backend_alsa;
extern const struct simpleaudio_backend simpleaudio_backend_pulseaudio;
#endif #endif