diff options
-rw-r--r-- | src/library_browser.js | 31 | ||||
-rw-r--r-- | src/library_sdl.js | 118 | ||||
-rwxr-xr-x | tests/runner.py | 4 | ||||
-rw-r--r-- | tests/sdl_audio.c | 29 |
4 files changed, 146 insertions, 36 deletions
diff --git a/src/library_browser.js b/src/library_browser.js index 7f79b2bd..0db2cc44 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -70,18 +70,6 @@ mergeInto(LibraryManager.library, { // (possibly modified) data. For example, a plugin might decompress a file, or it // might create some side data structure for use later (like an Image element, etc.). - function getMimetype(name) { - return { - 'jpg': 'image/jpeg', - 'jpeg': 'image/jpeg', - 'png': 'image/png', - 'bmp': 'image/bmp', - 'ogg': 'audio/ogg', - 'wav': 'audio/wav', - 'mp3': 'audio/mpeg' - }[name.substr(name.lastIndexOf('.')+1)]; - } - var imagePlugin = {}; imagePlugin['canHandle'] = function(name) { return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name); @@ -90,10 +78,10 @@ mergeInto(LibraryManager.library, { var b = null; if (Browser.hasBlobConstructor) { try { - b = new Blob([byteArray], { type: getMimetype(name) }); + b = new Blob([byteArray], { type: Browser.getMimetype(name) }); if (b.size !== byteArray.length) { // Safari bug #118630 // Safari's Blob can only take an ArrayBuffer - b = new Blob([(new Uint8Array(byteArray)).buffer], { type: getMimetype(name) }); + b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) }); } } catch(e) { Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder'); @@ -148,7 +136,7 @@ mergeInto(LibraryManager.library, { } if (Browser.hasBlobConstructor) { try { - var b = new Blob([byteArray], { type: getMimetype(name) }); + var b = new Blob([byteArray], { type: Browser.getMimetype(name) }); } catch(e) { return fail(); } @@ -391,6 +379,18 @@ mergeInto(LibraryManager.library, { }, timeout); }, + getMimetype: function(name) { + return { + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'png': 'image/png', + 'bmp': 'image/bmp', + 'ogg': 'audio/ogg', + 'wav': 'audio/wav', + 'mp3': 'audio/mpeg' + }[name.substr(name.lastIndexOf('.')+1)]; + }, + getUserMedia: function(func) { if(!window.getUserMedia) { window.getUserMedia = navigator['getUserMedia'] || @@ -399,6 +399,7 @@ mergeInto(LibraryManager.library, { window.getUserMedia(func); }, + getMovementX: function(event) { return event['movementX'] || event['mozMovementX'] || diff --git a/src/library_sdl.js b/src/library_sdl.js index 9287bd3e..7078aa9d 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -28,6 +28,7 @@ var LibrarySDL = { // The currently preloaded audio elements ready to be played audios: [null], + rwops: [null], // The currently playing audio element. There's only one music track. music: { audio: null, @@ -1228,9 +1229,24 @@ var LibrarySDL = { return flags; // We support JPG, PNG, TIF because browsers do }, - IMG_Load__deps: ['SDL_LockSurface'], - IMG_Load: function(filename) { - filename = FS.standardizePath(Pointer_stringify(filename)); + IMG_Load_RW__deps: ['SDL_LockSurface'], + IMG_Load_RW: function(rwopsID, freesrc) { + var rwops = SDL.rwops[rwopsID]; + + if (rwops === undefined) { + return 0; + } + + var filename = rwops.filename; + + if (filename === undefined) { + Runtime.warnOnce('Only file names that have been preloaded are supported for IMG_Load_RW.'); + // TODO. Support loading image data from embedded files, similarly to Mix_LoadWAV_RW + // TODO. Support loading image data from byte arrays, similarly to Mix_LoadWAV_RW + return 0; + } + + filename = FS.standardizePath(filename); if (filename[0] == '/') { // Convert the path to relative filename = filename.substr(1); @@ -1262,8 +1278,14 @@ var LibrarySDL = { return surf; }, SDL_LoadBMP: 'IMG_Load', - SDL_LoadBMP_RW: 'IMG_Load', - IMG_Load_RW: 'IMG_Load', + SDL_LoadBMP_RW: 'IMG_Load_RW', + IMG_Load__deps: ['IMG_Load_RW', 'SDL_RWFromFile', 'SDL_FreeRW'], + IMG_Load: function(filename){ + var rwops = _SDL_RWFromFile(filename); + var result = _IMG_Load_RW(rwops); + _SDL_FreeRW(rwops); + return result; + }, // SDL_Audio @@ -1399,22 +1421,62 @@ var LibrarySDL = { return 0; // error }, - Mix_LoadWAV_RW: function(filename, freesrc) { - filename = FS.standardizePath(Pointer_stringify(filename)); - var raw = Module["preloadedAudios"][filename]; - if (!raw) { - if (raw === null) Module.printErr('Trying to reuse preloaded audio, but freePreloadedMediaOnUse is set!'); - Runtime.warnOnce('Cannot find preloaded audio ' + filename); + Mix_LoadWAV_RW: function(rwopsID, freesrc) { + var rwops = SDL.rwops[rwopsID]; + + if (rwops === undefined) + return 0; + + var filename = ''; + var audio; + var bytes; + + if (rwops.filename !== undefined) { + filename = rwops.filename; + filename = FS.standardizePath(filename); + var raw = Module["preloadedAudios"][filename]; + if (!raw) { + if (raw === null) Module.printErr('Trying to reuse preloaded audio, but freePreloadedMediaOnUse is set!'); + Runtime.warnOnce('Cannot find preloaded audio ' + filename); + + // see if we can read the file-contents from the in-memory FS + var fileObject = FS.findObject(filename); + + if (fileObject === null) Module.printErr('Couldn\'t find file for: ' + filename); + + // We found the file. Load the contents + if (fileObject && !fileObject.isFolder && fileObject.read) { + bytes = fileObject.contents + } else { + return 0; + } + } + if (Module['freePreloadedMediaOnUse']) { + Module["preloadedAudios"][filename] = null; + } + audio = raw; + } + else if (rwops.bytes !== undefined) { + bytes = HEAPU8.subarray(rwops.bytes, rwops.bytes + rwops.count); + } + else { return 0; } - if (Module['freePreloadedMediaOnUse']) { - Module["preloadedAudios"][filename] = null; + + // Here, we didn't find a preloaded audio but we either were passed a filepath for + // which we loaded bytes, or we were passed some bytes + if (audio === undefined && bytes) { + var blob = new Blob([new Uint8Array(bytes)], {type: rwops.mimetype}); + var url = URL.createObjectURL(blob); + audio = new Audio(); + audio.src = url; } + var id = SDL.audios.length; // Keep the loaded audio in the audio arrays, ready for playback SDL.audios.push({ source: filename, - audio: raw + audio: audio }); return id; }, @@ -1574,8 +1636,14 @@ var LibrarySDL = { return SDL.setGetVolume(SDL.music, volume); }, - Mix_LoadMUS: 'Mix_LoadWAV_RW', Mix_LoadMUS_RW: 'Mix_LoadWAV_RW', + Mix_LoadMUS__deps: ['Mix_LoadMUS_RW', 'SDL_RWFromFile', 'SDL_FreeRW'], + Mix_LoadMUS: function(filename) { + var rwops = _SDL_RWFromFile(filename); + var result = _Mix_LoadMUS_RW(rwops); + _SDL_FreeRW(rwops); + return result; + }, Mix_FreeMusic: 'Mix_FreeChunk', @@ -1978,9 +2046,24 @@ var LibrarySDL = { // Misc SDL_InitSubSystem: function(flags) { return 0 }, + SDL_RWFromConstMem: function(mem, size) { + var id = SDL.rwops.length; // TODO: recycle ids when they are null + SDL.rwops.push({ bytes: mem, count: size }); + return id; + }, - SDL_RWFromFile: function(filename, mode) { - return filename; // XXX We just forward the filename + SDL_RWFromFile: function(_name, mode) { + var id = SDL.rwops.length; // TODO: recycle ids when they are null + var name = Pointer_stringify(_name) + SDL.rwops.push({ filename: name, mimetype: Browser.getMimetype(name) }); + return id; + }, + + SDL_FreeRW: function(rwopsID) { + SDL.rwops[rwopsID] = null; + while (SDL.rwops.length > 0 && SDL.rwops[SDL.rwops.length-1] === null) { + SDL.rwops.pop(); + } }, SDL_EnableUNICODE: function(on) { @@ -2007,7 +2090,6 @@ var LibrarySDL = { SDL_GetThreadID: function() { throw 'SDL_GetThreadID' }, SDL_ThreadID: function() { throw 'SDL_ThreadID' }, SDL_AllocRW: function() { throw 'SDL_AllocRW: TODO' }, - SDL_FreeRW: function() { throw 'SDL_FreeRW: TODO' }, SDL_CondBroadcast: function() { throw 'SDL_CondBroadcast: TODO' }, SDL_CondWaitTimeout: function() { throw 'SDL_CondWaitTimeout: TODO' }, SDL_WM_IconifyWindow: function() { throw 'SDL_WM_IconifyWindow TODO' }, diff --git a/tests/runner.py b/tests/runner.py index e16fc12e..4a9bf623 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -12998,11 +12998,13 @@ Press any key to continue.''' def test_sdl_audio(self): shutil.copyfile(path_from_root('tests', 'sounds', 'alarmvictory_1.ogg'), os.path.join(self.get_dir(), 'sound.ogg')) shutil.copyfile(path_from_root('tests', 'sounds', 'alarmcreatemiltaryfoot_1.wav'), os.path.join(self.get_dir(), 'sound2.wav')) + shutil.copyfile(path_from_root('tests', 'sounds', 'noise.ogg'), os.path.join(self.get_dir(), 'noise.ogg')) + shutil.copyfile(path_from_root('tests', 'sounds', 'the_entertainer.ogg'), os.path.join(self.get_dir(), 'the_entertainer.ogg')) open(os.path.join(self.get_dir(), 'bad.ogg'), 'w').write('I claim to be audio, but am lying') open(os.path.join(self.get_dir(), 'sdl_audio.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio.c')).read())) # use closure to check for a possible bug with closure minifying away newer Audio() attributes - Popen([PYTHON, EMCC, '-O2', '--closure', '1', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio.c'), '--preload-file', 'sound.ogg', '--preload-file', 'sound2.wav', '--preload-file', 'bad.ogg', '-o', 'page.html', '-s', 'EXPORTED_FUNCTIONS=["_main", "_play", "_play2"]']).communicate() + Popen([PYTHON, EMCC, '-O2', '--closure', '1', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio.c'), '--preload-file', 'sound.ogg', '--preload-file', 'sound2.wav', '--embed-file', 'the_entertainer.ogg', '--preload-file', 'noise.ogg', '--preload-file', 'bad.ogg', '-o', 'page.html', '-s', 'EXPORTED_FUNCTIONS=["_main", "_play", "_play2"]']).communicate() self.run_browser('page.html', '', '/report_result?1') def test_sdl_audio_mix_channels(self): diff --git a/tests/sdl_audio.c b/tests/sdl_audio.c index ae1b89e9..7373d220 100644 --- a/tests/sdl_audio.c +++ b/tests/sdl_audio.c @@ -1,11 +1,13 @@ #include <stdio.h> +#include <stdlib.h> #include <SDL/SDL.h> #include <SDL/SDL_mixer.h> #include <assert.h> #include <emscripten.h> +#include <sys/stat.h> -Mix_Chunk *sound, *sound2; - +Mix_Chunk *sound, *sound2, *sound3; +Mix_Music * music; int play2(); int play() { @@ -28,6 +30,9 @@ int play2() { int channel2 = Mix_PlayChannel(-1, sound2, 0); assert(channel2 == 1); + int channel3 = Mix_PlayChannel(-1, sound3, 0); + assert(channel3 == 2); + assert(Mix_PlayMusic(music, 1) == 0); return channel2; } @@ -39,6 +44,26 @@ int main(int argc, char **argv) { sound = Mix_LoadWAV("sound.ogg"); assert(sound); + + { + struct stat info; + int result = stat("noise.ogg", &info); + char * bytes = malloc( info.st_size ); + FILE * f = fopen( "noise.ogg", "rb" ); + fread( bytes, 1, info.st_size, f ); + fclose(f); + + SDL_RWops * ops = SDL_RWFromConstMem(bytes, info.st_size); + sound3 = Mix_LoadWAV_RW(ops, 0); + SDL_FreeRW(ops); + free(bytes); + } + + { + music = Mix_LoadMUS("the_entertainer.ogg"); + } + + sound2 = Mix_LoadWAV("sound2.wav"); assert(sound); |