ios - 从 Core Audio Callback 更新 UI 的最佳实践是什么?

标签 ios c swift callback core-audio

我目前正全神贯注于 Core Audio,我被如何更新 GUI AudioQueueInputCallback 的问题击中了。首先,我想用从麦克风读取的电平表更新标签。

在我的代码中,我将当前电平表值存储在每个回调的结构中。

func MyAudioQueueInputCallback(inUserData: UnsafeMutablePointer<Void>, inAQ: AudioQueueRef, inBuffer: AudioQueueBufferRef, inStartTime: UnsafePointer<AudioTimeStamp>, var inNumberPacketDesc: UInt32, inPacketDesc: UnsafePointer<AudioStreamPacketDescription>){

var error: OSStatus

if (inNumberPacketDesc > 0){

    error = AudioFileWritePackets(MyRecorder.recordFile, false, inBuffer.memory.mAudioDataByteSize, inPacketDesc, MyRecorder.recordPacket, &inNumberPacketDesc, inBuffer.memory.mAudioData)
    checkError(error, operation: "AudioFileWritePackets Failed ")

    // Increment the packet index
    MyRecorder.recordPacket += Int64(inNumberPacketDesc)

    if (MyRecorder.running){
        error = AudioQueueEnqueueBuffer(inAQ, inBuffer, inNumberPacketDesc, inPacketDesc)
        checkError(error, operation: "AudioQueueEnqueueBuffer Failed BAHHHH")

        var level: Float32 = 0
        var levelSize = UInt32(sizeof(level.dynamicType))
        error = AudioQueueGetProperty(inAQ, kAudioQueueProperty_CurrentLevelMeter, &level, &levelSize)
        checkError(error, operation: "AudioQueueGetProperty Failed...  Get help!")

        MyRecorder.meterLevel = level // meter level stored in public struct
    } 
}    

//MARK:  User Data Struct / Class
struct MyRecorder {
    static var recordFile: AudioFileID = nil
    static var recordPacket: Int64 = 0
    static var running: Bool = false
    static var queue: AudioQueueRef = nil
    static var meterLevel: Float32 = 0.00
}

从这里开始,在主线程上使用 NSTimer 轮询 meterLevel 变量。

func setMeterLabel() -> Void{

    meter.text = String(MyRecorder.meterLevel)

}

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    main()

    var timer = NSTimer.scheduledTimerWithTimeInterval(0.05, target: self, selector: "setMeterLabel", userInfo: nil, repeats: true)

}

这段代码工作得很好,但我觉得使用 NSTimer 可能不是最好的方法。有没有办法让我的回调直接更新标签?

最佳答案

使用重复的 NSTimer 或 CADisplayLink 是执行此操作的良好且标准的方法。任何其他方法都可能导致您的音频回调阻塞时间过长。

您知道音频采样率和音频缓冲区的大小。因此,您大致知道新数据缓冲区出现的频率。因此,在 2 种速率中最慢的(新音频缓冲速率或您想要的帧动画速率,通常为 60 或 30 Hz 或更慢),您可以设置重复计时器回调(或 CADisplayLink 计时器回调)以轮询是否有新音频数据已被记录,并做一些事情,例如在需要更新的某些 View 上调用 setNeedsDisplay。 (UIView drawRect 更新将始终在主 UI 线程上调用)。

将状态或数据从音频回调传递到计时器回调的一种好方法是使用无锁循环 FIFO/缓冲区。然后你保证永远不会阻塞你的音频回调线程。

如果您在 UI 线程上运行计时器回调,则无需对同一线程执行异步分派(dispatch)。

关于ios - 从 Core Audio Callback 更新 UI 的最佳实践是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36053250/

相关文章:

iOS UITextField addTarget 和 textFieldDidEndEditing 之间的区别

ios - 结合导航 Controller 和标签栏 Controller

ios - 如何在自动调整 UIView 后获取真实框架

c++ - 开机自检

编码二叉搜索树

ios - 使用 Swift 使用 Segue 发送数据

ios - 共享 iAd 横幅

objective-c - 启动模态视图 Controller 来解决选项卡栏和导航 VC 的方向 "lock"?

PHP处理大字符串

ios - 在 iOS 中移动 Google map 信息窗口