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