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 定义。
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 定义。