Merge pull request #38816 from Faless/js/fix_audio_driver_4.0

AudioDriverJavaScript buffer size calculation.
This commit is contained in:
Rémi Verschelde 2020-05-18 13:43:24 +02:00 committed by GitHub
commit 37efaad8fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 56 additions and 33 deletions

View file

@ -38,7 +38,7 @@
#include <errno.h> #include <errno.h>
Error AudioDriverALSA::init_device() { Error AudioDriverALSA::init_device() {
mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE); mix_rate = GLOBAL_GET("audio/mix_rate");
speaker_mode = SPEAKER_MODE_STEREO; speaker_mode = SPEAKER_MODE_STEREO;
channels = 2; channels = 2;
@ -104,7 +104,7 @@ Error AudioDriverALSA::init_device() {
// In ALSA the period size seems to be the one that will determine the actual latency // In ALSA the period size seems to be the one that will determine the actual latency
// Ref: https://www.alsa-project.org/main/index.php/FramesPeriods // Ref: https://www.alsa-project.org/main/index.php/FramesPeriods
unsigned int periods = 2; unsigned int periods = 2;
int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY); int latency = GLOBAL_GET("audio/output_latency");
buffer_frames = closest_power_of_2(latency * mix_rate / 1000); buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
buffer_size = buffer_frames * periods; buffer_size = buffer_frames * periods;
period_size = buffer_frames; period_size = buffer_frames;

View file

@ -116,7 +116,7 @@ Error AudioDriverCoreAudio::init() {
break; break;
} }
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); mix_rate = GLOBAL_GET("audio/mix_rate");
zeromem(&strdesc, sizeof(strdesc)); zeromem(&strdesc, sizeof(strdesc));
strdesc.mFormatID = kAudioFormatLinearPCM; strdesc.mFormatID = kAudioFormatLinearPCM;
@ -131,7 +131,7 @@ Error AudioDriverCoreAudio::init() {
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc)); result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc));
ERR_FAIL_COND_V(result != noErr, FAILED); ERR_FAIL_COND_V(result != noErr, FAILED);
int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); int latency = GLOBAL_GET("audio/output_latency");
// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels) // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
buffer_frames = closest_power_of_2(latency * mix_rate / 1000); buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
@ -403,7 +403,7 @@ Error AudioDriverCoreAudio::capture_init() {
break; break;
} }
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); mix_rate = GLOBAL_GET("audio/mix_rate");
zeromem(&strdesc, sizeof(strdesc)); zeromem(&strdesc, sizeof(strdesc));
strdesc.mFormatID = kAudioFormatLinearPCM; strdesc.mFormatID = kAudioFormatLinearPCM;

View file

@ -179,7 +179,7 @@ Error AudioDriverPulseAudio::init_device() {
break; break;
} }
int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); int latency = GLOBAL_GET("audio/output_latency");
buffer_frames = closest_power_of_2(latency * mix_rate / 1000); buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
pa_buffer_size = buffer_frames * pa_map.channels; pa_buffer_size = buffer_frames * pa_map.channels;
@ -237,7 +237,7 @@ Error AudioDriverPulseAudio::init() {
thread_exited = false; thread_exited = false;
exit_thread = false; exit_thread = false;
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); mix_rate = GLOBAL_GET("audio/mix_rate");
pa_ml = pa_mainloop_new(); pa_ml = pa_mainloop_new();
ERR_FAIL_COND_V(pa_ml == nullptr, ERR_CANT_OPEN); ERR_FAIL_COND_V(pa_ml == nullptr, ERR_CANT_OPEN);

View file

@ -387,7 +387,7 @@ Error AudioDriverWASAPI::finish_capture_device() {
} }
Error AudioDriverWASAPI::init() { Error AudioDriverWASAPI::init() {
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); mix_rate = GLOBAL_GET("audio/mix_rate");
Error err = init_render_device(); Error err = init_render_device();
if (err != OK) { if (err != OK) {

View file

@ -44,12 +44,12 @@ Error AudioDriverXAudio2::init() {
pcm_open = false; pcm_open = false;
samples_in = nullptr; samples_in = nullptr;
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); mix_rate = GLOBAL_GET("audio/mix_rate");
// FIXME: speaker_mode seems unused in the Xaudio2 driver so far // FIXME: speaker_mode seems unused in the Xaudio2 driver so far
speaker_mode = SPEAKER_MODE_STEREO; speaker_mode = SPEAKER_MODE_STEREO;
channels = 2; channels = 2;
int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); int latency = GLOBAL_GET("audio/output_latency");
buffer_size = closest_power_of_2(latency * mix_rate / 1000); buffer_size = closest_power_of_2(latency * mix_rate / 1000);
samples_in = memnew_arr(int32_t, buffer_size * channels); samples_in = memnew_arr(int32_t, buffer_size * channels);

View file

@ -73,9 +73,9 @@ Error AudioDriverAndroid::init() {
// __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device"); // __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device");
JNIEnv *env = ThreadAndroid::get_env(); JNIEnv *env = ThreadAndroid::get_env();
int mix_rate = GLOBAL_DEF_RST("audio/mix_rate", 44100); int mix_rate = GLOBAL_GET("audio/mix_rate");
int latency = GLOBAL_DEF_RST("audio/output_latency", 25); int latency = GLOBAL_GET("audio/output_latency");
unsigned int buffer_size = next_power_of_2(latency * mix_rate / 1000); unsigned int buffer_size = next_power_of_2(latency * mix_rate / 1000);
print_verbose("Audio buffer size: " + itos(buffer_size)); print_verbose("Audio buffer size: " + itos(buffer_size));

View file

@ -39,11 +39,11 @@ int32_t *AudioDriverMediaKit::samples_in = nullptr;
Error AudioDriverMediaKit::init() { Error AudioDriverMediaKit::init() {
active = false; active = false;
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); mix_rate = GLOBAL_GET("audio/mix_rate");
speaker_mode = SPEAKER_MODE_STEREO; speaker_mode = SPEAKER_MODE_STEREO;
channels = 2; channels = 2;
int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); int latency = GLOBAL_GET("audio/output_latency");
buffer_size = next_power_of_2(latency * mix_rate / 1000); buffer_size = next_power_of_2(latency * mix_rate / 1000);
samples_in = memnew_arr(int32_t, buffer_size * channels); samples_in = memnew_arr(int32_t, buffer_size * channels);

View file

@ -30,6 +30,8 @@
#include "audio_driver_javascript.h" #include "audio_driver_javascript.h"
#include "core/project_settings.h"
#include <emscripten.h> #include <emscripten.h>
AudioDriverJavaScript *AudioDriverJavaScript::singleton = nullptr; AudioDriverJavaScript *AudioDriverJavaScript::singleton = nullptr;
@ -62,10 +64,15 @@ void AudioDriverJavaScript::process_capture(float sample) {
} }
Error AudioDriverJavaScript::init() { Error AudioDriverJavaScript::init() {
int mix_rate = GLOBAL_GET("audio/mix_rate");
int latency = GLOBAL_GET("audio/output_latency");
/* clang-format off */ /* clang-format off */
_driver_id = EM_ASM_INT({ _driver_id = EM_ASM_INT({
const MIX_RATE = $0;
const LATENCY = $1;
return Module.IDHandler.add({ return Module.IDHandler.add({
'context': new (window.AudioContext || window.webkitAudioContext), 'context': new (window.AudioContext || window.webkitAudioContext)({ sampleRate: MIX_RATE, latencyHint: LATENCY}),
'input': null, 'input': null,
'stream': null, 'stream': null,
'script': null 'script': null
@ -74,26 +81,19 @@ Error AudioDriverJavaScript::init() {
/* clang-format on */ /* clang-format on */
int channel_count = get_total_channels_by_speaker_mode(get_speaker_mode()); 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 */ /* clang-format off */
buffer_length = EM_ASM_INT({ buffer_length = EM_ASM_INT({
var ref = Module.IDHandler.get($0); var ref = Module.IDHandler.get($0);
var ctx = ref['context']; const ctx = ref['context'];
var CHANNEL_COUNT = $1; const BUFFER_LENGTH = $1;
const CHANNEL_COUNT = $2;
var channelCount = ctx.destination.channelCount; var script = ctx.createScriptProcessor(BUFFER_LENGTH, 2, CHANNEL_COUNT);
var script = null;
try {
// Try letting the browser recommend a buffer length.
script = ctx.createScriptProcessor(0, 2, channelCount);
} catch (e) {
// ...otherwise, default to 4096.
script = ctx.createScriptProcessor(4096, 2, channelCount);
}
script.connect(ctx.destination); script.connect(ctx.destination);
ref['script'] = script; ref['script'] = script;
return script.bufferSize; return script.bufferSize;
}, _driver_id, channel_count); }, _driver_id, buffer_length, channel_count);
/* clang-format on */ /* clang-format on */
if (!buffer_length) { if (!buffer_length) {
return FAILED; return FAILED;
@ -156,6 +156,25 @@ void AudioDriverJavaScript::resume() {
/* clang-format on */ /* clang-format on */
} }
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 { int AudioDriverJavaScript::get_mix_rate() const {
/* clang-format off */ /* clang-format off */
return EM_ASM_INT({ return EM_ASM_INT({

View file

@ -50,6 +50,7 @@ public:
virtual Error init(); virtual Error init();
virtual void start(); virtual void start();
void resume(); void resume();
virtual float get_latency();
virtual int get_mix_rate() const; virtual int get_mix_rate() const;
virtual SpeakerMode get_speaker_mode() const; virtual SpeakerMode get_speaker_mode() const;
virtual void lock(); virtual void lock();

View file

@ -39,11 +39,11 @@ Error AudioDriverDummy::init() {
exit_thread = false; exit_thread = false;
samples_in = nullptr; samples_in = nullptr;
mix_rate = DEFAULT_MIX_RATE; mix_rate = GLOBAL_GET("audio/mix_rate");
speaker_mode = SPEAKER_MODE_STEREO; speaker_mode = SPEAKER_MODE_STEREO;
channels = 2; channels = 2;
int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); int latency = GLOBAL_GET("audio/output_latency");
buffer_frames = closest_power_of_2(latency * mix_rate / 1000); buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
samples_in = memnew_arr(int32_t, buffer_frames * channels); samples_in = memnew_arr(int32_t, buffer_frames * channels);

View file

@ -182,6 +182,9 @@ int AudioDriverManager::get_driver_count() {
void AudioDriverManager::initialize(int p_driver) { void AudioDriverManager::initialize(int p_driver) {
GLOBAL_DEF_RST("audio/enable_audio_input", false); GLOBAL_DEF_RST("audio/enable_audio_input", false);
GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
int failed_driver = -1; int failed_driver = -1;
// Check if there is a selected driver // Check if there is a selected driver

View file

@ -80,9 +80,6 @@ public:
SPEAKER_SURROUND_71, SPEAKER_SURROUND_71,
}; };
static const int DEFAULT_MIX_RATE = 44100;
static const int DEFAULT_OUTPUT_LATENCY = 15;
static AudioDriver *get_singleton(); static AudioDriver *get_singleton();
void set_singleton(); void set_singleton();
@ -129,6 +126,9 @@ class AudioDriverManager {
MAX_DRIVERS = 10 MAX_DRIVERS = 10
}; };
static const int DEFAULT_MIX_RATE = 44100;
static const int DEFAULT_OUTPUT_LATENCY = 15;
static AudioDriver *drivers[MAX_DRIVERS]; static AudioDriver *drivers[MAX_DRIVERS];
static int driver_count; static int driver_count;