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

View File

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

View File

@ -34,6 +34,8 @@ typedef struct backend_node_s {
static backend_node_s *head = NULL; static backend_node_s *head = NULL;
static AudioBackend_s *currentBackend = NULL;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) { long audio_createSoundBuffer(INOUT AudioBuffer_s **audioBuffer) {
@ -82,10 +84,10 @@ bool audio_init(void) {
do { do {
if (audioContext) { 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) { if (err) {
LOG("Failed to create an audio context!"); LOG("Failed to create an audio context!");
break; break;
@ -103,7 +105,7 @@ void audio_shutdown(void) {
if (!audio_isAvailable) { if (!audio_isAvailable) {
return; return;
} }
audio_getCurrentBackend()->shutdown(&audioContext); currentBackend->shutdown(&audioContext);
audio_isAvailable = false; audio_isAvailable = false;
} }
@ -118,7 +120,7 @@ void audio_pause(void) {
if (!audio_isAvailable) { if (!audio_isAvailable) {
return; return;
} }
audio_getCurrentBackend()->pause(audioContext); currentBackend->pause(audioContext);
} }
void audio_resume(void) { void audio_resume(void) {
@ -127,7 +129,7 @@ void audio_resume(void) {
if (!audio_isAvailable) { if (!audio_isAvailable) {
return; return;
} }
audio_getCurrentBackend()->resume(audioContext); currentBackend->resume(audioContext);
} }
void audio_setLatency(float latencySecs) { void audio_setLatency(float latencySecs) {
@ -141,9 +143,6 @@ float audio_getLatency(void) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void audio_registerBackend(AudioBackend_s *backend, long order) { 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)); backend_node_s *node = MALLOC(sizeof(backend_node_s));
assert(node); assert(node);
node->next = NULL; node->next = NULL;
@ -163,11 +162,46 @@ void audio_registerBackend(AudioBackend_s *backend, long order) {
} }
node->next = p; 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) { 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) { 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) { static void _init_soundcore(void) {
LOG("Initializing audio subsystem"); LOG("Initializing audio subsystem");
static AudioBackend_s null_backend = { { 0 } }; static AudioBackend_s null_backend = { { 0 } };
null_backend.name = &_null_backend_name;
null_backend.setup = &_null_backend_setup; null_backend.setup = &_null_backend_setup;
null_backend.shutdown = &_null_backend_shutdown; null_backend.shutdown = &_null_backend_shutdown;
null_backend.pause = &_null_backend_pause; null_backend.pause = &_null_backend_pause;

View File

@ -137,6 +137,8 @@ typedef struct AudioBackend_s {
AudioSettings_s systemSettings; AudioSettings_s systemSettings;
const char *(*name)(void);
// basic backend functionality controlled by soundcore // basic backend functionality controlled by soundcore
PRIVATE long (*setup)(INOUT AudioContext_s **audio_context); PRIVATE long (*setup)(INOUT AudioContext_s **audio_context);
PRIVATE long (*shutdown)(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_registerBackend(AudioBackend_s *backend, long prio);
void audio_printBackends(FILE *out);
void audio_chooseBackend(const char *name);
AudioBackend_s *audio_getCurrentBackend(void); AudioBackend_s *audio_getCurrentBackend(void);
#endif /* whole file */ #endif /* whole file */

View File

@ -44,6 +44,43 @@ static void _init_common(void) {
static __attribute__((constructor)) void __init_common(void) { static __attribute__((constructor)) void __init_common(void) {
emulator_registerStartupCallback(CTOR_PRIORITY_FIRST, &_init_common); 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) #elif defined(ANDROID) || (TARGET_OS_MAC || TARGET_OS_PHONE)
// data_dir is set up elsewhere // data_dir is set up elsewhere
#else #else
@ -371,6 +408,10 @@ void emulator_start(void) {
prefs_load(); // user prefs prefs_load(); // user prefs
prefs_sync(NULL); prefs_sync(NULL);
#if defined(CONFIG_DATADIR)
_cli_argsToPrefs();
#endif
#if defined(INTERFACE_CLASSIC) && !TESTING #if defined(INTERFACE_CLASSIC) && !TESTING
c_keys_set_key(kF8); // show credits before emulation start c_keys_set_key(kF8); // show credits before emulation start
#endif #endif
@ -439,7 +480,7 @@ int main(int _argc, char **_argv) {
LOG("Emulator exit ..."); LOG("Emulator exit ...");
return 0; return EXIT_SUCCESS;
} }
#endif #endif

View File

@ -138,10 +138,17 @@ static void _glnode_initGLUTPost(void) {
} }
#endif #endif
static const char *glnode_name(void) {
return "OpenGL";
}
static void glnode_setupNodes(void *ctx) { static void glnode_setupNodes(void *ctx) {
LOG("BEGIN glnode_setupNodes ..."); LOG("BEGIN glnode_setupNodes ...");
#if USE_GLUT #if USE_GLUT
# if !TEST_CPU
joydriver_resetJoystick = &_glutJoystickReset;
# endif
_glnode_initGLUTPre(); _glnode_initGLUTPre();
#endif #endif
@ -238,6 +245,7 @@ static void glnode_mainLoop(void) {
static void _init_glnode_manager(void) { static void _init_glnode_manager(void) {
LOG("Initializing GLNode manager subsystem"); LOG("Initializing GLNode manager subsystem");
glnode_backend.name = &glnode_name;
glnode_backend.init = &glnode_setupNodes; glnode_backend.init = &glnode_setupNodes;
glnode_backend.main_loop = &glnode_mainLoop; glnode_backend.main_loop = &glnode_mainLoop;
glnode_backend.render = &glnode_renderNodes; glnode_backend.render = &glnode_renderNodes;
@ -248,10 +256,6 @@ static void _init_glnode_manager(void) {
interface_onTouchEvent = &glnode_onTouchEvent; interface_onTouchEvent = &glnode_onTouchEvent;
#endif #endif
#if USE_GLUT && !TEST_CPU
joydriver_resetJoystick = &_glutJoystickReset;
#endif
video_registerBackend(&glnode_backend, VID_PRIO_GRAPHICS_GL); 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) { void video_registerBackend(video_backend_s *backend, long order) {
assert(!video_initialized); // backends cannot be registered after we've picked one to use 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)); backend_node_s *node = MALLOC(sizeof(backend_node_s));
assert(node); assert(node);
node->next = NULL; node->next = NULL;
@ -134,17 +131,54 @@ void video_registerBackend(video_backend_s *backend, long order) {
node->next = p; node->next = p;
currentBackend = head->backend; 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) { video_animation_s *video_getAnimationDriver(void) {
return currentBackend->anim; return currentBackend->anim;
} }
video_backend_s *video_getCurrentBackend(void) {
return currentBackend;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// NULL video backend ... // NULL video backend ...
static const char *_null_backend_name(void) {
return "none";
}
static void _null_backend_init(void *context) { 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 __attribute__((constructor)) void _init_video(void) {
static video_backend_s null_backend = { 0 }; static video_backend_s null_backend = { 0 };
null_backend.name = &_null_backend_name;
null_backend.init = &_null_backend_init; null_backend.init = &_null_backend_init;
null_backend.main_loop = &_null_backend_main_loop; null_backend.main_loop = &_null_backend_main_loop;
null_backend.render = &_null_backend_render; null_backend.render = &_null_backend_render;

View File

@ -115,6 +115,7 @@ video_animation_s *video_getAnimationDriver(void);
// Video Backend API // Video Backend API
typedef struct video_backend_s { typedef struct video_backend_s {
const char *(*name)(void);
void (*init)(void *context); void (*init)(void *context);
void (*main_loop)(void); void (*main_loop)(void);
void (*render)(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_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 */ #endif /* !A2_VIDEO_H */

View File

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