适用于 macOS 的 Xcode 应用程序。这就是我设置从 USB 麦克风输入获取音频的方式。一年前工作,现在不行。为啥
Posted
技术标签:
【中文标题】适用于 macOS 的 Xcode 应用程序。这就是我设置从 USB 麦克风输入获取音频的方式。一年前工作,现在不行。为啥【英文标题】:Xcode app for macOS. This is how I setup to get audio from usb mic input. Worked a year ago, now doesn't. Why适用于 macOS 的 Xcode 应用程序。这就是我设置从 USB 麦克风输入获取音频的方式。一年前工作,现在不行。为什么 【发布时间】:2020-05-17 21:16:03 【问题描述】:这是我的音频初始化代码。当队列缓冲区准备好时,我的应用程序会做出响应,但缓冲区中的所有数据都为零。检查系统首选项中的声音表明声音输入对话框中的 USB 音频编解码器处于活动状态。应用启动后立即调用 AudioInit()。
#pragma mark user data struct
typedef struct MyRecorder
AudioFileID recordFile;
SInt64 recordPacket;
Float32 *pSampledData;
MorseDecode *pMorseDecoder;
MyRecorder;
#pragma mark utility functions
void CheckError(OSStatus error, const char *operation)
if(error == noErr) return;
char errorString[20];
// see if it appears to be a 4 char code
*(UInt32*)(errorString + 1) = CFSwapInt32HostToBig(error);
if (isprint(errorString[1]) && isprint(errorString[2]) &&
isprint(errorString[3]) && isprint(errorString[4]))
errorString[0] = errorString[5] = '\'';
errorString[6] = '\0';
else
sprintf(errorString, "%d", (int)error);
fprintf(stderr, "Error: %s (%s)\n", operation, errorString);
OSStatus MyGetDefaultInputDeviceSampleRate(Float64 *outSampleRate)
OSStatus error;
AudioDeviceID deviceID = 0;
AudioObjectPropertyAddress propertyAddress;
UInt32 propertySize;
propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = 0;
propertySize = sizeof(AudioDeviceID);
error = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&propertyAddress,
0,
NULL,
&propertySize,
&deviceID);
if(error)
return error;
propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate;
propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
propertyAddress.mElement = 0;
propertySize = sizeof(Float64);
error = AudioObjectGetPropertyData(deviceID,
&propertyAddress,
0,
NULL,
&propertySize,
outSampleRate);
return error;
static int MyComputeRecordBufferSize(const AudiostreamBasicDescription *format,
AudioQueueRef queue,
float seconds)
int packets, frames, bytes;
frames = (int)ceil(seconds * format->mSampleRate);
if(format->mBytesPerFrame > 0)
bytes = frames * format->mBytesPerFrame;
else
UInt32 maxPacketSize;
if(format->mBytesPerPacket > 0)
// constant packet size
maxPacketSize = format->mBytesPerPacket;
else
// get the largest single packet size possible
UInt32 propertySize = sizeof(maxPacketSize);
CheckError(AudioQueueGetProperty(queue,
kAudioConverterPropertyMaximumOutputPacketSize,
&maxPacketSize,
&propertySize),
"Couldn't get queues max output packet size");
if(format->mFramesPerPacket > 0)
packets = frames / format->mFramesPerPacket;
else
// worst case scenario: 1 frame in a packet
packets = frames;
// sanity check
if(packets == 0)
packets = 1;
bytes = packets * maxPacketSize;
return bytes;
extern void bridgeToMainThread(MorseDecode *pDecode);
static int callBacks = 0;
// ---------------------------------------------
static void MyAQInputCallback(void *inUserData,
AudioQueueRef inQueue,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription *inPacketDesc)
MyRecorder *recorder = (MyRecorder*)inUserData;
Float32 *pAudioData = (Float32*)(inBuffer->mAudioData);
recorder->pMorseDecoder->pBuffer = pAudioData;
recorder->pMorseDecoder->bufferSize = inNumPackets;
bridgeToMainThread(recorder->pMorseDecoder);
CheckError(AudioQueueEnqueueBuffer(inQueue,
inBuffer,
0,
NULL),
"AudioQueueEnqueueBuffer failed");
printf("packets = %ld, bytes = %ld\n",(long)inNumPackets,(long)inBuffer->mAudioDataByteSize);
callBacks++;
//printf("\ncallBacks = %d\n",callBacks);
//if(callBacks == 0)
//audioStop();
static AudioQueueRef queue = 0;
static MyRecorder recorder = 0;
static AudioStreamBasicDescription recordFormat;
void audioInit()
// set up format
memset(&recordFormat,0,sizeof(recordFormat));
recordFormat.mFormatID = kAudioFormatLinearPCM;
recordFormat.mChannelsPerFrame = 2;
recordFormat.mBitsPerChannel = 32;
recordFormat.mBytesPerPacket = recordFormat.mBytesPerFrame = recordFormat.mChannelsPerFrame * sizeof(Float32);
recordFormat.mFramesPerPacket = 1;
//recordFormat.mFormatFlags = kAudioFormatFlagsCanonical;
recordFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
MyGetDefaultInputDeviceSampleRate(&recordFormat.mSampleRate);
UInt32 propSize = sizeof(recordFormat);
CheckError(AudioFormatGetProperty(kAudioFormatProperty_FormatInfo,
0,
NULL,
&propSize,
&recordFormat),
"AudioFormatProperty failed");
recorder.pMorseDecoder = MorseDecode::pInstance();
recorder.pMorseDecoder->m_sampleRate = recordFormat.mSampleRate;
// recorder.pMorseDecoder->setCircularBuffer();
//set up queue
CheckError(AudioQueueNewInput(&recordFormat,
MyAQInputCallback,
&recorder,
NULL,
kCFRunLoopCommonModes,
0,
&queue),
"AudioQueueNewInput failed");
UInt32 size = sizeof(recordFormat);
CheckError(AudioQueueGetProperty(queue,
kAudioConverterCurrentOutputStreamDescription,
&recordFormat,
&size), "Couldn't get queue's format");
// set up buffers and enqueue
const int kNumberRecordBuffers = 3;
int bufferByteSize = MyComputeRecordBufferSize(&recordFormat, queue, AUDIO_BUFFER_DURATION);
for(int bufferIndex = 0; bufferIndex < kNumberRecordBuffers; bufferIndex++)
AudioQueueBufferRef buffer;
CheckError(AudioQueueAllocateBuffer(queue,
bufferByteSize,
&buffer),
"AudioQueueAllocateBuffer failed");
CheckError(AudioQueueEnqueueBuffer(queue,
buffer,
0,
NULL),
"AudioQueueEnqueueBuffer failed");
void audioRun()
CheckError(AudioQueueStart(queue, NULL), "AudioQueueStart failed");
void audioStop()
CheckError(AudioQueuePause(queue), "AudioQueuePause failed");
【问题讨论】:
如何将我的应用列表添加到麦克风访问列表中?我在 Xcode 中工作并使用调试器运行。我需要做些什么来安装它以便 macOS 识别它吗? 你不能。此行为旨在让用户控制哪些应用程序可以访问麦克风。 【参考方案1】:这听起来像是新的 macOS 的“麦克风隐私”设置,如果将您的应用设置为“禁止访问”,则会导致这种行为。所以:
打开“系统偏好设置”窗格。
点击“安全和隐私”。
选择“隐私”选项卡。
点击左侧窗格中的“麦克风”。
在右侧窗格中找到您的应用并勾选旁边的复选框。
然后重新启动您的应用并进行测试。
乏味,不是吗?
编辑:如 cmets 中所述,您不能直接请求麦克风访问权限,但您可以通过调用 [AVCaptureDevice authorizationStatusForMediaType: AVMediaTypeAudio]
来检测它是否已授予您的应用程序。
【讨论】:
我没有专门使用麦克风,该设备名为“USB”类型的“USB Audio CODEC”。我在输入选项卡下的系统偏好设置的声音框中选择了它。它在输入电平指示器中显示活动。 “麦克风”是 Apple 所说的任何形式的音频输入,系统偏好设置面板中的信号是偶然的。被阻止的是您的应用的信号,上述步骤将修复它。 那么我需要知道如何进行。我的应用程序是否可以通过某种方式请求访问权限,然后将其传递给可以允许访问的用户?当我转到隐私选项卡时,我看不到我的应用程序。如何将它添加到我可以授予访问权限的需要访问权限的应用列表中? 当您的应用程序第一次尝试访问“麦克风”时,MacOS 会弹出一个框询问用户他/她是否希望允许它。如果他们说是,那么 MacOS 会记住该选择并允许此后访问您的应用程序。您的应用也将出现在隐私选项卡中,并勾选复选框。如果他们说不,那么您的应用将在此后收到无声的音频流,并且它会出现在隐私选项卡中,且复选框未选中。 您无法直接影响任何此类行为,但请参阅我的编辑。以上是关于适用于 macOS 的 Xcode 应用程序。这就是我设置从 USB 麦克风输入获取音频的方式。一年前工作,现在不行。为啥的主要内容,如果未能解决你的问题,请参考以下文章
在 MacOS 上构建 SwiftUI “Hello World”
SwiftUI Preview 不适用于 MacOS 构建,而它适用于 iOS 构建