diff --git a/src/minimodem.c b/src/minimodem.c index 5acaf69..7639beb 100644 --- a/src/minimodem.c +++ b/src/minimodem.c @@ -284,17 +284,13 @@ main( int argc, char*argv[] ) float carrier_autodetect_threshold = 0.0; 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 nchannels = 1; // FIXME: only works with one channel - /* configure the default system audio mechanism */ -#if USE_PULSEAUDIO - simpleaudio_open_system_audio = simpleaudio_open_stream_pulseaudio; -#elif USE_ALSA - simpleaudio_open_system_audio = simpleaudio_open_stream_alsa; -#else + /* validate the default system audio mechanism */ +#if !(USE_PULSEAUDIO || USE_ALSA) # define _MINIMODEM_NO_SYSTEM_AUDIO # if !USE_SNDFILE # error At least one of {USE_PULSEAUDIO,USE_ALSA,USE_SNDFILE} must be enabled! @@ -391,7 +387,7 @@ main( int argc, char*argv[] ) break; case 'A': #if USE_ALSA - simpleaudio_open_system_audio = simpleaudio_open_stream_alsa; + sa_backend = SA_BACKEND_ALSA; #else fprintf(stderr, "E: This build of minimodem was configured without alsa support.\n"); exit(1); @@ -508,31 +504,29 @@ main( int argc, char*argv[] ) band_width = bfsk_data_rate; + char *stream_name = NULL;; + + if ( filename ) { + sa_backend = SA_BACKEND_FILE; + stream_name = filename; + } + /* * Handle transmit mode */ if ( TX_mode ) { - simpleaudio *sa_out = NULL; - int tx_interactive = 1; - - if ( filename ) { - 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; + int tx_interactive = 0; + if ( ! stream_name ) { + tx_interactive = 1; + stream_name = "output audio"; } - if ( ! sa_out ) - sa_out = simpleaudio_open_system_audio(SA_STREAM_PLAYBACK, + simpleaudio *sa_out; + sa_out = simpleaudio_open_stream(sa_backend, SA_STREAM_PLAYBACK, SA_SAMPLE_FORMAT_FLOAT, sample_rate, nchannels, - program_name, "output audio"); + program_name, stream_name); if ( ! sa_out ) return 1; @@ -543,6 +537,9 @@ main( int argc, char*argv[] ) bfsk_txstopbits, bfsk_framebits_encode ); + + simpleaudio_close(sa_out); + return 0; } @@ -550,24 +547,16 @@ main( int argc, char*argv[] ) /* * 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 ) - sa = simpleaudio_open_system_audio(SA_STREAM_RECORD, + if ( ! stream_name ) + stream_name = "input audio"; + + simpleaudio *sa; + sa = simpleaudio_open_stream(sa_backend, SA_STREAM_RECORD, SA_SAMPLE_FORMAT_FLOAT, sample_rate, nchannels, - program_name, "input audio"); - if ( !sa ) + program_name, stream_name); + if ( ! sa ) return 1; diff --git a/src/simpleaudio-alsa.c b/src/simpleaudio-alsa.c index b2d1e25..68610d1 100644 --- a/src/simpleaudio-alsa.c +++ b/src/simpleaudio-alsa.c @@ -95,17 +95,11 @@ sa_alsa_close( simpleaudio *sa ) snd_pcm_close(sa->backend_handle); } - -static const struct simpleaudio_backend simpleaudio_backend_alsa = { - sa_alsa_read, - sa_alsa_write, - sa_alsa_close, -}; - -simpleaudio * -simpleaudio_open_stream_alsa( - int sa_stream_direction, - sa_sample_format_t sa_sample_format, +static int +sa_alsa_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 ) { @@ -118,10 +112,10 @@ simpleaudio_open_stream_alsa( 0 /*mode*/); if (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 */ error = snd_pcm_set_params(pcm, @@ -134,7 +128,7 @@ simpleaudio_open_stream_alsa( if (error) { fprintf(stderr, "E: %s\n", snd_strerror(error)); snd_pcm_close(pcm); - return NULL; + return 0; } #if 0 @@ -157,21 +151,18 @@ simpleaudio_open_stream_alsa( } #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_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 */ diff --git a/src/simpleaudio-pulse.c b/src/simpleaudio-pulse.c index 47741af..1a84204 100644 --- a/src/simpleaudio-pulse.c +++ b/src/simpleaudio-pulse.c @@ -79,17 +79,11 @@ sa_pulse_close( simpleaudio *sa ) pa_simple_free(sa->backend_handle); } - -static const struct simpleaudio_backend simpleaudio_backend_pulse = { - sa_pulse_read, - sa_pulse_write, - sa_pulse_close, -}; - -simpleaudio * -simpleaudio_open_stream_pulseaudio( - int sa_stream_direction, - sa_sample_format_t sa_sample_format, +static int +sa_pulse_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 ) { @@ -98,7 +92,7 @@ simpleaudio_open_stream_pulseaudio( // FIXME - use source for something // 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 */ pa_sample_spec ss = { @@ -128,26 +122,25 @@ simpleaudio_open_stream_pulseaudio( &ss, NULL, &attr, &error); if ( !s ) { fprintf(stderr, "E: Cannot create PulseAudio stream: %s\n ", pa_strerror(error)); - return NULL; + return 0; } - simpleaudio *sa = malloc(sizeof(simpleaudio)); - if ( !sa ) { - perror("malloc"); - pa_simple_free(s); - return NULL; - } - sa->format = sa_sample_format; + /* good or bad to override these? */ sa->rate = ss.rate; sa->channels = ss.channels; - sa->samplesize = sizeof(float); - sa->backend = &simpleaudio_backend_pulse; + sa->backend_handle = s; sa->backend_framesize = pa_frame_size(&ss); - assert( sa->backend_framesize == sa->channels * sa->samplesize ); - - return sa; + return 1; } + +const struct simpleaudio_backend simpleaudio_backend_pulseaudio = { + sa_pulse_open_stream, + sa_pulse_read, + sa_pulse_write, + sa_pulse_close, +}; + #endif /* USE_PULSEAUDIO */ diff --git a/src/simpleaudio-sndfile.c b/src/simpleaudio-sndfile.c index 94abfb2..0a4c77b 100644 --- a/src/simpleaudio-sndfile.c +++ b/src/simpleaudio-sndfile.c @@ -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?... */ static const struct sndfile_format { unsigned int major_format; @@ -132,14 +125,17 @@ sndfile_format_from_path( const char *path ) return SF_FORMAT_WAV; } -simpleaudio * -simpleaudio_open_stream_sndfile( - int sa_stream_direction, - sa_sample_format_t sa_sample_format, +static int +sa_sndfile_open_stream( + simpleaudio *sa, + sa_direction_t sa_stream_direction, + sa_format_t sa_format, 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) */ SF_INFO sfinfo = { @@ -159,24 +155,25 @@ simpleaudio_open_stream_sndfile( if ( !s ) { fprintf(stderr, "%s: ", path); sf_perror(s); - return NULL; + return 0; } - simpleaudio *sa = malloc(sizeof(simpleaudio)); - if ( !sa ) { - perror("malloc"); - sf_close(s); - return NULL; - } - sa->format = sa_sample_format; + /* good or bad to override these? */ sa->rate = sfinfo.samplerate; sa->channels = sfinfo.channels; - sa->samplesize = sizeof(float); - sa->backend = &simpleaudio_backend_sndfile; + sa->backend_handle = s; 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 */ diff --git a/src/simpleaudio.c b/src/simpleaudio.c index 4a86fa0..5c68b3f 100644 --- a/src/simpleaudio.c +++ b/src/simpleaudio.c @@ -19,9 +19,101 @@ #include "simpleaudio.h" #include "simpleaudio_internal.h" -#include "malloc.h" -sa_sample_format_t +#include +#include + +#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 ) { return sa->format; diff --git a/src/simpleaudio.h b/src/simpleaudio.h index f922ba9..4dd8b7c 100644 --- a/src/simpleaudio.h +++ b/src/simpleaudio.h @@ -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 */ -enum { - SA_STREAM_PLAYBACK, - SA_STREAM_RECORD, -}; +typedef enum { + SA_STREAM_PLAYBACK, + SA_STREAM_RECORD, +} sa_direction_t; /* sa_stream_format */ typedef enum { - SA_SAMPLE_FORMAT_S16, - SA_SAMPLE_FORMAT_FLOAT, -} sa_sample_format_t; + SA_SAMPLE_FORMAT_S16, + SA_SAMPLE_FORMAT_FLOAT, +} sa_format_t; simpleaudio * -simpleaudio_open_stream_pulseaudio( - int sa_stream_direction, - sa_sample_format_t sa_sample_format, +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 * -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 simpleaudio_get_rate( simpleaudio *sa ); @@ -77,7 +68,7 @@ simpleaudio_get_channels( simpleaudio *sa ); unsigned int simpleaudio_get_framesize( simpleaudio *sa ); -sa_sample_format_t +sa_format_t simpleaudio_get_format( simpleaudio *sa ); unsigned int diff --git a/src/simpleaudio_internal.h b/src/simpleaudio_internal.h index 688c908..c14df0d 100644 --- a/src/simpleaudio_internal.h +++ b/src/simpleaudio_internal.h @@ -23,17 +23,13 @@ #include "simpleaudio.h" -/* - * Backend modules must provide an "open" routine which returns a - * (simpleaudio *) to the caller. - */ struct simpleaudio_backend; typedef struct simpleaudio_backend simpleaudio_backend; struct simpleaudio { const struct simpleaudio_backend *backend; - sa_sample_format_t format; + sa_format_t format; unsigned int rate; unsigned int channels; void * backend_handle; @@ -42,13 +38,27 @@ struct simpleaudio { }; 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 (*simpleaudio_read)( simpleaudio *sa, float *buf, size_t nframes ); + ssize_t (*simpleaudio_write)( simpleaudio *sa, float *buf, size_t nframes ); + void (*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