Try to improve audio playback on mobile

This commit is contained in:
Maximilian Mader 2019-06-08 19:10:23 +02:00
parent 7550707562
commit f9c932b737
Signed by: Max
GPG Key ID: F71D56A3151C4FB3
5 changed files with 145 additions and 36 deletions

View File

@ -58,7 +58,7 @@ endif
CFLAGS += -Werror -Wall -Wno-strict-aliasing -Wno-unknown-warning -Wno-unknown-warning-option -Wno-multichar -Wno-int-in-bool-context -std=gnu11 -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES
# CFLAGS += -DGB_INTERNAL=1 # get access to internal APIs
CFLAGS += -I$(CORE_DIR)
CFLAGS += -s WASM=1 -s USE_SDL=2 --preload-file $(BOOTROMS_DIR)@/BootROMs -s "EXTRA_EXPORTED_RUNTIME_METHODS=['FS']"
CFLAGS += -s WASM=1 -s USE_SDL=2 --preload-file $(BOOTROMS_DIR)@/BootROMs -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap', 'getValue', 'AsciiToString', 'FS']"
# CFLAGS += -Wcast-align -Wover-aligned -s SAFE_HEAP=1 -s WARN_UNALIGNED=1
WASM_LDFLAGS :=

View File

@ -98,6 +98,34 @@
const progressElement = document.querySelector('#progress');
var Module = {
get_models: function () {
const ptr = Module._get_models_string_pointer();
const ptr_size = Module._get_models_string_pointer_size();
const size = Module._get_models_string_size() - ptr_size; // last element is a end marker
const models = [];
for (let i = 0; i < size; i += ptr_size) {
const key = AsciiToString(getValue(ptr + i, '*'));
models.push(key.replace(/^MODEL_/, ''));
}
return models
},
get_sgb_revisions: function () {
const ptr = Module._get_sgb_revisions_string_pointer();
const ptr_size = Module._get_sgb_revisions_string_pointer_size();
const size = Module._get_sgb_revisions_string_size() - ptr_size; // last element is a end marker
const revisions = [];
for (let i = 0; i < size; i += ptr_size) {
const key = AsciiToString(getValue(ptr + i, '*'));
revisions.push(key.replace(/^SGB_/, ''));
}
return revisions
},
sync_fs: function () {
console.log("Syncing file system ...");

View File

@ -80,11 +80,15 @@ int save_battery(GB_gameboy_t *gb, const char *path) {
unsigned query_sample_rate_of_audiocontexts() {
return EM_ASM_INT({
const AudioContext = window.AudioContext || window.webkitAudioContext;
const ctx = new AudioContext();
const sr = ctx.sampleRate;
ctx.close();
return sr;
if (!Module.SDL2 || !Module.SDL2.audioContext) {
const AudioContext = window.AudioContext || window.webkitAudioContext;
const ctx = new AudioContext();
const sr = ctx.sampleRate;
ctx.close();
return sr;
}
return Module.SDL2.audioContext.sampleRate;
});
}
@ -217,7 +221,7 @@ void init_gb() {
}
int EMSCRIPTEN_KEEPALIVE init() {
#define str(x) #x
#define str(x) #x
#define xstr(x) str(x)
pixel_format = (SDL_PixelFormat *) malloc(sizeof(SDL_PixelFormat));
@ -292,7 +296,7 @@ int EMSCRIPTEN_KEEPALIVE init() {
want_aspec.freq = audio_sample_rate;
want_aspec.format = AUDIO_S16SYS;
want_aspec.channels = 2;
want_aspec.samples = 512;
want_aspec.samples = 2048;
want_aspec.callback = audio_callback;
want_aspec.userdata = &gb;
@ -302,27 +306,51 @@ int EMSCRIPTEN_KEEPALIVE init() {
fprintf(stderr, "Failed to open audio: %s", SDL_GetError());
}
EM_ASM({
var AudioContext = window.AudioContext || window.webkitAudioContext;
var ctx = new AudioContext();
fprintf(stderr, "WANT:\nfreq: %d\nchannels: %d\nsilence: %d\nsamples: %d\nsize: %d\nformat: %d\n", want_aspec.freq, want_aspec.channels, want_aspec.silence, want_aspec.samples, want_aspec.size, want_aspec.format);
fprintf(stderr, "HAVE:\nfreq: %d\nchannels: %d\nsilence: %d\nsamples: %d\nsize: %d\nformat: %d\n", have_aspec.freq, have_aspec.channels, have_aspec.silence, have_aspec.samples, have_aspec.size, have_aspec.format);
// unlock audio for iOS
if (ctx && ctx.currentTime == 0) {
var buffer = ctx.createBuffer(1, 1, 22050);
var source = ctx.createBufferSource();
source.buffer = buffer;
source.connect(ctx.destination);
source.start(0);
EM_ASM({
function audio_workaround(e) {
if (!Module.SDL2 || !Module.SDL2.audioContext || !Module.SDL2.audioContext.resume) return;
console.log('Applying audio workarounds...');
if (Module.SDL2.audioContext.state == 'suspended') {
Module.SDL2.audioContext.resume();
}
if (Module.SDL2.audioContext.state == 'running') {
document.removeEventListener('touchstart', audio_workaround);
document.removeEventListener('click', audio_workaround);
document.removeEventListener('keydown', audio_workaround);
if (Module.canvas) {
Module.canvas.removeEventListener('touchstart', audio_workaround);
Module.canvas.removeEventListener('click', audio_workaround);
Module.canvas.removeEventListener('keydown', audio_workaround);
}
}
else if (Module.SDL2.audioContext && Module.SDL2.audioContext.currentTime == 0) {
// unlock audio for iOS
let buffer = Module.SDL2.audioContext.createBuffer(1, 1, 22050);
let source = Module.SDL2.audioContext.createBufferSource();
source.buffer = buffer;
source.connect(Module.SDL2.audioContext.destination);
source.start(0);
}
}
// Google audio enable work-around:
// https://github.com/emscripten-ports/SDL2/issues/57
try {
if (!Module.SDL2 || !ctx || !ctx.resume) return;
ctx.resume();
} catch (err) {}
document.addEventListener('touchstart', audio_workaround);
document.addEventListener('click', audio_workaround);
document.addEventListener('keydown', audio_workaround);
ctx.close();
if (Module.canvas) {
Module.canvas.addEventListener('touchstart', audio_workaround);
Module.canvas.addEventListener('click', audio_workaround);
Module.canvas.addEventListener('keydown', audio_workaround);
}
audio_workaround();
});
init_gb();
@ -332,7 +360,11 @@ int EMSCRIPTEN_KEEPALIVE init() {
return EXIT_SUCCESS;
}
int EMSCRIPTEN_KEEPALIVE load_rom(char* filename, char* battery_save_path) {
int EMSCRIPTEN_KEEPALIVE load_boot_rom_from_file(char* filename) {
return GB_load_boot_rom(&gb, filename);
}
int EMSCRIPTEN_KEEPALIVE load_rom_from_file(char* filename, char* battery_save_path) {
int result = GB_load_rom(&gb, filename);
if (result == 0) {

View File

@ -1,6 +1,9 @@
#ifndef main_h
#define main_h
#define str(x) #x
#define xstr(x) str(x)
#define VIDEO_WIDTH 160
#define VIDEO_HEIGHT 144
#define VIDEO_PIXELS (VIDEO_WIDTH * VIDEO_HEIGHT)
@ -9,6 +12,22 @@
#define SGB_VIDEO_HEIGHT 224
#define SGB_VIDEO_PIXELS (SGB_VIDEO_WIDTH * SGB_VIDEO_HEIGHT)
#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,
#define MODELS(MODEL) \
MODEL(MODEL_DMG) \
MODEL(MODEL_CGB) \
MODEL(MODEL_AGB) \
MODEL(MODEL_SGB) \
MODEL(MODEL_MAX)
#define SGB_REVISIONS(REVISION) \
REVISION(SGB_NTSC) \
REVISION(SGB_PAL) \
REVISION(SGB_2) \
REVISION(SGB_MAX)
typedef enum {
JOYPAD_AXISES_X,
JOYPAD_AXISES_Y,
@ -24,11 +43,7 @@ typedef struct {
char filter[32];
enum {
MODEL_DMG,
MODEL_CGB,
MODEL_AGB,
MODEL_SGB,
MODEL_MAX,
MODELS(GENERATE_ENUM)
} model;
/* v0.11 */
@ -39,11 +54,42 @@ typedef struct {
/* v0.12 */
enum {
SGB_NTSC,
SGB_PAL,
SGB_2,
SGB_MAX
SGB_REVISIONS(GENERATE_ENUM)
} sgb_revision;
} configuration_t;
// TODO: There must be a better way to not duplicate this data on the JavaScript side
static const char *MODELS_STRING[] = {
MODELS(GENERATE_STRING)
};
static const char *SGB_REVISIONS_STRING[] = {
SGB_REVISIONS(GENERATE_STRING)
};
static const char** EMSCRIPTEN_KEEPALIVE get_models_string_pointer() {
return MODELS_STRING;
}
static const size_t EMSCRIPTEN_KEEPALIVE get_models_string_pointer_size() {
return sizeof(*MODELS_STRING);
}
static const size_t EMSCRIPTEN_KEEPALIVE get_models_string_size() {
return sizeof(MODELS_STRING);
}
static const char** EMSCRIPTEN_KEEPALIVE get_sgb_revisions_string_pointer() {
return SGB_REVISIONS_STRING;
}
static const size_t EMSCRIPTEN_KEEPALIVE get_sgb_revisions_string_pointer_size() {
return sizeof(*SGB_REVISIONS_STRING);
}
static const size_t EMSCRIPTEN_KEEPALIVE get_sgb_revisions_string_size() {
return sizeof(SGB_REVISIONS_STRING);
}
#endif /* main_h */

View File

@ -50,7 +50,7 @@ const loadRomFromMemory = (name, data) => {
const rom_path = allocate(intArrayFromString(`/rom/${name}`), 'i8', ALLOC_NORMAL);
const battery_path = allocate(intArrayFromString(`/persist/${battery_name}`), 'i8', ALLOC_NORMAL);
Module._load_rom(rom_path, battery_path);
Module._load_rom_from_file(rom_path, battery_path);
// The ROM has been read into memory, we can unlink the file now
FS.unlink(`/rom/${name}`)
@ -123,6 +123,9 @@ document.getElementById('file').addEventListener('change', e => {
}, false);
Module.onRuntimeInitialized = _ => {
console.log(Module.get_models());
console.log(Module.get_sgb_revisions());
FS.mkdir('/persist');
FS.mount(IDBFS, { }, '/persist');