拿 Audio Queue Services ,处理上一步获取的音频二进制数据 data,解析为音频数据包 packet
1. 建立音频的处理通道, 注册解析回调方法
public init() throws { let context = unsafeBitCast(self, to: UnsafeMutableRawPointer.self)
// 创建一个活跃的音频文件流解析器,创建解析器 ID
guard AudioFileStreamOpen(context, ParserPropertyChangeCallback, ParserPacketCallback, kAudioFileMP3Type, &streamID) == noErr else {
throw ParserError.streamCouldNotOpen
}
}
2. 传递数据进来,开始解析
public func parse(data: Data) throws { let streamID = self.streamID! let count = data.count
_ = try data.withUnsafeBytes({ (rawBufferPointer) in let bufferPointer = rawBufferPointer.bindMemory(to: UInt8.self) if let address = bufferPointer.baseAddress{
// 把音频数据,传给解析器
// streamID, 指定解析器 let result = AudioFileStreamParseBytes(streamID, UInt32(count), address, [])
guard result == noErr else {
throw ParserError.failedToParseBytes(result)
}
}
})
}
3. 音频信息解析先
func ParserPropertyChangeCallback(_ context: UnsafeMutableRawPointer, _ streamID: AudioFileStreamID, _ propertyID: AudioFileStreamPropertyID, _ flags: UnsafeMutablePointer<AudioFileStreamPropertyFlags>) { let parser = Unmanaged<Parser>.fromOpaque(context).takeUnretainedValue()
// 关心什么信息,取什么
switch propertyID { case kAudioFileStreamProperty_DataFormat:
// 拿数据格式
var format = AudioStreamBasicDescription()
GetPropertyValue(&format, streamID, propertyID)
parser.dataFormat = AVAudioFormat(streamDescription: &format) case kAudioFileStreamProperty_AudioDataPacketCount:
// 音频流文件,分离出来的音频数据中,的包 packet 个数
GetPropertyValue(&parser.packetCount, streamID, propertyID)
default:
()
}
}
// 套路就是,先拿内存大小 propSize, 再拿关心的属性的值 value
func GetPropertyValue<T>(_ value: inout T, _ streamID: AudioFileStreamID, _ propertyID: AudioFileStreamPropertyID) {
var propSize: UInt32 = 0
guard AudioFileStreamGetPropertyInfo(streamID, propertyID, &propSize, nil) == noErr else { return }
guard AudioFileStreamGetProperty(streamID, propertyID, &propSize, &value) == noErr else { return }
}
4. 解析回调,处理数据
func ParserPacketCallback(_ context: UnsafeMutableRawPointer, _ byteCount: UInt32, _ packetCount: UInt32, _ data: UnsafeRawPointer, _ packetDescriptions: UnsafeMutablePointer<AudioStreamPacketDescription>) {
// 拿回了 self ( parser ) let parser = Unmanaged<Parser>.fromOpaque(context).takeUnretainedValue() let packetDescriptionsOrNil: UnsafeMutablePointer<AudioStreamPacketDescription>? = packetDescriptions
// ASPD 存在,就是压缩的音频包
// 未压缩的 pcm, 使用 ASBD let isCompressed = packetDescriptionsOrNil != nil
guard let dataFormat = parser.dataFormat else { return }
// 拿到了数据,遍历,
// 存储进去 parser.packets, 也就是 self.packets if isCompressed { for i in 0 ..< Int(packetCount) {
// 压缩音频数据,每一个包对应一个 ASPD, 逐个计算 let packetDescription = packetDescriptions[i] let packetStart = Int(packetDescription.mStartOffset) let packetSize = Int(packetDescription.mDataByteSize) let packetData = Data(bytes: data.advanced(by: packetStart), count: packetSize)
parser.packets.append((packetData, packetDescription))
}
} else {
// 原始音频数据 pcm,文件统一配置,计算比较简单 let format = dataFormat.streamDescription.pointee let bytesPerPacket = Int(format.mBytesPerPacket) for i in 0 ..< Int(packetCount) { let packetStart = i * bytesPerPacket let packetSize = bytesPerPacket let packetData = Data(bytes: data.advanced(by: packetStart), count: packetSize)
parser.packets.append((packetData, nil))
}
}
}