在iOS 10中实现异步调用有效同步的最佳方法
为了更好地解释我的情况,我正在尝试制作一个应用程序,当按下一个按钮时,它会发出ping的声音,然后在按下按钮后立即录制和转录用户的声音 对于ping声音,我使用系统声音服务,录制音频,我使用AudioToolbox,转录它,我使用语音工具包 我认为问题的关键在于异步系统声音服务发挥功能的时间安排:在iOS 10中实现异步调用有效同步的最佳方法,ios,asynchronous,audio,swift3,ios10,Ios,Asynchronous,Audio,Swift3,Ios10,为了更好地解释我的情况,我正在尝试制作一个应用程序,当按下一个按钮时,它会发出ping的声音,然后在按下按钮后立即录制和转录用户的声音 对于ping声音,我使用系统声音服务,录制音频,我使用AudioToolbox,转录它,我使用语音工具包 我认为问题的关键在于异步系统声音服务发挥功能的时间安排: //Button pressed function let audiosession = AVAudioSession.sharedInstance() let filen
//Button pressed function
let audiosession = AVAudioSession.sharedInstance()
let filename = "Ping"
let ext = "wav"
if let soundUrl = Bundle.main.url(forResource: filename, withExtension: ext){
var soundId: SystemSoundID = 0
AudioServicesCreateSystemSoundID(soundUrl as CFURL, &soundId)
AudioServicesAddSystemSoundCompletion(soundId, nil, nil, {(soundid,_) -> Void in
AudioServicesDisposeSystemSoundID(soundid)
print("Sound played!")}, nil)
AudioServicesPlaySystemSound(soundId)
}
do{
try audiosession.setCategory(AVAudioSessionCategoryRecord)
try audiosession.setMode(AVAudioSessionModeMeasurement)
try audiosession.setActive(true, with: .notifyOthersOnDeactivation)
print("Changing modes!")
}catch{
print("error with audio session")
}
recognitionRequest = SFSpeechAudioBufferRecognitionRequest()
guard let inputNode = audioEngine.inputNode else{
fatalError("Audio engine has no input node!")
}
guard let recognitionRequest = recognitionRequest else{
fatalError("Unable to create a speech audio buffer recognition request object")
}
recognitionRequest.shouldReportPartialResults = true
recognitionTask = speechRecognizer?.recognitionTask(with: recognitionRequest, delegate: self)
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { (buffer, when) in
self.recognitionRequest?.append(buffer)
}
audioEngine.prepare()
do{
try audioEngine.start()
delegate?.didStartRecording()
}catch{
print("audioEngine couldn't start because of an error")
}
当我运行这段代码时,它会成功地录制语音并转录。然而,乒乓球从来没有打过。我这里的两条(无错误)打印语句按顺序排列:
var me = self
let userData = withUnsafePointer(to: &me) { ptr in
return unsafeBitCast(ptr, to: UnsafeMutableRawPointer.self)
接下来,我在回调块中使用该常量,并尝试从中访问self:
AudioServicesAddSystemSoundCompletion(soundId, nil, nil, {(sounded,me) -> Void in
AudioServicesDisposeSystemSoundID(sounded)
let myself = Unmanaged<myclassname>.fromOpaque(me!).takeRetainedValue()
myself.doOtherStuff()
print("Sound played!")}, userData)
AudioServicesAddSystemSoundCompletion(soundId,nil,nil,{(sounded,me)->中的Void
AudioServicesDisposeSystemSoundID(已发声)
让我自己=Unmanaged.from不透明(我!).takeRetainedValue()
我自己
打印(“播放声音!”)},用户数据)
尝试在完成块中调用doOtherStuff()是正确的方法(唯一的另一个是通知,这是唯一的两个选项)
在这种情况下,使其复杂化的是从Obj-C到Swift的必要桥接。执行此操作的代码是:
let myData = unsafeBitCast(self, UnsafeMutablePointer<Void>.self)
AudioServicesAddSystemSoundCompletion(YOUR_SOUND_ID, CFRunLoopGetMain(), kCFRunLoopDefaultMode,{ (mSound, mVoid) in
let me = unsafeBitCast(mVoid, YOURCURRENTCLASS.self)
//me it is your current object so if yo have a variable like
// var someVar you can do
print(me.someVar)
}, myData)
let myData=unsafeBitCast(self,UnsafeMutablePointer.self)
AudioServicesAddSystemSoundCompletion(您的声音ID,CFRunLoopGetMain(),kCFRunLoopDefaultMode,{(mSound,mVoid)在
let me=unsafeBitCast(mVoid,YOURCURRENTCLASS.self)
//如果你有一个变量,比如
//你能做什么
打印(me.someVar)
},myData)
信用:该代码取自对该问题的回答,尽管它不是公认的答案:
我希望它能这么简单。。。然而,我遇到的问题是,我不能简单地在闭包中引用self。具体地说,如果我把self.doOtherStuff()放在那里,我会得到以下编译器错误:“不能从捕获上下文的闭包中形成C函数指针”。AudioServicesAddSystemSoundCompletion方法的最终参数称为“inClientData”,它在文档中有用地表示“调用回调函数时要传递给回调函数的应用程序数据”。这种类型是UnsafemeutableRawPointer,这就是为什么我最初会做整个userData的事情您尝试在完成块中调用doOtherStuff()是一种正确的方法(唯一的另一种是通知,这是唯一的两个选项)。在这种情况下,使其复杂化的是从Obj-C到Swift的桥接,这是必要的。最后一个(不被接受的)答案对你有用吗@绿豆,谢谢!这就成功了。事实上,我在早些时候试图弄明白这一点的时候,偶然发现了同样的问题。但我甚至没有看那个答案,因为低评级和不可接受的状态。。。如果你想发表你的评论作为对我问题的回答,我会接受的。