import Foundation import AVFoundation import YbridOpus @available(iOS 13.0, *) class SwiftOpusAudioProcessor: NSObject { protocol AudioDataCallback: AnyObject { func onAudioDataReceived(data: Data) } private var isDecodingActive = false private weak var callback: AudioDataCallback? // Opus 解码器相关 - 使用 YbridOpus C API private var decoder: OpaquePointer? private var sampleRate: Int32 = 16000 private var channels: Int32 = 1 private let maxFrameSize: Int32 = 5760 // 120 ms @48 kHz 的最大值 override init() { super.init() } deinit { cleanup() } private func initializeOpusDecoder() -> Bool { if decoder != nil { return true } var error: Int32 = 0 decoder = opus_decoder_create(sampleRate, channels, &error) guard error == OPUS_OK, decoder != nil else { return false } return true } private func destroyOpusDecoder() { if let decoder = decoder { opus_decoder_destroy(decoder) self.decoder = nil } } func setCallback(_ callback: AudioDataCallback?) { self.callback = callback } func startDecoding(sampleRate: Int32 = 16000, channels: Int32 = 1, frameSize: Int32 = 640) -> Bool { if isDecodingActive { return true } self.sampleRate = sampleRate self.channels = channels guard initializeOpusDecoder() else { return false } isDecodingActive = true return true } func stopDecoding() -> Bool { if !isDecodingActive { return false } isDecodingActive = false destroyOpusDecoder() return true } func processAudioData(_ data: Data) { guard isDecodingActive, let decoder = decoder, data.count > 0 else { return } // 增强的数据包验证 guard data.count <= 1275 else { print("音频数据包太大: \(data.count) bytes,跳过处理") return } // 检查最小数据包大小(Opus最小包通常至少几个字节) guard data.count >= 3 else { print("音频数据包太小: \(data.count) bytes,跳过处理") return } // 简单的 Opus 头部验证(检查是否是有效的 Opus 数据包格式) let firstByte = data[0] // Opus packets start with a TOC (Table of Contents) byte // 检查TOC字节是否在合理范围内 if firstByte == 0x00 || firstByte == 0xFF { print("可疑的Opus数据包头部: 0x\(String(format: "%02X", firstByte)),跳过处理") return } DispatchQueue.global(qos: .userInitiated).async { [weak self] in self?.decodeOpusPacket(data) } } // 简化的 Opus 解码方法,重点是容错处理 private func decodeOpusPacket(_ packet: Data) { guard let decoder = decoder else { return } let maxSamples = Int(maxFrameSize) var pcmBuffer = [opus_int16](repeating: 0, count: maxSamples * Int(channels)) let decodedSamples = packet.withUnsafeBytes { packetPtr in let uint8Ptr = packetPtr.bindMemory(to: UInt8.self).baseAddress return opus_decode( decoder, uint8Ptr, opus_int32(packet.count), &pcmBuffer, Int32(maxSamples), 0 ) } // 增强的错误处理:检查各种错误情况 if decodedSamples <= 0 { let errorCode = decodedSamples print("Opus解码失败,错误代码: \(errorCode),重新初始化解码器") // 根据错误类型进行不同的处理 if errorCode == -1 { // OPUS_BAD_ARG print("Opus解码参数错误,执行完全重置") performCompleteReset() } else if errorCode == -2 { // OPUS_BUFFER_TOO_SMALL print("Opus缓冲区太小") resetDecoder() } else if errorCode == -3 { // OPUS_INTERNAL_ERROR print("Opus内部错误,执行完全重置") performCompleteReset() } else { print("Opus其他错误,尝试简单重置") resetDecoder() } return } // 验证解码结果的合理性 guard decodedSamples <= maxFrameSize else { print("Opus解码样本数超出预期: \(decodedSamples) > \(maxFrameSize)") resetDecoder() return } // 提取解码的音频数据 let samplesPerChannel = Int(decodedSamples) let totalSamples = samplesPerChannel * Int(channels) // 验证总样本数的合理性 guard totalSamples <= pcmBuffer.count else { print("计算的总样本数超出缓冲区: \(totalSamples) > \(pcmBuffer.count)") resetDecoder() return } let outputPCM = Array(pcmBuffer[0...size) // 回调通知 DispatchQueue.main.async { [weak self] in self?.callback?.onAudioDataReceived(data: data) } } func isDecoding() -> Bool { return isDecodingActive } func cleanup() { stopDecoding() } // MARK: - 公共接口 /// 获取当前配置信息 func getCurrentConfig() -> (sampleRate: Int32, channels: Int32) { return (sampleRate, channels) } }