Skip to content

Commit

Permalink
WIP - coreaudio microphone
Browse files Browse the repository at this point in the history
  • Loading branch information
warmenhoven committed May 14, 2024
1 parent 7cb9b01 commit 070e4d2
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 5 deletions.
214 changes: 214 additions & 0 deletions audio/drivers_microphone/coreaudio_microphone.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2023 Jesse Talavera-Greenberg
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/

#include "verbosity.h"
#include "retro_assert.h"
#include "retro_math.h"
#include "audio/microphone_driver.h"
#include <rthreads/rthreads.h>
#include <queues/fifo_queue.h>

#ifndef TARGET_OS_IPHONE
#include <CoreAudio/CoreAudio.h>
#endif

#include <AudioToolbox/AudioToolbox.h>
#include <AudioUnit/AudioUnit.h>

typedef struct
{
bool nonblock;
} ca_mic_drv_t;

typedef struct
{
AudioQueueRef audioQueue;
AudioQueueBufferRef buffers[3];
fifo_buffer_t *buffer;
slock_t *lock;
scond_t *cond;
bool running;
} ca_mic_t;

static void *coreaudio_microphone_init(void)
{
ca_mic_drv_t *drv = (ca_mic_drv_t *)calloc(1, sizeof(*drv));
return drv;
}

static void coreaudio_microphone_free(void *drv)
{
if (drv)
free(drv);
}

static int coreaudio_microphone_read(void *drv, void *m, void *buf, size_t sz)
{
ca_mic_drv_t *cadrv = (ca_mic_drv_t *)drv;
ca_mic_t *mic = (ca_mic_t *)m;
size_t read = 0;
slock_lock(mic->lock);
if (cadrv->nonblock)
{
size_t avail, read_amt;
avail = FIFO_READ_AVAIL(mic->buffer);
read_amt = avail > sz ? sz : avail;
if (read_amt > 0)
fifo_read(mic->buffer, buf, read_amt);
read = read_amt;
}
else
{
while (read < sz)
{
size_t avail = FIFO_READ_AVAIL(mic->buffer);
if (avail)
{
size_t read_amt = MIN(sz - read, avail);
fifo_read(mic->buffer, buf + read, read_amt);
read += read_amt;
}
// if (read != sz)
// scond_wait(mic->cond, mic->lock);
}
}
scond_signal(mic->cond);
slock_lock(mic->lock);
return (int)read;
}

static void coreaudio_microphone_set_nonblock_state(void *drv, bool nonblock)
{
ca_mic_drv_t *cadrv = (ca_mic_drv_t *)drv;
if (cadrv)
cadrv->nonblock = nonblock;
}

static void AudioInputCallback(void *inUserData, AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime,
UInt32 inNumPackets, const AudioStreamPacketDescription *inPacketDesc)
{
ca_mic_t *mic = (ca_mic_t *)inUserData;

if (inNumPackets > 0) {
size_t read = 0;
slock_lock(mic->lock);
while (read < inBuffer->mAudioDataByteSize)
{
if (FIFO_WRITE_AVAIL(mic->buffer) >= inBuffer->mAudioDataByteSize)
{
fifo_write(mic->buffer, inBuffer->mAudioData, inBuffer->mAudioDataByteSize);
read += inBuffer->mAudioDataByteSize;
}
}
scond_signal(mic->cond);
slock_unlock(mic->lock);
}

OSStatus status = AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
printf("%d\n", status);
}

static void *coreaudio_microphone_open_mic(void *drv, const char *device, unsigned rate, unsigned latency, unsigned *new_rate)
{
ca_mic_t *mic = (ca_mic_t *)calloc(1, sizeof(*mic));
if (!mic)
return NULL;

int frames = next_pow2(rate * latency / 1000);
AudioStreamBasicDescription audioFormat;
memset(&audioFormat, 0, sizeof(audioFormat));
audioFormat.mSampleRate = rate;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = 2;
audioFormat.mBytesPerFrame = 2;

AudioQueueRef audioQueue;
AudioQueueNewInput(&audioFormat, AudioInputCallback, mic, NULL, kCFRunLoopCommonModes, 0, &audioQueue);

const int bufferByteSize = frames * 2;

for (int i = 0; i < 3; ++i)
AudioQueueAllocateBuffer(audioQueue, bufferByteSize, &mic->buffers[i]);

mic->audioQueue = audioQueue;
mic->buffer = fifo_new(frames << 3);
mic->lock = slock_new();
mic->cond = scond_new();
mic->running = false;
return mic;
}

static void coreaudio_microphone_close_mic(void *drv, void *m)
{
ca_mic_t *mic = (ca_mic_t *)m;
AudioQueueDispose(mic->audioQueue, true);
fifo_free(mic->buffer);
slock_free(mic->lock);
scond_free(mic->cond);
free(mic);
}

static bool coreaudio_microphone_mic_alive(const void *drv, const void *m)
{
ca_mic_t *mic = (ca_mic_t *)m;
return mic && mic->running;
}

static bool coreaudio_microphone_start_mic(void *drv, void *m)
{
ca_mic_t *mic = (ca_mic_t *)m;
if (!mic->running)
{
for (int i = 0; i < 3; i++)
AudioQueueEnqueueBuffer(mic->audioQueue, mic->buffers[i], 0, NULL);
OSStatus status = AudioQueueStart(mic->audioQueue, NULL);
mic->running = (status == 0);
}
return mic->running;
}

static bool coreaudio_microphone_stop_mic(void *drv, void *m)
{
ca_mic_t *mic = (ca_mic_t *)m;
AudioQueueStop(mic->audioQueue, true);
mic->running = false;
return true;
}

static bool coreaudio_microphone_mic_use_float(const void *drv, const void *mic)
{
return false;
}

microphone_driver_t microphone_coreaudio = {
coreaudio_microphone_init,
coreaudio_microphone_free,
coreaudio_microphone_read,
coreaudio_microphone_set_nonblock_state,
"coreaudio",
NULL,
NULL,
coreaudio_microphone_open_mic,
coreaudio_microphone_close_mic,
coreaudio_microphone_mic_alive,
coreaudio_microphone_start_mic,
coreaudio_microphone_stop_mic,
coreaudio_microphone_mic_use_float,
};
3 changes: 3 additions & 0 deletions audio/microphone_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ microphone_driver_t *microphone_drivers[] = {
#endif
#ifdef HAVE_SDL2
&microphone_sdl, /* Microphones are not supported in SDL 1 */
#endif
#ifdef HAVE_COREAUDIO
&microphone_coreaudio,
#endif
&microphone_null,
NULL,
Expand Down
5 changes: 5 additions & 0 deletions audio/microphone_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,11 @@ extern microphone_driver_t microphone_sdl;
*/
extern microphone_driver_t microphone_wasapi;

/**
* The coreaudio-backed microphone driver.
*/
extern microphone_driver_t microphone_coreaudio;

/**
* @return Pointer to the global microphone driver state.
*/
Expand Down
3 changes: 3 additions & 0 deletions griffin/griffin.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,9 @@ AUDIO

#ifdef HAVE_COREAUDIO
#include "../audio/drivers/coreaudio.c"
#ifdef HAVE_MICROPHONE
#include "../audio/drivers_microphone/coreaudio_microphone.c"
#endif
#endif

#if defined(HAVE_WASAPI) || ((_WIN32_WINNT >= 0x0602) && !defined(__WINRT__))
Expand Down
1 change: 1 addition & 0 deletions pkg/apple/BaseConfig.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ OTHER_CFLAGS = $(inherited) -DHAVE_MATERIALUI
OTHER_CFLAGS = $(inherited) -DHAVE_MENU
OTHER_CFLAGS = $(inherited) -DHAVE_METAL
OTHER_CFLAGS = $(inherited) -DHAVE_MFI
OTHER_CFLAGS = $(inherited) -DHAVE_MICROPHONE
OTHER_CFLAGS = $(inherited) -DHAVE_MMAP
OTHER_CFLAGS = $(inherited) -DHAVE_NETPLAYDISCOVERY
OTHER_CFLAGS = $(inherited) -DHAVE_NETPLAYDISCOVERY_NSNET
Expand Down
2 changes: 2 additions & 0 deletions pkg/apple/OSX/Info_Metal.plist
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
<string>Copyright © 2024 RetroArch. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu_Metal</string>
<key>NSMicrophoneUsageDescription</key>
<string>We use it.</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>RAPortableInstall</key>
Expand Down
2 changes: 2 additions & 0 deletions pkg/apple/RetroArch.entitlements
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
</dict>
</plist>
6 changes: 3 additions & 3 deletions pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
0790F67B2BF282B400AA58C9 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0790F6782BF282B400AA58C9 /* Media.xcassets */; };
0790F67C2BF2925400AA58C9 /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0790F6782BF282B400AA58C9 /* Media.xcassets */; };
0795A8C7299A095300D5035D /* CoreHaptics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0795A8C6299A095300D5035D /* CoreHaptics.framework */; };
07AC0F542A7215E200016C17 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07AC0F532A7215E200016C17 /* CoreMedia.framework */; };
07AC0F552A72160500016C17 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07AC0F532A7215E200016C17 /* CoreMedia.framework */; };
07EF0FF62BEB114000EDCA9B /* MoltenVK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07EF0FF42BEB114000EDCA9B /* MoltenVK.xcframework */; };
07EF0FF92BEB117000EDCA9B /* MoltenVK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07EF0FF42BEB114000EDCA9B /* MoltenVK.xcframework */; };
07EF0FFA2BEB117000EDCA9B /* MoltenVK.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 07EF0FF42BEB114000EDCA9B /* MoltenVK.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -101,8 +103,6 @@
07F2BBE02BE83A4700FD1295 /* AudioUnit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DD5EB21A89E6C0007336C1 /* AudioUnit.framework */; };
07F2BBE12BE83A4700FD1295 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97324FDCFA39411CA2CEA /* AppKit.framework */; };
07F2BBE22BE83A4700FD1295 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84DD5EB41A89E737007336C1 /* IOKit.framework */; };
07AC0F542A7215E200016C17 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07AC0F532A7215E200016C17 /* CoreMedia.framework */; };
07AC0F552A72160500016C17 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 07AC0F532A7215E200016C17 /* CoreMedia.framework */; };
5061C8A41AE47E510080AE14 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5061C8A31AE47E510080AE14 /* libz.dylib */; };
509F0C9D1AA23AFC00619ECC /* griffin_objc.m in Sources */ = {isa = PBXBuildFile; fileRef = 509F0C9C1AA23AFC00619ECC /* griffin_objc.m */; };
840222FC1A889EE2009AB261 /* griffin.c in Sources */ = {isa = PBXBuildFile; fileRef = 840222FB1A889EE2009AB261 /* griffin.c */; settings = {COMPILER_FLAGS = "-include $(DERIVED_FILE_DIR)/git_version.h"; }; };
Expand Down Expand Up @@ -563,11 +563,11 @@
0776EF3829A005D600AF0237 /* Steam.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Steam.xcconfig; sourceTree = "<group>"; };
0790F6782BF282B400AA58C9 /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Media.xcassets; path = OSX/Media.xcassets; sourceTree = "<group>"; };
0795A8C6299A095300D5035D /* CoreHaptics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreHaptics.framework; path = System/Library/Frameworks/CoreHaptics.framework; sourceTree = SDKROOT; };
07AC0F532A7215E200016C17 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
07EF0FF42BEB114000EDCA9B /* MoltenVK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MoltenVK.xcframework; path = Frameworks/MoltenVK.xcframework; sourceTree = "<group>"; };
07F2BBC22BE83A4200FD1295 /* AppStore.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppStore.xcconfig; sourceTree = "<group>"; };
07F2BBE92BE83A4700FD1295 /* RetroArch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RetroArch.app; sourceTree = BUILT_PRODUCTS_DIR; };
07F8037C2BEFE4BD000FD557 /* RetroArchAppStore.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RetroArchAppStore.entitlements; sourceTree = "<group>"; };
07AC0F532A7215E200016C17 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
089C165DFE840E0CC02AAC07 /* InfoPlist.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = InfoPlist.strings; path = OSX/en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
5061C8A31AE47E510080AE14 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
Expand Down
6 changes: 4 additions & 2 deletions pkg/apple/RetroArch_iOS13.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2392,7 +2392,6 @@
"-DHAVE_GLSL",
"-DHAVE_GLSLANG",
"-DHAVE_GRIFFIN",
"-DHAVE_VULKAN",
"-DHAVE_HID",
"-DHAVE_IFINFO",
"-DHAVE_IMAGEVIEWER",
Expand All @@ -2403,6 +2402,7 @@
"-DHAVE_MENU",
"-DHAVE_METAL",
"-DHAVE_MFI",
"-DHAVE_MICROPHONE",
"-DHAVE_MINIUPNPC",
"-DHAVE_NETPLAYDISCOVERY",
"-DHAVE_NETPLAYDISCOVERY_NSNET",
Expand Down Expand Up @@ -2437,6 +2437,7 @@
"-DHAVE_UPDATE_ASSETS",
"-DHAVE_UPDATE_CORE_INFO",
"-DHAVE_VIDEO_FILTER",
"-DHAVE_VULKAN",
"-DHAVE_XDELTA",
"-DHAVE_XMB",
"-DHAVE_ZLIB",
Expand Down Expand Up @@ -2521,7 +2522,6 @@
"-DHAVE_GLSL",
"-DHAVE_GLSLANG",
"-DHAVE_GRIFFIN",
"-DHAVE_VULKAN",
"-DHAVE_HID",
"-DHAVE_IFINFO",
"-DHAVE_IMAGEVIEWER",
Expand All @@ -2532,6 +2532,7 @@
"-DHAVE_MENU",
"-DHAVE_METAL",
"-DHAVE_MFI",
"-DHAVE_MICROPHONE",
"-DHAVE_MINIUPNPC",
"-DHAVE_NETPLAYDISCOVERY",
"-DHAVE_NETPLAYDISCOVERY_NSNET",
Expand Down Expand Up @@ -2566,6 +2567,7 @@
"-DHAVE_UPDATE_ASSETS",
"-DHAVE_UPDATE_CORE_INFO",
"-DHAVE_VIDEO_FILTER",
"-DHAVE_VULKAN",
"-DHAVE_XDELTA",
"-DHAVE_XMB",
"-DHAVE_ZLIB",
Expand Down

0 comments on commit 070e4d2

Please sign in to comment.