Objective-C/Swift 在 AudioUnit Render 回调中的用法

Objective-C/Swift usage in AudioUnit Render callback

Apple 建议不要在 AudioUnit 输入或渲染回调中使用 Objective-C 和 Swift。所以回调主要是用 C 语言编写的,我们可以在其中快速复制数据并将该数据传递给辅助线程进行处理。要在 C 和 Objective C 之间共享变量,建议使用 inRefCon 作为指向 Controller 对象的指针,然后访问它的变量。在下面的代码中,我访问了 MyController 对象的两个成员变量——muteAudio 和回调队列。这不是完整的代码,只是突出问题的示例。

 static OSStatus renderCallback       (void *                            inRefCon,
                                     AudioUnitRenderActionFlags *      ioActionFlags,
                                     const AudioTimeStamp *            inTimeStamp,
                                     UInt32                            inBusNumber,
                                     UInt32                            inNumberFrames,
                                     AudioBufferList *                 ioData)

 {
     MyController* THIS = (MyController *)inRefCon;

    if (!THIS->muteAudio) {
         for (UInt32 i=0; i<ioData->mNumberBuffers; ++i)
         memset(ioData->mBuffers[i].mData, 0, ioData->mBuffers[i].mDataByteSize);
      return noErr;
    }

    OSStatus status = AudioUnitRender(THIS->mAudioUnit,
                         ioActionFlags,
                         inTimeStamp,
                         kInputBus,
                         inNumberFrames,
                         ioData);

  if (status != noErr) {
    // printf("Render error %d", status);
  }

 dispatch_async(THIS->mCallbackQueue,^{ 
   //Execute some code
     if (THIS->mActive) {
      ....
     }
 });

 return noErr;
}

我的问题:

一个。诸如 THIS->silentAudio 之类的调用访问 MyController 实例的成员变量与 Objective C 消息传递访问属性有什么不同吗?我的理解是像 THIS->silentAudio 这样的调用实际上是直接访问指针位置的内存,而不是 Objective C 消息传递,但只是为了确认这是否正确。

b。我如何将上面的 (THIS->silentAudio) 准确翻译成 Swift? Swift 运行时是否会像 Objective C 一样使用指针而不是消息传递来访问 MyController 的私有变量?

c。在 Swift 的情况下,implicit/explicit 展开是否会影响性能?

请原谅我对 Swift 的了解,因为我是新手。

编辑:根据 hotpaw2 的回答,我将代码翻译如下:

  func renderCallback(inRefCon:UnsafeMutableRawPointer,                        ioActionFlags:UnsafeMutablePointer<AudioUnitRenderActionFlags>,
                inTimeStamp:UnsafePointer<AudioTimeStamp>,
                inBusNumber:UInt32,
                inNumberFrames:UInt32,
                ioData:UnsafeMutablePointer<AudioBufferList>?) -> OSStatus
 {
    let controller = unsafeBitCast(inRefCon, to: MyController) 

    if !controller.muteAudio {
       ....
    }

    return noErr;

}

我现在怀疑 controller.muteAudio 是否确实被 Swift 编译器翻译为对内存 baseAddress + 偏移量的访问,或者它可以是 Swift 消息传递。

C 代码不会通过 Objective C 运行时调用 Objective C 消息(除非使用传递给消息函数的指针显式完成)。但是 Xcode C 编译器确实知道 Objective C object 的内存布局;所以 (THIS->silentAudio) 在 C 中编译为基指针 + 偏移内存访问代码。

通过在 C 结构指针上使用 UnsafeRawPointers、UnsafeMutableRawPointers 和 unsafeBitCasts,您可以获得 Swift 中基指针 + 偏移量访问的等价物。 Wrapped 在处理不安全指针时没有意义,你需要自己检查它们的有效性。

您可能需要使用 C 结构或 Objective C object 与 Swift 代码共享数据结构,因为 non-Swift 语言编译器可能不知道或不知道能够使用 Swift object 的布局。而 Swift 编译器可以通过使用桥接 header 以另一种方式找出内存布局,它可以包含 C 结构和 Obj C class 和 object 定义。