From: Andre Date: Mon, 17 Apr 2006 20:25:34 +0000 (+0200) Subject: make para_play use the error subsystem X-Git-Tag: v0.2.12~77 X-Git-Url: http://git.tue.mpg.de/?a=commitdiff_plain;h=dbe43bcc5e084cce14dc83647eaba25099226929;p=paraslash.git make para_play use the error subsystem --- diff --git a/Makefile.in b/Makefile.in index 7a7fe2e0..50767941 100644 --- a/Makefile.in +++ b/Makefile.in @@ -108,7 +108,6 @@ fade_objs = fade.cmdline.o fade.o exec.o close_on_fork.o string.o fd.o krell_objs = krell.o string.o slider_objs = slider.o string.o audioc_objs = audioc.cmdline.o audioc.o string.o net.o fd.o -play_objs = play.cmdline.o play.o time.o fd.o *.o: para.h config.h gcc-compat.h @@ -196,8 +195,8 @@ para_server: @server_objs@ para_sdl_gui: $(sdl_gui_objs) $(CC) -o $@ $(sdl_gui_objs) -lSDL_image -para_play: $(play_objs) - $(CC) -o $@ $(play_objs) -lasound +para_play: @play_objs@ + $(CC) -o $@ @play_objs@ @play_ldflags@ para_compress: $(compress_objs) $(CC) -o $@ $(compress_objs) diff --git a/configure.ac b/configure.ac index ec30d88b..61b1808a 100644 --- a/configure.ac +++ b/configure.ac @@ -76,6 +76,10 @@ server_errlist_objs="server mp3 afs command net string signal random_selector ipc dccp dccp_send fd" server_ldflags="" +play_cmdline_objs="play.cmdline" +play_errlist_objs="play time fd string" +play_ldflags="" + ########################################################################### ssl dnl @synopsis CHECK_SSL dnl @@ -213,19 +217,20 @@ else AC_MSG_WARN([no mp3dec support in para_audiod/para_filter]) fi ########################################################################### alsa -play="para_play" -msg="will not build para_play" +have_alsa="yes" +msg="=> no para_play" AC_CHECK_HEADERS([alsa/asoundlib.h], [], [ - AC_MSG_WARN([no alsa/asoundlib, $msg]) - play="" + AC_MSG_WARN([no alsa/asoundlib $msg]) + have_alsa="no" ]) AC_CHECK_LIB([asound], [snd_pcm_open], [], [ - AC_MSG_WARN([no libasound, $msg]) - play="" + AC_MSG_WARN([no libasound $msg]) + have_alsa="no" ]) -extras="$extras $play" - - +if test "$have_alsa" = "yes"; then + extras="$extras para_play" + play_ldflags="$play_ldflags -lasound" +fi ########################################################################### ortp have_ortp="yes" AC_CHECK_HEADERS([ortp/ortp.h], [], [ @@ -288,6 +293,7 @@ recv_objs="$recv_cmdline_objs $recv_errlist_objs" filter_objs="$filter_cmdline_objs $filter_errlist_objs" audiod_objs="$audiod_cmdline_objs $audiod_errlist_objs" server_objs="$server_cmdline_objs $server_errlist_objs" +play_objs="$play_cmdline_objs $play_errlist_objs" AC_SUBST(recv_objs, add_dot_o($recv_objs)) AC_SUBST(recv_ldflags, $recv_ldflags) @@ -296,7 +302,7 @@ AC_DEFINE_UNQUOTED(INIT_RECV_ERRLISTS, objlist_to_errlist($recv_errlist_objs), AC_SUBST(filter_objs, add_dot_o($filter_objs)) AC_SUBST(filter_ldflags, $filter_ldflags) -AC_DEFINE_UNQUOTED(INIT_FILTER_ERRLISTS, +AC_DEFINE_UNQUOTED(INIT_FILTER_ERRLISTS, objlist_to_errlist($filter_errlist_objs), errors used by para_filter) AC_SUBST(audiod_objs, add_dot_o($audiod_objs)) @@ -306,9 +312,14 @@ AC_DEFINE_UNQUOTED(INIT_AUDIOD_ERRLISTS, objlist_to_errlist($audiod_errlist_objs AC_SUBST(server_objs, add_dot_o($server_objs)) AC_SUBST(server_ldflags, $server_ldflags) -AC_DEFINE_UNQUOTED(INIT_SERVER_ERRLISTS, +AC_DEFINE_UNQUOTED(INIT_SERVER_ERRLISTS, objlist_to_errlist($server_errlist_objs), errors used by para_server) +AC_SUBST(play_objs, add_dot_o($play_objs)) +AC_SUBST(play_ldflags, $play_ldflags) +AC_DEFINE_UNQUOTED(INIT_PLAY_ERRLISTS, + objlist_to_errlist($play_errlist_objs), errors used by para_play) + gui_cmdline_objs="gui.cmdline" gui_errlist_objs="exec close_on_fork signal string stat ringbuffer fd" gui_other_objs="gui gui_common gui_theme" @@ -328,4 +339,5 @@ ogg vorbis support: $have_ogg mp3dec support (libmad): $have_mad ortp support: $have_ortp unix socket credentials: $have_ucred +alsa support (para_play): $have_alsa ]) diff --git a/error.h b/error.h index 478aec1f..583d2ce5 100644 --- a/error.h +++ b/error.h @@ -58,6 +58,8 @@ enum para_subsystem { SS_DCCP_SEND, SS_FD, SS_GUI, + SS_PLAY, + SS_ALSA, SS_RINGBUFFER}; #define NUM_SS (SS_RINGBUFFER + 1) @@ -292,9 +294,36 @@ extern const char **para_errlist[]; #define FD_ERRORS \ PARA_ERROR(F_GETFL, "failed to get fd flags"), \ - PARA_ERROR(F_SETFL, "failed to set fd flags") + PARA_ERROR(F_SETFL, "failed to set fd flags"), \ + + +#define PLAY_ERRORS \ + PARA_ERROR(READ_HDR, "failed to read audio file header"), \ + PARA_ERROR(READ_STDIN, "failed to read from stdin"), \ + PARA_ERROR(PLAY_SYNTAX, "syntax error"), \ + PARA_ERROR(BROKEN_CONF, "Broken alsa configuration"), \ + PARA_ERROR(ACCESS_TYPE, "alsa access type not available"), \ + PARA_ERROR(SAMPLE_FORMAT, "sample format not available"), \ + PARA_ERROR(CHANNEL_COUNT, "channels count not available"), \ + PARA_ERROR(HW_PARAMS, "unable to install hw params"), \ + PARA_ERROR(SW_PARAMS, "unable to install sw params"), \ + PARA_ERROR(BAD_PERIOD, "can not use period equal to buffer size"), \ + PARA_ERROR(GET_XFER, "unable to obtain xfer align"), \ + PARA_ERROR(SET_XFER, "snd_pcm_sw_params_set_xfer_align() failed"), \ + PARA_ERROR(ALSA_WRITE, "alsa write error"), \ + PARA_ERROR(PCM_OPEN, "unable to open pcm"), \ + PARA_ERROR(SND_PCM_INFO, "pcm info error"), \ + PARA_ERROR(GET_BUFFER_TIME, "snd_pcm_hw_params_get_buffer_time_max() failed"), \ + PARA_ERROR(SET_BUFFER_TIME, "snd_pcm_hw_params_set_buffer_time_near() failed"), \ + PARA_ERROR(SET_RATE, "snd_pcm_hw_params_set_rate_near failed"), \ + PARA_ERROR(START_THRESHOLD, "snd_pcm_sw_params_set_start_threshold() failed"), \ + PARA_ERROR(STOP_THRESHOLD, "snd_pcm_sw_params_set_stop_threshold() failed"), \ + PARA_ERROR(ALSA_LOG, "snd_output_stdio_attach() failed"), \ + + /* these do not need error handling (yet) */ +#define ALSA_ERRORS #define SERVER_ERRORS #define WAV_ERRORS #define COMPRESS_ERRORS @@ -414,6 +443,8 @@ SS_ENUM(DCCP_RECV); SS_ENUM(DCCP_SEND); SS_ENUM(FD); SS_ENUM(GUI); +SS_ENUM(PLAY); +SS_ENUM(ALSA); SS_ENUM(RINGBUFFER); /** \endcond */ #undef PARA_ERROR diff --git a/play.c b/play.c index 0a53331b..ab541345 100644 --- a/play.c +++ b/play.c @@ -28,38 +28,11 @@ #include "fd.h" #include "play.cmdline.h" #include - -enum { E_BROKEN_CONF, /* Broken configuration for this PCM */ - E_ACCESS_TYPE, /* Access type not available */ - E_SAMPLE_FORMAT, /* Sample format not available */ - E_CHANNEL_COUNT, /* Channels count not available */ - E_HW_PARAMS, /* Unable to install hw params */ - E_SW_PARAMS, /* Unable to install sw params */ - E_BAD_PERIOD, /* Can't use period equal to buffer size */ - E_GET_XFER, /* Unable to obtain xfer align */ - E_SET_XFER, /* snd_pcm_sw_params_set_xfer_align failed */ - E_MEM, /* not enough memory */ - E_READ, /* read error */ - E_WRITE, /* write error */ - E_PIPE, /* write to pipe with other side closed */ - E_PCM_OPEN, /* unable to open pcm */ - E_SND_PCM_INFO, /* pcm info error */ - E_GET_BUFFER_TIME, /* snd_pcm_hw_params_get_buffer_time_max failed */ - E_SET_BUFFER_TIME, /* snd_pcm_hw_params_set_buffer_time_near failed */ - E_SET_RATE, /* snd_pcm_hw_params_set_rate_near failed */ - E_START_THRESHOLD, /* snd_pcm_sw_params_set_start_threshold failed */ - E_STOP_THRESHOLD, /* snd_pcm_sw_params_set_stop_threshold failed */ - E_LOG, /* snd_output_stdio_attach failed */ - E_SYNTAX /* could not parse start_time option */ -}; +#include "string.h" +#include "error.h" #define FORMAT SND_PCM_FORMAT_S16_LE -#define EXIT(EXP) \ -do { if (EXP) \ - fprintf (stderr, "error: " #EXP "\n"); exit(EXP);} \ -while (0) - static snd_pcm_t *handle; static snd_pcm_uframes_t chunk_size; static unsigned char *audiobuf; @@ -67,6 +40,8 @@ static size_t bytes_per_frame; static struct timeval *start_time; static struct gengetopt_args_info conf; +INIT_PLAY_ERRLISTS; + void para_log(__a_unused int ll, const char* fmt,...) { va_list argp; @@ -76,21 +51,23 @@ void para_log(__a_unused int ll, const char* fmt,...) va_end(argp); } -/* - * read_wav_header - read WAV_HEADER_LEN bytes from stdin to audio buffer +/** + * read WAV_HEADER_LEN bytes from stdin to audio buffer * - * Exit on errors and on eof before WAV_HEADER_LEN could be read. + * \return -E_READ_HDR on errors and on eof before WAV_HEADER_LEN could be + * read. A positive return value indicates success. */ -static void read_wav_header(void) +static int read_wav_header(void) { ssize_t ret, count = 0; while (count < WAV_HEADER_LEN) { ret = read(STDIN_FILENO, audiobuf + count, WAV_HEADER_LEN - count); if (ret <= 0) - EXIT(E_READ); + return -E_READ_HDR; count += ret; } + return 1; } /* @@ -111,46 +88,46 @@ static int alsa_init(void) snd_pcm_info_alloca(&info); if (snd_output_stdio_attach(&log, stderr, 0) < 0) - EXIT(E_LOG); + return -E_ALSA_LOG; err = snd_pcm_open(&handle, conf.device_arg, SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) - EXIT(E_PCM_OPEN); + return -E_PCM_OPEN; if ((err = snd_pcm_info(handle, info)) < 0) - EXIT(E_SND_PCM_INFO); + return -E_SND_PCM_INFO; snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if (snd_pcm_hw_params_any(handle, hwparams) < 0) - EXIT(E_BROKEN_CONF); + return -E_BROKEN_CONF; if (snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) - EXIT(E_ACCESS_TYPE); + return -E_ACCESS_TYPE; if (snd_pcm_hw_params_set_format(handle, hwparams, FORMAT) < 0) - EXIT(E_SAMPLE_FORMAT); + return -E_SAMPLE_FORMAT; if (snd_pcm_hw_params_set_channels(handle, hwparams, conf.channels_arg) < 0) - EXIT(E_CHANNEL_COUNT); + return -E_CHANNEL_COUNT; if (snd_pcm_hw_params_set_rate_near(handle, hwparams, (unsigned int*) &conf.sample_rate_arg, 0) < 0) - EXIT(E_SET_RATE); + return -E_SET_RATE; err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0); if (err < 0 || !buffer_time) - EXIT(E_GET_BUFFER_TIME); + return -E_GET_BUFFER_TIME; PARA_DEBUG_LOG("buffer time: %d\n", buffer_time); if (snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0) < 0) - EXIT(E_SET_BUFFER_TIME); + return -E_SET_BUFFER_TIME; if (snd_pcm_hw_params(handle, hwparams) < 0) - EXIT(E_HW_PARAMS); + return -E_HW_PARAMS; snd_pcm_hw_params_get_period_size(hwparams, &chunk_size, 0); snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); PARA_DEBUG_LOG("buffer size: %lu, period_size: %lu\n", buffer_size, chunk_size); if (chunk_size == buffer_size) - EXIT(E_BAD_PERIOD); + return -E_BAD_PERIOD; snd_pcm_sw_params_current(handle, swparams); err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align); if (err < 0 || !xfer_align) - EXIT(E_GET_XFER); + return -E_GET_XFER; // snd_pcm_sw_params_set_sleep_min(handle, swparams, 0); snd_pcm_sw_params_set_avail_min(handle, swparams, chunk_size); /* round to closest transfer boundary */ @@ -159,15 +136,15 @@ static int alsa_init(void) start_threshold = 1; if (snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold) < 0) - EXIT(E_START_THRESHOLD); + return -E_START_THRESHOLD; stop_threshold = buffer_size; if (snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold) < 0) - EXIT(E_STOP_THRESHOLD); + return -E_STOP_THRESHOLD; if (snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align) < 0) - EXIT(E_SET_XFER); + return -E_SET_XFER; if (snd_pcm_sw_params(handle, swparams) < 0) - EXIT(E_SW_PARAMS); + return -E_SW_PARAMS; bytes_per_frame = snd_pcm_format_physical_width(FORMAT) * conf.channels_arg / 8; return chunk_size * bytes_per_frame; } @@ -177,9 +154,9 @@ static int alsa_init(void) * \param data pointer do data to be written * \param nbytes number of bytes (not frames) * - * \return Number of bytes written. Exit on errors. + * \return Number of bytes written, -E_ALSA_WRITE on errors. */ -int alsa_write(u_char *data, size_t nbytes) +static int alsa_write(u_char *data, size_t nbytes) { size_t frames = nbytes / bytes_per_frame; snd_pcm_sframes_t r, result = 0; @@ -193,7 +170,7 @@ int alsa_write(u_char *data, size_t nbytes) else if (r == -EPIPE) snd_pcm_prepare(handle); else if (r < 0) - EXIT(E_WRITE); + return -E_ALSA_WRITE; if (r > 0) { result += r; frames -= r; @@ -203,15 +180,15 @@ int alsa_write(u_char *data, size_t nbytes) return result * bytes_per_frame; } -void alsa_shutdown(void) +static void alsa_shutdown(void) { snd_pcm_drain(handle); snd_pcm_close(handle); snd_config_update_free_global(); } -/* - * start_time_in_future - check if current time is later than start_time +/** + * check if current time is later than start_time * \param diff pointer to write remaining time to * * If start_time was not given, or current time is later than given @@ -230,8 +207,8 @@ static int start_time_in_future(struct timeval *diff) return tv_diff(start_time, &now, diff) > 0? 1 : 0; } -/* - * do_initial_delay - sleep until time given at command line +/** + * sleep until time given at command line * * This is called if the initial buffer is filled. It returns * immediately if no start_time was given at the command line @@ -245,26 +222,28 @@ static void do_initial_delay(struct timeval *delay) while (start_time_in_future(delay)); } -/* - * play_pcm - play raw pcm data +/** + * play raw pcm data * \param loaded number of bytes already loaded * * If start_time was given, prebuffer data until buffer is full or * start_time is reached. In any case, do not start playing before * start_time. + * + * \return positive on success, negative on errors. */ -static void play_pcm(size_t loaded) +static int play_pcm(size_t loaded) { size_t bufsize, written = 0, prebuf_size; - ssize_t ret; unsigned char *p; struct timeval delay; - int chunk_bytes = alsa_init(); + int chunk_bytes, ret = alsa_init(); + if (ret < 0) + goto out; + chunk_bytes = ret; bufsize = (conf.bufsize_arg * 1024 / chunk_bytes) * chunk_bytes; - audiobuf = realloc(audiobuf, bufsize); - if (!audiobuf) - EXIT(E_MEM); + audiobuf = para_realloc(audiobuf, bufsize); prebuf_size = conf.prebuffer_arg * bufsize / 100; again: if (!written) { @@ -278,6 +257,8 @@ again: p = audiobuf; while (loaded >= chunk_bytes) { ret = alsa_write(p, chunk_bytes); + if (ret < 0) + goto out; p += ret; written += ret; loaded -= ret; @@ -286,19 +267,24 @@ again: memmove(audiobuf, p, loaded); read: ret = read(STDIN_FILENO, audiobuf + loaded, bufsize - loaded); - if (ret < 0) - EXIT(E_READ); + if (ret < 0) { + ret = -E_READ_STDIN; + goto out; + } if (ret) { loaded += ret; goto again; } + ret = 1; +out: alsa_shutdown(); + return ret; } -/* - * check_wave - test if audio buffer contains a valid wave header +/** + * test if audio buffer contains a valid wave header * - * If not, return 0, otherwise, store number of channels and sample rate + * \return If not, return 0, otherwise, store number of channels and sample rate * in struct conf and return WAV_HEADER_LEN. */ static size_t check_wave(void) @@ -314,17 +300,24 @@ static size_t check_wave(void) int main(int argc, char *argv[]) { struct timeval tv; + int ret; cmdline_parser(argc, argv, &conf); if (conf.start_time_given) { + ret = -E_PLAY_SYNTAX; if (sscanf(conf.start_time_arg, "%lu:%lu", &tv.tv_sec, &tv.tv_usec) != 2) - EXIT(E_SYNTAX); + goto out; start_time = &tv; } - audiobuf = malloc(WAV_HEADER_LEN); - read_wav_header(); - play_pcm(check_wave()); + audiobuf = para_malloc(WAV_HEADER_LEN); + ret = read_wav_header(); + if (ret < 0) + goto out; + ret = play_pcm(check_wave()); +out: free(audiobuf); - return EXIT_SUCCESS; + if (ret < 0) + PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret)); + return ret; }