【发布时间】:2012-11-29 10:18:34
【问题描述】:
我目前正在学习在 iOS 中使用音频队列服务。为此,我关注了Audio Queue Services Programming Guide - Recording Audio。这行得通。
现在我想在callback function 接收到来自麦克风的输入数据时更新一个 UI 元素(功率计)。这就是我遇到问题的地方。
我不确定从回调函数调用视图/视图控制器以更新功率计的好方法是什么。我试过这个: 对于指南中描述的custom struct to manage state,我添加了一个指向我的视图控制器的指针:
struct AQRecorderState {
AudioStreamBasicDescription mDataFormat; // 2
AudioQueueRef mQueue; // 3
AudioQueueBufferRef mBuffers[kNumberBuffers]; // 4
AudioFileID mAudioFile; // 5
UInt32 bufferByteSize; // 6
SInt64 mCurrentPacket; // 7
bool mIsRunning; // 8
void* mViewController; // <- I've added this line
};
我在开始录制时初始化此指针。这是在视图控制器的方法中完成的,当开始按钮接收到 TouchUp 事件时会调用该方法:
- (IBAction)startAudioRecording:(id)sender {
struct AQRecorderState* aqData = createAQRecorderState();
void* pViewControllerAsVoidPointer = (__bridge void*) self;
aqData->mViewController = pViewControllerAsVoidPointer;
//...
分配结构体的方法createAQRecorderState()如下所示:
struct AQRecorderState* createAQRecorderState() {
struct AQRecorderState* pAqData = (struct AQRecorderState*) malloc(sizeof(AQRecorderState));
initializeAQRecorderState(*pAqData); // sets members of the struct; does not set pointer to view controller
return pAqData;
}
AFAIK,我在开始录制时创建的结构的实例被传递给以后对回调函数的调用。为此,我在回调函数中添加了以下代码,以便随后调用视图控制器:
void HandleInputBuffer(
void *aqData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription *inPacketDesc
) {
//...
NSLog(@"interesting part start");
void* pViewControllerAsVoidPtr = pAqData->mViewController;
NSLog(@"localized pointer to void");
ViewController* pViewController = (__bridge ViewController*) pViewControllerAsVoidPtr; //EXC_BAD_ACCESS
NSLog(@"localized pointer to ViewController");
//...
}
但是,当我进行桥接指针转换时,我在上面标记行的回调函数中得到了 EXC_BAD_ACCESS (code=1, address=0xffffffff)。然后我用调试器检查了这一点,实际上pViewControllerAsVoidPtr 不保存了我在执行方法startAudioRecording: 期间存储在pAqData->mViewController 中的地址。
为什么指针会改变?或者:如何正确地从我的回调函数调用到视图控制器以更新 UI?
【问题讨论】:
-
除非已更新,否则 SpeakHere 示例是 ARC 之前的示例。您是否已将其转换为 ARC?我假设这是您使用的示例项目,因为它使用音频队列来控制电平表。
-
我确实在我的项目中使用了 ARC。代码与 ARC 的兼容性是我将遵循的一个好主意。我也不得不承认我并不完全理解桥接指针转换。但是,我没有使用示例项目。我使用了一个新创建的项目,并从我链接到的指南中复制了大部分代码。
-
@MaxMacLeod,顺便说一句,看看 SpeakHere 示例是个好主意。如果他们使用音频队列并有电平表,那么我应该能够在那里看到它是如何完成的。
-
大好时光!这正是你所需要的。 Btw AudioQueue 可能不适合您,具体取决于您在做什么。 AudioUnit 可以更容易使用。此外,如果您使用 SpeakHere,它不是 ARC,因此只需为项目中的这些类设置编译器标志。检查我的答案。我介绍了很多与 SpeakHere 相关的 AudioQueue 和 AudioUnit 问题。
标签: objective-c ios uiviewcontroller callback audioqueueservices