From eab850524ead092ed9fe22e57955e59eae373b79 Mon Sep 17 00:00:00 2001 From: Marcelo Fernandez Date: Thu, 17 Aug 2017 18:35:55 -0300 Subject: Add closest_power_of_2 func and implement mix_rate/latency on OS X --- platform/android/audio_driver_jandroid.cpp | 2 +- platform/haiku/audio_driver_media_kit.cpp | 2 +- platform/osx/audio_driver_osx.cpp | 102 +++++++++++++++++++---------- platform/osx/audio_driver_osx.h | 4 +- 4 files changed, 71 insertions(+), 39 deletions(-) (limited to 'platform') diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp index d293f3ed30..763eff2863 100644 --- a/platform/android/audio_driver_jandroid.cpp +++ b/platform/android/audio_driver_jandroid.cpp @@ -81,7 +81,7 @@ Error AudioDriverAndroid::init() { int latency = GLOBAL_DEF("audio/output_latency", 25); latency = 50; - unsigned int buffer_size = nearest_power_of_2(latency * mix_rate / 1000); + unsigned int buffer_size = next_power_of_2(latency * mix_rate / 1000); if (OS::get_singleton()->is_stdout_verbose()) { print_line("audio buffer size: " + itos(buffer_size)); } diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp index 93351e0799..802f6b2d32 100644 --- a/platform/haiku/audio_driver_media_kit.cpp +++ b/platform/haiku/audio_driver_media_kit.cpp @@ -43,7 +43,7 @@ Error AudioDriverMediaKit::init() { channels = 2; int latency = GLOBAL_DEF("audio/output_latency", 25); - buffer_size = nearest_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); media_raw_audio_format format; diff --git a/platform/osx/audio_driver_osx.cpp b/platform/osx/audio_driver_osx.cpp index d7a91b1653..da5cd8f65e 100644 --- a/platform/osx/audio_driver_osx.cpp +++ b/platform/osx/audio_driver_osx.cpp @@ -30,6 +30,10 @@ #ifdef OSX_ENABLED #include "audio_driver_osx.h" +#include "core/project_settings.h" +#include "os/os.h" + +#define kOutputBus 0 static OSStatus outputDeviceAddressCB(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *__nullable inClientData) { AudioDriverOSX *driver = (AudioDriverOSX *)inClientData; @@ -40,42 +44,69 @@ static OSStatus outputDeviceAddressCB(AudioObjectID inObjectID, UInt32 inNumberA } Error AudioDriverOSX::initDevice() { + AudioComponentDescription desc; + zeromem(&desc, sizeof(desc)); + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_HALOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + + AudioComponent comp = AudioComponentFindNext(NULL, &desc); + ERR_FAIL_COND_V(comp == NULL, FAILED); + + OSStatus result = AudioComponentInstanceNew(comp, &audio_unit); + ERR_FAIL_COND_V(result != noErr, FAILED); + AudioStreamBasicDescription strdesc; + + // TODO: Implement this + /*zeromem(&strdesc, sizeof(strdesc)); + UInt32 size = sizeof(strdesc); + result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &strdesc, &size); + ERR_FAIL_COND_V(result != noErr, FAILED); + + switch (strdesc.mChannelsPerFrame) { + case 2: // Stereo + case 6: // Surround 5.1 + case 8: // Surround 7.1 + channels = strdesc.mChannelsPerFrame; + break; + + default: + // Unknown number of channels, default to stereo + channels = 2; + break; + }*/ + + mix_rate = GLOBAL_DEF("audio/mix_rate", 44100); + + zeromem(&strdesc, sizeof(strdesc)); strdesc.mFormatID = kAudioFormatLinearPCM; strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; strdesc.mChannelsPerFrame = channels; - strdesc.mSampleRate = 44100; + strdesc.mSampleRate = mix_rate; strdesc.mFramesPerPacket = 1; strdesc.mBitsPerChannel = 16; strdesc.mBytesPerFrame = strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8; strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; - OSStatus result; - AURenderCallbackStruct callback; - AudioComponentDescription desc; - AudioComponent comp = NULL; - const AudioUnitElement output_bus = 0; - const AudioUnitElement bus = output_bus; - const AudioUnitScope scope = kAudioUnitScope_Input; - - zeromem(&desc, sizeof(desc)); - desc.componentType = kAudioUnitType_Output; - desc.componentSubType = kAudioUnitSubType_HALOutput; - desc.componentManufacturer = kAudioUnitManufacturer_Apple; + result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc)); + ERR_FAIL_COND_V(result != noErr, FAILED); - comp = AudioComponentFindNext(NULL, &desc); - ERR_FAIL_COND_V(comp == NULL, FAILED); + int latency = GLOBAL_DEF("audio/output_latency", 25); + unsigned int buffer_size = closest_power_of_2(latency * mix_rate / 1000); - result = AudioComponentInstanceNew(comp, &audio_unit); - ERR_FAIL_COND_V(result != noErr, FAILED); + if (OS::get_singleton()->is_stdout_verbose()) { + print_line("audio buffer size: " + itos(buffer_size) + " calculated latency: " + itos(buffer_size * 1000 / mix_rate)); + } - result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, scope, bus, &strdesc, sizeof(strdesc)); - ERR_FAIL_COND_V(result != noErr, FAILED); + samples_in.resize(buffer_size); + buffer_frames = buffer_size / channels; + AURenderCallbackStruct callback; zeromem(&callback, sizeof(AURenderCallbackStruct)); callback.inputProc = &AudioDriverOSX::output_callback; callback.inputProcRefCon = this; - result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, scope, bus, &callback, sizeof(callback)); + result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); ERR_FAIL_COND_V(result != noErr, FAILED); result = AudioUnitInitialize(audio_unit); @@ -114,15 +145,10 @@ Error AudioDriverOSX::init() { result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this); ERR_FAIL_COND_V(result != noErr, FAILED); - const int samples = 1024; - samples_in = memnew_arr(int32_t, samples); // whatever - buffer_frames = samples / channels; - return initDevice(); }; Error AudioDriverOSX::reopen() { - Error err; bool restart = false; lock(); @@ -131,7 +157,7 @@ Error AudioDriverOSX::reopen() { restart = true; } - err = finishDevice(); + Error err = finishDevice(); if (err != OK) { ERR_PRINT("finishDevice failed"); unlock(); @@ -179,7 +205,7 @@ OSStatus AudioDriverOSX::output_callback(void *inRefCon, while (frames_left) { int frames = MIN(frames_left, ad->buffer_frames); - ad->audio_server_process(frames, ad->samples_in); + ad->audio_server_process(frames, ad->samples_in.ptr()); for (int j = 0; j < frames * ad->channels; j++) { @@ -232,29 +258,33 @@ bool AudioDriverOSX::try_lock() { } void AudioDriverOSX::finish() { - OSStatus result; - finishDevice(); - result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this); + OSStatus result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this); if (result != noErr) { ERR_PRINT("AudioObjectRemovePropertyListener failed"); } + AURenderCallbackStruct callback; + zeromem(&callback, sizeof(AURenderCallbackStruct)); + result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); + if (result != noErr) { + ERR_PRINT("AudioUnitSetProperty failed"); + } + if (mutex) { memdelete(mutex); mutex = NULL; } - - if (samples_in) { - memdelete_arr(samples_in); - samples_in = NULL; - } }; AudioDriverOSX::AudioDriverOSX() { + active = false; mutex = NULL; - samples_in = NULL; + + mix_rate = 44100; + channels = 2; + samples_in.clear(); }; AudioDriverOSX::~AudioDriverOSX(){}; diff --git a/platform/osx/audio_driver_osx.h b/platform/osx/audio_driver_osx.h index 287c9d6cbf..4576100690 100644 --- a/platform/osx/audio_driver_osx.h +++ b/platform/osx/audio_driver_osx.h @@ -44,10 +44,12 @@ class AudioDriverOSX : public AudioDriver { bool active; Mutex *mutex; + int mix_rate; int channels; - int32_t *samples_in; int buffer_frames; + Vector samples_in; + static OSStatus output_callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, -- cgit v1.2.3