mirror of
https://github.com/mpv-player/mpv
synced 2024-12-25 08:12:17 +00:00
audio output: add a new AO driver API
Add a new audio output driver API. The main change is the addition of a context struct where data can be kept instead of using globals. The old API remains available. This commit does not yet convert any driver to use the new API.
This commit is contained in:
parent
df7825eb31
commit
3a5fd15fa2
@ -21,40 +21,42 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user