diff options
Diffstat (limited to 'platform/javascript/audio_driver_javascript.cpp')
-rw-r--r-- | platform/javascript/audio_driver_javascript.cpp | 177 |
1 files changed, 111 insertions, 66 deletions
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp index b359699d3a..b52bd4ce60 100644 --- a/platform/javascript/audio_driver_javascript.cpp +++ b/platform/javascript/audio_driver_javascript.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,27 +30,25 @@ #include "audio_driver_javascript.h" +#include "core/project_settings.h" + #include <emscripten.h> -AudioDriverJavaScript *AudioDriverJavaScript::singleton = NULL; +AudioDriverJavaScript *AudioDriverJavaScript::singleton = nullptr; 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); @@ -61,39 +59,41 @@ void AudioDriverJavaScript::mix_to_js() { } void AudioDriverJavaScript::process_capture(float sample) { - int32_t sample32 = int32_t(sample * 32768.f) * (1U << 16); - capture_buffer_write(sample32); + 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({ - _audioDriver_audioContext = new (window.AudioContext || window.webkitAudioContext); - _audioDriver_audioInput = null; - _audioDriver_inputStream = null; - _audioDriver_scriptNode = null; + _driver_id = EM_ASM_INT({ + const MIX_RATE = $0; + const LATENCY = $1; + return Module.IDHandler.add({ + 'context': new (window.AudioContext || window.webkitAudioContext)({ sampleRate: MIX_RATE, latencyHint: LATENCY}), + 'input': null, + 'stream': null, + 'script': null + }); }); /* clang-format on */ int channel_count = get_total_channels_by_speaker_mode(get_speaker_mode()); + buffer_length = closest_power_of_2((latency * mix_rate / 1000) * channel_count); /* clang-format off */ buffer_length = EM_ASM_INT({ - var CHANNEL_COUNT = $0; - - var channelCount = _audioDriver_audioContext.destination.channelCount; - try { - // Try letting the browser recommend a buffer length. - _audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(0, 2, channelCount); - } catch (e) { - // ...otherwise, default to 4096. - _audioDriver_scriptNode = _audioDriver_audioContext.createScriptProcessor(4096, 2, channelCount); - } - _audioDriver_scriptNode.connect(_audioDriver_audioContext.destination); - - return _audioDriver_scriptNode.bufferSize; - }, channel_count); + var ref = Module.IDHandler.get($0); + const ctx = ref['context']; + const BUFFER_LENGTH = $1; + const CHANNEL_COUNT = $2; + + 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; @@ -109,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; @@ -133,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++) { @@ -142,34 +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 */ } -int AudioDriverJavaScript::get_mix_rate() const { +float AudioDriverJavaScript::get_latency() { + /* clang-format off */ + return EM_ASM_DOUBLE({ + const ref = Module.IDHandler.get($0); + var latency = 0; + if (ref && ref['context']) { + const ctx = ref['context']; + if (ctx.baseLatency) { + latency += ctx.baseLatency; + } + 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 */ } @@ -180,32 +200,54 @@ 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; + internal_buffer = nullptr; } } Error AudioDriverJavaScript::capture_start() { - - capture_buffer_init(buffer_length); + 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) { @@ -219,38 +261,41 @@ 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(); + return OK; } AudioDriverJavaScript::AudioDriverJavaScript() { - - internal_buffer = NULL; + _driver_id = 0; + internal_buffer = nullptr; + buffer_length = 0; singleton = this; } |