Allow CLI dynamic choice of A/V backends

This commit is contained in:
Aaron Culliney 2017-09-09 15:35:00 -10:00
parent 2517b45720
commit 8e6701bcbb
9 changed files with 163 additions and 20 deletions

View File

@ -539,6 +539,10 @@ static long openal_systemShutdown(INOUT AudioContext_s **audio_context) {
return 0;
}
static const char *openal_systemName(void) {
return "OpenAL";
}
static long openal_systemSetup(INOUT AudioContext_s **audio_context) {
assert(*audio_context == NULL);
assert(voices == NULL);
@ -625,6 +629,7 @@ static long openal_systemResume(AudioContext_s *audio_context) {
static void _init_openal(void) {
LOG("Initializing OpenAL sound system");
openal_audio_backend.name = &openal_systemName;
openal_audio_backend.setup = &openal_systemSetup;
openal_audio_backend.shutdown = &openal_systemShutdown;
openal_audio_backend.pause = &openal_systemPause;

View File

@ -526,6 +526,10 @@ static long opensles_systemShutdown(AudioContext_s **audio_context) {
return 0;
}
static const char *opensles_systemName(void) {
return "OpenSLES";
}
static long opensles_systemSetup(INOUT AudioContext_s **audio_context) {
assert(*audio_context == NULL);
@ -760,6 +764,7 @@ static long opensles_systemResume(AudioContext_s *audio_context) {
static void _init_opensl(void) {
LOG("Initializing OpenSLES sound system");
opensles_audio_backend.name = &opensles_systemName;
opensles_audio_backend.setup = &opensles_systemSetup;
opensles_audio_backend.shutdown = &opensles_systemShutdown;
opensles_audio_backend.pause = &opensles_systemPause;

View File

@ -34,6 +34,8 @@ typedef struct backend_node_s {
static backend_node_s *head = NULL;
static AudioBackend_s *currentBackend = NULL;
//-----------------------------------------------------------------------------
long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
@ -82,10 +84,10 @@ bool audio_init(void) {
do {
if (audioContext) {
audio_getCurrentBackend()->shutdown(&audioContext);
currentBackend->shutdown(&audioContext);
}
long err = audio_getCurrentBackend()->setup((AudioContext_s**)&audioContext);
long err = currentBackend->setup((AudioContext_s**)&audioContext);
if (err) {
LOG("Failed to create an audio context!");
break;
@ -103,7 +105,7 @@ void audio_shutdown(void) {
if (!audio_isAvailable) {
return;
}
audio_getCurrentBackend()->shutdown(&audioContext);
currentBackend->shutdown(&audioContext);
audio_isAvailable = false;
}
@ -118,7 +120,7 @@ void audio_pause(void) {
if (!audio_isAvailable) {
return;
}
audio_getCurrentBackend()->pause(audioContext);
currentBackend->pause(audioContext);
}
void audio_resume(void) {
@ -127,7 +129,7 @@ void audio_resume(void) {
if (!audio_isAvailable) {
return;
}
audio_getCurrentBackend()->resume(audioContext);
currentBackend->resume(audioContext);
}
void audio_setLatency(float latencySecs) {
@ -141,9 +143,6 @@ float audio_getLatency(void) {
//-----------------------------------------------------------------------------
void audio_registerBackend(AudioBackend_s *backend, long order) {
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
backend_node_s *node = MALLOC(sizeof(backend_node_s));
assert(node);
node->next = NULL;
@ -163,11 +162,46 @@ void audio_registerBackend(AudioBackend_s *backend, long order) {
}
node->next = p;
pthread_mutex_unlock(&mutex);
currentBackend = head->backend;
}
void audio_printBackends(FILE *out) {
backend_node_s *p = head;
int count = 0;
while (p) {
const char *name = p->backend->name();
if (count++) {
fprintf(out, "|");
}
fprintf(out, "%s", name);
p = p->next;
}
}
static const char *_null_backend_name(void);
void audio_chooseBackend(const char *name) {
if (!name) {
name = _null_backend_name();
}
backend_node_s *p = head;
while (p) {
const char *bname = p->backend->name();
if (strcasecmp(name, bname) == 0) {
currentBackend = p->backend;
LOG("Setting current audio backend to %s", name);
break;
}
p = p->next;
}
}
AudioBackend_s *audio_getCurrentBackend(void) {
return head->backend;
return currentBackend;
}
static const char *_null_backend_name(void) {
return "none";
}
static long _null_backend_setup(INOUT AudioContext_s **audio_context) {
@ -191,6 +225,7 @@ static long _null_backend_resume(AudioContext_s *audio_context) {
static void _init_soundcore(void) {
LOG("Initializing audio subsystem");
static AudioBackend_s null_backend = { { 0 } };
null_backend.name = &_null_backend_name;
null_backend.setup = &_null_backend_setup;
null_backend.shutdown = &_null_backend_shutdown;
null_backend.pause = &_null_backend_pause;

View File

@ -137,6 +137,8 @@ typedef struct AudioBackend_s {
AudioSettings_s systemSettings;
const char *(*name)(void);
// basic backend functionality controlled by soundcore
PRIVATE long (*setup)(INOUT AudioContext_s **audio_context);
PRIVATE long (*shutdown)(INOUT AudioContext_s **audio_context);
@ -155,6 +157,10 @@ enum {
void audio_registerBackend(AudioBackend_s *backend, long prio);
void audio_printBackends(FILE *out);
void audio_chooseBackend(const char *name);
AudioBackend_s *audio_getCurrentBackend(void);
#endif /* whole file */

View File

@ -44,6 +44,43 @@ static void _init_common(void) {
static __attribute__((constructor)) void __init_common(void) {
emulator_registerStartupCallback(CTOR_PRIORITY_FIRST, &_init_common);
}
static void _cli_help(void) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [-A <audio>] [-V <video>]\n", argv[0]);
const char *aname = audio_getCurrentBackend()->name();
fprintf(stderr, "\t-A <");
audio_printBackends(stderr);
fprintf(stderr, "> -- choose audio renderer (default: %s)\n", aname);
const char *vname = video_getCurrentBackend()->name();
fprintf(stderr, "\t-V <");
video_printBackends(stderr);
fprintf(stderr, "> -- choose video renderer (default: %s)\n", vname);
fprintf(stderr, "\n");
}
static void _cli_argsToPrefs(void) {
int opt = -1;
while ((opt = getopt(argc, argv, "?hA:V:")) != -1) {
switch (opt) {
case 'A':
audio_chooseBackend(optarg);
break;
case 'V':
video_chooseBackend(optarg);
break;
case '?':
case 'h':
default:
_cli_help();
exit(EXIT_FAILURE);
}
}
}
#elif defined(ANDROID) || (TARGET_OS_MAC || TARGET_OS_PHONE)
// data_dir is set up elsewhere
#else
@ -371,6 +408,10 @@ void emulator_start(void) {
prefs_load(); // user prefs
prefs_sync(NULL);
#if defined(CONFIG_DATADIR)
_cli_argsToPrefs();
#endif
#if defined(INTERFACE_CLASSIC) && !TESTING
c_keys_set_key(kF8); // show credits before emulation start
#endif
@ -439,7 +480,7 @@ int main(int _argc, char **_argv) {
LOG("Emulator exit ...");
return 0;
return EXIT_SUCCESS;
}
#endif

View File

@ -138,10 +138,17 @@ static void _glnode_initGLUTPost(void) {
}
#endif
static const char *glnode_name(void) {
return "OpenGL";
}
static void glnode_setupNodes(void *ctx) {
LOG("BEGIN glnode_setupNodes ...");
#if USE_GLUT
# if !TEST_CPU
joydriver_resetJoystick = &_glutJoystickReset;
# endif
_glnode_initGLUTPre();
#endif
@ -238,6 +245,7 @@ static void glnode_mainLoop(void) {
static void _init_glnode_manager(void) {
LOG("Initializing GLNode manager subsystem");
glnode_backend.name = &glnode_name;
glnode_backend.init = &glnode_setupNodes;
glnode_backend.main_loop = &glnode_mainLoop;
glnode_backend.render = &glnode_renderNodes;
@ -248,10 +256,6 @@ static void _init_glnode_manager(void) {
interface_onTouchEvent = &glnode_onTouchEvent;
#endif
#if USE_GLUT && !TEST_CPU
joydriver_resetJoystick = &_glutJoystickReset;
#endif
video_registerBackend(&glnode_backend, VID_PRIO_GRAPHICS_GL);
}

View File

@ -111,9 +111,6 @@ bool video_loadState(StateHelper_s *helper) {
void video_registerBackend(video_backend_s *backend, long order) {
assert(!video_initialized); // backends cannot be registered after we've picked one to use
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
backend_node_s *node = MALLOC(sizeof(backend_node_s));
assert(node);
node->next = NULL;
@ -134,17 +131,54 @@ void video_registerBackend(video_backend_s *backend, long order) {
node->next = p;
currentBackend = head->backend;
}
pthread_mutex_unlock(&mutex);
void video_printBackends(FILE *out) {
backend_node_s *p = head;
int count = 0;
while (p) {
const char *name = p->backend->name();
if (count++) {
fprintf(out, "|");
}
fprintf(out, "%s", name);
p = p->next;
}
}
static const char *_null_backend_name(void);
void video_chooseBackend(const char *name) {
if (!name) {
name = _null_backend_name();
}
backend_node_s *p = head;
while (p) {
const char *bname = p->backend->name();
if (strcasecmp(name, bname) == 0) {
currentBackend = p->backend;
LOG("Setting current video backend to %s", name);
break;
}
p = p->next;
}
}
video_animation_s *video_getAnimationDriver(void) {
return currentBackend->anim;
}
video_backend_s *video_getCurrentBackend(void) {
return currentBackend;
}
// ----------------------------------------------------------------------------
// NULL video backend ...
static const char *_null_backend_name(void) {
return "none";
}
static void _null_backend_init(void *context) {
}
@ -163,6 +197,7 @@ static void _null_backend_shutdown(void) {
static __attribute__((constructor)) void _init_video(void) {
static video_backend_s null_backend = { 0 };
null_backend.name = &_null_backend_name;
null_backend.init = &_null_backend_init;
null_backend.main_loop = &_null_backend_main_loop;
null_backend.render = &_null_backend_render;

View File

@ -115,6 +115,7 @@ video_animation_s *video_getAnimationDriver(void);
// Video Backend API
typedef struct video_backend_s {
const char *(*name)(void);
void (*init)(void *context);
void (*main_loop)(void);
void (*render)(void);
@ -142,9 +143,15 @@ enum {
};
/*
* Register a video backend at the specific prioritization, regardless of user choice.
* Register a video backend at the specific prioritization
*/
void video_registerBackend(video_backend_s *backend, long prio);
void video_printBackends(FILE *out);
void video_chooseBackend(const char *name);
video_backend_s *video_getCurrentBackend(void);
#endif /* !A2_VIDEO_H */

View File

@ -639,6 +639,10 @@ static void _redo_image(void) {
_size_hints_set_fixed();
}
static const char *xdriver_name(void) {
return "X11";
}
static void xdriver_init(void *context) {
XSetWindowAttributes attribs;
unsigned long attribmask;
@ -888,6 +892,7 @@ static void _init_xvideo(void) {
static video_backend_s xvideo_backend = { 0 };
static video_animation_s xdriver_animations = { 0 };
xvideo_backend.name = &xdriver_name;
xvideo_backend.init = &xdriver_init;
xvideo_backend.main_loop = &xdriver_main_loop;
xvideo_backend.render = &xdriver_render;