Skip to content

Commit 9e86d60

Browse files
committed
Setup AVAudioSession in coreaudio driver, add low latency mode for it
1 parent 1df3101 commit 9e86d60

File tree

5 files changed

+134
-3
lines changed

5 files changed

+134
-3
lines changed

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ elseif(NOT BUILD_SHARED_LIBS)
3838
message(WARNING "Your version of CMake is very old. This may cause linking issues if your dependencies are not in your compiler's default search paths.")
3939
endif()
4040

41-
project ( FluidSynth C CXX )
41+
project ( FluidSynth C CXX OBJC)
4242
list( APPEND CMAKE_MODULE_PATH ${FluidSynth_SOURCE_DIR}/cmake_admin )
4343

4444
# FluidSynth package name
@@ -423,7 +423,7 @@ if ( CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS" )
423423
check_include_file ( CoreAudio/CoreAudioTypes.h COREAUDIO_FOUND )
424424
if ( COREAUDIO_FOUND )
425425
set ( COREAUDIO_SUPPORT 1 )
426-
set ( COREAUDIO_LIBS "-Wl,-framework,CoreAudio,-framework,AudioToolbox" )
426+
set ( COREAUDIO_LIBS "-Wl,-framework,CoreAudio,-framework,AudioToolbox,-framework,AVFoundation" )
427427
endif ( COREAUDIO_FOUND )
428428
check_include_file ( CoreAudio/AudioHardware.h COREAUDIO_HAL_FOUND )
429429
if ( COREAUDIO_HAL_FOUND )

src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ endif ( ALSA_SUPPORT )
3131

3232
if ( COREAUDIO_SUPPORT )
3333
set ( fluid_coreaudio_SOURCES drivers/fluid_coreaudio.c )
34+
if ( NOT COREAUDIO_SUPPORT_HAL )
35+
set ( fluid_coreaudio_SOURCES ${fluid_coreaudio_SOURCES} drivers/fluid_coreaudio_avaudiosession.m )
36+
endif ( COREAUDIO_SUPPORT_HAL )
3437
endif ( COREAUDIO_SUPPORT )
3538

3639
if ( COREMIDI_SUPPORT )

src/drivers/fluid_coreaudio.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,13 @@
3838
#include <CoreAudio/CoreAudioTypes.h>
3939
#if COREAUDIO_SUPPORT_HAL
4040
#include <CoreAudio/AudioHardware.h>
41+
#else
42+
#include "fluid_coreaudio_avaudiosession.h"
4143
#endif
4244
#include <AudioUnit/AudioUnit.h>
4345

46+
const char PERF_MODE[] = "audio.coreaudio.performance-mode";
47+
4448
/*
4549
* fluid_core_audio_driver_t
4650
*
@@ -204,6 +208,12 @@ fluid_core_audio_driver_settings(fluid_settings_t *settings)
204208
fluid_settings_register_str(settings, "audio.coreaudio.channel-map", "", 0);
205209
fluid_settings_add_option(settings, "audio.coreaudio.device", "default");
206210

211+
#if !COREAUDIO_SUPPORT_HAL
212+
fluid_settings_register_str(settings, PERF_MODE, "None", 0);
213+
fluid_settings_add_option(settings, PERF_MODE, "None");
214+
fluid_settings_add_option(settings, PERF_MODE, "LowLatency");
215+
#endif
216+
207217
#if COREAUDIO_SUPPORT_HAL
208218
if(OK(AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa, 0, 0, &size)))
209219
{
@@ -251,6 +261,10 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
251261
#if COREAUDIO_SUPPORT_HAL
252262
char *devname = NULL;
253263
int i;
264+
#else
265+
int avsession_ok;
266+
int performance_mode;
267+
char avaudiosession_msg[128] = "";
254268
#endif
255269
char *channel_map = NULL;
256270
fluid_core_audio_driver_t *dev = NULL;
@@ -386,7 +400,24 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
386400
}
387401
}
388402
FLUID_FREE(devname); /* free device name */
389-
#endif
403+
404+
#else /* COREAUDIO_SUPPORT_HAL */
405+
performance_mode = fluid_settings_str_equal(settings, PERF_MODE, "LowLatency")
406+
? AVAUDIOSESSION_MODE_LOW_LATENCY : AVAUDIOSESSION_MODE_NONE;
407+
408+
avsession_ok = setupAVAudioSession(performance_mode, period_size, sample_rate,
409+
avaudiosession_msg, sizeof(avaudiosession_msg));
410+
411+
if (avaudiosession_msg[0] != 0) {
412+
if (avsession_ok) {
413+
FLUID_LOG(FLUID_INFO, "%s", avaudiosession_msg);
414+
}
415+
else {
416+
FLUID_LOG(FLUID_ERR, "%s", avaudiosession_msg);
417+
}
418+
}
419+
#endif /* !COREAUDIO_SUPPORT_HAL */
420+
390421

391422

392423
dev->buffer_size = period_size * periods;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef FLUID_COREAUDIO_AVAUDIOSESSION_H
2+
#define FLUID_COREAUDIO_AVAUDIOSESSION_H
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
8+
/* PowerSaving mode is not yet supported, but in oboe driver,
9+
PowerSaving mode is 1, so we leave LowLatency as 2,
10+
for consistency with fluid_oboe.c */
11+
#define AVAUDIOSESSION_MODE_NONE 0
12+
#define AVAUDIOSESSION_MODE_LOW_LATENCY 2
13+
14+
int setupAVAudioSession(int mode, int period_size, double sample_rate, char* msgbuf, int msgbufsize);
15+
16+
#ifdef __cplusplus
17+
}
18+
#endif
19+
20+
#endif /* FLUID_COREAUDIO_AVAUDIOSESSION_H */
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#import <unistd.h>
2+
#import <AVFoundation/AVFoundation.h>
3+
#import "fluid_coreaudio_avaudiosession.h"
4+
5+
void renderError(NSError* error, const char* desc, char* msgbuf, int msgbufsize) {
6+
if (error != nil) {
7+
snprintf(msgbuf, msgbufsize, "Error %s for low-latency audio session: %s",
8+
desc, error.description.UTF8String);
9+
}
10+
else {
11+
snprintf(msgbuf, msgbufsize, "%s", desc);
12+
}
13+
}
14+
15+
int setupAVAudioSession(int mode, int period_size, double sample_rate, char* msgbuf, int msgbufsize) {
16+
NSError *error = nil;
17+
BOOL success = false;
18+
NSTimeInterval bufDuration;
19+
NSTimeInterval periodDuration;
20+
NSString *category;
21+
NSUInteger options;
22+
23+
AVAudioSession *session = [AVAudioSession sharedInstance];
24+
25+
if (mode == AVAUDIOSESSION_MODE_LOW_LATENCY) {
26+
category = AVAudioSessionCategoryPlayAndRecord;
27+
}
28+
else {
29+
category = AVAudioSessionCategoryPlayback;
30+
}
31+
options = AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionDefaultToSpeaker;
32+
33+
success = [session setCategory:category withOptions:options error:&error];
34+
if (!success) {
35+
renderError(error, "setting audio session category", msgbuf, msgbufsize);
36+
return 0;
37+
}
38+
39+
success = [session setMode:AVAudioSessionModeDefault error:&error];
40+
if (!success) {
41+
renderError(error, "setting audio session mode", msgbuf, msgbufsize);
42+
return 0;
43+
}
44+
45+
success = [session setActive:YES error:&error];
46+
if (!success) {
47+
renderError(error, "activating audio session", msgbuf, msgbufsize);
48+
return 0;
49+
}
50+
51+
if (mode != AVAUDIOSESSION_MODE_LOW_LATENCY) {
52+
snprintf(msgbuf, msgbufsize, "setupAVAudioSession: success");
53+
}
54+
else {
55+
periodDuration = (double)period_size / sample_rate;
56+
if (periodDuration == 0.0) {
57+
periodDuration = 0.001;
58+
}
59+
bufDuration = periodDuration;
60+
61+
while (session.IOBufferDuration > bufDuration) {
62+
success = [session setPreferredIOBufferDuration:bufDuration error:&error];
63+
64+
if (!success) {
65+
renderError(error, "setting preferred I/O buffer duration", msgbuf, msgbufsize);
66+
return 0;
67+
}
68+
69+
bufDuration += periodDuration;
70+
}
71+
72+
snprintf(msgbuf, msgbufsize, "setupAVAudioSession for low latency: success, io buffer duration = %f seconds",
73+
session.IOBufferDuration);
74+
}
75+
76+
return 1;
77+
}

0 commit comments

Comments
 (0)