Merge pull request #38816 from Faless/js/fix_audio_driver_4.0
AudioDriverJavaScript buffer size calculation.
This commit is contained in:
commit
37efaad8fb
12 changed files with 56 additions and 33 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue