Skip to content

Commit c8609f4

Browse files
committed
[macOS/iOS] Use hardware sampling rates for audio I/O.
1 parent 6732a0f commit c8609f4

File tree

8 files changed

+78
-18
lines changed

8 files changed

+78
-18
lines changed

doc/classes/AudioServer.xml

+6
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@
117117
[b]Note:[/b] [member ProjectSettings.audio/driver/enable_input] must be [code]true[/code] for audio input to work. See also that setting's description for caveats related to permissions and operating system privacy settings.
118118
</description>
119119
</method>
120+
<method name="get_input_mix_rate" qualifiers="const">
121+
<return type="float" />
122+
<description>
123+
Returns the sample rate at the input of the [AudioServer].
124+
</description>
125+
</method>
120126
<method name="get_mix_rate" qualifiers="const">
121127
<return type="float" />
122128
<description>

drivers/SCsub

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

1515
# Sounds drivers
1616
SConscript("alsa/SCsub")
17-
SConscript("coreaudio/SCsub")
17+
if env["platform"] == "ios" or env["platform"] == "macos":
18+
SConscript("coreaudio/SCsub")
1819
SConscript("pulseaudio/SCsub")
1920
if env["platform"] == "windows":
2021
SConscript("wasapi/SCsub")

drivers/coreaudio/SCsub

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ from misc.utility.scons_hints import *
44
Import("env")
55

66
# Driver source files
7-
env.add_source_files(env.drivers_sources, "*.cpp")
7+
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_input_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

+55-14
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 */
@@ -121,7 +121,24 @@ Error AudioDriverCoreAudio::init() {
121121
break;
122122
}
123123

124-
mix_rate = _get_configured_mix_rate();
124+
#ifdef MACOS_ENABLED
125+
AudioDeviceID device_id;
126+
UInt32 dev_id_size = sizeof(AudioDeviceID);
127+
128+
AudioObjectPropertyAddress property_dev_id = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
129+
result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property_dev_id, 0, nullptr, &dev_id_size, &device_id);
130+
ERR_FAIL_COND_V(result != noErr, FAILED);
131+
132+
double hw_mix_rate;
133+
UInt32 hw_mix_rate_size = sizeof(hw_mix_rate);
134+
135+
AudioObjectPropertyAddress property_sr = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain };
136+
result = AudioObjectGetPropertyData(device_id, &property_sr, 0, nullptr, &hw_mix_rate_size, &hw_mix_rate);
137+
ERR_FAIL_COND_V(result != noErr, FAILED);
138+
#else
139+
double hw_mix_rate = [AVAudioSession sharedInstance].sampleRate;
140+
#endif
141+
mix_rate = hw_mix_rate;
125142

126143
memset(&strdesc, 0, sizeof(strdesc));
127144
strdesc.mFormatID = kAudioFormatLinearPCM;
@@ -147,10 +164,10 @@ Error AudioDriverCoreAudio::init() {
147164

148165
unsigned int buffer_size = buffer_frames * channels;
149166
samples_in.resize(buffer_size);
150-
input_buf.resize(buffer_size);
151167

152168
print_verbose("CoreAudio: detected " + itos(channels) + " channels");
153-
print_verbose("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
169+
print_verbose("CoreAudio: output sampling rate: " + itos(mix_rate) + " Hz");
170+
print_verbose("CoreAudio: output audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
154171

155172
AURenderCallbackStruct callback;
156173
memset(&callback, 0, sizeof(AURenderCallbackStruct));
@@ -275,6 +292,10 @@ int AudioDriverCoreAudio::get_mix_rate() const {
275292
return mix_rate;
276293
}
277294

295+
int AudioDriverCoreAudio::get_input_mix_rate() const {
296+
return capture_mix_rate;
297+
}
298+
278299
AudioDriver::SpeakerMode AudioDriverCoreAudio::get_speaker_mode() const {
279300
return get_speaker_mode_by_total_channels(channels);
280301
}
@@ -378,14 +399,14 @@ Error AudioDriverCoreAudio::init_input_device() {
378399

379400
UInt32 size;
380401
#ifdef MACOS_ENABLED
381-
AudioDeviceID deviceId;
402+
AudioDeviceID device_id;
382403
size = sizeof(AudioDeviceID);
383404
AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain };
384405

385-
result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, nullptr, &size, &deviceId);
406+
result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, nullptr, &size, &device_id);
386407
ERR_FAIL_COND_V(result != noErr, FAILED);
387408

388-
result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID));
409+
result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &device_id, sizeof(AudioDeviceID));
389410
ERR_FAIL_COND_V(result != noErr, FAILED);
390411
#endif
391412

@@ -410,13 +431,23 @@ Error AudioDriverCoreAudio::init_input_device() {
410431
break;
411432
}
412433

413-
mix_rate = _get_configured_mix_rate();
434+
#ifdef MACOS_ENABLED
435+
double hw_mix_rate;
436+
UInt32 hw_mix_rate_size = sizeof(hw_mix_rate);
437+
438+
AudioObjectPropertyAddress property_sr = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain };
439+
result = AudioObjectGetPropertyData(device_id, &property_sr, 0, nullptr, &hw_mix_rate_size, &hw_mix_rate);
440+
ERR_FAIL_COND_V(result != noErr, FAILED);
441+
#else
442+
double hw_mix_rate = [AVAudioSession sharedInstance].sampleRate;
443+
#endif
444+
capture_mix_rate = hw_mix_rate;
414445

415446
memset(&strdesc, 0, sizeof(strdesc));
416447
strdesc.mFormatID = kAudioFormatLinearPCM;
417448
strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
418449
strdesc.mChannelsPerFrame = capture_channels;
419-
strdesc.mSampleRate = mix_rate;
450+
strdesc.mSampleRate = capture_mix_rate;
420451
strdesc.mFramesPerPacket = 1;
421452
strdesc.mBitsPerChannel = 16;
422453
strdesc.mBytesPerFrame = strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
@@ -425,6 +456,13 @@ Error AudioDriverCoreAudio::init_input_device() {
425456
result = AudioUnitSetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc));
426457
ERR_FAIL_COND_V(result != noErr, FAILED);
427458

459+
int latency = Engine::get_singleton()->get_audio_output_latency();
460+
// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
461+
capture_buffer_frames = closest_power_of_2(latency * capture_mix_rate / 1000);
462+
463+
unsigned int buffer_size = capture_buffer_frames * capture_channels;
464+
input_buf.resize(buffer_size);
465+
428466
AURenderCallbackStruct callback;
429467
memset(&callback, 0, sizeof(AURenderCallbackStruct));
430468
callback.inputProc = &AudioDriverCoreAudio::input_callback;
@@ -435,6 +473,9 @@ Error AudioDriverCoreAudio::init_input_device() {
435473
result = AudioUnitInitialize(input_unit);
436474
ERR_FAIL_COND_V(result != noErr, FAILED);
437475

476+
print_verbose("CoreAudio: input sampling rate: " + itos(capture_mix_rate) + " Hz");
477+
print_verbose("CoreAudio: input audio buffer frames: " + itos(capture_buffer_frames) + " calculated latency: " + itos(capture_buffer_frames * 1000 / capture_mix_rate) + "ms");
478+
438479
return OK;
439480
}
440481

@@ -477,7 +518,7 @@ void AudioDriverCoreAudio::finish_input_device() {
477518
}
478519

479520
Error AudioDriverCoreAudio::input_start() {
480-
input_buffer_init(buffer_frames);
521+
input_buffer_init(capture_buffer_frames);
481522

482523
OSStatus result = AudioOutputUnitStart(input_unit);
483524
if (result != noErr) {
@@ -561,7 +602,7 @@ PackedStringArray AudioDriverCoreAudio::_get_device_list(bool input) {
561602
}
562603

563604
void AudioDriverCoreAudio::_set_device(const String &output_device, bool input) {
564-
AudioDeviceID deviceId;
605+
AudioDeviceID device_id;
565606
bool found = false;
566607
if (output_device != "Default") {
567608
AudioObjectPropertyAddress prop;
@@ -608,7 +649,7 @@ void AudioDriverCoreAudio::_set_device(const String &output_device, bool input)
608649
if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) {
609650
String name = String::utf8(buffer) + " (" + itos(audioDevices[i]) + ")";
610651
if (name == output_device) {
611-
deviceId = audioDevices[i];
652+
device_id = audioDevices[i];
612653
found = true;
613654
}
614655
}
@@ -626,14 +667,14 @@ void AudioDriverCoreAudio::_set_device(const String &output_device, bool input)
626667
UInt32 elem = input ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice;
627668
AudioObjectPropertyAddress property = { elem, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain };
628669

629-
OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, nullptr, &size, &deviceId);
670+
OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, nullptr, &size, &device_id);
630671
ERR_FAIL_COND(result != noErr);
631672

632673
found = true;
633674
}
634675

635676
if (found) {
636-
OSStatus result = AudioUnitSetProperty(input ? input_unit : audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID));
677+
OSStatus result = AudioUnitSetProperty(input ? input_unit : audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &device_id, sizeof(AudioDeviceID));
637678
ERR_FAIL_COND(result != noErr);
638679

639680
if (input) {

servers/audio/audio_stream.cpp

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

391391
Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer();
392392
unsigned int input_size = AudioDriver::get_singleton()->get_input_size();
393-
int mix_rate = AudioDriver::get_singleton()->get_mix_rate();
393+
int mix_rate = AudioDriver::get_singleton()->get_input_mix_rate();
394394
unsigned int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1);
395395
#ifdef DEBUG_ENABLED
396396
unsigned int input_position = AudioDriver::get_singleton()->get_input_position();
@@ -441,7 +441,7 @@ int AudioStreamPlaybackMicrophone::mix(AudioFrame *p_buffer, float p_rate_scale,
441441
}
442442

443443
float AudioStreamPlaybackMicrophone::get_stream_sampling_rate() {
444-
return AudioDriver::get_singleton()->get_mix_rate();
444+
return AudioDriver::get_singleton()->get_input_mix_rate();
445445
}
446446

447447
void AudioStreamPlaybackMicrophone::start(double p_from_pos) {

servers/audio_server.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1614,6 +1614,10 @@ float AudioServer::get_mix_rate() const {
16141614
return AudioDriver::get_singleton()->get_mix_rate();
16151615
}
16161616

1617+
float AudioServer::get_input_mix_rate() const {
1618+
return AudioDriver::get_singleton()->get_input_mix_rate();
1619+
}
1620+
16171621
float AudioServer::read_output_peak_db() const {
16181622
return 0;
16191623
}
@@ -1946,6 +1950,7 @@ void AudioServer::_bind_methods() {
19461950

19471951
ClassDB::bind_method(D_METHOD("get_speaker_mode"), &AudioServer::get_speaker_mode);
19481952
ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioServer::get_mix_rate);
1953+
ClassDB::bind_method(D_METHOD("get_input_mix_rate"), &AudioServer::get_input_mix_rate);
19491954

19501955
ClassDB::bind_method(D_METHOD("get_output_device_list"), &AudioServer::get_output_device_list);
19511956
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
@@ -99,6 +99,7 @@ class AudioDriver {
9999
virtual Error init() = 0;
100100
virtual void start() = 0;
101101
virtual int get_mix_rate() const = 0;
102+
virtual int get_input_mix_rate() const { return get_mix_rate(); }
102103
virtual SpeakerMode get_speaker_mode() const = 0;
103104
virtual float get_latency() { return 0; }
104105

@@ -441,6 +442,7 @@ class AudioServer : public Object {
441442

442443
virtual SpeakerMode get_speaker_mode() const;
443444
virtual float get_mix_rate() const;
445+
virtual float get_input_mix_rate() const;
444446

445447
virtual float read_output_peak_db() const;
446448

0 commit comments

Comments
 (0)