#include "config.h" #include "memory.h" #include "plat.h" #ifdef plat_posix #define _POSIX_SOURCE #define _GNU_SOURCE #include #include #include #include #include #include #include #include extern int fileno(FILE*); void print(const char* fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stdout, fmt, args); va_end(args); } void print_err(const char* fmt, ...) { va_list args; va_start(args, fmt); if (isatty(fileno(stderr))) { fprintf(stderr, "\033[31;31m"); } vfprintf(stderr, fmt, args); if (isatty(fileno(stderr))) { fprintf(stderr, "\033[0m"); } va_end(args); } void print_war(const char* fmt, ...) { va_list args; va_start(args, fmt); if (isatty(fileno(stderr))) { fprintf(stderr, "\033[31;35m"); } vfprintf(stderr, fmt, args); if (isatty(fileno(stderr))) { fprintf(stderr, "\033[0m"); } va_end(args); } void pbreak(Error code) { #if defined(DEBUG) && defined(plat_x86) __asm__("int3;"); (void)code; #else exit(code); #endif } void iter_dir(const char* path, Dir_Iter fn, void* u) { struct dirent* de; int l; DIR* di; char buf[256]; char* p; di = opendir(path); if (!di) return; strcpy(buf, path); l = strlen(buf); if (!l) return; if (buf[l - 1] != '/') { strcat(buf, "/"); l++; } p = buf + l; while ((de = readdir(di))) { if (de->d_name[0] == '.') continue; strcpy(p, de->d_name); if (de->d_type == DT_DIR) iter_dir(buf, fn, u); else fn(u, buf); } closedir(di); } int dir_exist(const char* p) { DIR* di; di = opendir(p); if (di) { closedir(di); return 1; } return 0; } int make_dir(const char* p) { return mkdir( p, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH ) == 0; } pthread_t audio_thread; pthread_mutex_t audio_mutex; #define inline /* erm sir we are using C90 here... */ #include struct { unsigned char* buf; pa_simple* dev; int chan, r; } audio; extern int sound_mix(void*, unsigned char*, int); void* audio_worker(void* arg) { const int s = audio_buffer_size; int c = 1, as; unsigned char* buf = audio.buf; pa_simple* dev = audio.dev; (void)arg; while (c) { lock_audio(); if (!audio.r) c = 0; as = sound_mix(arg, buf, s); unlock_audio(); if (as) pa_simple_write(dev, buf, as, 0); else usleep(25000); /* avoid hammering the thread */ } return 0; } void stop_audio(void) { lock_audio(); audio.r = 0; unlock_audio(); } void wait_audio(void) { pthread_mutex_destroy(&audio_mutex); pthread_join(audio_thread, 0); } void init_audio(void* uptr, int sample, int channels) { if (audio.dev) { wait_audio(); pa_simple_free(audio.dev); gfree(audio.buf); } audio.buf = galloc(audio_buffer_size * channels); pa_sample_spec sp = { 0 }; sp.format = PA_SAMPLE_S32LE; sp.channels = channels; sp.rate = sample; audio.dev = pa_simple_new( 0, app_name, PA_STREAM_PLAYBACK, 0, "Twink Player audio", &sp, 0, 0, 0 ); audio.r = 0; if (!audio.dev) { print_err("Failed to create audio device.\n"); return; } audio.r = 1; audio.chan = channels; pthread_create( &audio_thread, 0, audio_worker, uptr ); pthread_mutex_init(&audio_mutex, 0); } void lock_audio(void) { pthread_mutex_lock(&audio_mutex); } void unlock_audio(void) { pthread_mutex_unlock(&audio_mutex); } int audio_done(void) { int r; lock_audio(); r = !audio.r; unlock_audio(); return r; } extern int prog_main(void*); int main() { int r; void* mem; audio.dev = 0; mem = malloc(memory_size); r = prog_main(mem); if (audio.dev) { stop_audio(); wait_audio(); pa_simple_free(audio.dev); gfree(audio.buf); } free(mem); return r; } #endif