mirror of
https://github.com/mauiaaron/apple2.git
synced 2024-11-17 13:10:38 +00:00
Allow CLI dynamic choice of A/V backends
This commit is contained in:
parent
2517b45720
commit
8e6701bcbb
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
43
src/misc.c
43
src/misc.c
@ -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
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user