使用AVAudioEngine播放一串Int16 PCM样本的解决方法如下所示:
import AVFoundation
func playPCM(samples: [Int16]) {
// 创建AVAudioEngine实例
let engine = AVAudioEngine()
// 创建AVAudioFormat,指定采样率和声道数
let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 44100, channels: 1, interleaved: false)
// 创建AVAudioPlayerNode实例
let playerNode = AVAudioPlayerNode()
// 将playerNode添加到engine的主Mixer中
engine.attach(playerNode)
// 连接playerNode到engine的输出
engine.connect(playerNode, to: engine.mainMixerNode, format: format)
// 启动引擎
do {
try engine.start()
} catch {
print("Failed to start AVAudioEngine: \(error)")
return
}
// 创建AVAudioPCMBuffer实例,用于存储PCM样本数据
let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(samples.count))
// 将样本数据写入buffer
buffer?.frameLength = AVAudioFrameCount(samples.count)
let audioBuffer = buffer?.int16ChannelData![0]
memcpy(audioBuffer, samples, samples.count * MemoryLayout.size)
// 安装buffer到playerNode
playerNode.scheduleBuffer(buffer!, at: nil, options: .interrupts, completionHandler: nil)
// 播放音频
playerNode.play()
// 播放完成后停止引擎
playerNode.scheduleBuffer(buffer!, at: nil, options: .interrupts, completionHandler: {
engine.stop()
})
}
// 使用示例
let samples: [Int16] = [0, 100, 200, 300, 400] // 替换为实际的PCM样本
playPCM(samples: samples)
上述代码首先创建了一个AVAudioEngine实例和一个AVAudioPlayerNode实例。然后,将AVAudioPlayerNode添加到AVAudioEngine的主Mixer中,并将其连接到engine的输出。接下来,启动AVAudioEngine。
然后,创建一个AVAudioPCMBuffer实例,用于存储PCM样本数据。将样本数据写入buffer,并将buffer安装到playerNode。最后,调用playerNode的play()方法来播放音频。
播放完成后,我们可以选择停止引擎。在示例中,我选择在完成回调中停止引擎。你也可以根据自己的需求选择什么时候停止引擎。
注意:在使用AVAudioPCMBuffer的int16ChannelData属性时,我们可以使用![0]来访问单个声道的样本数据。如果有多个声道,可以使用多个索引来访问它们。