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 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;

View File

@ -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 */

View File

@ -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 */

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?... */
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 */

View File

@ -19,9 +19,101 @@
#include "simpleaudio.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 )
{
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 */
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

View File

@ -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