Skip to content

Commit 37cb3f2

Browse files
committed
[macOS/iOS] Use hardware sampling rates for audio I/O.
1 parent 04c71d9 commit 37cb3f2

File tree

8 files changed

+71
-11
lines changed

8 files changed

+71
-11
lines changed

doc/classes/AudioServer.xml

+6
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@
110110
Returns the volume of the bus at index [param bus_idx] in dB.
111111
</description>
112112
</method>
113+
<method name="get_capture_mix_rate" qualifiers="const">
114+
<return type="float" />
115+
<description>
116+
Returns the sample rate at the input of the [AudioServer].
117+
</description>
118+
</method>
113119
<method name="get_input_device_list">
114120
<return type="PackedStringArray" />
115121
<description>

drivers/SCsub

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ SConscript("windows/SCsub")
1010

1111
# Sounds drivers
1212
SConscript("alsa/SCsub")
13-
SConscript("coreaudio/SCsub")
13+
if env["platform"] == "ios" or env["platform"] == "macos":
14+
SConscript("coreaudio/SCsub")
1415
SConscript("pulseaudio/SCsub")
1516
if env["platform"] == "windows":
1617
SConscript("wasapi/SCsub")

drivers/coreaudio/SCsub

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
Import("env")
44

55
# Driver source files
6-
env.add_source_files(env.drivers_sources, "*.cpp")
6+
env.add_source_files(env.drivers_sources, "*.mm")

drivers/coreaudio/audio_driver_coreaudio.h

+5
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
#import <AudioUnit/AudioUnit.h>
3939
#ifdef MACOS_ENABLED
4040
#import <CoreAudio/AudioHardware.h>
41+
#else
42+
#import <AVFoundation/AVFoundation.h>
4143
#endif
4244

4345
class AudioDriverCoreAudio : public AudioDriver {
@@ -51,9 +53,11 @@ class AudioDriverCoreAudio : public AudioDriver {
5153
String input_device_name = "Default";
5254

5355
int mix_rate = 0;
56+
int capture_mix_rate = 0;
5457
unsigned int channels = 2;
5558
unsigned int capture_channels = 2;
5659
unsigned int buffer_frames = 0;
60+
unsigned int capture_buffer_frames = 0;
5761

5862
Vector<int32_t> samples_in;
5963
Vector<int16_t> input_buf;
@@ -94,6 +98,7 @@ class AudioDriverCoreAudio : public AudioDriver {
9498
virtual Error init() override;
9599
virtual void start() override;
96100
virtual int get_mix_rate() const override;
101+
virtual int get_capture_mix_rate() const override;
97102
virtual SpeakerMode get_speaker_mode() const override;
98103

99104
virtual void lock() override;

drivers/coreaudio/audio_driver_coreaudio.cpp drivers/coreaudio/audio_driver_coreaudio.mm

+48-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**************************************************************************/
2-
/* audio_driver_coreaudio.cpp */
2+
/* audio_driver_coreaudio.mm */
33
/**************************************************************************/
44
/* This file is part of: */
55
/* GODOT ENGINE */
@@ -116,7 +116,24 @@ Error AudioDriverCoreAudio::init() {
116116
break;
117117
}
118118

119-
mix_rate = _get_configured_mix_rate();
119+
#if MACOS_ENABLED
120+
AudioDeviceID deviceId;
121+
UInt32 devIDsize = sizeof(AudioDeviceID);
122+
123+
AudioObjectPropertyAddress property_dev_id = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
124+
result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property_dev_id, 0, nullptr, &devIDsize, &deviceId);
125+
ERR_FAIL_COND_V(result != noErr, FAILED);
126+
127+
double hw_mix_rate;
128+
UInt32 hw_mix_rate_size = sizeof(hw_mix_rate);
129+
130+
AudioObjectPropertyAddress property_sr = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain };
131+
result = AudioObjectGetPropertyData(deviceId, &property_sr, 0, nullptr, &hw_mix_rate_size, &hw_mix_rate);
132+
ERR_FAIL_COND_V(result != noErr, FAILED);
133+
#else
134+
double hw_mix_rate = [AVAudioSession sharedInstance].sampleRate;
135+
#endif
136+
mix_rate = hw_mix_rate;
120137

121138
memset(&strdesc, 0, sizeof(strdesc));
122139
strdesc.mFormatID = kAudioFormatLinearPCM;
@@ -142,10 +159,10 @@ Error AudioDriverCoreAudio::init() {
142159

143160
unsigned int buffer_size = buffer_frames * channels;
144161
samples_in.resize(buffer_size);
145-
input_buf.resize(buffer_size);
146162

147163
print_verbose("CoreAudio: detected " + itos(channels) + " channels");
148-
print_verbose("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
164+
print_verbose("CoreAudio: output sampling rate: " + itos(mix_rate) + " Hz");
165+
print_verbose("CoreAudio: output audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
149166

150167
AURenderCallbackStruct callback;
151168
memset(&callback, 0, sizeof(AURenderCallbackStruct));
@@ -270,6 +287,10 @@ int AudioDriverCoreAudio::get_mix_rate() const {
270287
return mix_rate;
271288
}
272289

290+
int AudioDriverCoreAudio::get_capture_mix_rate() const {
291+
return capture_mix_rate;
292+
}
293+
273294
AudioDriver::SpeakerMode AudioDriverCoreAudio::get_speaker_mode() const {
274295
return get_speaker_mode_by_total_channels(channels);
275296
}
@@ -405,13 +426,23 @@ Error AudioDriverCoreAudio::init_input_device() {
405426
break;
406427
}
407428

408-
mix_rate = _get_configured_mix_rate();
429+
#if MACOS_ENABLED
430+
double hw_mix_rate;
431+
UInt32 hw_mix_rate_size = sizeof(hw_mix_rate);
432+
433+
AudioObjectPropertyAddress property_sr = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain };
434+
result = AudioObjectGetPropertyData(deviceId, &property_sr, 0, nullptr, &hw_mix_rate_size, &hw_mix_rate);
435+
ERR_FAIL_COND_V(result != noErr, FAILED);
436+
#else
437+
double hw_mix_rate = [AVAudioSession sharedInstance].sampleRate;
438+
#endif
439+
capture_mix_rate = hw_mix_rate;
409440

410441
memset(&strdesc, 0, sizeof(strdesc));
411442
strdesc.mFormatID = kAudioFormatLinearPCM;
412443
strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
413444
strdesc.mChannelsPerFrame = capture_channels;
414-
strdesc.mSampleRate = mix_rate;
445+
strdesc.mSampleRate = capture_mix_rate;
415446
strdesc.mFramesPerPacket = 1;
416447
strdesc.mBitsPerChannel = 16;
417448
strdesc.mBytesPerFrame = strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
@@ -420,6 +451,13 @@ Error AudioDriverCoreAudio::init_input_device() {
420451
result = AudioUnitSetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc));
421452
ERR_FAIL_COND_V(result != noErr, FAILED);
422453

454+
int latency = Engine::get_singleton()->get_audio_output_latency();
455+
// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
456+
capture_buffer_frames = closest_power_of_2(latency * capture_mix_rate / 1000);
457+
458+
unsigned int buffer_size = capture_buffer_frames * capture_channels;
459+
input_buf.resize(buffer_size);
460+
423461
AURenderCallbackStruct callback;
424462
memset(&callback, 0, sizeof(AURenderCallbackStruct));
425463
callback.inputProc = &AudioDriverCoreAudio::input_callback;
@@ -430,6 +468,9 @@ Error AudioDriverCoreAudio::init_input_device() {
430468
result = AudioUnitInitialize(input_unit);
431469
ERR_FAIL_COND_V(result != noErr, FAILED);
432470

471+
print_verbose("CoreAudio: input sampling rate: " + itos(capture_mix_rate) + " Hz");
472+
print_verbose("CoreAudio: input audio buffer frames: " + itos(capture_buffer_frames) + " calculated latency: " + itos(capture_buffer_frames * 1000 / capture_mix_rate) + "ms");
473+
433474
return OK;
434475
}
435476

@@ -472,7 +513,7 @@ void AudioDriverCoreAudio::finish_input_device() {
472513
}
473514

474515
Error AudioDriverCoreAudio::input_start() {
475-
input_buffer_init(buffer_frames);
516+
input_buffer_init(capture_buffer_frames);
476517

477518
OSStatus result = AudioOutputUnitStart(input_unit);
478519
if (result != noErr) {

servers/audio/audio_stream.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ int AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fra
326326

327327
Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer();
328328
unsigned int input_size = AudioDriver::get_singleton()->get_input_size();
329-
int mix_rate = AudioDriver::get_singleton()->get_mix_rate();
329+
int mix_rate = AudioDriver::get_singleton()->get_capture_mix_rate();
330330
unsigned int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1);
331331
#ifdef DEBUG_ENABLED
332332
unsigned int input_position = AudioDriver::get_singleton()->get_input_position();
@@ -377,7 +377,7 @@ int AudioStreamPlaybackMicrophone::mix(AudioFrame *p_buffer, float p_rate_scale,
377377
}
378378

379379
float AudioStreamPlaybackMicrophone::get_stream_sampling_rate() {
380-
return AudioDriver::get_singleton()->get_mix_rate();
380+
return AudioDriver::get_singleton()->get_capture_mix_rate();
381381
}
382382

383383
void AudioStreamPlaybackMicrophone::start(double p_from_pos) {

servers/audio_server.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1521,6 +1521,10 @@ float AudioServer::get_mix_rate() const {
15211521
return AudioDriver::get_singleton()->get_mix_rate();
15221522
}
15231523

1524+
float AudioServer::get_capture_mix_rate() const {
1525+
return AudioDriver::get_singleton()->get_capture_mix_rate();
1526+
}
1527+
15241528
float AudioServer::read_output_peak_db() const {
15251529
return 0;
15261530
}
@@ -1743,6 +1747,7 @@ void AudioServer::_bind_methods() {
17431747

17441748
ClassDB::bind_method(D_METHOD("get_speaker_mode"), &AudioServer::get_speaker_mode);
17451749
ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioServer::get_mix_rate);
1750+
ClassDB::bind_method(D_METHOD("get_capture_mix_rate"), &AudioServer::get_capture_mix_rate);
17461751

17471752
ClassDB::bind_method(D_METHOD("get_output_device_list"), &AudioServer::get_output_device_list);
17481753
ClassDB::bind_method(D_METHOD("get_output_device"), &AudioServer::get_output_device);

servers/audio_server.h

+2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ class AudioDriver {
9797
virtual Error init() = 0;
9898
virtual void start() = 0;
9999
virtual int get_mix_rate() const = 0;
100+
virtual int get_capture_mix_rate() const { return get_mix_rate(); };
100101
virtual SpeakerMode get_speaker_mode() const = 0;
101102
virtual float get_latency() { return 0; }
102103

@@ -405,6 +406,7 @@ class AudioServer : public Object {
405406

406407
virtual SpeakerMode get_speaker_mode() const;
407408
virtual float get_mix_rate() const;
409+
virtual float get_capture_mix_rate() const;
408410

409411
virtual float read_output_peak_db() const;
410412

0 commit comments

Comments
 (0)