diff --git a/libao2/audio_out.c b/libao2/audio_out.c index 3e37cfb70b..da471f0cc7 100644 --- a/libao2/audio_out.c +++ b/libao2/audio_out.c @@ -21,40 +21,42 @@ #include #include +#include "talloc.h" + #include "config.h" #include "audio_out.h" #include "mp_msg.h" // there are some globals: -struct ao ao_data; +struct ao *global_ao; char *ao_subdevice = NULL; -extern const ao_functions_t audio_out_oss; -extern const ao_functions_t audio_out_coreaudio; -extern const ao_functions_t audio_out_arts; -extern const ao_functions_t audio_out_esd; -extern const ao_functions_t audio_out_pulse; -extern const ao_functions_t audio_out_jack; -extern const ao_functions_t audio_out_openal; -extern const ao_functions_t audio_out_null; -extern const ao_functions_t audio_out_alsa5; -extern const ao_functions_t audio_out_alsa; -extern const ao_functions_t audio_out_nas; -extern const ao_functions_t audio_out_sdl; -extern const ao_functions_t audio_out_sun; -extern const ao_functions_t audio_out_sgi; -extern const ao_functions_t audio_out_win32; -extern const ao_functions_t audio_out_dsound; -extern const ao_functions_t audio_out_kai; -extern const ao_functions_t audio_out_dart; -extern const ao_functions_t audio_out_ivtv; -extern const ao_functions_t audio_out_v4l2; -extern const ao_functions_t audio_out_mpegpes; -extern const ao_functions_t audio_out_pcm; -extern const ao_functions_t audio_out_pss; +extern const struct ao_driver audio_out_oss; +extern const struct ao_driver audio_out_coreaudio; +extern const struct ao_driver audio_out_arts; +extern const struct ao_driver audio_out_esd; +extern const struct ao_driver audio_out_pulse; +extern const struct ao_driver audio_out_jack; +extern const struct ao_driver audio_out_openal; +extern const struct ao_driver audio_out_null; +extern const struct ao_driver audio_out_alsa5; +extern const struct ao_driver audio_out_alsa; +extern const struct ao_driver audio_out_nas; +extern const struct ao_driver audio_out_sdl; +extern const struct ao_driver audio_out_sun; +extern const struct ao_driver audio_out_sgi; +extern const struct ao_driver audio_out_win32; +extern const struct ao_driver audio_out_dsound; +extern const struct ao_driver audio_out_kai; +extern const struct ao_driver audio_out_dart; +extern const struct ao_driver audio_out_ivtv; +extern const struct ao_driver audio_out_v4l2; +extern const struct ao_driver audio_out_mpegpes; +extern const struct ao_driver audio_out_pcm; +extern const struct ao_driver audio_out_pss; -static const ao_functions_t *const audio_out_drivers[] = { +static const struct ao_driver * const audio_out_drivers[] = { // native: #ifdef CONFIG_DIRECTX &audio_out_dsound, @@ -136,12 +138,17 @@ void list_audio_out(void) struct ao *ao_create(void) { - ao_data = (struct ao){.outburst = OUTBURST, .buffersize = -1}; - return &ao_data; + struct ao *r = talloc(NULL, struct ao); + *r = (struct ao){.outburst = OUTBURST, .buffersize = -1}; + return r; } void ao_init(struct ao *ao, char **ao_list) { + /* Caller adding child blocks is not supported as we may call + * talloc_free_children() to clean up after failed open attempts. + */ + assert(talloc_total_blocks(ao) == 1); struct ao backup = *ao; if (!ao_list) @@ -153,19 +160,18 @@ void ao_init(struct ao *ao, char **ao_list) if (!*ao_name) goto try_defaults; // empty entry means try defaults int ao_len; - assert(!ao_subdevice); - ao_subdevice = strchr(ao_name, ':'); - if (ao_subdevice) { - ao_len = ao_subdevice - ao_name; - ao_subdevice = strdup(ao_subdevice + 1); + char *params = strchr(ao_name, ':'); + if (params) { + ao_len = params - ao_name; + params++; } else ao_len = strlen(ao_name); mp_tmsg(MSGT_AO, MSGL_V, "Trying preferred audio driver '%.*s', options '%s'\n", - ao_len, ao_name, ao_subdevice ? ao_subdevice : "[none]"); + ao_len, ao_name, params ? params : "[none]"); - const ao_functions_t *audio_out = NULL; + const struct ao_driver *audio_out = NULL; for (int i = 0; audio_out_drivers[i]; i++) { audio_out = audio_out_drivers[i]; if (!strncmp(audio_out->info->short_name, ao_name, ao_len)) @@ -174,19 +180,19 @@ void ao_init(struct ao *ao, char **ao_list) } if (audio_out) { // name matches, try it - if (audio_out->init(ao->samplerate, ao->channels, ao->format, 0)) { + ao->driver = audio_out; + if (audio_out->init(ao, params) >= 0) { ao->driver = audio_out; ao->initialized = true; return; } mp_tmsg(MSGT_AO, MSGL_WARN, "Failed to initialize audio driver '%s'\n", ao_name); + talloc_free_children(ao); *ao = backup; } else mp_tmsg(MSGT_AO, MSGL_WARN, "No such audio driver '%.*s'\n", ao_len, ao_name); - free(ao_subdevice); - ao_subdevice = NULL; ++ao_list; } return; @@ -196,57 +202,113 @@ void ao_init(struct ao *ao, char **ao_list) // now try the rest... for (int i = 0; audio_out_drivers[i]; i++) { - const ao_functions_t *audio_out = audio_out_drivers[i]; - if (audio_out->init(ao->samplerate, ao->channels, ao->format, 0)) { + const struct ao_driver *audio_out = audio_out_drivers[i]; + ao->driver = audio_out; + if (audio_out->init(ao, NULL) >= 0) { ao->initialized = true; ao->driver = audio_out; return; } + talloc_free_children(ao); *ao = backup; } return; } -void ao_uninit(struct ao *ao, bool drain_audio) +void ao_uninit(struct ao *ao, bool cut_audio) { if (ao->initialized) - ao->driver->uninit(drain_audio); - ao->initialized = false; - free(ao_subdevice); - ao_subdevice = NULL; + ao->driver->uninit(ao, cut_audio); + talloc_free(ao); } int ao_play(struct ao *ao, void *data, int len, int flags) { - return ao->driver->play(data, len, flags); + return ao->driver->play(ao, data, len, flags); } int ao_control(struct ao *ao, int cmd, void *arg) { - return ao->driver->control(cmd, arg); + if (ao->driver->control) + return ao->driver->control(ao, cmd, arg); + return CONTROL_UNKNOWN; } double ao_get_delay(struct ao *ao) { - return ao->driver->get_delay(); + return ao->driver->get_delay(ao); } int ao_get_space(struct ao *ao) { - return ao->driver->get_space(); + return ao->driver->get_space(ao); } void ao_reset(struct ao *ao) { - ao->driver->reset(); + ao->driver->reset(ao); } void ao_pause(struct ao *ao) { - ao->driver->pause(); + ao->driver->pause(ao); } void ao_resume(struct ao *ao) { - ao->driver->resume(); + ao->driver->resume(ao); +} + + + +int old_ao_init(struct ao *ao, char *params) +{ + assert(!global_ao); + global_ao = ao; + ao_subdevice = params ? talloc_strdup(ao, params) : NULL; + if (ao->driver->old_functions->init(ao->samplerate, ao->channels, + ao->format, 0) == 0) + return -1; + return 0; +} + +void old_ao_uninit(struct ao *ao, bool cut_audio) +{ + ao->driver->old_functions->uninit(cut_audio); + global_ao = NULL; +} + +int old_ao_play(struct ao *ao, void *data, int len, int flags) +{ + return ao->driver->old_functions->play(data, len, flags); +} + +int old_ao_control(struct ao *ao, int cmd, void *arg) +{ + return ao->driver->old_functions->control(cmd, arg); +} + +float old_ao_get_delay(struct ao *ao) +{ + return ao->driver->old_functions->get_delay(); +} + +int old_ao_get_space(struct ao *ao) +{ + return ao->driver->old_functions->get_space(); +} + +void old_ao_reset(struct ao *ao) +{ + ao->driver->old_functions->reset(); +} + +void old_ao_pause(struct ao *ao) +{ + ao->driver->old_functions->pause(); +} + +void old_ao_resume(struct ao *ao) +{ + ao->driver->old_functions->resume(); } diff --git a/libao2/audio_out.h b/libao2/audio_out.h index dddcb55a6a..c60819e545 100644 --- a/libao2/audio_out.h +++ b/libao2/audio_out.h @@ -33,8 +33,7 @@ typedef struct ao_info { } ao_info_t; /* interface towards mplayer and */ -typedef struct ao_functions { - const ao_info_t *info; +typedef struct ao_old_functions { int (*control)(int cmd, void *arg); int (*init)(int rate, int channels, int format, int flags); void (*uninit)(int immed); @@ -46,6 +45,23 @@ typedef struct ao_functions { void (*resume)(void); } ao_functions_t; +struct ao; + +struct ao_driver { + bool is_new; + const struct ao_info *info; + const struct ao_old_functions *old_functions; + int (*control)(struct ao *ao, int cmd, void *arg); + int (*init)(struct ao *ao, char *params); + void (*uninit)(struct ao *ao, bool cut_audio); + void (*reset)(struct ao*ao); + int (*get_space)(struct ao *ao); + int (*play)(struct ao *ao, void *data, int len, int flags); + float (*get_delay)(struct ao *ao); + void (*pause)(struct ao *ao); + void (*resume)(struct ao *ao); +}; + /* global data used by mplayer and plugins */ struct ao { int samplerate; @@ -56,7 +72,8 @@ struct ao { int buffersize; int pts; bool initialized; - const struct ao_functions *driver; + const struct ao_driver *driver; + void *priv; }; extern char *ao_subdevice; @@ -87,7 +104,7 @@ typedef struct ao_control_vol { struct ao *ao_create(void); void ao_init(struct ao *ao, char **ao_list); -void ao_uninit(struct ao *ao, bool drain_audio); +void ao_uninit(struct ao *ao, bool cut_audio); int ao_play(struct ao *ao, void *data, int len, int flags); int ao_control(struct ao *ao, int cmd, void *arg); double ao_get_delay(struct ao *ao); @@ -96,4 +113,14 @@ void ao_reset(struct ao *ao); void ao_pause(struct ao *ao); void ao_resume(struct ao *ao); +int old_ao_control(struct ao *ao, int cmd, void *arg); +int old_ao_init(struct ao *ao, char *params); +void old_ao_uninit(struct ao *ao, bool cut_audio); +void old_ao_reset(struct ao*ao); +int old_ao_get_space(struct ao *ao); +int old_ao_play(struct ao *ao, void *data, int len, int flags); +float old_ao_get_delay(struct ao *ao); +void old_ao_pause(struct ao *ao); +void old_ao_resume(struct ao *ao); + #endif /* MPLAYER_AUDIO_OUT_H */ diff --git a/libao2/audio_out_internal.h b/libao2/audio_out_internal.h index c093be6989..67bcfa953d 100644 --- a/libao2/audio_out_internal.h +++ b/libao2/audio_out_internal.h @@ -31,20 +31,31 @@ static float get_delay(void); static void audio_pause(void); static void audio_resume(void); -extern struct ao ao_data; +extern struct ao *global_ao; +#define ao_data (*global_ao) -#define LIBAO_EXTERN(x) const ao_functions_t audio_out_##x =\ -{\ - &info,\ - control,\ - init,\ - uninit,\ - reset,\ - get_space,\ - play,\ - get_delay,\ - audio_pause,\ - audio_resume\ +#define LIBAO_EXTERN(x) const struct ao_driver audio_out_##x = { \ + .info = &info, \ + .control = old_ao_control, \ + .init = old_ao_init, \ + .uninit = old_ao_uninit, \ + .reset = old_ao_reset, \ + .get_space = old_ao_get_space, \ + .play = old_ao_play, \ + .get_delay = old_ao_get_delay, \ + .pause = old_ao_pause, \ + .resume = old_ao_resume, \ + .old_functions = &(const struct ao_old_functions) { \ + .control = control, \ + .init = init, \ + .uninit = uninit, \ + .reset = reset, \ + .get_space = get_space, \ + .play = play, \ + .get_delay = get_delay, \ + .pause = audio_pause, \ + .resume = audio_resume, \ + }, \ }; #endif /* MPLAYER_AUDIO_OUT_INTERNAL_H */