Swift 中的 AURenderCallback
AURenderCallback in Swift
我正在创建一个使用音频单元的应用程序,虽然 Objective-C 中有很多代码示例(包括 Apple 自己的 aurioTouch 和其他),但我正试图在 [=41= 中编写整个代码].
我已经能够通过它设置我的 AUGraph 和 运行 一些音频,但我似乎无法弄清楚渲染回调的语法。我尝试了几种方法:
方法一:直接创建AURenderCallback
let render : AURenderCallback = { (
inRefCon: UnsafeMutablePointer<Void>,
ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBufNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus in
return noErr
}
我在这个回调中除了返回 noErr 之外什么都不做,因为我只是想让它工作。但是,编译returns出现如下错误:
(UnsafeMutablePointer,
UnsafeMutablePointer,
UnsafePointer, UInt32, UInt32,
UnsafeMutablePointer) -> OSStatus' is not convertible
to 'AURenderCallback
文档中AURenderCallback的定义是这样的:
typealias AURenderCallback = (UnsafeMutablePointer<Void>,UnsafeMutablePointer<AudioUnitRenderActionFlags>,UnsafePointer<AudioTimeStamp>, UInt32, UInt32,UnsafeMutablePointer<AudioBufferList>) -> OSStatus
好像和我输入的一样,虽然可能是我不明白文档要求什么。
方法二:创建一个代表AURenderCallback的函数
func render(
inRefCon: UnsafeMutablePointer<Void>,
ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBufNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus {
return noErr
}
这不会作为函数给出任何错误,但是当我将它放入 inputProc 参数中的 AURenderCallbackStruct 时,我收到一个错误:
Cannot find an initializer for type 'AURenderCallbackStruct' that
accepts an argument list of type '(inputProc:
(UnsafeMutablePointer,
UnsafeMutablePointer,
UnsafePointer, UInt32, UInt32,
UnsafeMutablePointer) -> OSStatus, inputProcRefCon:
nil)
我在Swift中没有找到很多创建AURenderCallbacks的例子,而且和Objective-C相比语法上似乎有很大差异。任何帮助将不胜感激。
我刚刚找到你的 post,同时试图找出相同的(找到示例代码和结合 CoreAudio/Audio 单元和 Swift 的示例并不容易)。
通过查看 this repository and reading (several times :-)) Apples documentation about Using Swift with Cocoa and Objective-C,我设法拼凑了一些东西。正如Function Pointers
部分所说
When calling a function that takes a function pointer argument, you can pass a top-level Swift function, a closure literal, or nil.
所以。在我的 class 之外,我有一个看起来像这样的方法:
func renderCallback(inRefCon:UnsafeMutablePointer<Void>,
ioActionFlags:UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp:UnsafePointer<AudioTimeStamp>,
inBusNumber:UInt32,
inNumberFrames:UInt32,
ioData:UnsafeMutablePointer<AudioBufferList>) -> OSStatus {
let delegate = unsafeBitCast(inRefCon, AURenderCallbackDelegate.self)
let result = delegate.performRender(ioActionFlags,
inTimeStamp: inTimeStamp,
inBusNumber: inBusNumber,
inNumberFrames: inNumberFrames,
ioData: ioData)
return result
}
如您所见,我只是在这里调用了一个代理。那个委托是这样声明的(也在 class 之外,但你已经知道了:-))
@objc protocol AURenderCallbackDelegate {
func performRender(ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBusNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus
}
这样做使我能够 "get back inside my class" 通过符合 AURenderCallbackDelegate
像这样:
class AudioUnitGraphManager: NSObject, AURenderCallbackDelegate
然后在我的 AudioUnitGraphManager
class
中实现 renderCallback
方法
func performRender(ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, inTimeStamp: UnsafePointer<AudioTimeStamp>, inBusNumber: UInt32, inNumberFrames: UInt32, ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus {
print("Hello there!")
return noErr
}
最后一块拼图是实际启用我喜欢的渲染通知回调:
AudioUnitAddRenderNotify(mixerUnit, renderCallback, UnsafeMutablePointer(unsafeAddressOf(self)))
希望这能给你继续奋斗的动力。
变化 Swift 3
在 Swift 3 中 AURenderCallback
的声明已更改为:
typealias AURenderCallback = (UnsafeMutableRawPointer, UnsafeMutablePointer<AudioUnitRenderActionFlags>, UnsafePointer<AudioTimeStamp>, UInt32, UInt32, UnsafeMutablePointer<AudioBufferList>?) -> OSStatus
请注意,与之前的 UnsafeMutablePointer<AudioBufferList>
相比,最后一个参数现在是 UnsafeMutablePointer<AudioBufferList>?
(现在是可选参数)。
这意味着代码现在看起来像这样。
renderCallback
函数
func renderCallback(inRefCon:UnsafeMutablePointer<Void>,
ioActionFlags:UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp:UnsafePointer<AudioTimeStamp>,
inBusNumber:UInt32,
inNumberFrames:UInt32,
ioData:UnsafeMutablePointer<AudioBufferList>?) -> OSStatus {
let delegate = unsafeBitCast(inRefCon, AURenderCallbackDelegate.self)
let result = delegate.performRender(ioActionFlags,
inTimeStamp: inTimeStamp,
inBusNumber: inBusNumber,
inNumberFrames: inNumberFrames,
ioData: ioData)
return result
}
AURenderCallbackDelegate
协议
@objc protocol AURenderCallbackDelegate {
func performRender(ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBusNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList>?) -> OSStatus
}
实际执行performRender
func performRender(ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, inTimeStamp: UnsafePointer<AudioTimeStamp>, inBusNumber: UInt32, inNumberFrames: UInt32, ioData: UnsafeMutablePointer<AudioBufferList>?) -> OSStatus {
print("Hello there!")
return noErr
}
启用渲染通知回调
AudioUnitAddRenderNotify(mixerUnit!, renderCallback, Unmanaged.passUnretained(self).toOpaque())
我来晚了一点,但我找到了一种可能比上述答案更直接的方法。我们可以使用您可以在回调结构中设置的 inRefCon
指针。 inRefCon
被传递给您的回调函数,因此如果您将 inRefCon
设置为您的 class 引用,您可以直接“找到回到 class 的方式”而无需去loopdyloop 与代表。这是我的做法:
/* below code is inside some function in MyClass */
var callbackStruct = AURenderCallbackStruct()
// set inRefCon to reference to self by casting to pointer
callbackStruct.inputProcRefCon = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
// create our C closure
callbackStruct.inputProc = {
(inRefCon : UnsafeMutableRawPointer,
ioActionFlags : UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp : UnsafePointer<AudioTimeStamp>,
inBusNumber : UInt32,
inNumberFrames : UInt32,
ioData : UnsafeMutablePointer<AudioBufferList>?) -> OSStatus in
// get reference to my class by de-referencing inRefCon
let _self = Unmanaged<MyClass>.fromOpaque(inRefCon).takeUnretainedValue()
// time to profit with reference to our class _self
// ...
return 0
}
// set callback
AudioUnitSetProperty(audioUnit!,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
0,
&callbackStruct,
UInt32(MemoryLayout.size(ofValue: callbackStruct)))
我正在创建一个使用音频单元的应用程序,虽然 Objective-C 中有很多代码示例(包括 Apple 自己的 aurioTouch 和其他),但我正试图在 [=41= 中编写整个代码].
我已经能够通过它设置我的 AUGraph 和 运行 一些音频,但我似乎无法弄清楚渲染回调的语法。我尝试了几种方法:
方法一:直接创建AURenderCallback
let render : AURenderCallback = { (
inRefCon: UnsafeMutablePointer<Void>,
ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBufNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus in
return noErr
}
我在这个回调中除了返回 noErr 之外什么都不做,因为我只是想让它工作。但是,编译returns出现如下错误:
(UnsafeMutablePointer, UnsafeMutablePointer, UnsafePointer, UInt32, UInt32, UnsafeMutablePointer) -> OSStatus' is not convertible to 'AURenderCallback
文档中AURenderCallback的定义是这样的:
typealias AURenderCallback = (UnsafeMutablePointer<Void>,UnsafeMutablePointer<AudioUnitRenderActionFlags>,UnsafePointer<AudioTimeStamp>, UInt32, UInt32,UnsafeMutablePointer<AudioBufferList>) -> OSStatus
好像和我输入的一样,虽然可能是我不明白文档要求什么。
方法二:创建一个代表AURenderCallback的函数
func render(
inRefCon: UnsafeMutablePointer<Void>,
ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBufNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus {
return noErr
}
这不会作为函数给出任何错误,但是当我将它放入 inputProc 参数中的 AURenderCallbackStruct 时,我收到一个错误:
Cannot find an initializer for type 'AURenderCallbackStruct' that accepts an argument list of type '(inputProc: (UnsafeMutablePointer, UnsafeMutablePointer, UnsafePointer, UInt32, UInt32, UnsafeMutablePointer) -> OSStatus, inputProcRefCon: nil)
我在Swift中没有找到很多创建AURenderCallbacks的例子,而且和Objective-C相比语法上似乎有很大差异。任何帮助将不胜感激。
我刚刚找到你的 post,同时试图找出相同的(找到示例代码和结合 CoreAudio/Audio 单元和 Swift 的示例并不容易)。
通过查看 this repository and reading (several times :-)) Apples documentation about Using Swift with Cocoa and Objective-C,我设法拼凑了一些东西。正如Function Pointers
When calling a function that takes a function pointer argument, you can pass a top-level Swift function, a closure literal, or nil.
所以。在我的 class 之外,我有一个看起来像这样的方法:
func renderCallback(inRefCon:UnsafeMutablePointer<Void>,
ioActionFlags:UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp:UnsafePointer<AudioTimeStamp>,
inBusNumber:UInt32,
inNumberFrames:UInt32,
ioData:UnsafeMutablePointer<AudioBufferList>) -> OSStatus {
let delegate = unsafeBitCast(inRefCon, AURenderCallbackDelegate.self)
let result = delegate.performRender(ioActionFlags,
inTimeStamp: inTimeStamp,
inBusNumber: inBusNumber,
inNumberFrames: inNumberFrames,
ioData: ioData)
return result
}
如您所见,我只是在这里调用了一个代理。那个委托是这样声明的(也在 class 之外,但你已经知道了:-))
@objc protocol AURenderCallbackDelegate {
func performRender(ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBusNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus
}
这样做使我能够 "get back inside my class" 通过符合 AURenderCallbackDelegate
像这样:
class AudioUnitGraphManager: NSObject, AURenderCallbackDelegate
然后在我的 AudioUnitGraphManager
class
renderCallback
方法
func performRender(ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, inTimeStamp: UnsafePointer<AudioTimeStamp>, inBusNumber: UInt32, inNumberFrames: UInt32, ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus {
print("Hello there!")
return noErr
}
最后一块拼图是实际启用我喜欢的渲染通知回调:
AudioUnitAddRenderNotify(mixerUnit, renderCallback, UnsafeMutablePointer(unsafeAddressOf(self)))
希望这能给你继续奋斗的动力。
变化 Swift 3
在 Swift 3 中 AURenderCallback
的声明已更改为:
typealias AURenderCallback = (UnsafeMutableRawPointer, UnsafeMutablePointer<AudioUnitRenderActionFlags>, UnsafePointer<AudioTimeStamp>, UInt32, UInt32, UnsafeMutablePointer<AudioBufferList>?) -> OSStatus
请注意,与之前的 UnsafeMutablePointer<AudioBufferList>
相比,最后一个参数现在是 UnsafeMutablePointer<AudioBufferList>?
(现在是可选参数)。
这意味着代码现在看起来像这样。
renderCallback
函数
func renderCallback(inRefCon:UnsafeMutablePointer<Void>,
ioActionFlags:UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp:UnsafePointer<AudioTimeStamp>,
inBusNumber:UInt32,
inNumberFrames:UInt32,
ioData:UnsafeMutablePointer<AudioBufferList>?) -> OSStatus {
let delegate = unsafeBitCast(inRefCon, AURenderCallbackDelegate.self)
let result = delegate.performRender(ioActionFlags,
inTimeStamp: inTimeStamp,
inBusNumber: inBusNumber,
inNumberFrames: inNumberFrames,
ioData: ioData)
return result
}
AURenderCallbackDelegate
协议
@objc protocol AURenderCallbackDelegate {
func performRender(ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBusNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList>?) -> OSStatus
}
实际执行performRender
func performRender(ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, inTimeStamp: UnsafePointer<AudioTimeStamp>, inBusNumber: UInt32, inNumberFrames: UInt32, ioData: UnsafeMutablePointer<AudioBufferList>?) -> OSStatus {
print("Hello there!")
return noErr
}
启用渲染通知回调
AudioUnitAddRenderNotify(mixerUnit!, renderCallback, Unmanaged.passUnretained(self).toOpaque())
我来晚了一点,但我找到了一种可能比上述答案更直接的方法。我们可以使用您可以在回调结构中设置的 inRefCon
指针。 inRefCon
被传递给您的回调函数,因此如果您将 inRefCon
设置为您的 class 引用,您可以直接“找到回到 class 的方式”而无需去loopdyloop 与代表。这是我的做法:
/* below code is inside some function in MyClass */
var callbackStruct = AURenderCallbackStruct()
// set inRefCon to reference to self by casting to pointer
callbackStruct.inputProcRefCon = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
// create our C closure
callbackStruct.inputProc = {
(inRefCon : UnsafeMutableRawPointer,
ioActionFlags : UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp : UnsafePointer<AudioTimeStamp>,
inBusNumber : UInt32,
inNumberFrames : UInt32,
ioData : UnsafeMutablePointer<AudioBufferList>?) -> OSStatus in
// get reference to my class by de-referencing inRefCon
let _self = Unmanaged<MyClass>.fromOpaque(inRefCon).takeUnretainedValue()
// time to profit with reference to our class _self
// ...
return 0
}
// set callback
AudioUnitSetProperty(audioUnit!,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
0,
&callbackStruct,
UInt32(MemoryLayout.size(ofValue: callbackStruct)))