一段时间以来,我一直在尝试如何从iOS中的URLSessionDataTask提供的数据中流式传输实时音频。
我已经声明了一个用于管理玩家动作的自定义类,它看起来像这样:
import UIKit
import AVFoundation
class AudioDataPlayer: NSObject {
//MARK:- Variables
//MARK: Constants
enum Status{
case playing
case notPlaying
}
let audioPlayerQueue = DispatchQueue(label: "audioPlayerQueue", qos: DispatchQoS.userInteractive)
//MARK: Vars
private (set) var currentStatus:Status = .notPlaying
private var audioEngine: AVAudioEngine = AVAudioEngine()
private var streamingAudioPlayerNode: AVAudioPlayerNode = AVAudioPlayerNode()
private (set) var streamingAudioFormat: AVAudioFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 48000, channels: 2, interleaved: false)!
//MARK:- Constructor
override init() {
super.init()
}
//MARK:- Private methods
//MARK:- Public methods
func processData(_ data:Data) throws{
if currentStatus == .notPlaying{
do{
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [.allowAirPlay])
try AVAudioSession.sharedInstance().setActive(true)
if #available(iOS 11.0, *) {
try audioEngine.enableManualRenderingMode(.realtime, format: streamingAudioFormat, maximumFrameCount: 3072)
}
audioEngine.attach(streamingAudioPlayerNode)
audioEngine.connect(streamingAudioPlayerNode, to: audioEngine.mainMixerNode, format: streamingAudioFormat)
currentStatus = .playing
}
catch{
print("\(logClassName) ERROR -> \(error.localizedDescription)")
}
}
audioPlayerQueue.async {
if let audioPCMBuffer = data.makePCMBuffer(format: self.streamingAudioFormat){
self.streamingAudioPlayerNode.scheduleBuffer(audioPCMBuffer, completionHandler: {
//TODO
})
if !self.audioEngine.isRunning{
try! self.audioEngine.start()
self.streamingAudioPlayerNode.play()
}
}
else{
print("\(self.logClassName) TEST -> Ignoring data to play ...")
}
}
}
func stop(){
audioEngine.stop()
audioEngine.detach(streamingAudioPlayerNode)
currentStatus = .notPlaying
}
}
管理传入数据的函数是'processData(_ data:Data)',它是从另一个类中这样调用的:
let processingQueue = DispatchQueue(label: "processingQueue", qos: DispatchQoS.userInteractive)
var audioDataPlayer:AudioDataPlayer = AudioDataPlayer()
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
processingQueue.async {
try! self.audioDataPlayer.processData(data)
}
}
我从论坛和苹果documanetation网站获得了代码。但是,也许我还是不太了解它是如何工作的,并且设备没有声音发出……
音频数据为48K,16位和2通道格式。
有什么想法吗?
答案 0 :(得分:0)
如果您的音频数据是16位(整数,假设是整数),则需要使用AVAudioFormat
而不是pcmFormatInt16
来初始化pcmFormatFloat32
。
对于这种格式,非交错式似乎有些奇怪,因此您可能必须将interleaved
设置为true
。