Skip to content

Commit 05cefc9

Browse files
committed
AudioWorklet driver, misc. emscripten fixes
1 parent cb69d25 commit 05cefc9

23 files changed

Lines changed: 1029 additions & 134 deletions

File tree

Makefile.common

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,9 @@ ifeq ($(HAVE_EMSCRIPTEN), 1)
790790
ifeq ($(HAVE_RWEBAUDIO), 1)
791791
OBJ += audio/drivers/rwebaudio.o
792792
endif
793+
ifeq ($(HAVE_AUDIOWORKLET), 1)
794+
OBJ += audio/drivers/audioworklet.o
795+
endif
793796
endif
794797

795798
ifeq ($(HAVE_BLUETOOTH), 1)

Makefile.emscripten

Lines changed: 106 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ TARGET := $(LIBRETRO)_libretro.js
88
endif
99
endif
1010

11-
EOPT = USE_ZLIB=1 # Emscripten specific options
12-
EOPTS = $(addprefix -s $(EMPTY), $(EOPT)) # Add '-s ' to each option
13-
1411
OS = Emscripten
1512
OBJ :=
1613
DEFINES := -DRARCH_INTERNAL -DHAVE_MAIN -DEMSCRIPTEN -DNO_CANVAS_RESIZE
@@ -20,7 +17,7 @@ HAVE_PATCH = 1
2017
HAVE_DSP_FILTER = 1
2118
HAVE_VIDEO_FILTER = 1
2219
HAVE_OVERLAY = 1
23-
HAVE_NETWORKING = 1
20+
HAVE_NETWORKING ?= 1
2421
HAVE_LIBRETRODB = 1
2522
HAVE_COMPRESSION = 1
2623
HAVE_UPDATE_ASSETS = 1
@@ -32,10 +29,10 @@ HAVE_AUDIOMIXER = 1
3229
HAVE_CC_RESAMPLER = 1
3330
HAVE_EGL ?= 0
3431
HAVE_OPENGLES = 1
35-
HAVE_RJPEG = 0
36-
HAVE_RPNG = 1
32+
HAVE_RJPEG = 0
33+
HAVE_RPNG = 1
3734
HAVE_EMSCRIPTEN = 1
38-
HAVE_MENU = 1
35+
HAVE_MENU ?= 1
3936
HAVE_GFX_WIDGETS = 1
4037
HAVE_RGUI = 1
4138
HAVE_SDL = 0
@@ -47,37 +44,63 @@ HAVE_STATIC_AUDIO_FILTERS = 1
4744
HAVE_STB_FONT = 1
4845
HAVE_CONFIGFILE = 1
4946
HAVE_COMMAND = 1
50-
HAVE_STDIN_CMD = 1
47+
HAVE_STDIN_CMD ?= 1
5148
HAVE_CHEATS = 1
5249
HAVE_IBXM = 1
5350
HAVE_CORE_INFO_CACHE = 1
5451
HAVE_7ZIP = 1
5552
HAVE_BSV_MOVIE = 1
56-
HAVE_AL = 1
5753
HAVE_CHD ?= 0
5854
HAVE_NETPLAYDISCOVERY ?= 0
55+
56+
HAVE_AL ?= 1
57+
58+
# enables pthreads, requires special headers on the web server:
59+
# see https://web.dev/articles/coop-coep
5960
HAVE_THREADS ?= 0
6061

62+
# requires HAVE_THREADS
63+
HAVE_AUDIOWORKLET ?= 0
64+
6165
# WARNING -- READ BEFORE ENABLING
6266
# The rwebaudio driver is known to have several audio bugs, such as
6367
# minor crackling, or the entire page freezing/crashing.
6468
# It works perfectly on chrome, but even firefox has really bad audio quality.
6569
# I should also note, the driver on iOS is completely broken (crashes the page).
6670
# You have been warned.
67-
HAVE_RWEBAUDIO = 0
71+
HAVE_RWEBAUDIO ?= 0
72+
73+
# whether the browser thread is allowed to block to wait for audio to play,
74+
# may lead to the issues mentioned above.
75+
# currently this variable is only used by audioworklet;
76+
# rwebaudio will always busywait and openal will never busywait.
77+
ALLOW_AUDIO_BUSYWAIT ?= 0
78+
79+
# minimal asyncify; better performance than full asyncify,
80+
# but sleeping on the main thread is only possible in some places.
81+
MIN_ASYNC ?= 0
82+
83+
# runs RetroArch on a pthread instead of the browser thread; requires HAVE_THREADS
84+
PROXY_TO_PTHREAD ?= 0
85+
86+
# recommended FS when using HAVE_THREADS
87+
HAVE_WASMFS ?= 0
88+
89+
# enables OPFS (origin private file system) and FETCHFS, requires PROXY_TO_PTHREAD
90+
HAVE_EXTRA_WASMFS ?= 0
91+
92+
# enable javascript filesystem tracking, incompatible with HAVE_WASMFS
93+
FS_DEBUG ?= 0
6894

6995
# help diagnose GL problems (can cause issues in normal operation)
7096
GL_DEBUG ?= 0
7197

72-
# enable javascript filesystem tracking
73-
FS_DEBUG = 0
98+
# does nothing on its own, but automatically selected by some other options
99+
WASM_WORKERS = 0
74100

75101
HAVE_OPENGLES ?= 1
76102
HAVE_OPENGLES3 ?= 0
77103

78-
HAVE_WASMFS ?= 0
79-
PROXY_TO_PTHREAD ?= 0
80-
81104
ASYNC ?= 0
82105
LTO ?= 0
83106
PTHREAD_POOL_SIZE ?= 4
@@ -102,26 +125,32 @@ OBJDIR := obj-emscripten
102125
EXPORTED_FUNCTIONS = _main,_malloc,_free,_cmd_savefiles,_cmd_save_state,_cmd_load_state,_cmd_undo_save_state,_cmd_undo_load_state,_cmd_take_screenshot,\
103126
_cmd_toggle_menu,_cmd_reload_config,_cmd_toggle_grab_mouse,_cmd_toggle_game_focus,_cmd_reset,_cmd_toggle_pause,_cmd_pause,_cmd_unpause,\
104127
_cmd_set_volume,_cmd_set_shader,_cmd_cheat_set_code,_cmd_cheat_get_code,_cmd_cheat_toggle_index,_cmd_cheat_get_code_state,_cmd_cheat_realloc,\
105-
_cmd_cheat_get_size,_cmd_cheat_apply_cheats,_update_canvas_dimensions,_update_window_hidden,_update_power_state,_update_memory_usage,\
106-
EmscriptenSendCommand,EmscriptenReceiveCommandReply
128+
_cmd_cheat_get_size,_cmd_cheat_apply_cheats,EmscriptenSendCommand,EmscriptenReceiveCommandReply
107129

108130
EXPORTS := callMain,FS,PATH,ERRNO_CODES,ENV,stringToNewUTF8,UTF8ToString,Browser,EmscriptenSendCommand,EmscriptenReceiveCommandReply
109131

110-
LIBS := -s USE_ZLIB=1
132+
LIBS := -s USE_ZLIB=1
133+
CFLAGS := -s USE_ZLIB=1
111134

112-
ifeq ($(HAVE_WASMFS), 1)
113-
LIBS += -s WASMFS -s FORCE_FILESYSTEM=1 -lfetchfs.js -lopfs.js
114-
DEFINES += -DHAVE_WASMFS
135+
ifeq ($(HAVE_EXTRA_WASMFS), 1)
136+
LIBS += -lfetchfs.js -lopfs.js
137+
DEFINES += -DHAVE_EXTRA_WASMFS
138+
override HAVE_WASMFS = 1
115139
ifeq ($(PROXY_TO_PTHREAD), 0)
116-
$(error ERROR: WASMFS requires PROXY_TO_PTHREAD)
140+
$(error ERROR: HAVE_EXTRA_WASMFS requires PROXY_TO_PTHREAD)
117141
endif
118142
endif
119143

144+
ifeq ($(HAVE_WASMFS), 1)
145+
LIBS += -s WASMFS -s FORCE_FILESYSTEM=1
146+
endif
147+
120148
# note: real PROXY_TO_PTHREAD is not used here; we do the pthread management ourselves
121149
ifeq ($(PROXY_TO_PTHREAD), 1)
122150
LIBS += -s OFFSCREENCANVAS_SUPPORT
123151
DEFINES += -DPROXY_TO_PTHREAD -DEMSCRIPTEN_STACK_SIZE=$(STACK_SIZE)
124152
override HAVE_THREADS = 1
153+
override WASM_WORKERS = 1
125154
# use the default stack size for the browser thread; the RetroArch thread will be created with the specified stack size
126155
override STACK_SIZE = 4194304
127156
else ifeq ($(HAVE_AL), 1)
@@ -165,6 +194,40 @@ ifeq ($(HAVE_RWEBAUDIO), 1)
165194
DEFINES += -DHAVE_RWEBAUDIO
166195
endif
167196

197+
ifeq ($(HAVE_AUDIOWORKLET), 1)
198+
LDFLAGS += -s AUDIO_WORKLET=1
199+
DEFINES += -DHAVE_AUDIOWORKLET
200+
override WASM_WORKERS = 1
201+
ifeq ($(HAVE_THREADS), 0)
202+
$(error ERROR: AUDIOWORKLET requires HAVE_THREADS)
203+
endif
204+
ifeq ($(PROXY_TO_PTHREAD), 1)
205+
else ifeq ($(ASYNC), 1)
206+
else
207+
DEFINES += -DEMSCRIPTEN_AUDIO_EXTERNAL_BLOCK
208+
ifeq ($(MIN_ASYNC), 1)
209+
DEFINES += -DEMSCRIPTEN_AUDIO_ASYNC_BLOCK
210+
else
211+
DEFINES += -DEMSCRIPTEN_AUDIO_FAKE_BLOCK
212+
endif
213+
ifneq ($(ALLOW_AUDIO_BUSYWAIT), 1)
214+
DEFINES += -DEMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK
215+
endif
216+
endif
217+
endif
218+
219+
ifeq ($(ALLOW_AUDIO_BUSYWAIT), 1)
220+
DEFINES += -DEMSCRIPTEN_AUDIO_BUSYWAIT
221+
endif
222+
223+
# explanation of some of these defines:
224+
# EMSCRIPTEN_AUDIO_EXTERNAL_BLOCK: audio blocking occurs in the main loop instead of in the audio driver functions.
225+
# EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK: along with above, enables external blocking in the write function.
226+
# ALLOW_AUDIO_BUSYWAIT: write function will busywait. init function may still use an external block.
227+
# EMSCRIPTEN_AUDIO_ASYNC_BLOCK: external block uses emscripten_sleep (requires MIN_ASYNC).
228+
# EMSCRIPTEN_AUDIO_FAKE_BLOCK: external block uses main loop timing (doesn't require asyncify).
229+
# when building with either PROXY_TO_PTHREAD or ASYNC (full asyncify), none of the above are required.
230+
168231
ifeq ($(HAVE_AL), 1)
169232
LDFLAGS += -lopenal
170233
DEFINES += -DHAVE_AL
@@ -175,11 +238,21 @@ ifeq ($(HAVE_THREADS), 1)
175238
CFLAGS += -pthread -s SHARED_MEMORY
176239
endif
177240

241+
ifeq ($(WASM_WORKERS), 1)
242+
LDFLAGS += -s WASM_WORKERS=2
243+
endif
244+
178245
ifeq ($(ASYNC), 1)
179-
DEFINES += -DEMSCRIPTEN_ASYNCIFY
246+
DEFINES += -DEMSCRIPTEN_ASYNCIFY -DEMSCRIPTEN_FULL_ASYNCIFY
180247
LDFLAGS += -s ASYNCIFY=1 -s ASYNCIFY_STACK_SIZE=8192
181248
ifeq ($(DEBUG), 1)
182-
LDFLAGS += -s ASYNCIFY_DEBUG=1 # -s ASYNCIFY_ADVISE
249+
#LDFLAGS += -s ASYNCIFY_DEBUG=1 # broken?
250+
endif
251+
else ifeq ($(MIN_ASYNC), 1)
252+
DEFINES += -DEMSCRIPTEN_ASYNCIFY -DEMSCRIPTEN_MIN_ASYNCIFY
253+
LDFLAGS += -s ASYNCIFY=1 -s ASYNCIFY_STACK_SIZE=8192 -s ASYNCIFY_IGNORE_INDIRECT=1 -s ASYNCIFY_ADD='dynCall_*,emscripten_mainloop' -s ASYNCIFY_REMOVE='threaded_worker'
254+
ifeq ($(DEBUG), 1)
255+
LDFLAGS += -s ASYNCIFY_ADVISE #-s ASYNCIFY_DEBUG=1
183256
endif
184257
endif
185258

@@ -202,7 +275,7 @@ ifneq ($(V), 1)
202275
endif
203276

204277
ifeq ($(DEBUG), 1)
205-
LDFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=1 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
278+
LDFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=2 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
206279
# -O0 in cflags gives "too many locals" errors
207280
CFLAGS += -O1 -g -gsource-map
208281
else
@@ -223,19 +296,25 @@ all: $(TARGET)
223296
$(libretro_new) : $(libretro)
224297
mv -f $(libretro) $(libretro_new)
225298

299+
# until emscripten adds something like WASM_WORKERS=2 but for audio worklets, DIY.
226300
$(TARGET): $(RARCH_OBJ) $(libretro_new)
227301
@$(if $(Q), $(shell echo echo "LD $@ \<obj\> $(libretro_new) $(LIBS) $(LDFLAGS)"),)
228302
$(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro_new) $(LIBS) $(LDFLAGS)
303+
@if [ "$(HAVE_AUDIOWORKLET)" = 1 ]; then\
304+
tr -d '\n' < "$${TARGET%%\.js}.aw.js" | sed -e "s/[\/&]/\\\\&/g" -e "s/'/\\\\\\\\&/g" > _audioworklet.js;\
305+
sed -i "s/\"$${TARGET%%\.js}\.aw\.js\"/URL.createObjectURL(new Blob(['$$(cat _audioworklet.js)'],{type:'text\/javascript'}))/" "$@";\
306+
rm "$${TARGET%%\.js}.aw.js" _audioworklet.js;\
307+
fi
229308

230309
$(OBJDIR)/%.o: %.c
231310
@mkdir -p $(dir $@)
232311
@$(if $(Q), $(shell echo echo CC $<),)
233-
$(Q)$(CC) $(CFLAGS) $(DEFINES) $(EOPTS) -c -o $@ $<
312+
$(Q)$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
234313

235314
$(OBJDIR)/%.o: %.cpp
236315
@mkdir -p $(dir $@)
237316
@$(if $(Q), $(shell echo echo CXX $<),)
238-
$(Q)$(CXX) $(CXXFLAGS) $(DEFINES) $(EOPTS) -c -o $@ $<
317+
$(Q)$(CXX) $(CXXFLAGS) $(DEFINES) -c -o $@ $<
239318

240319
clean:
241320
rm -rf $(OBJDIR)

audio/audio_driver.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,12 @@ audio_driver_t *audio_drivers[] = {
147147
#ifdef WIIU
148148
&audio_ax,
149149
#endif
150-
#if defined(EMSCRIPTEN) && defined(HAVE_RWEBAUDIO)
150+
#if defined(HAVE_RWEBAUDIO)
151151
&audio_rwebaudio,
152152
#endif
153+
#if defined(HAVE_AUDIOWORKLET)
154+
&audio_audioworklet,
155+
#endif
153156
#if defined(PSP) || defined(VITA) || defined(ORBIS)
154157
&audio_psp,
155158
#endif
@@ -463,19 +466,19 @@ static void audio_driver_flush(
463466
= avail;
464467
audio_st->source_ratio_current
465468
= audio_st->source_ratio_original * adjust;
466-
}
467469

468470
#if 0
469-
if (verbosity_is_enabled())
470-
{
471-
RARCH_LOG_OUTPUT("[Audio]: Audio buffer is %u%% full\n",
472-
(unsigned)(100 - (avail * 100) /
473-
audio_st->buffer_size));
474-
RARCH_LOG_OUTPUT("[Audio]: New rate: %lf, Orig rate: %lf\n",
475-
audio_st->source_ratio_current,
476-
audio_st->source_ratio_original);
477-
}
471+
if (verbosity_is_enabled())
472+
{
473+
RARCH_LOG_OUTPUT("[Audio]: Audio buffer is %u%% full\n",
474+
(unsigned)(100 - (avail * 100) /
475+
audio_st->buffer_size));
476+
RARCH_LOG_OUTPUT("[Audio]: New rate: %lf, Orig rate: %lf\n",
477+
audio_st->source_ratio_current,
478+
audio_st->source_ratio_original);
479+
}
478480
#endif
481+
}
479482
}
480483

481484
src_data.ratio = audio_st->source_ratio_current;

audio/audio_driver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ extern audio_driver_t audio_switch_thread;
439439
extern audio_driver_t audio_switch_libnx_audren;
440440
extern audio_driver_t audio_switch_libnx_audren_thread;
441441
extern audio_driver_t audio_rwebaudio;
442+
extern audio_driver_t audio_audioworklet;
442443

443444
audio_driver_state_t *audio_state_get_ptr(void);
444445

0 commit comments

Comments
 (0)