You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
3.8 KiB

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()
}
}