mirror of
https://github.com/godotengine/godot.git
synced 2025-10-20 08:23:29 +00:00
[HTML5] Refactor JS, threads support, closures.
- Refactored the Engine code, splitted across files. - Use MODULARIZE option to build emscripten code into it's own closure. - Optional closure compiler run for JS and generated code. - Enable lto support (saves ~2MiB in release). - Can now build with tools=yes (not much to see yet). - Dropped some deprecated code for older toolchains. - Add onExit, and onExecute JS function. - Add files drag and drop support. - Add support for low precessor usage mode (via offscreen render, swap).
This commit is contained in:
parent
93e20a4cd4
commit
21c9f37757
18 changed files with 1097 additions and 627 deletions
|
@ -37,22 +37,18 @@
|
|||
AudioDriverJavaScript *AudioDriverJavaScript::singleton = NULL;
|
||||
|
||||
const char *AudioDriverJavaScript::get_name() const {
|
||||
|
||||
return "JavaScript";
|
||||
}
|
||||
|
||||
extern "C" EMSCRIPTEN_KEEPALIVE void audio_driver_js_mix() {
|
||||
|
||||
AudioDriverJavaScript::singleton->mix_to_js();
|
||||
}
|
||||
|
||||
extern "C" EMSCRIPTEN_KEEPALIVE void audio_driver_process_capture(float sample) {
|
||||
|
||||
AudioDriverJavaScript::singleton->process_capture(sample);
|
||||
}
|
||||
|
||||
void AudioDriverJavaScript::mix_to_js() {
|
||||
|
||||
int channel_count = get_total_channels_by_speaker_mode(get_speaker_mode());
|
||||
int sample_count = memarr_len(internal_buffer) / channel_count;
|
||||
int32_t *stream_buffer = reinterpret_cast<int32_t *>(internal_buffer);
|
||||
|
@ -63,24 +59,24 @@ void AudioDriverJavaScript::mix_to_js() {
|
|||
}
|
||||
|
||||
void AudioDriverJavaScript::process_capture(float sample) {
|
||||
|
||||
int32_t sample32 = int32_t(sample * 32768.f) * (1U << 16);
|
||||
input_buffer_write(sample32);
|
||||
}
|
||||
|
||||
Error AudioDriverJavaScript::init() {
|
||||
|
||||
int mix_rate = GLOBAL_GET("audio/mix_rate");
|
||||
int latency = GLOBAL_GET("audio/output_latency");
|
||||
|
||||
/* clang-format off */
|
||||
EM_ASM({
|
||||
_driver_id = EM_ASM_INT({
|
||||
const MIX_RATE = $0;
|
||||
const LATENCY = $1 / 1000;
|
||||
_audioDriver_audioContext = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: MIX_RATE, latencyHint: LATENCY});
|
||||
_audioDriver_audioInput = null;
|
||||
_audioDriver_inputStream = null;
|
||||
_audioDriver_scriptNode = null;
|
||||
return Module.IDHandler.add({
|
||||
'context': new (window.AudioContext || window.webkitAudioContext)({ sampleRate: MIX_RATE, latencyHint: LATENCY}),
|
||||
'input': null,
|
||||
'stream': null,
|
||||
'script': null
|
||||
});
|
||||
}, mix_rate, latency);
|
||||
/* clang-format on */
|
||||
|
||||
|
@ -88,14 +84,16 @@ Error AudioDriverJavaScript::init() {
|
|||
buffer_length = closest_power_of_2((latency * mix_rate / 1000) * channel_count);
|
||||
/* clang-format off */
|
||||
buffer_length = EM_ASM_INT({
|
||||
const BUFFER_LENGTH = $0;
|
||||
const CHANNEL_COUNT = $1;
|
||||
var ref = Module.IDHandler.get($0);
|
||||
const ctx = ref['context'];
|
||||
const BUFFER_LENGTH = $1;
|
||||
const CHANNEL_COUNT = $2;
|
||||
|
||||
_audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(BUFFER_LENGTH, 2, CHANNEL_COUNT);
|
||||
_audioDriver_scriptNode.connect(_audioDriver_audioContext.destination);
|
||||
|
||||
return _audioDriver_scriptNode.bufferSize;
|
||||
}, buffer_length, channel_count);
|
||||
var script = ctx.createScriptProcessor(BUFFER_LENGTH, 2, CHANNEL_COUNT);
|
||||
script.connect(ctx.destination);
|
||||
ref['script'] = script;
|
||||
return script.bufferSize;
|
||||
}, _driver_id, buffer_length, channel_count);
|
||||
/* clang-format on */
|
||||
if (!buffer_length) {
|
||||
return FAILED;
|
||||
|
@ -111,14 +109,14 @@ Error AudioDriverJavaScript::init() {
|
|||
}
|
||||
|
||||
void AudioDriverJavaScript::start() {
|
||||
|
||||
/* clang-format off */
|
||||
EM_ASM({
|
||||
var INTERNAL_BUFFER_PTR = $0;
|
||||
const ref = Module.IDHandler.get($0);
|
||||
var INTERNAL_BUFFER_PTR = $1;
|
||||
|
||||
var audioDriverMixFunction = cwrap('audio_driver_js_mix');
|
||||
var audioDriverProcessCapture = cwrap('audio_driver_process_capture', null, ['number']);
|
||||
_audioDriver_scriptNode.onaudioprocess = function(audioProcessingEvent) {
|
||||
ref['script'].onaudioprocess = function(audioProcessingEvent) {
|
||||
audioDriverMixFunction();
|
||||
|
||||
var input = audioProcessingEvent.inputBuffer;
|
||||
|
@ -135,7 +133,7 @@ void AudioDriverJavaScript::start() {
|
|||
}
|
||||
}
|
||||
|
||||
if (_audioDriver_audioInput) {
|
||||
if (ref['input']) {
|
||||
var inputDataL = input.getChannelData(0);
|
||||
var inputDataR = input.getChannelData(1);
|
||||
for (var i = 0; i < inputDataL.length; i++) {
|
||||
|
@ -144,51 +142,54 @@ void AudioDriverJavaScript::start() {
|
|||
}
|
||||
}
|
||||
};
|
||||
}, internal_buffer);
|
||||
}, _driver_id, internal_buffer);
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
void AudioDriverJavaScript::resume() {
|
||||
/* clang-format off */
|
||||
EM_ASM({
|
||||
if (_audioDriver_audioContext.resume)
|
||||
_audioDriver_audioContext.resume();
|
||||
});
|
||||
const ref = Module.IDHandler.get($0);
|
||||
if (ref && ref['context'] && ref['context'].resume)
|
||||
ref['context'].resume();
|
||||
}, _driver_id);
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
float AudioDriverJavaScript::get_latency() {
|
||||
/* clang-format off */
|
||||
return EM_ASM_DOUBLE({
|
||||
const ref = Module.IDHandler.get($0);
|
||||
var latency = 0;
|
||||
if (_audioDriver_audioContext) {
|
||||
if (_audioDriver_audioContext.baseLatency) {
|
||||
latency += _audioDriver_audioContext.baseLatency;
|
||||
if (ref && ref['context']) {
|
||||
const ctx = ref['context'];
|
||||
if (ctx.baseLatency) {
|
||||
latency += ctx.baseLatency;
|
||||
}
|
||||
if (_audioDriver_audioContext.outputLatency) {
|
||||
latency += _audioDriver_audioContext.outputLatency;
|
||||
if (ctx.outputLatency) {
|
||||
latency += ctx.outputLatency;
|
||||
}
|
||||
}
|
||||
return latency;
|
||||
});
|
||||
}, _driver_id);
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
int AudioDriverJavaScript::get_mix_rate() const {
|
||||
|
||||
/* clang-format off */
|
||||
return EM_ASM_INT_V({
|
||||
return _audioDriver_audioContext.sampleRate;
|
||||
});
|
||||
return EM_ASM_INT({
|
||||
const ref = Module.IDHandler.get($0);
|
||||
return ref && ref['context'] ? ref['context'].sampleRate : 0;
|
||||
}, _driver_id);
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
AudioDriver::SpeakerMode AudioDriverJavaScript::get_speaker_mode() const {
|
||||
|
||||
/* clang-format off */
|
||||
return get_speaker_mode_by_total_channels(EM_ASM_INT_V({
|
||||
return _audioDriver_audioContext.destination.channelCount;
|
||||
}));
|
||||
return get_speaker_mode_by_total_channels(EM_ASM_INT({
|
||||
const ref = Module.IDHandler.get($0);
|
||||
return ref && ref['context'] ? ref['context'].destination.channelCount : 0;
|
||||
}, _driver_id));
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
|
@ -199,16 +200,38 @@ void AudioDriverJavaScript::lock() {
|
|||
void AudioDriverJavaScript::unlock() {
|
||||
}
|
||||
|
||||
void AudioDriverJavaScript::finish() {
|
||||
void AudioDriverJavaScript::finish_async() {
|
||||
// Close the context, add the operation to the async_finish list in module.
|
||||
int id = _driver_id;
|
||||
_driver_id = 0;
|
||||
|
||||
/* clang-format off */
|
||||
EM_ASM({
|
||||
_audioDriver_audioContext = null;
|
||||
_audioDriver_audioInput = null;
|
||||
_audioDriver_scriptNode = null;
|
||||
});
|
||||
var ref = Module.IDHandler.get($0);
|
||||
Module.async_finish.push(new Promise(function(accept, reject) {
|
||||
if (!ref) {
|
||||
console.log("Ref not found!", $0, Module.IDHandler);
|
||||
setTimeout(accept, 0);
|
||||
} else {
|
||||
const context = ref['context'];
|
||||
// Disconnect script and input.
|
||||
ref['script'].disconnect();
|
||||
if (ref['input'])
|
||||
ref['input'].disconnect();
|
||||
ref = null;
|
||||
context.close().then(function() {
|
||||
accept();
|
||||
}).catch(function(e) {
|
||||
accept();
|
||||
});
|
||||
}
|
||||
}));
|
||||
Module.IDHandler.remove($0);
|
||||
}, id);
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
void AudioDriverJavaScript::finish() {
|
||||
if (internal_buffer) {
|
||||
memdelete_arr(internal_buffer);
|
||||
internal_buffer = NULL;
|
||||
|
@ -216,15 +239,15 @@ void AudioDriverJavaScript::finish() {
|
|||
}
|
||||
|
||||
Error AudioDriverJavaScript::capture_start() {
|
||||
|
||||
input_buffer_init(buffer_length);
|
||||
|
||||
/* clang-format off */
|
||||
EM_ASM({
|
||||
function gotMediaInput(stream) {
|
||||
_audioDriver_inputStream = stream;
|
||||
_audioDriver_audioInput = _audioDriver_audioContext.createMediaStreamSource(stream);
|
||||
_audioDriver_audioInput.connect(_audioDriver_scriptNode);
|
||||
var ref = Module.IDHandler.get($0);
|
||||
ref['stream'] = stream;
|
||||
ref['input'] = ref['context'].createMediaStreamSource(stream);
|
||||
ref['input'].connect(ref['script']);
|
||||
}
|
||||
|
||||
function gotMediaInputError(e) {
|
||||
|
@ -238,30 +261,30 @@ Error AudioDriverJavaScript::capture_start() {
|
|||
navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
|
||||
navigator.getUserMedia({"audio": true}, gotMediaInput, gotMediaInputError);
|
||||
}
|
||||
});
|
||||
}, _driver_id);
|
||||
/* clang-format on */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error AudioDriverJavaScript::capture_stop() {
|
||||
|
||||
/* clang-format off */
|
||||
EM_ASM({
|
||||
if (_audioDriver_inputStream) {
|
||||
const tracks = _audioDriver_inputStream.getTracks();
|
||||
var ref = Module.IDHandler.get($0);
|
||||
if (ref['stream']) {
|
||||
const tracks = ref['stream'].getTracks();
|
||||
for (var i = 0; i < tracks.length; i++) {
|
||||
tracks[i].stop();
|
||||
}
|
||||
_audioDriver_inputStream = null;
|
||||
ref['stream'] = null;
|
||||
}
|
||||
|
||||
if (_audioDriver_audioInput) {
|
||||
_audioDriver_audioInput.disconnect();
|
||||
_audioDriver_audioInput = null;
|
||||
if (ref['input']) {
|
||||
ref['input'].disconnect();
|
||||
ref['input'] = null;
|
||||
}
|
||||
|
||||
});
|
||||
}, _driver_id);
|
||||
/* clang-format on */
|
||||
|
||||
input_buffer.clear();
|
||||
|
@ -270,8 +293,9 @@ Error AudioDriverJavaScript::capture_stop() {
|
|||
}
|
||||
|
||||
AudioDriverJavaScript::AudioDriverJavaScript() {
|
||||
|
||||
_driver_id = 0;
|
||||
internal_buffer = NULL;
|
||||
buffer_length = 0;
|
||||
|
||||
singleton = this;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue