问题
We are trying to connect varispeed unit with output unit using AUGraph. This is our current code:
var graph: AUGraph?
var varispeedNode: AUNode = 0
var varispeedUnit: AudioUnit?
var outputNode: AUNode = 0
var outputUnit: AudioUnit?
init(_ client: UDPClient, _ tcpClient: TCPClient, _ opusHelper: OpusHelper, _ tvTemp: UILabel) {
super.init()
let success = initCircularBuffer(&circularBuffer, 4096)
if success {
print("Circular buffer init was successful")
} else {
print("Circular buffer init not successful")
}
self.tvTemp = tvTemp
self.opusHelper = opusHelper
monotonicTimer = MonotonicTimer()
udpClient = client
self.tcpClient = tcpClient
status = NewAUGraph(&graph)
if status != noErr {
print("NEW AUGrpah ERROR: \(status!)")
}
var varispeedDesc = AudioComponentDescription(
componentType: OSType(kAudioUnitType_FormatConverter),
componentSubType: OSType(kAudioUnitSubType_Varispeed),
componentManufacturer: OSType(kAudioUnitManufacturer_Apple),
componentFlags: 0,
componentFlagsMask: 0
)
status = AUGraphAddNode(self.graph!, &varispeedDesc, &varispeedNode)
if status != noErr {
print("Varispeed desc ERRROR: \(status!)")
}
var outputDesc = AudioComponentDescription(
componentType: OSType(kAudioUnitType_Output),
componentSubType: OSType(kAudioUnitSubType_VoiceProcessingIO),
componentManufacturer: OSType(kAudioUnitManufacturer_Apple),
componentFlags: 0,
componentFlagsMask: 0
)
status = AUGraphAddNode(self.graph!, &outputDesc, &outputNode)
if status != noErr {
print("Output Desc ERROR \(status!)")
}
status = AUGraphOpen(graph!)
if status != noErr {
print("AUGraph open ERROR: \(status!)")
}
status = AUGraphNodeInfo(self.graph!, self.varispeedNode, nil, &varispeedUnit)
if status != noErr {
print("Varispeed Unit Unable to get INFO: \(status!)")
}
status = AUGraphNodeInfo(self.graph!, self.outputNode, nil, &outputUnit)
if status != noErr {
print("Output Unit Unable to get INFO: \(status!)")
}
let inputComponent = AudioComponentFindNext(nil, &outputDesc)
status = AudioComponentInstanceNew(inputComponent!, &outputUnit)
if status != noErr {
print("Audio component instance new error \(status!)")
}
var flag: UInt32 = 1
var ioFormat = CAStreamBasicDescription(
sampleRate: 48000.0,
numChannels: 1,
pcmf: .int16,
isInterleaved: false
)
status = AudioUnitSetProperty(
outputUnit!,
AudioUnitPropertyID(kAudioUnitProperty_StreamFormat),
AudioUnitScope(kAudioUnitScope_Input),
0,
&ioFormat!,
MemoryLayoutStride.SizeOf32(ioFormat)
)
if status != noErr {
print("Unable to set stream format input to output \(status!)")
}
// Set the MaximumFramesPerSlice property. This property is used to describe to an audio unit the maximum number
// of samples it will be asked to produce on any single given call to AudioUnitRender
var maxFramesPerSlice: UInt32 = 4096
status = AudioUnitSetProperty(
varispeedUnit!,
AudioUnitPropertyID(kAudioUnitProperty_MaximumFramesPerSlice),
AudioUnitScope(kAudioUnitScope_Global),
0,
&maxFramesPerSlice,
MemoryLayoutStride.SizeOf32(UInt32.self)
)
if status != noErr {
print("Unable to set max frames per slice 1 \(status!)")
}
var playbackCallback = AURenderCallbackStruct(
inputProc: AudioController_PlaybackCallback,
inputProcRefCon: UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
)
status = AudioUnitSetProperty(
outputUnit!,
AudioUnitPropertyID(kAudioUnitProperty_SetRenderCallback),
AudioUnitScope(kAudioUnitScope_Global),
kOutputBus,
&playbackCallback,
MemoryLayout<AURenderCallbackStruct>.size.ui
)
if status != noErr {
print("Failed to set recording render callback \(status!)")
}
status = AUGraphConnectNodeInput(
graph!,
varispeedNode,
AudioUnitElement(0),
outputNode,
AudioUnitElement(0)
)
if status != noErr {
print("Failed to connect varispeed node to output node \(status!)")
}
status = AudioUnitSetParameter(
varispeedUnit!,
AudioUnitParameterID(kVarispeedParam_PlaybackRate),
AudioUnitScope(kAudioUnitScope_Global),
0,
AudioUnitParameterValue(0.2000000082426955),
0
)
if status != noErr {
print("Varispeed rate failed to set \(status!)")
}
status = AudioOutputUnitStart(outputUnit!)
if status != noErr {
print("Failed to initialize output unit \(status!)")
}
if graph != nil {
var outIsInitialized = DarwinBoolean(false)
status = AUGraphIsInitialized(graph!, &outIsInitialized)
if status != noErr {
print("AUGraph is initialized 1 ERROR \(status!)")
}
if !outIsInitialized.boolValue {
status = AUGraphInitialize(graph!)
if status != noErr {
print("AUGraph is initialized 2 ERROR \(status!)")
}
} else {
print("AUGraph is already init")
}
var isRunning = DarwinBoolean(false)
status = AUGraphIsRunning(graph!, &isRunning)
if status != noErr {
print("AUGraph is running \(status!)")
}
if !isRunning.boolValue {
status = AUGraphStart(graph!)
if status != noErr {
print("AUGraph was not started \(status!)")
}
} else {
print("AUGraph is running")
}
} else {
print("Error processing graph NULL")
}
}
We can hear the voice but the output is not affected by the varispeed property when we set the rate on it. We are getting real time audio through UDP and we are trying to change the playout speed on iOS.
Can anyone guide us to connect Varispeed unit and output Unit properly.
https://stackoverflow.com/a/59061396/12020007
回答1:
You probably want the input callback to be on the input to your graph, not the middle.
You may want to try the kAudioUnitSubType_NewTimePitch effect, instead of the Varispeed effect audio unit.
You may need to set the format of the input and output of your effect node and make sure the output format of your effect node matches that of the input to the next node in your graph.
You might also want to check to see whether the bypass property of your effect node is enabled or not, and set it appropriately.
来源:https://stackoverflow.com/questions/60550421/varispeed-unit-with-augraph-ios-swift