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.