macOS下如何从仅含输出通道的虚拟设备获取音频
音频捕获问题:仅输出虚拟设备无法捕获音频流
当虚拟设备同时具备输入和输出通道时,我可以通过以下代码捕获音频流并转发至耳机,但将虚拟设备设置为仅输出模式后,无法捕获音频流:
init() { let allDevices = simply.allDevices for item in allDevices { if item.name == loopback_name{ loopbackDevice = item } if item.name == m2_output_name{ M2OutDevice = item } } var inputAcd = AudioComponentDescription() inputAcd.componentType = kAudioUnitType_Output; inputAcd.componentSubType = kAudioUnitSubType_HALOutput; inputAcd.componentManufacturer = kAudioUnitManufacturer_Apple; let comp = AudioComponentFindNext(nil, &inputAcd); AudioComponentInstanceNew(comp!, &inputUnit) AudioUnitInitialize(inputUnit!) var enableFlag = UInt32(1) var disableFlag = UInt32(0) let inputBus:UInt32 = 1 let outputBus:UInt32 = 0 checkErr(inputUnit!.setPropertyEnableIO(&enableFlag, .input,inputBus)) checkErr(inputUnit!.setPropertyEnableIO(&disableFlag, .output,outputBus)) var deviceid = loopbackDevice!.id checkErr(inputUnit!.setPropertyCurrentDevice(&deviceid,.output)) var streamFormat1 = AudioStreamBasicDescription() checkErr(inputUnit!.getPropertyStreamFormat(&streamFormat1,.output,inputBus)) var streamFormat2 = AudioStreamBasicDescription() checkErr(inputUnit!.getPropertyStreamFormat(&streamFormat2,.input,inputBus)) debugPrint(streamFormat1,"=== ",streamFormat2) inputUnit!.setPropertyStreamFormat(&streamFormat1, .output, inputBus) inputUnit!.setPropertyStreamFormat(&streamFormat1, .input, inputBus) var bufferSizeFrames : UInt32 = 0 checkErr(inputUnit!.getPropertyBufferFrameSize(&bufferSizeFrames, .global)) inputUnit!.setInputBuffer(&inputBuffer, streamFormat1, bufferSizeFrames) ringBuffer = CircularBuffer<Int32>(channelCount: Int(streamFormat2.mChannelsPerFrame), capacity: Int(bufferSizeFrames) * 2048) var callback = AURenderCallbackStruct() callback.inputProc = inputRenderCallback callback.inputProcRefCon = Unmanaged.passUnretained(self).toOpaque() AudioUnitSetProperty(inputUnit!,kAudioOutputUnitProperty_SetInputCallback,kAudioUnitScope_Input, inputBus, &callback,UInt32(MemoryLayout<AURenderCallbackStruct>.size)) checkErr(NewAUGraph(&graph)) checkErr(AUGraphInitialize(graph!)) var outNode :AUNode = 0 checkErr(graph!.getNode(&outNode)) var mixerNode :AUNode = 0 checkErr(graph!.getNode(&mixerNode,.mixer,.stereoMixer)) checkErr(AUGraphOpen(graph!)) checkErr(graph!.getUnit(outNode , &outputUnit)) checkErr(graph!.getUnit(mixerNode, &mixerUnit)) checkErr(AUGraphConnectNodeInput(graph!, mixerNode, 0, outNode, 0)) var outputCallback = AURenderCallbackStruct() outputCallback.inputProc = outputRenderCallBack outputCallback.inputProcRefCon = Unmanaged.passUnretained(self).toOpaque() AUGraphSetNodeInputCallback(graph!, mixerNode, 0, &outputCallback) deviceid = M2OutDevice!.id outputUnit!.setPropertyCurrentDevice(&deviceid,.output) AudioOutputUnitStart(inputUnit!) checkErr(AUGraphStart(graph!)) } // MARK: - inputUnit单元获取音频写入环形缓冲区 - let inputRenderCallback: AURenderCallback = { (inRefCon: UnsafeMutableRawPointer, ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, inTimeStamp: UnsafePointer<AudioTimeStamp>, inBusNumber: UInt32, inNumberFrames: UInt32, ioData: UnsafeMutablePointer<AudioBufferList>?) -> OSStatus in let inSelf = Unmanaged<IXIAudioTestOutputHelper>.fromOpaque(inRefCon).takeUnretainedValue() AudioUnitRender(inSelf.inputUnit!, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, inSelf.inputBuffer!.unsafeMutablePointer); let start = inTimeStamp.pointee.mSampleTime.int64Value let end = start + Int64(inNumberFrames) if (inSelf.inputLatestSampleTime == -1) { inSelf.inputLatestSampleTime = start return noErr } inSelf.inputLatestSampleTime = start _ = inSelf.ringBuffer!.write(from: inSelf.inputBuffer!.unsafeMutablePointer, start: start, end: end) debugPrint("inputRenderCallback") return noErr } let outputRenderCallBack: AURenderCallback = { (inRefCon: UnsafeMutableRawPointer, ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, inTimeStamp: UnsafePointer<AudioTimeStamp>, inBusNumber: UInt32, inNumberFrames: UInt32, ioData: UnsafeMutablePointer<AudioBufferList>?) -> OSStatus in let inSelf = Unmanaged<IXIAudioTestOutputHelper>.fromOpaque(inRefCon).takeUnretainedValue() let sampleTime = inTimeStamp.pointee.mSampleTime if (inSelf.outputLatestSampleTime == -1) { inSelf.outputLatestSampleTime = sampleTime.int64Value inSelf.computeOffset() return noErr } else { inSelf.outputLatestSampleTime = sampleTime.int64Value } let from = Int64(sampleTime + inSelf.sampleOffset - inSelf.safetyOffset) let to = from + Int64(inNumberFrames) _ = inSelf.ringBuffer!.read(into: ioData!, from: from, to: to) return noErr }
我尝试禁用inputUnit的输入、启用输出,并使用kAudioUnitProperty_SetRenderCallback捕获音频流但未成功,还出现错误提示ioData.mNumberBuffers=2, ASBD::NumberChannelStreams(output.GetStreamFormat())=1,表明捕获的音频为交错格式,而我设置的inputBuffer为非交错格式;设置非交错缓冲区后,捕获的音频流为空,相关代码如下:
var enableFlag = UInt32(1) var disableFlag = UInt32(0) let inputBus:UInt32 = 1 let outputBus:UInt32 = 0 checkErr(inputUnit!.setPropertyEnableIO(&disableFlag, .input,inputBus)) checkErr(inputUnit!.setPropertyEnableIO(&enableFlag, .output,outputBus)) var deviceid = loopbackDevice!.id checkErr(inputUnit!.setPropertyCurrentDevice(&deviceid,.output)) var streamFormat1 = AudioStreamBasicDescription() checkErr(inputUnit!.getPropertyStreamFormat(&streamFormat1,.output,outputBus)) var streamFormat2 = AudioStreamBasicDescription() checkErr(inputUnit!.getPropertyStreamFormat(&streamFormat2,.input,outputBus)) debugPrint(streamFormat1,"=== ",streamFormat2) inputUnit!.setPropertyStreamFormat(&streamFormat2, .output, outputBus) inputUnit!.setPropertyStreamFormat(&streamFormat2, .input, outputBus) var bufferSizeFrames : UInt32 = 0 checkErr(inputUnit!.getPropertyBufferFrameSize(&bufferSizeFrames, .global)) inputUnit!.setInputBuffer(&inputBuffer, streamFormat2, bufferSizeFrames) ringBuffer = CircularBuffer<Int32>(channelCount: Int(streamFormat2.mChannelsPerFrame), capacity: Int(bufferSizeFrames) * 2048) checkErr(NewAUGraph(&graph)) checkErr(AUGraphInitialize(graph!)) var outNode :AUNode = 0 checkErr(graph!.getNode(&outNode)) var mixerNode :AUNode = 0 checkErr(graph!.getNode(&mixerNode,.mixer,.stereoMixer)) checkErr(AUGraphOpen(graph!)) checkErr(graph!.getUnit(outNode , &outputUnit)) checkErr(graph!.getUnit(mixerNode, &mixerUnit)) checkErr(AUGraphConnectNodeInput(graph!, mixerNode, 0, outNode, 0)) var callback = AURenderCallbackStruct() callback.inputProc = inputRenderCallback callback.inputProcRefCon = Unmanaged.passUnretained(self).toOpaque() AudioUnitSetProperty(mixerUnit!,kAudioUnitProperty_SetRenderCallback,kAudioUnitScope_Output, 0, &callback,UInt32(MemoryLayout<AURenderCallbackStruct>.size)) deviceid = M2OutDevice!.id outputUnit!.setPropertyCurrentDevice(&deviceid,.output) AudioOutputUnitStart(inputUnit!) checkErr(AUGraphStart(graph!))
内容的提问来源于stack exchange,提问作者user22997196
相关产品推荐
相关产品推荐

