import Foundation import SpeexKit import os.log /// 基于杰理SpeexKit的Opus音频处理器 @available(iOS 13.0, *) class OpusAudioProcessor: NSObject { // MARK: - 回调代理协议 protocol AudioDataCallback: AnyObject { /// 接收到解码后的PCM音频数据 func onAudioDataReceived(data: Data) } // MARK: - 属性 private var isDecodingActive = false private weak var callback: AudioDataCallback? private let logger = OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "OpusAudioProcessor") // MARK: - 初始化 override init() { super.init() // 注册通知 - 这是SDK设计要求的 NotificationCenter.default.addObserver( self, selector: #selector(onOpusDecodedData(_:)), name: NSNotification.Name(rawValue: kOPUS_DECODE_DATA), object: nil ) // 启用日志 OpusUnit.opusIsLog(true) } deinit { stopDecoding() NotificationCenter.default.removeObserver(self) } // MARK: - 通知回调 @objc private func onOpusDecodedData(_ notification: Notification) { guard let pcmData = notification.object as? Data else { os_log("解码回调收到无效数据", log: logger, type: .error) return } // 传递给回调 DispatchQueue.main.async { [weak self] in self?.callback?.onAudioDataReceived(data: pcmData) } } // MARK: - 公共接口 /// 设置回调 func setCallback(_ callback: AudioDataCallback?) { self.callback = callback } /// 开始Opus解码 func startDecoding(sampleRate: Int32 = 16000, channels: Int32 = 1, frameSize: Int32 = 640) -> Bool { // 如果已经在解码,直接返回成功 if isDecodingActive { os_log("Opus解码器已经在运行", log: logger, type: .debug) return true } // 设置音频参数 OpusUnit.opusSetSampleRate(Int32(sampleRate), kbps: 16000, channels: Int32(channels)) // 必须在后台线程启动解码器(SDK要求) DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self = self else { return } // 启动解码器 let result = OpusUnit.opusDecoderRun() if result == 0 { os_log("Opus解码器启动成功: 采样率=%d Hz", log: self.logger, type: .info, sampleRate) self.isDecodingActive = true } else { os_log("Opus解码器启动失败: 错误=%d", log: self.logger, type: .error, result) } } return true } /// 停止Opus解码 func stopDecoding() -> Bool { if !isDecodingActive { return false } // 必须在后台线程停止解码器 DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self = self else { return } let result = OpusUnit.opusDecoderStop() os_log("Opus解码器停止: %d", log: self.logger, type: .info, result) self.isDecodingActive = false } return true } /// 处理Opus编码数据 func processAudioData(_ data: Data) { if !isDecodingActive { os_log("Opus解码器未启动", log: logger, type: .error) return } // 将Opus数据送入解码器 OpusUnit.opusWrite(data) // 解码结果将通过通知回调给onOpusDecodedData方法 } /// 判断解码器是否运行中 func isDecoding() -> Bool { return isDecodingActive } /// 清理资源 func cleanup() { stopDecoding() } }