The problem is scheduling an AAC buffer in a AVAudioPlayerNode
which solely consumes uncompressed linear pcm buffers.
The perform playAudio takes a Knowledge()
object that accommodates a bit of AAC being streamed to the consumer, usually just a few kilobytes in dimension. The method goes like this:
- Write AAC chunk to a
AVAudioCompressedBuffer
. - Create a pcm buffer and convert the
AVAudioCompressedBuffer
into it. - Schedule the buffer within the Participant Node
That is my try. Nevertheless it doesn’t work, the audio simply doesn’t play in any respect within the audio system. I wrote a bunch of debugging statements throughout the capabilities to determine what’s going on.
func preparePlayer() {
guard let engine = audioEngine else {
print("Audio engine will not be initialized")
return
}
// Initialize a participant node and fix it to the engine
playerNode = AVAudioPlayerNode()
engine.connect(playerNode!)
print("Output Node Format: (engine.outputNode.outputFormat(forBus: 0))")
pcmFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 48000, channels: 1, interleaved: false)
engine.join(playerNode!, to: engine.outputNode, format: pcmFormat)
var asbd = AudioStreamBasicDescription()
asbd.mSampleRate = 24000 // 24 kHz
asbd.mFormatID = kAudioFormatMPEG4AAC // AAC
asbd.mChannelsPerFrame = 1 // Mono
asbd.mBytesPerPacket = 0 // Varies (compressed format)
asbd.mFramesPerPacket = 1024
asbd.mBytesPerFrame = 0 // Varies (compressed format)
asbd.mBitsPerChannel = 0 // Varies (compressed format)
// Create an AVAudioFormat with the AudioStreamBasicDescription
sourceFormat = AVAudioFormat(streamDescription: &asbd)
// Initialize the audio converter with the supply (AAC) and vacation spot (PCM) codecs
audioConverter = AVAudioConverter(from: sourceFormat!, to: pcmFormat!)
}
func playAudio(audioData: Knowledge) {
guard let playerNode = self.playerNode else {
print("Participant node will not be initialized")
return
}
guard let engine = audioEngine else {
print("Audio engine will not be initialized")
return
}
let compressedBuffer = AVAudioCompressedBuffer(format: sourceFormat!, packetCapacity: 1024, maximumPacketSize: audioConverter!.maximumOutputPacketSize)
compressedBuffer.byteLength = AVAudioPacketCount(audioData.rely)
print("audioData accommodates (audioData.rely) counts")
let middleIndex = audioData.rely / 2
let middleRangeAudioData = middleIndex..<(middleIndex + 10)
print("Center bytes of audioData: (Array(audioData[middleRangeAudioData]))")
audioData.withUnsafeBytes {
compressedBuffer.knowledge.copyMemory(from: $0.baseAddress!, byteCount: audioData.rely)
}
print("compressedBuffer accommodates (compressedBuffer.packetCount) packet counts")
print("compressedBuffer accommodates (compressedBuffer.byteCapacity) byte capability")
print("compressedBuffer accommodates (compressedBuffer.byteLength) legitimate bytes")
print("compressedBuffer accommodates (compressedBuffer.packetCapacity) packet capability")
let bufferPointer = compressedBuffer.knowledge.bindMemory(to: UInt8.self, capability: audioData.rely)
let bufferBytes = Array(UnsafeBufferPointer(begin: bufferPointer, rely: audioData.rely))
let middleRangeCompressedBuffer = middleIndex..<(middleIndex + 10)
print("Center bytes of compressedBuffer: (Array(bufferBytes[middleRangeCompressedBuffer]))")
// Create a PCM buffer
let pcmBuffer = AVAudioPCMBuffer(pcmFormat: pcmFormat!, frameCapacity: 1024)
let inputBlock: AVAudioConverterInputBlock = { inNumPackets, outStatus in
outStatus.pointee = AVAudioConverterInputStatus.haveData
return compressedBuffer
}
var error: NSError?
let conversionResult = audioConverter!.convert(to: pcmBuffer!, error: &error, withInputFrom: inputBlock)
if conversionResult == .error {
print("Conversion failed with error: (String(describing: error))")
} else {
print("Conversion profitable")
print("buffer accommodates (pcmBuffer?.frameLength ?? 123456) frames")
}
if let frameLength = pcmBuffer?.frameLength, frameLength > 0 {
let channelCount = pcmFormat?.channelCount ?? 0
for channel in 0..<channelCount {
if let channelData = pcmBuffer?.floatChannelData?[Int(channel)] {
let channelDataPointer = UnsafeBufferPointer(begin: channelData, rely: Int(frameLength))
let firstFewSamples = Array(channelDataPointer.prefix(10))
print("First few samples of pcmBuffer in channel (channel): (firstFewSamples)")
}
}
}
if !engine.isRunning {
do {
attempt engine.begin()
} catch {
print("Error beginning audio engine: (error)")
}
}
playerNode.scheduleBuffer(pcmBuffer!, completionHandler: nil)
}
That is an instance debugging log:
audioData accommodates 1369 counts
Center bytes of audioData: [250, 206, 86, 76, 254, 10, 221, 187, 190, 243]
compressedBuffer accommodates 0 packet counts
compressedBuffer accommodates 4096 byte capability
compressedBuffer accommodates 1369 legitimate bytes
compressedBuffer accommodates 1024 packet capability
Center bytes of compressedBuffer: [250, 206, 86, 76, 254, 10, 221, 187, 190, 243]
Conversion profitable
buffer accommodates 0 frames
The converter doesn’t output any errors, however the pcm buffer accommodates 0 frames. Wanting backwards that is in all probability as a result of the compressedBuffer
additionally does include 0 frames. The audio will get written to the compressedBuffer
however there may be the place issues cease making sense. I’ve labored nearly all the time with pcm audio earlier than and since it’s linear I can interpolate what number of frames it has per packet based mostly on the audio settings, no large deal. In compressed audio that isn’t potential as a result of bitrate is usually variable. Possibly this subject is said to having 0 frames, or perhaps one thing else.