simpleaudio: generalized simpleaudio_open_stream
This commit is contained in:
parent
5dddc1445a
commit
4d326a8c82
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue