My task is to receive an audio stream and play it. On the server side, the audio is encoded by pcmInt16 (16bit, 44100 sample rate, 2 channels)
I accept a stream of bytes and encode in AVAudioPCMBuffer and then pass it to the player in the playMusicFromBuffer function.
while (inputStream!.hasBytesAvailable) {
let length = inputStream!.read(&buffer, maxLength: buffer.count)
if (length > 0) {
print("\(#file) > \(#function) > \(length) bytes read")
print(buffer)
let audioBuffer = bytesToAudioBuffer16(buffer)
playMusicFromBuffer(PCMBuffer: audioBuffer)
}
}
At first, for encoding in AVAudioPCMBuffer, I used the bytesToAudioBuffer method (the parameters do not match the server settings), however, the application starts and does not crash when converting, but still there is no sound.
func bytesToAudioBuffer(_ buf: [UInt8]) -> AVAudioPCMBuffer {
let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100.0, channels: 1, interleaved: true)
let frameLength = UInt32(buf.count) / (fmt?.streamDescription.pointee.mBytesPerFrame)!
let audioBuffer = AVAudioPCMBuffer(pcmFormat: fmt!, frameCapacity: frameLength)
audioBuffer!.frameLength = frameLength
let dstLeft = audioBuffer?.floatChannelData![0]
buf.withUnsafeBufferPointer {
let src = UnsafeRawPointer($0.baseAddress!).bindMemory(to: Float.self, capacity: Int(frameLength))
dstLeft!.initialize(from: src, count: Int(frameLength))
}
print("Convert to AVAudioPCMBuffer")
return audioBuffer!
}
func bytesToAudioBuffer16(_ buf: [UInt8]) -> AVAudioPCMBuffer {
let fmt = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 44100.0, channels: 2, interleaved: true)
let frameLength = UInt32(buf.count) / (fmt?.streamDescription.pointee.mBytesPerFrame)!
let audioBuffer = AVAudioPCMBuffer(pcmFormat: fmt!, frameCapacity: frameLength)
audioBuffer!.frameLength = frameLength
let dstLeft = audioBuffer?.int16ChannelData![0]
buf.withUnsafeBufferPointer {
let src = UnsafeRawPointer($0.baseAddress!).bindMemory(to: Int16.self, capacity: Int(frameLength))
dstLeft!.initialize(from: src, count: Int(frameLength))
}
print("Convert to AVAudioPCMBuffer")
return audioBuffer!
}
var audioEngine: AVAudioEngine = AVAudioEngine()
var audioFilePlayer: AVAudioPlayerNode = AVAudioPlayerNode()
func playMusicFromBuffer(PCMBuffer: AVAudioPCMBuffer) {
let mainMixer = audioEngine.mainMixerNode
audioEngine.attach(audioFilePlayer)
audioEngine.connect(audioFilePlayer, to:mainMixer, format: PCMBuffer.format)
try? audioEngine.start()
audioFilePlayer.play()
audioFilePlayer.scheduleBuffer(PCMBuffer, at: nil, options:AVAudioPlayerNodeBufferOptions.loops)
}
Next, I tried to fix this by changing the settings and writing the bytesToAudioBuffer16 function. But here when starting the application, when I convert the stream to AVAudioPCMBuffer and transfer it to the player, an error occurs:
[reason __NSCFString * "[[busArray objectAtIndexedSubscript: (NSUInteger) element] setFormat: format error: & nsErr]: returned false, error Error Domain = NSOSStatusErrorDomain Code = -10868 \" (null) \ "" 0x0000600000d2e00.
The question is how to fix this situation. Do I need to fix bytesToAudioBuffer16 or playMusicFromBuffer. If so, how?