Skip to content

Commit 3344af0

Browse files
committed
extract delay to define, 10ms
1 parent 663f318 commit 3344af0

File tree

1 file changed

+58
-56
lines changed

1 file changed

+58
-56
lines changed

audio/drivers_microphone/coreaudio_mic_macos.m

Lines changed: 58 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#include <math.h>
3434
#include <pthread.h> /* For mutexes */
3535

36+
#define COREAUDIO_MIC_BUFFER_DURATION_S 0.01f /* Buffer duration in seconds (e.g., 0.01f for 10ms) */
37+
3638
typedef struct coreaudio_macos_microphone
3739
{
3840
AudioUnit audio_unit;
@@ -85,35 +87,35 @@ static OSStatus coreaudio_macos_input_callback(void *inRefCon,
8587
coreaudio_macos_microphone_t *mic = (coreaudio_macos_microphone_t*)inRefCon;
8688
if (!mic || !atomic_load_explicit(&mic->is_running, memory_order_relaxed))
8789
return noErr;
88-
90+
8991
/* Calculate buffer size needed for this callback */
9092
size_t bytes_needed = inNumberFrames * mic->format.mBytesPerFrame;
9193
if (bytes_needed == 0)
9294
return noErr;
93-
95+
9496
/* Use a temporary buffer for AudioUnitRender - zero-initialized to avoid random data */
9597
void *temp_buffer = calloc(1, bytes_needed);
9698
if (!temp_buffer)
9799
{
98100
RARCH_ERR("[CoreAudio macOS Mic]: Failed to allocate temporary buffer\n");
99101
return kAudio_MemFullError;
100102
}
101-
103+
102104
/* Set up buffer list for rendering */
103105
AudioBufferList buffer_list;
104106
buffer_list.mNumberBuffers = 1;
105107
buffer_list.mBuffers[0].mDataByteSize = (UInt32)bytes_needed;
106108
buffer_list.mBuffers[0].mData = temp_buffer;
107109
buffer_list.mBuffers[0].mNumberChannels = mic->format.mChannelsPerFrame;
108-
110+
109111
/* Render audio from INPUT BUS (bus 1) */
110112
OSStatus status = AudioUnitRender(mic->audio_unit,
111113
ioActionFlags,
112114
inTimeStamp,
113115
1, /* Input bus is always 1 for HAL AudioUnits */
114116
inNumberFrames,
115117
&buffer_list);
116-
118+
117119
/* Handle both complete success and partial success cases */
118120
if (status == noErr || status == kAudioUnitErr_NoConnection)
119121
{
@@ -122,7 +124,7 @@ static OSStatus coreaudio_macos_input_callback(void *inRefCon,
122124
{
123125
/* Ensure we don't write more than what was actually rendered */
124126
size_t actual_bytes = MIN(bytes_needed, buffer_list.mBuffers[0].mDataByteSize);
125-
127+
126128
/* Write all audio data to FIFO - no silence detection to reduce CPU overhead */
127129
{
128130
/* Check if there's enough space in the FIFO */
@@ -145,7 +147,7 @@ static OSStatus coreaudio_macos_input_callback(void *inRefCon,
145147
{
146148
RARCH_ERR("[CoreAudio macOS Mic]: Failed to render audio: %d\n", (int)status);
147149
}
148-
150+
149151
/* Clean up temporary buffer */
150152
free(temp_buffer);
151153
return status;
@@ -183,16 +185,16 @@ static void coreaudio_macos_microphone_set_format(coreaudio_macos_microphone_t *
183185
{
184186
if (!mic)
185187
return;
186-
188+
187189
/* Store the format choice */
188190
mic->use_float = use_float;
189-
191+
190192
/* Setup the format for the AudioUnit based on the parameters */
191193
AudioStreamBasicDescription *format = &mic->format;
192-
194+
193195
/* Clear the format struct */
194196
memset(format, 0, sizeof(AudioStreamBasicDescription));
195-
197+
196198
/* Set basic properties */
197199
format->mSampleRate = mic->sample_rate;
198200
format->mFormatID = kAudioFormatLinearPCM;
@@ -204,7 +206,7 @@ static void coreaudio_macos_microphone_set_format(coreaudio_macos_microphone_t *
204206
format->mBitsPerChannel = use_float ? 32 : 16;
205207
format->mBytesPerFrame = format->mChannelsPerFrame * format->mBitsPerChannel / 8;
206208
format->mBytesPerPacket = format->mBytesPerFrame * format->mFramesPerPacket;
207-
209+
208210
RARCH_LOG("[CoreAudio macOS Mic]: Format setup: sample_rate=%.0f Hz, bits=%u, bytes_per_frame=%u, %s\n",
209211
format->mSampleRate,
210212
(unsigned)format->mBitsPerChannel,
@@ -422,7 +424,7 @@ static void coreaudio_macos_microphone_device_list_free(const void *data, struct
422424
{
423425
RARCH_ERR("[CoreAudio macOS Mic]: Failed to find HALOutput AudioComponent.\n");
424426
if (mic->device_name) free(mic->device_name);
425-
427+
426428
free(mic);
427429
return NULL;
428430
}
@@ -455,7 +457,7 @@ static void coreaudio_macos_microphone_device_list_free(const void *data, struct
455457
return NULL;
456458
}
457459
RARCH_LOG("[CoreAudio macOS Mic]: AudioUnit instance created: %p\n", mic->audio_unit);
458-
460+
459461
/* Set the specific audio device if one was requested (not default) */
460462
if (mic->selected_device_id != kAudioObjectUnknown)
461463
{
@@ -482,7 +484,7 @@ static void coreaudio_macos_microphone_device_list_free(const void *data, struct
482484

483485
/* 2. Enable input on the AudioUnit - CRITICAL STEP */
484486
UInt32 enable_io = 1;
485-
487+
486488
/* Enable input on input bus */
487489
status = AudioUnitSetProperty(mic->audio_unit,
488490
kAudioOutputUnitProperty_EnableIO,
@@ -495,7 +497,7 @@ static void coreaudio_macos_microphone_device_list_free(const void *data, struct
495497
RARCH_ERR("[CoreAudio macOS Mic]: Failed to enable input on AudioUnit: %d\n", (int)status);
496498
AudioComponentInstanceDispose(mic->audio_unit);
497499
if (mic->device_name) free(mic->device_name);
498-
500+
499501
free(mic);
500502
return NULL;
501503
}
@@ -564,7 +566,7 @@ static void coreaudio_macos_microphone_device_list_free(const void *data, struct
564566
(unsigned int)actual_device_id_check, (unsigned int)mic->selected_device_id);
565567
}
566568
/* Update mic->selected_device_id to reflect the actual one, especially if it was default or fallback */
567-
mic->selected_device_id = actual_device_id_check;
569+
mic->selected_device_id = actual_device_id_check;
568570
}
569571
else
570572
{
@@ -574,9 +576,9 @@ static void coreaudio_macos_microphone_device_list_free(const void *data, struct
574576

575577
/* 4. Set stream format */
576578
coreaudio_macos_microphone_set_format(mic, false /* use int16 for better compatibility */);
577-
579+
578580
RARCH_LOG("[CoreAudio macOS Mic]: After format setup - mic->format.mSampleRate = %.0f Hz\n", mic->format.mSampleRate);
579-
581+
580582
/* First get the device's native format from the INPUT scope, INPUT bus (bus 1) */
581583
AudioStreamBasicDescription device_format = {0};
582584
UInt32 prop_size = sizeof(device_format);
@@ -589,30 +591,30 @@ static void coreaudio_macos_microphone_device_list_free(const void *data, struct
589591
if (format_status != noErr) {
590592
RARCH_WARN("[CoreAudio macOS Mic]: Could not get device native format from input bus: %d. Using default format.\n", (int)format_status);
591593
} else {
592-
RARCH_LOG("[CoreAudio macOS Mic]: Device native format (input bus) - Sample rate: %.0f, Channels: %u, Bits: %u\n",
593-
device_format.mSampleRate,
594+
RARCH_LOG("[CoreAudio macOS Mic]: Device native format (input bus) - Sample rate: %.0f, Channels: %u, Bits: %u\n",
595+
device_format.mSampleRate,
594596
(unsigned)device_format.mChannelsPerFrame,
595597
(unsigned)device_format.mBitsPerChannel);
596-
598+
597599
/* Use the device's native sample rate but ALWAYS use mono for better compatibility */
598600
mic->format.mSampleRate = device_format.mSampleRate;
599601
mic->format.mChannelsPerFrame = 1; /* Always force mono regardless of device capabilities */
600-
602+
601603
/* Update mic->channels to match what we're actually using */
602604
mic->channels = device_format.mChannelsPerFrame;
603-
605+
604606
/* Re-calculate format bytes per frame to match the channel count */
605607
mic->format.mBytesPerFrame = mic->format.mChannelsPerFrame * (mic->format.mBitsPerChannel / 8);
606608
mic->format.mFramesPerPacket = 1;
607609
mic->format.mBytesPerPacket = mic->format.mBytesPerFrame * mic->format.mFramesPerPacket;
608-
610+
609611
RARCH_LOG("[CoreAudio macOS Mic]: Updated format - SR: %.0f, CH: %u, BitsPerCh: %u, BytesPerFrame: %u\n",
610-
mic->format.mSampleRate,
612+
mic->format.mSampleRate,
611613
(unsigned)mic->format.mChannelsPerFrame,
612614
(unsigned)mic->format.mBitsPerChannel,
613615
(unsigned)mic->format.mBytesPerFrame);
614616
}
615-
617+
616618
RARCH_LOG("[CoreAudio macOS Mic]: Setting client format on OUTPUT scope of INPUT bus\n");
617619
OSStatus set_format_status = AudioUnitSetProperty(mic->audio_unit,
618620
kAudioUnitProperty_StreamFormat,
@@ -625,34 +627,34 @@ static void coreaudio_macos_microphone_device_list_free(const void *data, struct
625627
RARCH_ERR("[CoreAudio macOS Mic]: Failed to set client stream format: %d\n", (int)set_format_status);
626628
AudioComponentInstanceDispose(mic->audio_unit);
627629
if (mic->device_name) free(mic->device_name);
628-
630+
629631
free(mic);
630632
return NULL;
631633
}
632-
634+
633635
/* Set up input callback */
634636
AURenderCallbackStruct callback_struct;
635637
callback_struct.inputProc = coreaudio_macos_input_callback;
636638
callback_struct.inputProcRefCon = mic;
637-
639+
638640
status = AudioUnitSetProperty(mic->audio_unit,
639-
kAudioOutputUnitProperty_SetInputCallback,
640-
kAudioUnitScope_Global,
641-
0,
641+
kAudioOutputUnitProperty_SetInputCallback,
642+
kAudioUnitScope_Global,
643+
0,
642644
&callback_struct,
643645
sizeof(callback_struct));
644646
if (status != noErr)
645647
{
646648
RARCH_ERR("[CoreAudio macOS Mic]: Failed to set INPUT callback: %d\n", (int)status);
647649
AudioComponentInstanceDispose(mic->audio_unit);
648650
if (mic->device_name) free(mic->device_name);
649-
651+
650652
free(mic);
651653
return NULL;
652654
}
653-
655+
654656
RARCH_LOG("[CoreAudio macOS Mic]: Initializing AudioUnit %p\n", mic->audio_unit);
655-
657+
656658
/* Set a smaller buffer frame size for lower latency */
657659
UInt32 buffer_frame_size = 256; /* Small buffer for lower latency */
658660
status = AudioUnitSetProperty(mic->audio_unit,
@@ -663,16 +665,16 @@ static void coreaudio_macos_microphone_device_list_free(const void *data, struct
663665
sizeof(buffer_frame_size));
664666
if (status != noErr)
665667
{
666-
RARCH_WARN("[CoreAudio macOS Mic]: Failed to set buffer frame size to %u: %d\n",
668+
RARCH_WARN("[CoreAudio macOS Mic]: Failed to set buffer frame size to %u: %d\n",
667669
(unsigned)buffer_frame_size, (int)status);
668670
/* Non-fatal, continue with default buffer size */
669671
}
670672
else
671673
{
672-
RARCH_LOG("[CoreAudio macOS Mic]: Set buffer frame size to %u frames for lower latency\n",
674+
RARCH_LOG("[CoreAudio macOS Mic]: Set buffer frame size to %u frames for lower latency\n",
673675
(unsigned)buffer_frame_size);
674676
}
675-
677+
676678
status = AudioUnitInitialize(mic->audio_unit);
677679
if (status != noErr)
678680
{
@@ -685,13 +687,13 @@ static void coreaudio_macos_microphone_device_list_free(const void *data, struct
685687
atomic_store(&mic->is_initialized, true);
686688
RARCH_LOG("[CoreAudio macOS Mic]: AudioUnit successfully initialized.\n");
687689

688-
/* Initialize FIFO buffer - 50ms buffer size */
689-
size_t fifo_size = mic->format.mSampleRate * mic->format.mBytesPerFrame * 0.05f;
690-
RARCH_LOG("[CoreAudio macOS Mic]: Creating FIFO buffer of size %u bytes (%.1f ms at %.0f Hz)\n",
691-
(unsigned)fifo_size,
690+
/* Initialize FIFO buffer */
691+
size_t fifo_size = mic->format.mSampleRate * mic->format.mBytesPerFrame * COREAUDIO_MIC_BUFFER_DURATION_S;
692+
RARCH_LOG("[CoreAudio macOS Mic]: Creating FIFO buffer of size %u bytes (%.1f ms at %.0f Hz)\n",
693+
(unsigned)fifo_size,
692694
(float)fifo_size * 1000.0f / (mic->format.mSampleRate * mic->format.mBytesPerFrame),
693695
mic->format.mSampleRate);
694-
696+
695697
/* Create and initialize FIFO buffer */
696698
mic->fifo = fifo_new(fifo_size);
697699
if (!mic->fifo)
@@ -700,23 +702,23 @@ static void coreaudio_macos_microphone_device_list_free(const void *data, struct
700702
AudioUnitUninitialize(mic->audio_unit);
701703
AudioComponentInstanceDispose(mic->audio_unit);
702704
if (mic->device_name) free(mic->device_name);
703-
705+
704706
free(mic);
705707
return NULL;
706708
}
707-
709+
708710
/* Explicitly clear the FIFO buffer to ensure no random data */
709711
fifo_clear(mic->fifo);
710712
RARCH_LOG("[CoreAudio macOS Mic]: FIFO buffer initialized and cleared\n");
711713

712714
/* Allocate AudioBufferList for AudioUnitRender in the callback */
713-
715+
714716
/* We don't need to pre-allocate buffer list or calculate max frames per slice
715717
* since we're using temporary buffers in the callback like the iOS version */
716718

717-
RARCH_LOG("[CoreAudio macOS Mic]: COMPLETE CONFIG - Sample rate: %.0f Hz, Format: %s, Channels: %u\n",
718-
mic->format.mSampleRate,
719-
mic->use_float ? "Float" : "Int16",
719+
RARCH_LOG("[CoreAudio macOS Mic]: COMPLETE CONFIG - Sample rate: %.0f Hz, Format: %s, Channels: %u\n",
720+
mic->format.mSampleRate,
721+
mic->use_float ? "Float" : "Int16",
720722
(unsigned)mic->format.mChannelsPerFrame);
721723

722724
if (new_rate)
@@ -749,7 +751,7 @@ static void coreaudio_macos_microphone_close_mic(void *data, void *mic_data)
749751

750752
/* No buffer list cleanup needed since we're using temporary buffers */
751753

752-
754+
753755

754756
if (mic->fifo)
755757
{
@@ -790,21 +792,21 @@ static bool coreaudio_macos_microphone_start_mic(void *data, void *mic_data)
790792

791793
/* Check microphone permission on macOS */
792794
RARCH_LOG("[CoreAudio macOS Mic]: Checking microphone permission...\n");
793-
795+
794796
/* Check if we have input devices available */
795797
AudioObjectPropertyAddress prop_addr = {
796798
kAudioHardwarePropertyDefaultInputDevice,
797799
kAudioObjectPropertyScopeGlobal,
798800
kAudioObjectPropertyElementMaster
799801
};
800-
802+
801803
AudioDeviceID default_input_device = kAudioObjectUnknown;
802804
UInt32 prop_size = sizeof(AudioDeviceID);
803805
OSStatus perm_status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop_addr, 0, NULL, &prop_size, &default_input_device);
804-
806+
805807
if (perm_status != noErr || default_input_device == kAudioObjectUnknown)
806808
{
807-
RARCH_ERR("[CoreAudio macOS Mic]: No default input device available or permission denied. Status: %d, Device ID: %u\n",
809+
RARCH_ERR("[CoreAudio macOS Mic]: No default input device available or permission denied. Status: %d, Device ID: %u\n",
808810
(int)perm_status, (unsigned)default_input_device);
809811
}
810812
else
@@ -823,7 +825,7 @@ static bool coreaudio_macos_microphone_start_mic(void *data, void *mic_data)
823825
RARCH_ERR("[CoreAudio macOS Mic]: No FIFO buffer available\n");
824826
return false;
825827
}
826-
828+
827829
OSStatus status = AudioOutputUnitStart(mic->audio_unit);
828830
if (status == noErr)
829831
{

0 commit comments

Comments
 (0)