mirror of
https://github.com/godotengine/godot.git
synced 2025-04-25 01:48:08 +08:00
Corrections to audio buffer size calculations
This commit is contained in:
parent
06d7e36898
commit
f231eadc9e
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#ifdef ALSA_ENABLED
|
#ifdef ALSA_ENABLED
|
||||||
|
|
||||||
|
#include "os/os.h"
|
||||||
#include "project_settings.h"
|
#include "project_settings.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -44,7 +45,7 @@ Error AudioDriverALSA::init() {
|
|||||||
samples_in = NULL;
|
samples_in = NULL;
|
||||||
samples_out = NULL;
|
samples_out = NULL;
|
||||||
|
|
||||||
mix_rate = GLOBAL_DEF("audio/mix_rate", 44100);
|
mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);
|
||||||
speaker_mode = SPEAKER_MODE_STEREO;
|
speaker_mode = SPEAKER_MODE_STEREO;
|
||||||
channels = 2;
|
channels = 2;
|
||||||
|
|
||||||
@ -86,19 +87,25 @@ Error AudioDriverALSA::init() {
|
|||||||
status = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &mix_rate, NULL);
|
status = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &mix_rate, NULL);
|
||||||
CHECK_FAIL(status < 0);
|
CHECK_FAIL(status < 0);
|
||||||
|
|
||||||
int latency = GLOBAL_DEF("audio/output_latency", 25);
|
// In ALSA the period size seems to be the one that will determine the actual latency
|
||||||
buffer_size = closest_power_of_2(latency * mix_rate / 1000);
|
// Ref: https://www.alsa-project.org/main/index.php/FramesPeriods
|
||||||
|
unsigned int periods = 2;
|
||||||
|
int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
||||||
|
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
||||||
|
buffer_size = buffer_frames * periods;
|
||||||
|
period_size = buffer_frames;
|
||||||
|
|
||||||
// set buffer size from project settings
|
// set buffer size from project settings
|
||||||
status = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size);
|
status = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size);
|
||||||
CHECK_FAIL(status < 0);
|
CHECK_FAIL(status < 0);
|
||||||
|
|
||||||
// make period size 1/8
|
|
||||||
period_size = buffer_size >> 3;
|
|
||||||
status = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &period_size, NULL);
|
status = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &period_size, NULL);
|
||||||
CHECK_FAIL(status < 0);
|
CHECK_FAIL(status < 0);
|
||||||
|
|
||||||
unsigned int periods = 2;
|
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||||
|
print_line("audio buffer frames: " + itos(period_size) + " calculated latency: " + itos(period_size * 1000 / mix_rate) + "ms");
|
||||||
|
}
|
||||||
|
|
||||||
status = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &periods, NULL);
|
status = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &periods, NULL);
|
||||||
CHECK_FAIL(status < 0);
|
CHECK_FAIL(status < 0);
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ class AudioDriverALSA : public AudioDriver {
|
|||||||
unsigned int mix_rate;
|
unsigned int mix_rate;
|
||||||
SpeakerMode speaker_mode;
|
SpeakerMode speaker_mode;
|
||||||
|
|
||||||
|
snd_pcm_uframes_t buffer_frames;
|
||||||
snd_pcm_uframes_t buffer_size;
|
snd_pcm_uframes_t buffer_size;
|
||||||
snd_pcm_uframes_t period_size;
|
snd_pcm_uframes_t period_size;
|
||||||
int channels;
|
int channels;
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include <pulse/error.h>
|
#include <pulse/error.h>
|
||||||
|
|
||||||
|
#include "os/os.h"
|
||||||
#include "project_settings.h"
|
#include "project_settings.h"
|
||||||
|
|
||||||
Error AudioDriverPulseAudio::init() {
|
Error AudioDriverPulseAudio::init() {
|
||||||
@ -44,7 +45,7 @@ Error AudioDriverPulseAudio::init() {
|
|||||||
samples_in = NULL;
|
samples_in = NULL;
|
||||||
samples_out = NULL;
|
samples_out = NULL;
|
||||||
|
|
||||||
mix_rate = GLOBAL_DEF("audio/mix_rate", 44100);
|
mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);
|
||||||
speaker_mode = SPEAKER_MODE_STEREO;
|
speaker_mode = SPEAKER_MODE_STEREO;
|
||||||
channels = 2;
|
channels = 2;
|
||||||
|
|
||||||
@ -53,12 +54,17 @@ Error AudioDriverPulseAudio::init() {
|
|||||||
spec.channels = channels;
|
spec.channels = channels;
|
||||||
spec.rate = mix_rate;
|
spec.rate = mix_rate;
|
||||||
|
|
||||||
int latency = GLOBAL_DEF("audio/output_latency", 25);
|
int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
||||||
buffer_size = closest_power_of_2(latency * mix_rate / 1000);
|
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
||||||
|
buffer_size = buffer_frames * channels;
|
||||||
|
|
||||||
|
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||||
|
print_line("audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
|
||||||
|
}
|
||||||
|
|
||||||
pa_buffer_attr attr;
|
pa_buffer_attr attr;
|
||||||
// set to appropriate buffer size from global settings
|
// set to appropriate buffer length (in bytes) from global settings
|
||||||
attr.tlength = buffer_size;
|
attr.tlength = buffer_size * sizeof(int16_t);
|
||||||
// set them to be automatically chosen
|
// set them to be automatically chosen
|
||||||
attr.prebuf = (uint32_t)-1;
|
attr.prebuf = (uint32_t)-1;
|
||||||
attr.maxlength = (uint32_t)-1;
|
attr.maxlength = (uint32_t)-1;
|
||||||
@ -80,8 +86,8 @@ Error AudioDriverPulseAudio::init() {
|
|||||||
ERR_FAIL_COND_V(pulse == NULL, ERR_CANT_OPEN);
|
ERR_FAIL_COND_V(pulse == NULL, ERR_CANT_OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
samples_in = memnew_arr(int32_t, buffer_size * channels);
|
samples_in = memnew_arr(int32_t, buffer_size);
|
||||||
samples_out = memnew_arr(int16_t, buffer_size * channels);
|
samples_out = memnew_arr(int16_t, buffer_size);
|
||||||
|
|
||||||
mutex = Mutex::create();
|
mutex = Mutex::create();
|
||||||
thread = Thread::create(AudioDriverPulseAudio::thread_func, this);
|
thread = Thread::create(AudioDriverPulseAudio::thread_func, this);
|
||||||
@ -106,18 +112,18 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
|
|||||||
|
|
||||||
while (!ad->exit_thread) {
|
while (!ad->exit_thread) {
|
||||||
if (!ad->active) {
|
if (!ad->active) {
|
||||||
for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) {
|
for (unsigned int i = 0; i < ad->buffer_size; i++) {
|
||||||
ad->samples_out[i] = 0;
|
ad->samples_out[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ad->lock();
|
ad->lock();
|
||||||
|
|
||||||
ad->audio_server_process(ad->buffer_size, ad->samples_in);
|
ad->audio_server_process(ad->buffer_frames, ad->samples_in);
|
||||||
|
|
||||||
ad->unlock();
|
ad->unlock();
|
||||||
|
|
||||||
for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) {
|
for (unsigned int i = 0; i < ad->buffer_size; i++) {
|
||||||
ad->samples_out[i] = ad->samples_in[i] >> 16;
|
ad->samples_out[i] = ad->samples_in[i] >> 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,7 +131,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
|
|||||||
// pa_simple_write always consumes the entire buffer
|
// pa_simple_write always consumes the entire buffer
|
||||||
|
|
||||||
int error_code;
|
int error_code;
|
||||||
int byte_size = ad->buffer_size * sizeof(int16_t) * ad->channels;
|
int byte_size = ad->buffer_size * sizeof(int16_t);
|
||||||
if (pa_simple_write(ad->pulse, ad->samples_out, byte_size, &error_code) < 0) {
|
if (pa_simple_write(ad->pulse, ad->samples_out, byte_size, &error_code) < 0) {
|
||||||
// can't recover here
|
// can't recover here
|
||||||
fprintf(stderr, "PulseAudio failed and can't recover: %s\n", pa_strerror(error_code));
|
fprintf(stderr, "PulseAudio failed and can't recover: %s\n", pa_strerror(error_code));
|
||||||
@ -175,13 +181,20 @@ void AudioDriverPulseAudio::finish() {
|
|||||||
exit_thread = true;
|
exit_thread = true;
|
||||||
Thread::wait_to_finish(thread);
|
Thread::wait_to_finish(thread);
|
||||||
|
|
||||||
if (pulse)
|
if (pulse) {
|
||||||
pa_simple_free(pulse);
|
pa_simple_free(pulse);
|
||||||
|
pulse = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (samples_in) {
|
if (samples_in) {
|
||||||
memdelete_arr(samples_in);
|
memdelete_arr(samples_in);
|
||||||
|
samples_in = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (samples_out) {
|
||||||
memdelete_arr(samples_out);
|
memdelete_arr(samples_out);
|
||||||
};
|
samples_out = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
memdelete(thread);
|
memdelete(thread);
|
||||||
if (mutex) {
|
if (mutex) {
|
||||||
@ -194,10 +207,15 @@ void AudioDriverPulseAudio::finish() {
|
|||||||
|
|
||||||
AudioDriverPulseAudio::AudioDriverPulseAudio() {
|
AudioDriverPulseAudio::AudioDriverPulseAudio() {
|
||||||
|
|
||||||
|
samples_in = NULL;
|
||||||
|
samples_out = NULL;
|
||||||
mutex = NULL;
|
mutex = NULL;
|
||||||
thread = NULL;
|
thread = NULL;
|
||||||
pulse = NULL;
|
pulse = NULL;
|
||||||
latency = 0;
|
latency = 0;
|
||||||
|
buffer_frames = 0;
|
||||||
|
buffer_size = 0;
|
||||||
|
channels = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDriverPulseAudio::~AudioDriverPulseAudio() {
|
AudioDriverPulseAudio::~AudioDriverPulseAudio() {
|
||||||
|
@ -51,6 +51,7 @@ class AudioDriverPulseAudio : public AudioDriver {
|
|||||||
unsigned int mix_rate;
|
unsigned int mix_rate;
|
||||||
SpeakerMode speaker_mode;
|
SpeakerMode speaker_mode;
|
||||||
|
|
||||||
|
unsigned int buffer_frames;
|
||||||
unsigned int buffer_size;
|
unsigned int buffer_size;
|
||||||
int channels;
|
int channels;
|
||||||
|
|
||||||
|
@ -107,14 +107,13 @@ Error AudioDriverRtAudio::init() {
|
|||||||
options.numberOfBuffers = 4;
|
options.numberOfBuffers = 4;
|
||||||
|
|
||||||
parameters.firstChannel = 0;
|
parameters.firstChannel = 0;
|
||||||
mix_rate = GLOBAL_DEF("audio/mix_rate", 44100);
|
mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);
|
||||||
|
|
||||||
int latency = GLOBAL_DEF("audio/output_latency", 25);
|
int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
||||||
// calculate desired buffer_size
|
unsigned int buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
||||||
unsigned int buffer_size = closest_power_of_2(latency * mix_rate / 1000);
|
|
||||||
|
|
||||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||||
print_line("audio buffer size: " + itos(buffer_size));
|
print_line("audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
short int tries = 2;
|
short int tries = 2;
|
||||||
@ -127,7 +126,7 @@ Error AudioDriverRtAudio::init() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dac->openStream(¶meters, NULL, RTAUDIO_SINT32, mix_rate, &buffer_size, &callback, this, &options);
|
dac->openStream(¶meters, NULL, RTAUDIO_SINT32, mix_rate, &buffer_frames, &callback, this, &options);
|
||||||
active = true;
|
active = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -199,7 +198,7 @@ AudioDriverRtAudio::AudioDriverRtAudio() {
|
|||||||
active = false;
|
active = false;
|
||||||
mutex = NULL;
|
mutex = NULL;
|
||||||
dac = NULL;
|
dac = NULL;
|
||||||
mix_rate = 44100;
|
mix_rate = DEFAULT_MIX_RATE;
|
||||||
speaker_mode = SPEAKER_MODE_STEREO;
|
speaker_mode = SPEAKER_MODE_STEREO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,18 @@ Error AudioDriverWASAPI::init_device() {
|
|||||||
format_tag = pwfex->wFormatTag;
|
format_tag = pwfex->wFormatTag;
|
||||||
bits_per_sample = pwfex->wBitsPerSample;
|
bits_per_sample = pwfex->wBitsPerSample;
|
||||||
|
|
||||||
|
switch (channels) {
|
||||||
|
case 2: // Stereo
|
||||||
|
case 6: // Surround 5.1
|
||||||
|
case 8: // Surround 7.1
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ERR_PRINT("WASAPI: Unsupported number of channels");
|
||||||
|
ERR_FAIL_V(ERR_CANT_OPEN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (format_tag == WAVE_FORMAT_EXTENSIBLE) {
|
if (format_tag == WAVE_FORMAT_EXTENSIBLE) {
|
||||||
WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE *)pwfex;
|
WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE *)pwfex;
|
||||||
|
|
||||||
@ -83,13 +95,6 @@ Error AudioDriverWASAPI::init_device() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int latency = GLOBAL_DEF("audio/output_latency", 25);
|
|
||||||
buffer_size = closest_power_of_2(latency * mix_rate / 1000);
|
|
||||||
|
|
||||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
|
||||||
print_line("audio buffer size: " + itos(buffer_size));
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, pwfex, NULL);
|
hr = audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, pwfex, NULL);
|
||||||
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
|
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
|
||||||
|
|
||||||
@ -102,11 +107,20 @@ Error AudioDriverWASAPI::init_device() {
|
|||||||
hr = audio_client->GetService(IID_IAudioRenderClient, (void **)&render_client);
|
hr = audio_client->GetService(IID_IAudioRenderClient, (void **)&render_client);
|
||||||
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
|
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
|
||||||
|
|
||||||
|
UINT32 max_frames;
|
||||||
hr = audio_client->GetBufferSize(&max_frames);
|
hr = audio_client->GetBufferSize(&max_frames);
|
||||||
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
|
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
|
||||||
|
|
||||||
|
// Due to WASAPI Shared Mode we have no control of the buffer size
|
||||||
|
buffer_frames = max_frames;
|
||||||
|
|
||||||
|
// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
|
||||||
|
buffer_size = buffer_frames * channels;
|
||||||
samples_in.resize(buffer_size);
|
samples_in.resize(buffer_size);
|
||||||
buffer_frames = buffer_size / channels;
|
|
||||||
|
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||||
|
print_line("audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
|
||||||
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -200,7 +214,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
|
|||||||
HRESULT hr = ad->audio_client->GetCurrentPadding(&cur_frames);
|
HRESULT hr = ad->audio_client->GetCurrentPadding(&cur_frames);
|
||||||
if (hr == S_OK) {
|
if (hr == S_OK) {
|
||||||
// Check how much frames are available on the WASAPI buffer
|
// Check how much frames are available on the WASAPI buffer
|
||||||
UINT32 avail_frames = ad->max_frames - cur_frames;
|
UINT32 avail_frames = ad->buffer_frames - cur_frames;
|
||||||
UINT32 write_frames = avail_frames > left_frames ? left_frames : avail_frames;
|
UINT32 write_frames = avail_frames > left_frames ? left_frames : avail_frames;
|
||||||
|
|
||||||
BYTE *buffer = NULL;
|
BYTE *buffer = NULL;
|
||||||
@ -332,7 +346,6 @@ AudioDriverWASAPI::AudioDriverWASAPI() {
|
|||||||
mutex = NULL;
|
mutex = NULL;
|
||||||
thread = NULL;
|
thread = NULL;
|
||||||
|
|
||||||
max_frames = 0;
|
|
||||||
format_tag = 0;
|
format_tag = 0;
|
||||||
bits_per_sample = 0;
|
bits_per_sample = 0;
|
||||||
|
|
||||||
|
@ -48,7 +48,6 @@ class AudioDriverWASAPI : public AudioDriver {
|
|||||||
Mutex *mutex;
|
Mutex *mutex;
|
||||||
Thread *thread;
|
Thread *thread;
|
||||||
|
|
||||||
UINT32 max_frames;
|
|
||||||
WORD format_tag;
|
WORD format_tag;
|
||||||
WORD bits_per_sample;
|
WORD bits_per_sample;
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ Error AudioDriverOSX::initDevice() {
|
|||||||
break;
|
break;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
mix_rate = GLOBAL_DEF("audio/mix_rate", 44100);
|
mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);
|
||||||
|
|
||||||
zeromem(&strdesc, sizeof(strdesc));
|
zeromem(&strdesc, sizeof(strdesc));
|
||||||
strdesc.mFormatID = kAudioFormatLinearPCM;
|
strdesc.mFormatID = kAudioFormatLinearPCM;
|
||||||
@ -92,16 +92,20 @@ Error AudioDriverOSX::initDevice() {
|
|||||||
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("audio/output_latency", 25);
|
int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
||||||
unsigned int buffer_size = closest_power_of_2(latency * mix_rate / 1000);
|
// 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);
|
||||||
|
|
||||||
|
result = AudioUnitSetProperty(audio_unit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, kOutputBus, &buffer_frames, sizeof(UInt32));
|
||||||
|
ERR_FAIL_COND_V(result != noErr, FAILED);
|
||||||
|
|
||||||
|
buffer_size = buffer_frames * channels;
|
||||||
|
samples_in.resize(buffer_size);
|
||||||
|
|
||||||
if (OS::get_singleton()->is_stdout_verbose()) {
|
if (OS::get_singleton()->is_stdout_verbose()) {
|
||||||
print_line("audio buffer size: " + itos(buffer_size) + " calculated latency: " + itos(buffer_size * 1000 / mix_rate));
|
print_line("audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
samples_in.resize(buffer_size);
|
|
||||||
buffer_frames = buffer_size / channels;
|
|
||||||
|
|
||||||
AURenderCallbackStruct callback;
|
AURenderCallbackStruct callback;
|
||||||
zeromem(&callback, sizeof(AURenderCallbackStruct));
|
zeromem(&callback, sizeof(AURenderCallbackStruct));
|
||||||
callback.inputProc = &AudioDriverOSX::output_callback;
|
callback.inputProc = &AudioDriverOSX::output_callback;
|
||||||
@ -234,7 +238,7 @@ void AudioDriverOSX::start() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int AudioDriverOSX::get_mix_rate() const {
|
int AudioDriverOSX::get_mix_rate() const {
|
||||||
return 44100;
|
return mix_rate;
|
||||||
};
|
};
|
||||||
|
|
||||||
AudioDriver::SpeakerMode AudioDriverOSX::get_speaker_mode() const {
|
AudioDriver::SpeakerMode AudioDriverOSX::get_speaker_mode() const {
|
||||||
@ -282,8 +286,12 @@ AudioDriverOSX::AudioDriverOSX() {
|
|||||||
active = false;
|
active = false;
|
||||||
mutex = NULL;
|
mutex = NULL;
|
||||||
|
|
||||||
mix_rate = 44100;
|
mix_rate = 0;
|
||||||
channels = 2;
|
channels = 2;
|
||||||
|
|
||||||
|
buffer_size = 0;
|
||||||
|
buffer_frames = 0;
|
||||||
|
|
||||||
samples_in.clear();
|
samples_in.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,8 +45,9 @@ class AudioDriverOSX : public AudioDriver {
|
|||||||
Mutex *mutex;
|
Mutex *mutex;
|
||||||
|
|
||||||
int mix_rate;
|
int mix_rate;
|
||||||
int channels;
|
unsigned int channels;
|
||||||
int buffer_frames;
|
unsigned int buffer_frames;
|
||||||
|
unsigned int buffer_size;
|
||||||
|
|
||||||
Vector<int32_t> samples_in;
|
Vector<int32_t> samples_in;
|
||||||
|
|
||||||
|
@ -37,17 +37,16 @@ Error AudioDriverDummy::init() {
|
|||||||
active = false;
|
active = false;
|
||||||
thread_exited = false;
|
thread_exited = false;
|
||||||
exit_thread = false;
|
exit_thread = false;
|
||||||
pcm_open = false;
|
|
||||||
samples_in = NULL;
|
samples_in = NULL;
|
||||||
|
|
||||||
mix_rate = 44100;
|
mix_rate = DEFAULT_MIX_RATE;
|
||||||
speaker_mode = SPEAKER_MODE_STEREO;
|
speaker_mode = SPEAKER_MODE_STEREO;
|
||||||
channels = 2;
|
channels = 2;
|
||||||
|
|
||||||
int latency = GLOBAL_DEF("audio/output_latency", 25);
|
int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
|
||||||
buffer_size = next_power_of_2(latency * mix_rate / 1000);
|
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
|
||||||
|
|
||||||
samples_in = memnew_arr(int32_t, buffer_size * channels);
|
samples_in = memnew_arr(int32_t, buffer_frames * channels);
|
||||||
|
|
||||||
mutex = Mutex::create();
|
mutex = Mutex::create();
|
||||||
thread = Thread::create(AudioDriverDummy::thread_func, this);
|
thread = Thread::create(AudioDriverDummy::thread_func, this);
|
||||||
@ -59,17 +58,15 @@ void AudioDriverDummy::thread_func(void *p_udata) {
|
|||||||
|
|
||||||
AudioDriverDummy *ad = (AudioDriverDummy *)p_udata;
|
AudioDriverDummy *ad = (AudioDriverDummy *)p_udata;
|
||||||
|
|
||||||
uint64_t usdelay = (ad->buffer_size / float(ad->mix_rate)) * 1000000;
|
uint64_t usdelay = (ad->buffer_frames / float(ad->mix_rate)) * 1000000;
|
||||||
|
|
||||||
while (!ad->exit_thread) {
|
while (!ad->exit_thread) {
|
||||||
|
|
||||||
if (!ad->active) {
|
if (ad->active) {
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
ad->lock();
|
ad->lock();
|
||||||
|
|
||||||
ad->audio_server_process(ad->buffer_size, ad->samples_in);
|
ad->audio_server_process(ad->buffer_frames, ad->samples_in);
|
||||||
|
|
||||||
ad->unlock();
|
ad->unlock();
|
||||||
};
|
};
|
||||||
|
@ -43,8 +43,8 @@ class AudioDriverDummy : public AudioDriver {
|
|||||||
int32_t *samples_in;
|
int32_t *samples_in;
|
||||||
|
|
||||||
static void thread_func(void *p_udata);
|
static void thread_func(void *p_udata);
|
||||||
int buffer_size;
|
|
||||||
|
|
||||||
|
unsigned int buffer_frames;
|
||||||
unsigned int mix_rate;
|
unsigned int mix_rate;
|
||||||
SpeakerMode speaker_mode;
|
SpeakerMode speaker_mode;
|
||||||
|
|
||||||
@ -53,7 +53,6 @@ class AudioDriverDummy : public AudioDriver {
|
|||||||
bool active;
|
bool active;
|
||||||
bool thread_exited;
|
bool thread_exited;
|
||||||
mutable bool exit_thread;
|
mutable bool exit_thread;
|
||||||
bool pcm_open;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const char *get_name() const {
|
const char *get_name() const {
|
||||||
|
@ -155,6 +155,29 @@ void AudioServer::_driver_process(int p_frames, int32_t *p_buffer) {
|
|||||||
todo -= to_copy;
|
todo -= to_copy;
|
||||||
to_mix -= to_copy;
|
to_mix -= to_copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENABLED
|
||||||
|
if (OS::get_singleton() && OS::get_singleton()->is_stdout_verbose()) {
|
||||||
|
static uint64_t first_ticks = 0;
|
||||||
|
static uint64_t last_ticks = 0;
|
||||||
|
static uint64_t ticks = 0;
|
||||||
|
static int count = 0;
|
||||||
|
static int total = 0;
|
||||||
|
|
||||||
|
ticks = OS::get_singleton()->get_ticks_msec();
|
||||||
|
if ((ticks - first_ticks) > 10 * 1000) {
|
||||||
|
print_line("Audio Driver " + String(AudioDriver::get_singleton()->get_name()) + " average latency: " + itos(total / count) + "ms (frame=" + itos(p_frames) + ")");
|
||||||
|
first_ticks = ticks;
|
||||||
|
total = 0;
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
total += ticks - last_ticks;
|
||||||
|
count++;
|
||||||
|
|
||||||
|
last_ticks = ticks;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioServer::_mix_step() {
|
void AudioServer::_mix_step() {
|
||||||
|
@ -54,6 +54,9 @@ 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();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user