diff --git a/SpeexKit.xcframework/Info.plist b/SpeexKit.xcframework/Info.plist
new file mode 100644
index 000000000..c654fe5c9
--- /dev/null
+++ b/SpeexKit.xcframework/Info.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ AvailableLibraries
+
+
+ BinaryPath
+ SpeexKit.framework/SpeexKit
+ LibraryIdentifier
+ ios-arm64
+ LibraryPath
+ SpeexKit.framework
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ ios
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/OpusTools.h b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/OpusTools.h
new file mode 100644
index 000000000..55fa7f1e0
--- /dev/null
+++ b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/OpusTools.h
@@ -0,0 +1,44 @@
+//
+// OpusTools.h
+// SpeexKit
+//
+// Created by EzioChan on 2024/1/17.
+// Copyright © 2024 www.zh-jieli.com. All rights reserved.
+//
+
+#import
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+@protocol OpusToolsDelegate
+
+-(void)opusToolsPcmData:(NSData*)data;
+
+-(void)opusToolsPcmFile:(NSData *)data;
+
+-(void)opusToolsOpusData:(NSData *)data;
+
+-(void)opusToolsOpusFile:(NSData *)data;
+
+@end
+
+@interface OpusTools : NSObject
+
+@property(nonatomic,weak)id delegate;
+
+-(void)opusDecodeInfo:(int)sampleRate Channel:(int)channel frameSize:(int) fs isHasHead:(BOOL)head;
+
+-(void)opusEncodeInfo:(int)sampleRate Channel:(int)channel frameSize:(int)fs isHasHead:(BOOL)head;
+
+-(void)decodeData:(NSData*)data;
+
+-(void)decodeFile:(NSString*)path;
+
+-(void)encodeData:(NSData*)data;
+
+-(void)encodeFile:(NSString*)path;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/OpusUnit.h b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/OpusUnit.h
new file mode 100644
index 000000000..37b12201a
--- /dev/null
+++ b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/OpusUnit.h
@@ -0,0 +1,100 @@
+//
+// OpusUnit.h
+// QCY_Demo
+//
+// Created by 杰理科技 on 2021/7/5.
+// Copyright © 2021 杰理科技. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ * 通知:流式编码回调Opus数据
+ * 通知数据类型:NSData(Opus)
+ */
+extern NSString *kOPUS_ENCODE_DATA;
+/**
+ * 通知:流式解码回调PCM数据
+ * 通知数据类型:NSData(PCM)
+ */
+extern NSString *kOPUS_DECODE_DATA;
+
+
+@interface OpusUnit : NSObject
+
++ (void)opusIsLog:(BOOL)log;
+
+#pragma mark - Opus参数
+/**
+ * 设置参数
+ * @param rate 采样率 例如:48000、24000、16000、12000、8000(默认 16000)
+ * @param frameRate 帧长度
+ * 16k :40
+ * 32K :80
+ * 64k :160
+ * 96k :320
+ * 128k:640
+ * @param channel 声道 例如:1、2 (默认 1)
+ * @param isHeader 是否带头
+ */
++(void)opusSetSampleRate:(int)rate frameRate:(int)frameRate Channels:(int)channel isHeader:(BOOL)isHeader;
+
+#pragma mark - Opus解码
+
+/**
+ * 直接【opus文件】转换成【pcm文件】
+ * @param path_opus opus文件路径
+ * @param path_pcm pcm文件路径
+ */
++ (int)opusDecodeOPUS:(NSString *)path_opus PCM:(NSString *)path_pcm;
+
+/**
+ * 流式解码【开启】
+ * 注意:需要异步调用,放在工程单利类中,切勿频繁开启。
+ */
++ (int)opusDecoderRun;
+
+/**
+ * 输入Opus的数据
+ * 通知监听“kOPUS_DECODE_DATA”获得解码后数据
+ * 通知数据类型:NSNotification.object => NSData(PCM格式)
+ * @param data opus数据流(长度:1024)
+ */
++ (void)opusWriteData:(NSData*)data;
+
+/**
+ * 流式解码【关闭】
+ */
++ (int)opusDecoderStop;
+
+#pragma mark - Opus编码
+
+/**
+ * 【pcm文件】转换成【opus文件】
+ */
++ (int)opusEncodePCM:(NSString *)path_pcm OPUS:(NSString *)path_opus;
+
+/**
+ * 流式编码【开启】
+ * 注意:需要异步调用,放在工程单利类中,切勿频繁开启。
+ */
++ (int)opusEncoderRun;
+
+/**
+ * 输入pcm的数据
+ * 通知监听“kOPUS_DECODE_DATA”获得解码后数据
+ * 通知数据类型:NSNotification.object => NSData(opus格式)
+ * @param data opus数据流(长度:1024)
+ */
++ (void)pcmWriteData:(NSData*)data;
+
+/**
+ * 流式编码【关闭】
+ */
++ (int)opusEncoderStop;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/SpeexKit.h b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/SpeexKit.h
new file mode 100644
index 000000000..0fb1c92bd
--- /dev/null
+++ b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/SpeexKit.h
@@ -0,0 +1,21 @@
+//
+// SpeexKit.h
+// SpeexKit
+//
+// Created by zhihui liang on 2018/8/20.
+// Copyright © 2018年 www.zh-jieli.com. All rights reserved.
+//
+
+#import
+
+//! Project version number for SpeexKit.
+FOUNDATION_EXPORT double SpeexKitVersionNumber;
+
+//! Project version string for SpeexKit.
+FOUNDATION_EXPORT const unsigned char SpeexKitVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import
+
+#import
+#import
+#import
diff --git a/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/SpeexUnit.h b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/SpeexUnit.h
new file mode 100644
index 000000000..da7e93dae
--- /dev/null
+++ b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Headers/SpeexUnit.h
@@ -0,0 +1,40 @@
+//
+// SpeexUnit.h
+// SpeexKit
+//
+// Created by zhihui liang on 2018/8/20.
+// Copyright © 2018年 www.zh-jieli.com. All rights reserved.
+//
+
+#import
+
+/**
+ * 流式解码回调PCM数据
+ */
+extern NSString *kSPEEX_DECODE_DATA; //speex decode
+
+@interface SpeexUnit : NSObject
+
++(void)speexIsLog:(BOOL)log;
+
+/**
+ * 直接【speex文件】转换成【pcm文件】
+ */
++(int)speexDecodeSPX:(NSString *)path_spx PCM:(NSString *)path_pcm;
+
+/**
+ * 流式解码【开启】
+ */
++(int)speexDecoderRun;
+
+/**
+ * 输入Speex的数据
+ */
++(void)speexWriteData:(NSData*)data;
+
+/**
+ * 流式解码【关闭】
+ */
++(int)speexDecoderStop;
+
+@end
diff --git a/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Info.plist b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Info.plist
new file mode 100644
index 000000000..f1478bd99
Binary files /dev/null and b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Info.plist differ
diff --git a/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Modules/module.modulemap b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Modules/module.modulemap
new file mode 100644
index 000000000..db8a36801
--- /dev/null
+++ b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/Modules/module.modulemap
@@ -0,0 +1,6 @@
+framework module SpeexKit {
+ umbrella header "SpeexKit.h"
+ export *
+
+ module * { export * }
+}
diff --git a/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/SpeexKit b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/SpeexKit
new file mode 100644
index 000000000..194c091f6
Binary files /dev/null and b/SpeexKit.xcframework/ios-arm64/SpeexKit.framework/SpeexKit differ
diff --git a/lib/modules/settings/views/settings_view.dart b/lib/modules/settings/views/settings_view.dart
index 4220460bd..c626f2e54 100644
--- a/lib/modules/settings/views/settings_view.dart
+++ b/lib/modules/settings/views/settings_view.dart
@@ -515,27 +515,27 @@ class SettingsView extends GetView {
// ? Colors.white.withOpacity(0.1)
// : Colors.grey[200]),
//BLE测试
- // _buildSimpleNavigationSetting(
- // title: 'opus解码测试',
- // subtitle: '测试opus解码',
- // icon: Icons.bluetooth_searching,
- // iconBgColor: isDarkMode
- // ? Colors.green[900]!.withOpacity(0.3)
- // : Colors.green[100]!,
- // iconColor:
- // isDarkMode ? Colors.green[300]! : Colors.green[600]!,
- // titleColor: isDarkMode ? Colors.white : null,
- // subtitleColor: isDarkMode ? Colors.white70 : null,
- // onTap: () {
- // Get.toNamed(Routes.opusTest);
- // },
- // isDarkMode: isDarkMode,
- // ),
- // Divider(
- // height: 1,
- // color: isDarkMode
- // ? Colors.white.withOpacity(0.1)
- // : Colors.grey[200]),
+ _buildSimpleNavigationSetting(
+ title: 'opus解码测试',
+ subtitle: '测试opus解码',
+ icon: Icons.bluetooth_searching,
+ iconBgColor: isDarkMode
+ ? Colors.green[900]!.withOpacity(0.3)
+ : Colors.green[100]!,
+ iconColor:
+ isDarkMode ? Colors.green[300]! : Colors.green[600]!,
+ titleColor: isDarkMode ? Colors.white : null,
+ subtitleColor: isDarkMode ? Colors.white70 : null,
+ onTap: () {
+ Get.toNamed(Routes.opusTest);
+ },
+ isDarkMode: isDarkMode,
+ ),
+ Divider(
+ height: 1,
+ color: isDarkMode
+ ? Colors.white.withOpacity(0.1)
+ : Colors.grey[200]),
// BLE测试
// _buildSimpleNavigationSetting(
diff --git a/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift b/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift
index 32cbf7d71..af51264a9 100644
--- a/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift
+++ b/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift
@@ -1463,7 +1463,7 @@ extension AgentServiceImpl: BleService.Callback {
}
func onAudioDataReceived1(data: Data) {
-
+
}
func onWakeupSignalReceived() {
diff --git a/local_plugins/azure_speech/ios/azure_speech/Package.swift b/local_plugins/azure_speech/ios/azure_speech/Package.swift
index 17ed7498e..ef7bf57ea 100644
--- a/local_plugins/azure_speech/ios/azure_speech/Package.swift
+++ b/local_plugins/azure_speech/ios/azure_speech/Package.swift
@@ -9,13 +9,16 @@ let package = Package(
],
dependencies: [
// 依赖speech接口模块
- .package(path: "../../../speech/ios/speech")
+ .package(path: "../../../speech/ios/speech"),
+ // 添加对ble_service的依赖
+ .package(path: "../../../ble_service/ios/ble_service")
],
targets: [
.target(
name: "azure_speech",
dependencies: [
.product(name: "speech", package: "speech"),
+ .product(name: "ble-service", package: "ble_service"),
"MicrosoftCognitiveServicesSpeech"
],
path: "Sources", // 修改为包含整个 Sources 目录
diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift
index fa5c166eb..fa4f5d684 100644
--- a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift
+++ b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift
@@ -3,6 +3,7 @@ import AVFoundation
import MicrosoftCognitiveServicesSpeech
import speech
import os.log
+import Network
// MARK: - 基于微软Azure语音服务的ASR实现
/**
@@ -21,6 +22,12 @@ public class AzureAsrHelper: NSObject {
private var recognizer: SPXSpeechRecognizer?
private var audioConfig: SPXAudioConfiguration?
+ // 网络监听相关
+ private var networkMonitor: NWPathMonitor?
+ private var networkQueue: DispatchQueue?
+ private var isNetworkAvailable = true
+ private var continuousCallback: ContinuousRecognizeCallback?
+
// 状态管理
private var _isContinuousRecognitionActive = false
@@ -110,20 +117,93 @@ public class AzureAsrHelper: NSObject {
// 预初始化音频组件
preInitializeAudioComponents()
+ // 初始化网络监听
+ initNetworkMonitoring()
+
return true
} catch {
os_log("初始化失败: %{public}@", log: log, type: .error, error.localizedDescription)
return false
}
}
-
+ /**
+ * 初始化网络监听
+ */
+ private func initNetworkMonitoring() {
+ networkQueue = DispatchQueue(label: "NetworkMonitor")
+ networkMonitor = NWPathMonitor()
+
+ networkMonitor?.pathUpdateHandler = { [weak self] path in
+ guard let self = self else { return }
+
+ let wasAvailable = self.isNetworkAvailable
+ self.isNetworkAvailable = (path.status == .satisfied)
+
+ if wasAvailable && !self.isNetworkAvailable {
+ // 网络断开
+ self.handleNetworkLost()
+ } else if !wasAvailable && self.isNetworkAvailable {
+ // 网络恢复
+ self.handleNetworkAvailable()
+ }
+ }
+
+ if let queue = networkQueue {
+ networkMonitor?.start(queue: queue)
+ }
+
+ os_log("网络监听已初始化", log: log, type: .info)
+ }
+
+ /**
+ * 处理网络可用事件
+ */
+ private func handleNetworkAvailable() {
+ os_log("网络已恢复", log: log, type: .info)
+
+ DispatchQueue.main.async { [weak self] in
+ // self?.continuousCallback?.onNetworkRestored()
+ }
+ }
+
+ /**
+ * 处理网络丢失事件
+ */
+ private func handleNetworkLost() {
+ os_log("网络连接丢失", log: log, type: .error)
+
+ // 立即停止音频处理
+ stopAudioProcessingImmediately()
+
+ DispatchQueue.main.async { [weak self] in
+ // self?.continuousCallback?.onNetworkError("网络连接已断开")
+ }
+ }
+
+ /**
+ * 立即停止音频处理
+ */
+ private func stopAudioProcessingImmediately() {
+ audioStream?.stopMicrophoneCapture()
+
+ if _isContinuousRecognitionActive {
+ do {
+ try recognizer?.stopContinuousRecognition()
+ _isContinuousRecognitionActive = false
+ os_log("因网络问题强制停止识别", log: log, type: .info)
+ } catch {
+ _isContinuousRecognitionActive = false
+ os_log("强制停止识别失败: %@", log: log, type: .error, error.localizedDescription)
+ }
+ }
+ }
/**
* 预初始化音频组件
* 在初始化阶段就准备好音频流和相关组件,减少首次启动延迟
*/
private func preInitializeAudioComponents() {
if audioStream == nil {
- audioStream = SimpleAudioReceiver(parentHelper: self)
+ audioStream = SimpleAudioReceiver()
audioStream?.initAudioRecord()
}
@@ -149,7 +229,11 @@ public class AzureAsrHelper: NSObject {
) -> Bool {
guard speechConfig != nil else {
print("语音服务未初始化")
- //callback.onError("语音服务未初始化")
+ return false
+ }
+
+ // 检查网络状态
+ if !checkNetworkStatus() {
return false
}
@@ -170,6 +254,8 @@ public class AzureAsrHelper: NSObject {
}
return false
}
+
+ print("startContinuousRecognition:\(audioSourceType)")
// 启动音频处理
audioStream?.startAudioRecord(audioSourceType: audioSourceType == .microphone ? .microphone : .external, audioDataCallback: audioDataCallback)
@@ -381,7 +467,7 @@ public class AzureAsrHelper: NSObject {
* 设置麦克风音频流
*/
private func setupMicrophoneStream() {
- audioStream = SimpleAudioReceiver(parentHelper: self)
+ audioStream = SimpleAudioReceiver()
// 【优化】检查音频配置是否已存在
if audioConfig == nil, let pushStream = audioStream?.pushAudioStream {
audioConfig = SPXAudioConfiguration(streamInput: pushStream)
@@ -462,15 +548,19 @@ public class AzureAsrHelper: NSObject {
/**
* 设置事件监听器
*/
- public func setupEventListeners(callback: ContinuousRecognizeCallback) -> Bool{
+ public func setupEventListeners(callback: ContinuousRecognizeCallback) -> Bool {
print("设置ssssss监听器:${speechConfig}")
- // 重设识别器
+ // 保存回调引用用于网络事件
+ self.continuousCallback = callback
+
+ // 重设识别器
if (!setupRecognizer()) {
return false
}
- guard let recognizer = recognizer else { return false}
- // 正在识别事件
+ guard let recognizer = recognizer else { return false }
+
+ // 正在识别事件
recognizer.addRecognizingEventHandler { [weak self] (_, event) in
guard let self = self else { return }
let result = event.result
@@ -532,7 +622,12 @@ public class AzureAsrHelper: NSObject {
os_log("识别取消: %{public}@", log: self.log, type: .error, errorDetails)
- callback.onCanceled(reason, errorDetails)
+ // 检查是否为网络相关错误
+ if self.isNetworkRelatedError(errorDetails) {
+ callback.onError("网络连接问题: \(errorDetails)")
+ } else {
+ callback.onCanceled(reason, errorDetails)
+ }
}
return true
}
@@ -575,7 +670,7 @@ public class AzureAsrHelper: NSObject {
if audioStream == nil {
// 创建外部音频拉流对象
- audioStream = SimpleAudioReceiver(parentHelper: self)
+ audioStream = SimpleAudioReceiver()
audioStream?.initAudioRecord()
}
@@ -702,6 +797,43 @@ public class AzureAsrHelper: NSObject {
*/
func onError(_ error: String)
}
+ /**
+ * 检查网络状态
+ * @return 网络是否可用
+ */
+private func checkNetworkStatus() -> Bool {
+ guard let monitor = networkMonitor else {
+ os_log("网络监听器未初始化,假设网络可用", log: log)
+ return true
+ }
+
+ let currentPath = monitor.currentPath
+ let isAvailable = currentPath.status == .satisfied
+
+ if !isAvailable {
+ os_log("网络不可用,无法启动语音识别", log: log, type: .error)
+ continuousCallback?.onError("网络连接不可用,请检查网络设置")
+ }
+
+ return isAvailable
+}
+
+/**
+ * 判断是否为网络相关错误
+ * @param errorDetails 错误详情
+ * @return 是否为网络错误
+ */
+private func isNetworkRelatedError(_ errorDetails: String) -> Bool {
+ let networkErrorKeywords = [
+ "network", "connection", "timeout", "unreachable",
+ "网络", "连接", "超时", "不可达",
+ "ConnectionFailure", "NetworkError", "TimeoutError"
+ ]
+
+ let lowercaseError = errorDetails.lowercased()
+ return networkErrorKeywords.contains { lowercaseError.contains($0.lowercased()) }
+}
+
}
// //ios 语言检测
@@ -754,3 +886,4 @@ public class AzureAsrHelper: NSObject {
// "originalCode": topResult.language
// ]
// }
+
diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift
index 4fbb39d9c..0f5c93eab 100644
--- a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift
+++ b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift
@@ -5,6 +5,8 @@ import MicrosoftCognitiveServicesSpeech
// 自定义语音处理组件,提供音频流处理等功能
import speech
import os.log
+// 导入蓝牙服务模块,用于处理蓝牙设备回调
+import ble_service
/**
* Azure Speech Plugin
@@ -32,6 +34,14 @@ import os.log
// 是否已添加TTS事件监听器
private var isTtsListenerAdded = false
+ // AST相关
+ private var astChannel: FlutterMethodChannel?
+ private var astEventChannel: FlutterEventChannel?
+ private let azureAstHelper = IntegratedSpeechTranslationService()
+ // 创建事件回调
+ private var astEventCallback: AstEventCallback?
+ // 是否已添加AST事件监听器
+ private var isAstListenerAdded = false
// 当前的连续识别回调
private var currentAsrCallback: AsrCallbackWrapper?
@@ -39,7 +49,9 @@ import os.log
// 插件注册
public static func register(with registrar: FlutterPluginRegistrar) {
let instance = AzureSpeechPlugin()
-
+ // 2. 初始化BleService并注册回调
+ BleService.shared.addCallback(instance)
+
// 初始化ASR通道
let asrChannel = FlutterMethodChannel(name: "azure_speech/asr", binaryMessenger: registrar.messenger())
registrar.addMethodCallDelegate(instance, channel: asrChannel)
@@ -60,6 +72,17 @@ import os.log
instance?.handleTtsMethodCall(call, result: result)
}
+
+ // 初始化AST通道
+ let astChannel = FlutterMethodChannel(name: "azure_speech/ast", binaryMessenger: registrar.messenger())
+ registrar.addMethodCallDelegate(instance, channel: astChannel)
+ instance.astChannel = astChannel
+
+ // 设置AST通道处理器 - 使用实例方法
+ astChannel.setMethodCallHandler { [weak instance] (call, result) in
+ instance?.handleAstMethodCall(call, result: result)
+ }
+
// 初始化ASR事件通道
let asrEventChannel = FlutterEventChannel(name: "azure_speech/asr_events", binaryMessenger: registrar.messenger())
asrEventChannel.setStreamHandler(instance)
@@ -69,6 +92,14 @@ import os.log
let ttsEventChannel = FlutterEventChannel(name: "azure_speech/tts_events", binaryMessenger: registrar.messenger())
ttsEventChannel.setStreamHandler(instance)
instance.ttsEventChannel = ttsEventChannel
+
+ // 初始化TTS事件通道
+ let astEventChannel = FlutterEventChannel(name: "azure_speech/asr_events", binaryMessenger: registrar.messenger())
+ astEventChannel.setStreamHandler(instance)
+ instance.astEventChannel = astEventChannel
+
+
+
}
// 发送ASR事件方法
internal func sendAsrEvent(_ event: [String: Any]) {
@@ -153,20 +184,21 @@ import os.log
return
}
- // 解析音频源类型
- let audioSourceType: AzureAsrHelper.AudioSourceType
- if let args = call.arguments as? [String: Any],
- let audioSourceString = args["audioSourceType"] as? String {
- switch audioSourceString.lowercased() {
- case "external":
- audioSourceType = .external
- default:
- audioSourceType = .microphone
- }
- } else {
- audioSourceType = .microphone
+ // 解析音频源类型参数
+ guard let args = call.arguments as? [String: Any],
+ let isExternalActive = args["audioSourceType"] as? Bool else {
+ result(FlutterError(code: "INVALID_ARGUMENTS", message: "必要的参数不能为空", details: nil))
+ return
}
+ // 根据参数确定音频源类型
+ let audioSourceType = isExternalActive ?
+ AzureAsrHelper.AudioSourceType.external :
+ AzureAsrHelper.AudioSourceType.microphone
+
+ print("startContinuousRecognition: \(audioSourceType)")
+
+ // 启动连续识别
let success = azureAsrHelper.startContinuousRecognition(
audioSourceType: audioSourceType
)
@@ -184,17 +216,17 @@ import os.log
callback: currentAsrCallback!
)
result(success)
-
- case "disableBluetoothAudio":
- azureAsrHelper.disableBluetoothAudio();
- return
-
- case "restoreOriginalAudioState":
- azureAsrHelper.restoreOriginalAudioState();
- return
-
+
+ case "disableBluetoothAudio":
+ azureAsrHelper.disableBluetoothAudio();
+ return
+
+ case "restoreOriginalAudioState":
+ azureAsrHelper.restoreOriginalAudioState();
+ return
+
case "stopContinuousRecognition":
-
+
let success = azureAsrHelper.stopContinuousRecognition()
currentAsrCallback = nil
result(success)
@@ -287,15 +319,15 @@ import os.log
} catch {
result(FlutterError(code: "ENABLERECORD_ERROR", message: error.localizedDescription, details: nil))
}
-
-
+
+
case "pauseRecord":
azureAsrHelper.pauseRecord()
result(true)
- // case "resumeRecord":
- // azureAsrHelper.resumeRecord()
- // result(true)
+ // case "resumeRecord":
+ // azureAsrHelper.resumeRecord()
+ // result(true)
case "stopRecord":
guard let args = call.arguments as? [String: Any],
@@ -311,16 +343,16 @@ import os.log
}
case "disableBluetoothAudio":
print("disableBluetoothAudio")
- azureAsrHelper.disableBluetoothAudio();
- azureTtsHelper.stop()
+ azureAsrHelper.disableBluetoothAudio();
+ azureTtsHelper.stop()
result(true)
case "restoreOriginalAudioState":
print("restoreOriginalAudioState")
- azureAsrHelper.restoreOriginalAudioState();
- azureTtsHelper.stop()
+ azureAsrHelper.restoreOriginalAudioState();
+ azureTtsHelper.stop()
result(true)
case "setAudioConfig":
@@ -415,13 +447,13 @@ import os.log
if (type == 0) {
// 默认(如果有耳机选耳机,否则使用系统扬声器)
azureAsrHelper.restoreOriginalAudioState();
- // azureTtsHelper.setAudioOutputDevice()
+ // azureTtsHelper.setAudioOutputDevice()
} else if (type == 1) {
// 强制使用声器
azureAsrHelper.disableBluetoothAudio();
- // azureTtsHelper.setAudioOutputDevice()
+ // azureTtsHelper.setAudioOutputDevice()
} else if (type == 2) {
// 强制使用耳机
@@ -437,60 +469,388 @@ import os.log
result(FlutterMethodNotImplemented)
}
}
+
+ // MARK: - AST 方法处理
+ private func handleAstMethodCall(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
+ switch call.method {
+ case "enableRecord":
+ guard let args = call.arguments as? [String: Any],
+ let filePath = args["filePath"] as? String else {
+ result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing filePath", details: nil))
+ return
+ }
+
+ do {
+ os_log("音频文件名称为: %@", log: log, type: .info, filePath)
+ try azureAstHelper.enableRecord(filePath: filePath)
+ result(true)
+ } catch {
+ result(FlutterError(code: "ENABLERECORD_ERROR", message: error.localizedDescription, details: nil))
+ }
+
+ case "startContinuousTranslation":
+ do {
+ os_log("开启翻译", log: log, type: .info)
+ try azureAstHelper.startContinuousTranslation()
+ result(true)
+ } catch {
+ result(FlutterError(code: "START_CONTINUOUS_TRANSLATION_ERROR", message: error.localizedDescription, details: nil))
+ }
+
+ case "stopContinuousTranslation":
+ do {
+ os_log("停止翻译", log: log, type: .info)
+ try azureAstHelper.stopContinuousTranslation()
+ result(true)
+ } catch {
+ result(FlutterError(code: "STOP_CONTINUOUS_TRANSLATION_ERROR", message: error.localizedDescription, details: nil))
+ }
+
+ case "dispose":
+ do {
+ os_log("释放AST资源", log: log, type: .info)
+ azureAstHelper.dispose()
+ result(true)
+ } catch {
+ result(FlutterError(code: "DISPOSE_ERROR", message: error.localizedDescription, details: nil))
+ }
+
+ case "recognizeCallback":
+ os_log("recognizeCallback:", log: log, type: .info)
+ result(true)
+
+ case "path":
+ guard let args = call.arguments as? [String: Any],
+ let filePath = args["filePath"] as? String else {
+ result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing filePath", details: nil))
+ return
+ }
+
+ let fileURL = URL(fileURLWithPath: filePath)
+
+ // if FileManager.default.fileExists(atPath: filePath) {
+ // // 启动异步任务来按播放速度读取音频文件
+ // Task {
+ // // await streamAudioFile(fileURL: fileURL)
+ // }
+ // result(true)
+ // } else {
+ // result(FlutterError(code: "FILE_NOT_FOUND", message: "音频文件不存在: \(filePath)", details: nil))
+ // }
+
+ case "initialize":
+ guard let args = call.arguments as? [String: Any] else {
+ result(FlutterError(code: "INVALID_ARGUMENTS", message: "Missing arguments", details: nil))
+ return
+ }
+
+ let subscriptionKey = args["subscriptionKey"] as? String ?? ""
+ let region = args["region"] as? String ?? ""
+ let supportedLanguages = args["supportedLanguages"] as? [String] ?? ["zh-CN"]
+ let useExternalAudio = args["useExternalAudio"] as? Bool ?? false
+
+ // 获取翻译服务配置参数
+ let translationAccessKey = args["translationAccessKey"] as? String ?? ""
+ let translationSecretKey = args["translationSecretKey"] as? String ?? ""
+ let translationRegion = args["translationRegion"] as? String ?? "cn-north-1"
+
+ os_log("初始化AST服务", log: log, type: .info)
+
+ // 创建Azure配置
+ let azureConfig = AzureConfiguration(
+ subscriptionKey: subscriptionKey,
+ region: region
+ )
+
+ // 创建翻译配置
+ let translationConfig = TranslationConfiguration(
+ accessKey: translationAccessKey,
+ secretKey: translationSecretKey,
+ region: translationRegion
+ )
+
+ // 创建服务配置
+ let serviceConfig = IntegratedSpeechTranslationService.ServiceConfiguration(
+ sourceLanguage: supportedLanguages.first ?? "zh-CN",
+ targetLanguage: supportedLanguages.count > 1 ? supportedLanguages[1] : "en-US"
+ )
+
+ // 创建事件回调
+ let callback = AstEventCallback(plugin: self)
+ astEventCallback = callback
+
+ // 使用异步任务调用初始化方法
+ Task {
+ await azureAstHelper.initialize(
+ azureConfig: azureConfig,
+ translationConfig: translationConfig,
+ serviceConfig: serviceConfig,
+ callback: callback
+ )
+ }
+ result(true)
+
+ default:
+ result(FlutterMethodNotImplemented)
+ }
+ }
+
}
-
-// MARK: - ASR回调包装器
-private class AsrCallbackWrapper: AzureAsrHelper.ContinuousRecognizeCallback {
+// MARK: - AST Event Callback
+/**
+ * AST事件回调类
+ * 实现 IntegratedSpeechTranslationService.ServiceEventCallback 协议
+ */
+private class AstEventCallback: IntegratedSpeechTranslationService.ServiceEventCallback {
private weak var plugin: AzureSpeechPlugin?
+ /**
+ * 构造函数
+ * @param plugin AzureSpeechPlugin 实例的弱引用
+ */
init(plugin: AzureSpeechPlugin) {
self.plugin = plugin
}
- func onResult(_ text: String, _ detectedLanguage: String) {
- plugin?.sendAsrEvent([
- "type": "result",
- "text": text,
- "detectedLanguage": detectedLanguage
- ])
+ /**
+ * 服务初始化完成回调
+ */
+ public func onServiceInitialized() {
+// plugin?.sendAsrEvent([
+// "type": "serviceInitialized"
+// ])
}
- func onRecognizing(_ recognizing: String, _ detectedLanguage: String) {
- plugin?.sendAsrEvent([
- "type": "recognizing",
- "text": recognizing,
- "detectedLanguage": detectedLanguage
- ])
+ /**
+ * 识别中回调
+ * @param text 正在识别的文本
+ * @param language 语言
+ * @param confidence 置信度
+ */
+ public func onRecognizing(text: String, language: String, confidence: Float) {
+// plugin?.sendAsrEvent([
+// "type": "recognizing",
+// "text": text,
+// "language": language,
+// "confidence": confidence
+// ])
}
- func onSessionStarted() {
- plugin?.sendAsrEvent([
- "type": "sessionStarted"
- ])
+ /**
+ * 识别完成回调
+ * @param text 识别的文本
+ * @param language 语言
+ * @param confidence 置信度
+ */
+ public func onRecognized(text: String, language: String, confidence: Float) {
+ print( "识别到文本: \(text), 语言: \(language), 置信度: \(confidence)")
+ plugin?.sendAsrEvent([
+ "type": "result1",
+ "text": text,
+ "language": language,
+ ])
}
- func onSessionStopped() {
- plugin?.sendAsrEvent([
- "type": "sessionStopped"
- ])
+ /**
+ * 翻译完成回调
+ * @param originalText 原始文本
+ * @param translatedText 翻译文本
+ * @param targetLanguage 目标语言
+ */
+ public func onTranslated(originalText: String, translatedText: String, targetLanguage: String) {
+// plugin?.sendAsrEvent([
+// "type": "translated",
+// "originalText": originalText,
+// "translatedText": translatedText,
+// "targetLanguage": targetLanguage
+// ])
}
- func onCanceled(_ reason: String, _ errorDetails: String) {
- plugin?.sendAsrEvent([
- "type": "canceled",
- "reason": reason,
- "errorDetails": errorDetails
- ])
+ /**
+ * 翻译开始回调
+ * @param text 要翻译的文本
+ */
+ public func onTranslationStarted(text: String) {
+// plugin?.sendAsrEvent([
+// "type": "translationStarted",
+// "text": text
+// ])
}
- func onError(_ error: String) {
- plugin?.sendAsrEvent([
- "type": "error",
- "error": error
- ])
+ /**
+ * 翻译失败回调
+ * @param text 翻译失败的文本
+ * @param error 错误信息
+ */
+ public func onTranslationFailed(text: String, error: String) {
+// plugin?.sendAsrEvent([
+// "type": "translationFailed",
+// "text": text,
+// "error": error
+// ])
+ }
+
+ /**
+ * 语音合成开始回调
+ * @param text 要合成的文本
+ */
+ func onSynthesisStarted(text: String) {
+// plugin?.sendAsrEvent([
+// "type": "synthesisStarted",
+// "text": text
+// ])
+ }
+
+ /**
+ * 语音合成完成回调
+ * @param text 合成的文本
+ */
+ public func onSynthesisCompleted(text: String) {
+// plugin?.sendAsrEvent([
+// "type": "synthesisCompleted",
+// "text": text
+// ])
+ }
+
+ /**
+ * 语音合成失败回调
+ * @param text 合成失败的文本
+ * @param error 错误信息
+ */
+ public func onSynthesisFailed(text: String, error: String) {
+// plugin?.sendAsrEvent([
+// "type": "synthesisFailed",
+// "text": text,
+// "error": error
+// ])
+ }
+
+ /**
+ * 语音合成进度回调
+ * @param text 正在合成的文本
+ * @param progress 进度(0.0-1.0)
+ */
+ public func onSynthesisProgress(text: String, progress: Float) {
+// plugin?.sendAsrEvent([
+// "type": "synthesisProgress",
+// "text": text,
+// "progress": progress
+// ])
+ }
+
+ /**
+ * 识别开始回调
+ */
+ func onRecognitionStarted() {
+// plugin?.sendAsrEvent([
+// "type": "recognitionStarted"
+// ])
+ }
+
+ /**
+ * 识别停止回调
+ */
+ public func onRecognitionStopped() {
+// plugin?.sendAsrEvent([
+// "type": "recognitionStopped"
+// ])
+ }
+
+ /**
+ * 状态变化回调
+ * @param component 组件名称
+ * @param isActive 是否激活
+ */
+ public func onStateChanged(component: String, isActive: Bool) {
+// plugin?.sendAsrEvent([
+// "type": "stateChanged",
+// "component": component,
+// "isActive": isActive
+// ])
+ }
+
+ /**
+ * 错误回调
+ * @param component 组件名称
+ * @param error 错误信息
+ */
+ public func onError(component: String, error: String) {
+// plugin?.sendAsrEvent([
+// "type": "error",
+// "component": component,
+// "error": error
+// ])
+ }
+
+ /**
+ * 语音合成音频数据生成回调
+ * @param text 合成的文本
+ * @param audioData 音频数据
+ */
+ public func onSynthesisAudioGenerated(text: String, audioData: Data) {
+ print("语音合成音频数据生成回调", text, audioData.count)
+ // 调用BLE服务写入音频数据
+ BleService.shared.writeExternalAudioData(data: audioData)
+
+// plugin?.sendAsrEvent([
+// "type": "synthesisAudioGenerated",
+// "text": text,
+// "audioDataSize": audioData.count
+// ])
}
}
+extension AzureSpeechPlugin: BleService.Callback {
+ /// 扫描结果回调
+ /// - Parameter devices: 扫描到的设备列表
+ public func onScanResult(devices: [[String: Any]]) {
+ }
+
+ /// 连接状态变化回调
+ /// - Parameter state: 连接状态
+ public func onConnectionStateChanged(state: Int) {
+ }
+
+ /// 接收到音频数据回调
+ /// - Parameter data: 音频数据
+ public func onAudioDataReceived(data: Data) {
+ // 安全解包版本
+ guard let audioStream = azureAsrHelper.audioStream else {
+ os_log("音频流未初始化", type: .error)
+ return
+ }
+ audioStream.saveAudioDataTo(data: data)
+ }
+
+ /// 接收到音频数据回调1
+ /// - Parameter data: 音频数据
+ public func onAudioDataReceived1(data: Data) {
+ // 安全解包版本
+ guard let audioStream = azureAstHelper.audioProcessor else {
+ os_log("音频流未初始化", type: .error)
+ return
+ }
+ audioStream.saveAudioDataTo(data: data)
+ }
+
+ /// 接收到编码数据回调
+ /// - Parameter data: 编码数据
+ public func onEncodedDataReceived(data: Data) {
+
+ }
+
+ /// 唤醒信号接收回调
+ public func onWakeupSignalReceived() {
+
+ }
+
+ /// 设备信息接收回调
+ /// - Parameters:
+ /// - infoType: 信息类型
+ /// - infoData: 信息数据
+ public func onDeviceInfoReceived(infoType: Int, infoData: [String: Any]) {
+ }
+}
// MARK: - 事件处理
extension AzureSpeechPlugin: FlutterStreamHandler {
public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
@@ -596,6 +956,7 @@ extension AzureSpeechPlugin: AudioDataListener {
}
}
+
// MARK: - 音频数据回调实现
/**
* 音频数据回调实现类
@@ -621,4 +982,89 @@ private class AudioDataCallbackImpl: SimpleAudioReceiver.AudioDataCallback {
}
}
+// MARK: - ASR Callback Wrapper
+/**
+ * ASR回调包装器类
+ * 实现 AzureAsrHelper.ContinuousRecognizeCallback 协议
+ */
+private class AsrCallbackWrapper: AzureAsrHelper.ContinuousRecognizeCallback {
+ private weak var plugin: AzureSpeechPlugin?
+
+ /**
+ * 初始化ASR回调包装器
+ * @param plugin AzureSpeechPlugin实例
+ */
+ init(plugin: AzureSpeechPlugin) {
+ self.plugin = plugin
+ }
+
+ /**
+ * 识别结果回调
+ * @param text 识别的文本
+ * @param detectedLanguage 检测到的语言
+ */
+ func onResult(_ text: String, _ detectedLanguage: String) {
+ plugin?.sendAsrEvent([
+ "type": "result",
+ "text": text,
+ "detectedLanguage": detectedLanguage
+ ])
+ }
+
+ /**
+ * 识别中回调
+ * @param text 正在识别的文本
+ * @param detectedLanguage 检测到的语言
+ */
+ func onRecognizing(_ text: String, _ detectedLanguage: String) {
+ plugin?.sendAsrEvent([
+ "type": "recognizing",
+ "text": text,
+ "detectedLanguage": detectedLanguage
+ ])
+ }
+
+ /**
+ * 会话开始回调
+ */
+ func onSessionStarted() {
+ plugin?.sendAsrEvent([
+ "type": "sessionStarted"
+ ])
+ }
+
+ /**
+ * 会话结束回调
+ */
+ func onSessionStopped() {
+ plugin?.sendAsrEvent([
+ "type": "sessionStopped"
+ ])
+ }
+
+ /**
+ * 识别取消回调
+ * @param reason 取消原因
+ * @param errorDetails 错误详情
+ */
+ func onCanceled(_ reason: String, _ errorDetails: String) {
+ plugin?.sendAsrEvent([
+ "type": "canceled",
+ "reason": reason,
+ "errorDetails": errorDetails
+ ])
+ }
+
+ /**
+ * 错误回调
+ * @param error 错误信息
+ */
+ func onError(_ error: String) {
+ plugin?.sendAsrEvent([
+ "type": "error",
+ "error": error
+ ])
+ }
+}
+
diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/IntegratedSpeechTranslationService.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/IntegratedSpeechTranslationService.swift
index 9c4e3791c..1cf58606a 100644
--- a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/IntegratedSpeechTranslationService.swift
+++ b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/IntegratedSpeechTranslationService.swift
@@ -44,7 +44,7 @@ import os.log
private var translationService: TranslationServiceInterface?
// 音频处理
- private var audioProcessor: SimpleAudioReceiver?
+ public var audioProcessor: SimpleAudioReceiver?
private var audioConfig: SPXAudioConfiguration?
// 录音文件处理
@@ -333,7 +333,7 @@ import os.log
* 初始化音频处理器
*/
private func initializeAudioProcessor() {
- audioProcessor = SimpleAudioReceiver(parentHelper: self as! AzureAsrHelper)
+ audioProcessor = SimpleAudioReceiver()
audioProcessor?.initAudioRecord()
// 检查音频配置是否已存在
if audioConfig == nil, let pushStream = audioProcessor?.pushAudioStream {
@@ -486,16 +486,24 @@ import os.log
}
}
- // 合成进行中事件
+ // 合成进行中事件 - 修改为返回音频数据
synthesizer?.addSynthesizingEventHandler { [weak self] (synthesizer, event) in
guard let self = self else { return }
- os_log("合成进行中事件", log: self.log, type: .debug)
- // 计算进度(简化版)
- let progress: Float = 0.5
+ // 安全解包audioData
+ guard let audioData = event.result.audioData else {
+ os_log("合成进行中事件,音频数据为空", log: self.log, type: .debug)
+ return
+ }
+
+ os_log("合成进行中事件,音频数据长度: %d bytes", log: self.log, type: .debug, audioData.count)
+
+
DispatchQueue.main.async {
- self.eventCallback?.onSynthesisProgress(text: "", progress: progress)
+
+ // 立即返回当前生成的音频数据
+ self.eventCallback?.onSynthesisAudioGenerated(text: "", audioData: audioData)
}
}
@@ -506,6 +514,7 @@ import os.log
os_log("合成完成事件", log: self.log, type: .info)
DispatchQueue.main.async {
+ self.serviceState.isSynthesizing = false
self.eventCallback?.onStateChanged(component: "Synthesis", isActive: false)
}
}
@@ -654,10 +663,8 @@ import os.log
}
// 进行语音合成
- if let audioData = synthesizeText(translatedText) {
- await MainActor.run {
- eventCallback?.onSynthesisAudioGenerated(text: translatedText, audioData: audioData)
- }
+ if synthesizeTextStreaming(translatedText) {
+ print("语音合成已启动")
}
} else {
let errorMessage = translationResult?.error ?? "翻译失败"
@@ -688,54 +695,34 @@ import os.log
/**
* 合成文本为音频数据
*/
- private func synthesizeText(_ text: String) -> Data? {
+ /// 流式语音合成
+ /// - Parameter text: 要合成的文本
+ /// - Returns: 合成是否成功启动
+ private func synthesizeTextStreaming(_ text: String) -> Bool {
guard let synthesizer = synthesizer else {
os_log("语音合成器未初始化", log: log, type: .error)
- return nil
+ return false
}
do {
let ssml = buildSSML(text: text)
- os_log("开始合成语音: %@", log: log, type: .info, text)
-
+ os_log("开始流式合成语音: %@", log: log, type: .info, text)
+
serviceState.isSynthesizing = true
DispatchQueue.main.async {
self.eventCallback?.onSynthesisStarted(text: text)
self.eventCallback?.onStateChanged(component: "Synthesis", isActive: true)
}
+ try synthesizer.speakSsml(ssml)
+
- let result = try synthesizer.speakSsml(ssml)
-
- serviceState.isSynthesizing = false
-
- DispatchQueue.main.async {
- self.eventCallback?.onStateChanged(component: "Synthesis", isActive: false)
- }
-
- if result.reason == .synthesizingAudioCompleted {
- os_log("语音合成成功", log: log, type: .info)
-
- DispatchQueue.main.async {
- self.eventCallback?.onSynthesisCompleted(text: text)
- }
-
- return result.audioData
- } else {
- let errorMessage = "合成失败: \(result.reason)"
- os_log("%@", log: log, type: .error, errorMessage)
-
- DispatchQueue.main.async {
- self.eventCallback?.onSynthesisFailed(text: text, error: errorMessage)
- }
-
- return nil
- }
+ return true
} catch {
serviceState.isSynthesizing = false
- let errorMessage = "合成异常: \(error.localizedDescription)"
+ let errorMessage = "合成启动异常: \(error.localizedDescription)"
os_log("%@", log: log, type: .error, errorMessage)
DispatchQueue.main.async {
@@ -743,10 +730,17 @@ import os.log
self.eventCallback?.onStateChanged(component: "Synthesis", isActive: false)
}
- return nil
+ return false
}
}
+ /// 保留原有的同步合成方法作为备用
+ private func synthesizeText(_ text: String) -> Data? {
+ // 现在调用流式合成方法
+ let success = synthesizeTextStreaming(text)
+ return success ? Data() : nil // 返回空数据表示已启动,实际数据通过回调返回
+ }
+
/**
* 构建SSML
*/
diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/tools/SimpleAudioReceiver.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/tools/SimpleAudioReceiver.swift
index 029ef7785..f9900b3b2 100644
--- a/local_plugins/azure_speech/ios/azure_speech/Sources/tools/SimpleAudioReceiver.swift
+++ b/local_plugins/azure_speech/ios/azure_speech/Sources/tools/SimpleAudioReceiver.swift
@@ -38,14 +38,8 @@ public class SimpleAudioReceiver: NSObject {
private var currentRoute: AudioOutputRoute?
//public var onAudioData: ((Data) -> Void)?
public var recordfile: RecordFile?
- // 添加对外部类的弱引用
- private weak var parentHelper: AzureAsrHelper?
-
- // 添加初始化方法,接收外部类引用
- init(parentHelper: AzureAsrHelper) {
- self.parentHelper = parentHelper
- super.init()
- }
+
+
/**
* 初始化
*/
@@ -170,7 +164,7 @@ public class SimpleAudioReceiver: NSObject {
*/
public func saveAudioDataTo(data: Data) {
// 通过父类引用调用方法
- if audioSourceType != .external || !(parentHelper?.isContinuousRecognitionActive() ?? false) {
+ if audioSourceType != .external {
return
}
// print("外部data=\(data)")
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/Info.plist b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/Info.plist
new file mode 100644
index 000000000..21abfc01c
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/Info.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ AvailableLibraries
+
+
+ BinaryPath
+ JLAudioUnitKit.framework/JLAudioUnitKit
+ LibraryIdentifier
+ ios-arm64
+ LibraryPath
+ JLAudioUnitKit.framework
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ ios
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLAudioUnitKit.h b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLAudioUnitKit.h
new file mode 100644
index 000000000..b7141b1bd
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLAudioUnitKit.h
@@ -0,0 +1,24 @@
+//
+// JLAudioUnitKit.h
+// JLAudioUnitKit
+//
+// Created by EzioChan on 2024/11/14.
+//
+
+#import
+
+//! Project version number for JLAudioUnitKit.
+FOUNDATION_EXPORT double JLAudioUnitKitVersionNumber;
+
+//! Project version string for JLAudioUnitKit.
+FOUNDATION_EXPORT const unsigned char JLAudioUnitKitVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import
+
+#import
+#import
+#import
+#import
+#import
+#import
+#import
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLAudioUnitPlayer.h b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLAudioUnitPlayer.h
new file mode 100644
index 000000000..7da831c67
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLAudioUnitPlayer.h
@@ -0,0 +1,58 @@
+//
+// JLAudioUnitPlayer.h
+// JLAudioUnitKit
+//
+// Created by EzioChan on 2025/4/16.
+// Copyright © 2025 ZhuHai JieLi Technology Co.,Ltd. All rights reserved.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NS_ENUM(NSInteger, JLAudioUnitPlayerType) {
+ JLAudioUnitPlayerTypeFile, // 支持 MP3/WAV/AAC 等文件格式(AVAudioPlayer)
+ JLAudioUnitPlayerTypePCM // 支持 PCM 流式播放(Audio Queue)
+};
+
+@class JLAudioUnitPlayer;
+
+@protocol JLAudioPlayerDelegate
+@optional
+// 播放进度更新(秒)
+- (void)audioPlayer:(JLAudioUnitPlayer *)player didUpdateProgress:(NSTimeInterval)currentTime duration:(NSTimeInterval)duration;
+// 播放完成
+- (void)audioPlayerDidFinishPlaying:(JLAudioUnitPlayer *)player;
+// 播放错误
+- (void)audioPlayer:(JLAudioUnitPlayer *)player didFailWithError:(NSError *)error;
+@end
+
+@interface JLAudioUnitPlayer : NSObject
+
+@property (nonatomic, weak) id delegate;
+@property (nonatomic, readonly) NSTimeInterval duration; // 总时长(文件模式下有效)
+@property (nonatomic, readonly) NSTimeInterval currentTime;
+@property (nonatomic, readonly) BOOL isPlaying;
+
+#pragma mark - 初始化方法
+
+/// 文件播放初始化(MP3/WAV/AAC)
+- (instancetype)initWithAudioFile:(NSString *)filePath;
+
+/// PCM 流播放初始化(需指定格式)
+- (instancetype)initWithPCMFormat:(AudioStreamBasicDescription)format;
+
+#pragma mark - 播放控制
+- (void)play;
+- (void)pause;
+- (void)stop;
+- (void)seekToTime:(NSTimeInterval)time; // 仅文件模式有效
+
+#pragma mark - PCM 流式输入(仅 PCM 模式有效)
+- (void)appendPCMData:(NSData *)pcmData;
+- (void)endPCMStream; // 结束 PCM 流输入
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLOpusDecoder.h b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLOpusDecoder.h
new file mode 100644
index 000000000..711e2e99a
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLOpusDecoder.h
@@ -0,0 +1,66 @@
+//
+// JLOpusDecoder.h
+// JLAudioUnitKit
+//
+// Created by EzioChan on 2024/11/14.
+// Copyright © 2024 ZhuHai JieLi Technology Co.,Ltd. All rights reserved.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+@class JLOpusDecoder;
+
+/// Opus 解码代理
+@protocol JLOpusDecoderDelegate
+
+/// Opus 数据解码
+/// - Parameters:
+/// - decoder: 解码器
+/// - data: pcm 数据
+/// - error: 错误信息
+-(void)opusDecoder:(JLOpusDecoder *)decoder Data:(NSData* _Nullable)data error:(NSError* _Nullable)error;
+
+@end
+
+typedef void(^JLOpusDecoderConvertBlock)(NSString *_Nullable pcmPath,NSError *_Nullable error);
+
+/// Opus 解码
+@interface JLOpusDecoder : NSObject
+
+/// 数据格式参数
+@property (nonatomic, strong) JLOpusFormat *opusFormat;
+
+/// 代理委托
+@property(nonatomic, weak) id delegate;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/// 初始化
+/// - Parameters:
+/// - format: 解码格式
+/// - delegate: 代理
+- (instancetype)initDecoder:(JLOpusFormat *)format delegate:(id)delegate;
+
+/// 重置解码格式
+/// - Parameter format: 解码格式
+-(void)resetOpusFramet:(JLOpusFormat *)format;
+
+/// 输入 Opus 数据
+/// - Parameter data: Opus 数据
+-(void)opusDecoderInputData:(NSData *)data;
+
+/// 解码文件
+/// - Parameters:
+/// - input: opus 文件
+/// - outPut: 输出路径
+/// - result: 结果回调
+-(void)opusDecodeFile:(NSString *)input outPut:(NSString *_Nullable)outPut Resoult:(JLOpusDecoderConvertBlock _Nullable)result;
+
+/// 释放
+-(void)opusOnRelease;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLOpusEncoder.h b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLOpusEncoder.h
new file mode 100644
index 000000000..ef8230537
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLOpusEncoder.h
@@ -0,0 +1,62 @@
+//
+// JLOpusEncoder.h
+// JLAudioUnitKit
+//
+// Created by EzioChan on 2024/11/14.
+// Copyright © 2024 ZhuHai JieLi Technology Co.,Ltd. All rights reserved.
+//
+
+#import
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+@class JLOpusEncoder;
+
+/// Opus 编码代理
+@protocol JLOpusEncoderDelegate
+
+/// PCM 数据编码
+/// - Parameters:
+/// - encoder: 解码器
+/// - data: opus 数据
+/// - error: 错误信息
+-(void)opusEncoder:(JLOpusEncoder *)encoder Data:(NSData* _Nullable)data error:(NSError* _Nullable)error;
+
+@end
+
+typedef void(^JLOpusEncoderConvertBlock)(NSString *_Nullable pcmPath,NSError *_Nullable error);
+
+/// Opus 编码
+@interface JLOpusEncoder : NSObject
+
+/// 音频格式
+@property (nonatomic, strong) JLOpusFormat *opusFormat;
+
+/// 代理
+@property (nonatomic, weak) id delegate;
+
+-(instancetype)init NS_UNAVAILABLE;
+
+/// 初始化
+/// - Parameters:
+/// - format: 音频格式
+/// - delegate: 代理
+-(instancetype)initFormat:(JLOpusFormat *)format delegate:(id)delegate;
+
+/// PCM 数据
+/// - Parameter data: PCM 数据
+-(void)opusEncodeData:(NSData *)data;
+
+/// PCM 文件转换成 Opus 文件
+/// - Parameters:
+/// - pcmPath: PCM 文件存放路径
+/// - outPut: 文件输出路径
+/// - result: 结果回调
+-(void)opusEncodeFile:(NSString *)pcmPath outPut:(NSString *_Nullable)outPut Resoult:(JLOpusEncoderConvertBlock _Nullable)result;
+
+/// 释放
+-(void)opusOnRelease;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLOpusFormat.h b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLOpusFormat.h
new file mode 100644
index 000000000..4b9b44184
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLOpusFormat.h
@@ -0,0 +1,53 @@
+//
+// JLOpusOptions.h
+// JLAudioUnitKit
+//
+// Created by EzioChan on 2024/11/14.
+// Copyright © 2024 ZhuHai JieLi Technology Co.,Ltd. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+#define OPUS_JL_MAX_FRAME_SIZE 48000 * 2
+#define OPUS_JL_MAX_PACKET_SIZE 1500
+
+
+@interface JLOpusFormat : NSObject
+
+/// 采样率
+@property (nonatomic, assign) int sampleRate;
+
+/// 单/双声道
+@property (nonatomic, assign) int channels;
+
+/// 帧长度 20ms 默认值
+@property (nonatomic, assign) int frameDuration;
+
+/// BitRate
+@property (nonatomic, assign) int bitRate;
+
+/// 数据帧大小
+@property (nonatomic, assign, readonly) int frameSize;
+
+/// 数据大小
+@property (nonatomic, assign) int dataSize;
+
+/// 是否包含数据头部
+@property (nonatomic, assign) BOOL hasDataHeader;
+
+-(instancetype)init NS_UNAVAILABLE;
+
+/// 默认配置
+/// sampleRate: 16000
+/// channels: 1
+/// frameDuration: 20
+/// dataSize: 40
+/// frameSize: 320
+/// hasDataHeader: YES
++(JLOpusFormat*)defaultFormats;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLPcmToWav.h b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLPcmToWav.h
new file mode 100644
index 000000000..b32ecef2d
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLPcmToWav.h
@@ -0,0 +1,55 @@
+//
+// JLPcmToWav.h
+// JLAudioUnitKit
+//
+// Created by EzioChan on 2025/4/15.
+// Copyright © 2025 ZhuHai JieLi Technology Co.,Ltd. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// PCM 转 WAV
+@interface JLPcmToWav : NSObject
+
+#pragma mark - 流式编码接口
+
+/// 初始化流式编码器
+/// @param outputPath 输出文件路径
+/// @param sampleRate 采样率(如 16000)
+/// @param numChannels 声道数(1 或 2)
+/// @param bitsPerSample 位深(16)
+- (instancetype)initWithOutputPath:(NSString *)outputPath
+ sampleRate:(uint32_t)sampleRate
+ numChannels:(uint16_t)numChannels
+ bitsPerSample:(uint16_t)bitsPerSample;
+
+/// 追加 PCM 数据(需确保数据格式与初始化参数一致)
+/// @param pcmData PCM 数据块
+/// @param error 错误信息
+- (BOOL)appendPCMData:(NSData *)pcmData error:(NSError **)error;
+
+/// 完成编码并关闭文件(必须调用以更新 WAV 头)
+/// @param error 错误信息
+- (BOOL)finishWithError:(NSError **)error;
+
+#pragma mark - 一次性编码接口(便捷方法)
+
+/// 将 PCM 数据一次性转为 WAV 文件
+/// @param pcmData PCM 数据块
+/// @param outputPath 输出文件路径
+/// @param sampleRate 采样率(如 16000)
+/// @param numChannels 声道数(1 或 2)
+/// @param bitsPerSample 位深(16)
+/// @param error 错误信息
++ (BOOL)convertPCMData:(NSData *)pcmData
+ toWAVFile:(NSString *)outputPath
+ sampleRate:(uint32_t)sampleRate
+ numChannels:(uint16_t)numChannels
+ bitsPerSample:(uint16_t)bitsPerSample
+ error:(NSError **)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLPcmToWtg.h b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLPcmToWtg.h
new file mode 100644
index 000000000..231b3e837
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLPcmToWtg.h
@@ -0,0 +1,51 @@
+//
+// JLPcmToWtg.h
+// JLAudioUnitKit
+//
+// Created by EzioChan on 2025/1/21.
+// Copyright © 2025 ZhuHai JieLi Technology Co.,Ltd. All rights reserved.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface JLPcm2WtgModel : NSObject
+
+/// 音频文件
+@property (nonatomic, copy) NSString *pcmPath;
+
+/// 输出文件
+@property (nonatomic, copy) NSString *wtgPath;
+
+@end
+
+
+/// JLPcmToWtgProtocol
+@protocol JLPcmToWtgDelegate
+
+/// 音频转码完成
+/// - Parameter model: 音频转码模型
+- (void)convertPcmToWtgDone:(JLPcm2WtgModel *)model;
+
+@end
+
+/// 音频转码
+/// PCM 转 WTG
+@interface JLPcmToWtg : NSObject
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/// 音频转码初始化
+/// - Parameter delegate: 音频转码代理
+- (instancetype)initWithDelegate:(id)delegate;
+
+/// 音频转码
+/// 当前接口模型只限制 PCM 文件格式为:8k 16bit
+/// 输入的pcm文件(16bit,小端,8k采样率),wtg_filename:输出的wtg文件
+/// - Parameter model: 音频转码模型
+-(void)convertPcmToWtg:(JLPcm2WtgModel *)model;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLSpeexDecoder.h b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLSpeexDecoder.h
new file mode 100644
index 000000000..ad223d087
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Headers/JLSpeexDecoder.h
@@ -0,0 +1,54 @@
+//
+// JLSpeexUnit.h
+// JLAudioUnitKit
+//
+// Created by EzioChan on 2024/11/14.
+//
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+@class JLSpeexDecoder;
+
+@protocol JLSpeexDelegate
+
+/// Speex 数据解码
+/// - Parameters:
+/// - decoder: 解码器
+/// - data: PCM 数据
+/// - error: 错误信息
+- (void)speexDecoder:(JLSpeexDecoder *)decoder Data:(NSData* _Nullable)data error:(NSError* _Nullable)error;
+
+@end
+
+typedef void(^JLSpeexConvertBlock)(NSString *_Nullable pcmPath,NSError *_Nullable error);
+
+/// Speex 数据解码
+@interface JLSpeexDecoder : NSObject
+
+-(instancetype)init NS_UNAVAILABLE;
+
+/// 初始化
+/// - Parameter delegate: 委托
+-(instancetype)initWithDelegate:(id)delegate;
+
+/// 委托
+@property (nonatomic, weak) id delegate;
+
+/// 输入 Speex 数据
+/// - Parameter data: Speex 数据
+-(void)speexInputData:(NSData*)data;
+
+/// 将 Speex 转换为 PCM
+/// - Parameters:
+/// - filePath: Speex 路径
+/// - opPath: 输出路径
+/// - result: 结果回调
+-(void)speexConvertToPcm:(NSString *)filePath outPutFilePath:(NSString * _Nullable)opPath Result:(JLSpeexConvertBlock)result;
+
+/// 释放对象
+-(void)speexOnRelease;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Info.plist b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Info.plist
new file mode 100644
index 000000000..8d397ffb8
Binary files /dev/null and b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Info.plist differ
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/JLAudioUnitKit b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/JLAudioUnitKit
new file mode 100755
index 000000000..4dc509fc5
Binary files /dev/null and b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/JLAudioUnitKit differ
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Modules/module.modulemap b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Modules/module.modulemap
new file mode 100644
index 000000000..5e1ae1d3d
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/Modules/module.modulemap
@@ -0,0 +1,6 @@
+framework module JLAudioUnitKit {
+ umbrella header "JLAudioUnitKit.h"
+ export *
+
+ module * { export * }
+}
diff --git a/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/readme.txt b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/readme.txt
new file mode 100644
index 000000000..6789fe6e1
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/JLAudioUnitKit.xcframework/ios-arm64/JLAudioUnitKit.framework/readme.txt
@@ -0,0 +1,52 @@
+DESCRIPTION
+-----------
+This package includes the files needed to build the fixed point implementation
+of the ITU-T G.729 Appendix IV.
+
+DIFFERENCES WITH G.729B
+-----------------------
+The ANSI-C source code simulating the bit-exact, fixed point simulation
+software of enhanced VAD is integrated into the G.729B source code.
+The modification to the G.729B source code updated files of coder.c,
+cod_ld8k.c, bits.c, dec_sid.c, dtx.c, qsidgain.c, qsidlsf.c, tab_dtx.c,
+tab_dtx.h, ld8k.h, deleted vad.c/h and integrated the enhanced VAD functions
+into the G.729B project. The modification also replaced the original basic
+operators used in the original G.729B source code by the basic operators of
+ITU-T Software Tool Library STL2005.
+
+COMPILATION
+-----------
+For UNIX systems the following makefiles are provided
+
+ coder.mak
+ decoder.mak
+
+Edit the makefiles coder.mak and decoder.mak to set the proper options
+for your system.
+The command to compile and link all code on a UNIX system is
+
+ make -f coder.mak
+ make -f decoder.mak
+
+For other platforms, the *.mak files can be used to work out the
+compilation procedures.
+
+USAGE
+-----
+The command line instruction for the encoder is as follows:
+ coder inputfile bitstreamfile dtx_option mode x
+where:
+ inputfile : 8 kHz sampled data file containing 16 bit linear PCM signal
+ bitstreamfile: binary file containing bitstream
+ dtx_option : = 1 : DTX enabled 0 : DTX disabled
+ mode X : Run encoder with enhanced VAD in operating point X,
+ X=0 or 1 or 2 representing balanced or quality-preferred
+ or bandwidth saving operating point, respectively
+
+The command line for the decoder is as follows:
+ decoder bitstreamfile outputfile
+where:
+ bitstreamfile: binary file containing bitstream
+ outputfile : 8 kHz sampled data file containing 16 bit linear PCM signal
+
+
diff --git a/local_plugins/ble_service/ios/ble_service/Package.swift b/local_plugins/ble_service/ios/ble_service/Package.swift
index f3e505b27..5f2e43c99 100644
--- a/local_plugins/ble_service/ios/ble_service/Package.swift
+++ b/local_plugins/ble_service/ios/ble_service/Package.swift
@@ -8,22 +8,34 @@ let package = Package(
.library(name: "ble-service", targets: ["ble_service"])
],
dependencies: [
- // YbridOpus SPM 包(替代CocoaPods依赖)
- .package(url: "https://github.com/ybrid/opus-swift.git", from: "0.8.0")
],
targets: [
.target(
name: "ble_service",
dependencies: [
- .product(name: "YbridOpus", package: "opus-swift")
+ "opus",
+ "SpeexKit",
+ "JLAudioUnitKit"
],
path: "Sources/ble_service",
linkerSettings: [
.linkedFramework("AVFoundation"),
.linkedFramework("AudioToolbox"),
.linkedFramework("CoreBluetooth")
- // 移除 AccessorySetupKit 链接,因为它只在 iOS 18+ 可用
]
+ ),
+ // 本地opus框架作为二进制目标(使用xcframework格式)
+ .binaryTarget(
+ name: "opus", // 改为与 xcframework 内部模块名称一致
+ path: "opus.xcframework"
+ ),
+ .binaryTarget(
+ name: "SpeexKit",
+ path: "SpeexKit.xcframework"
+ ), // 添加了缺失的逗号
+ .binaryTarget(
+ name: "JLAudioUnitKit",
+ path: "JLAudioUnitKit.xcframework"
)
]
)
\ No newline at end of file
diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleConst.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleConst.swift
index b0c76fa81..f15c40b8b 100644
--- a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleConst.swift
+++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleConst.swift
@@ -20,7 +20,12 @@ class BleConst {
/** 通知特征UUID - 文档中定义为0000ABC2-0000-1111-2222-123456789ABC */
static let NOTIFY_CHAR_UUID = CBUUID(string: "0000abc2-0000-1111-2222-123456789abc")
-
+ /** 通话音频服务UUID - 文档中定义为0000ABC0-0001-1111-2222-123456789ABC */
+
+ static let CALL_AUDIO_SERVICE_UUID = CBUUID(string: "0000abc0-0001-1111-2222-123456789abc")
+
+ /** 通话写入音频特征UUID - 文档中定义为0000ABC1-0001-1111-2222-123456789ABC */
+ static let CALL_WRITE_AUDIO_CHAR_UUID = CBUUID(string: "0000abc1-0001-1111-2222-123456789abc")
/** 客户端特征配置描述符UUID */
static let CLIENT_CHAR_CONFIG_UUID = CBUUID(string: "00002902-0000-1000-8000-00805f9b34fb")
diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift
index 33f0e9f14..ea066e7d2 100644
--- a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift
+++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift
@@ -28,6 +28,7 @@ public class BleService: NSObject {
// 数据相关回调
func onAudioDataReceived(data: Data)
+ func onAudioDataReceived1(data: Data)
// 唤醒信号回调
func onWakeupSignalReceived()
@@ -40,9 +41,14 @@ public class BleService: NSObject {
private var centralManager: CBCentralManager?
private var peripheralDevice: CBPeripheral?
private var writeCharacteristic: CBCharacteristic?
+ private var callAudioCharacteristic: CBCharacteristic?
+
private var notifyCharacteristic: CBCharacteristic?
private var audioCharacteristic: CBCharacteristic?
+ // 添加录制文件管理器
+ private var recordingFile: RecordingFile?
+
private var isScanning = false
private var scanTimer: Timer?
@@ -80,6 +86,24 @@ public class BleService: NSObject {
// 是否回复指令码
private var cmdReplyType: UInt8 = 0
+ // 新增:音频配置参数
+ private var sampleRate: Int32 = 16000
+ private var channels: Int32 = 1
+ private var frameSize: Int32 = 640
+
+ // MARK: - 音频数据发送相关属性
+ private var audioBuffer = [UInt8]() // 音频数据缓冲区
+ private var audioSendQueue = DispatchQueue(label: "com.yunqiinnovation.ble_service.audio_send", qos: .userInitiated)
+ private var audioDataQueue = [Data]() // 音频数据发送队列
+ private var isAudioSending = false // 音频发送状态
+ private var audioSendTimer: Timer? // 音频发送定时器
+
+ // 音频发送配置常量
+ private let AUDIO_CHUNK_SIZE = 120 // 每次发送120字节
+ private let AUDIO_SEND_INTERVAL: TimeInterval = 0.06 // 60毫秒间隔
+
+ private let audioQueueLock = NSLock() // 队列操作锁
+
//private var currentCommand: Command?
// 命令结构体
private struct Command {
@@ -121,16 +145,29 @@ private var cmdReplyType: UInt8 = 0
}
// 启动Opus解码流
- private func startOpusDecoding() {
+ private func startOpusDecoding(sampleRate: Int32 = 16000, channels: Int32 = 1, frameSize: Int32 = 640) {
+ // 检查参数是否与预设值匹配,如果不匹配则停止当前解码
+ if sampleRate != self.sampleRate || channels != self.channels || frameSize != self.frameSize {
+ opusProcessor?.stopDecoding()
+ }
+
let opusStarted = opusProcessor?.startDecoding(
- sampleRate: 16000, // 设备端Opus编码采样率
- channels: 1, // 单声道
- frameSize: 640 // 40ms at 16kHz = 640 samples
+ sampleRate: sampleRate, // 设备端Opus编码采样率
+ channels: channels, // 单声道
+ frameSize: frameSize // 40ms at 16kHz = 640 samples
) ?? false
-
+
if !opusStarted {
os_log("Opus解码流启动失败", log: logger, type: .error)
}
+ else{
+ os_log("Opus解码流启动成功", log: logger, type: .info)
+ // 保存音频配置参数
+ self.sampleRate = sampleRate
+ self.channels = channels
+ self.frameSize = frameSize
+
+ }
}
// MARK: - 回调管理
@@ -345,17 +382,18 @@ private var cmdReplyType: UInt8 = 0
peripheralDevice?.delegate = self
updateConnectionState(BleConst.STATE_CONNECTED)
- if opusProcessor?.isDecoding() != true {
+ // if opusProcessor?.isDecoding() != true {
startOpusDecoding()
- }
+ // }
// 清空特征引用,强制重新发现
writeCharacteristic = nil
+ callAudioCharacteristic = nil
notifyCharacteristic = nil
audioCharacteristic = nil
os_log("🔍 恢复会话时重新发现服务和特征", log: logger, type: .info)
- peripheral.discoverServices([BleConst.PRIMARY_SERVICE_UUID, BleConst.AUDIO_SERVICE_UUID])
+ peripheral.discoverServices([BleConst.PRIMARY_SERVICE_UUID, BleConst.AUDIO_SERVICE_UUID, BleConst.CALL_AUDIO_SERVICE_UUID])
os_log("✅ 已恢复设备会话: %@", log: logger, type: .info, peripheral.identifier.uuidString)
}
@@ -369,6 +407,16 @@ private var cmdReplyType: UInt8 = 0
if centralManager != nil {
isManualDisconnect = true // 标记为主动断开
+
+ // 停止音频发送定时器
+ stopAudioSendTimer()
+
+ // 清空音频缓冲区和队列
+ audioQueueLock.lock()
+ audioBuffer.removeAll()
+ audioDataQueue.removeAll()
+ audioQueueLock.unlock()
+
updateConnectionState(BleConst.STATE_DISCONNECTING)
centralManager?.cancelPeripheralConnection(peripheral)
os_log("🔌 开始断开设备连接", log: logger, type: .info)
@@ -481,6 +529,12 @@ private var cmdReplyType: UInt8 = 0
callback.onAudioDataReceived(data: data)
}
}
+ /// 通知所有回调接收到音频数据
+ private func notifyAudioDataReceived1(data: Data) {
+ for callback in callbacks {
+ callback.onAudioDataReceived1(data: data)
+ }
+ }
/// 通知所有回调接收到唤醒信号
private func notifyWakeupSignalReceived() {
@@ -527,11 +581,23 @@ private var cmdReplyType: UInt8 = 0
}
// MARK: - 编解码控制
-
+
+ public func writeExternalAudioData(data: Data) {
+ print("pcm音频进入编码", data.count)
+ // 确保Opus编码器处于活跃状态(如果不是则启动)
+
+ // 将外部音频数据写入编码流,每次处理1280字节
+ opusProcessor?.encodePCMData(data)
+
+ }
+
/// 打开编码器
func openEncoder() -> Bool {
os_log("🎙️ 准备打开编码(设备侧)...", log: logger, type: .info)
-
+ // 确保Opus解码器处于活跃状态(如果不是则启动)
+ // if opusProcessor?.isDecoding() != true {
+ startOpusDecoding()
+ //}
let paramData = Data([BleConst.CODEC_CONTROL_ENCODE_ON, BleConst.AUDIO_CHANNEL_RIGHT])
let result = sendCommand(BleConst.CMD_CONTROL_CODEC, data: paramData)
@@ -549,25 +615,50 @@ private var cmdReplyType: UInt8 = 0
os_log("打开解码...", log: logger, type: .info)
// 确保Opus解码器处于活跃状态(如果不是则启动)
- if opusProcessor?.isDecoding() != true {
+ //if opusProcessor?.isDecoding() != true {
startOpusDecoding()
- }
+ //}
// 发送命令通知设备开始解码
let paramData = Data([BleConst.CODEC_CONTROL_DECODE_ON, BleConst.AUDIO_CHANNEL_RIGHT])
return sendCommand(BleConst.CMD_CONTROL_CODEC, data: paramData)
}
+ /// 获取与Flutter getExternalStorageDirectories()一致的存储目录
+ /// 在iOS上,这相当于应用的Documents目录
+ func getExternalStorageDirectory() -> URL? {
+ // 获取Documents目录,这部分与Flutter的getExternalStorageDirectories()在iOS上的行为一致
+ return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
+ }
- /// 打开A2DP解码器
+ /// 打开A2DP解码器并开始录制
func openA2DPDecoder() -> Bool {
- os_log("打开A2DP解码...", log: logger, type: .info)
+ // 确保Opus解码器处于活跃状态(如果不是则启动)
+
+ startOpusDecoding(sampleRate: 16000, channels: 2, frameSize: 1280)
+ opusProcessor?.startEncoding(sampleRate: 16000, channels: 1, frameRate: 20)
+
+
+ os_log("打开A2DP解码并开始录制...", log: logger, type: .info)
let paramData = Data([BleConst.CODEC_CONTROL_A2DP_PLAY, BleConst.AUDIO_CHANNEL_RIGHT])
return sendCommand(BleConst.CMD_CONTROL_CODEC, data: paramData)
}
- /// 关闭编解码器
+ /// 关闭编解码器并停止录制
func closeCodec() -> Bool {
- os_log("关闭编解码...", log: logger, type: .info)
+ os_log("关闭编解码并停止录制...", log: logger, type: .info)
+
+ // 停止录制
+ recordingFile?.closeFile()
+ recordingFile = nil
+
+ // 停止音频发送定时器
+ stopAudioSendTimer()
+
+ // 清空音频缓冲区和队列
+ audioQueueLock.lock()
+ audioBuffer.removeAll()
+ audioDataQueue.removeAll()
+ audioQueueLock.unlock()
// 不停止Opus解码流,只发送命令通知设备关闭编解码
let paramData = Data([BleConst.CODEC_CONTROL_CLOSE, BleConst.AUDIO_CHANNEL_RIGHT])
@@ -1095,6 +1186,147 @@ extension BleService: SwiftOpusAudioProcessor.AudioDataCallback {
func onAudioDataReceived(data: Data) {
notifyAudioDataReceived(data: data)
}
+
+ /// 接收到解码后的PCM音频数据
+ func onAudioDataReceived1(data: Data) {
+ notifyAudioDataReceived1(data: data)
+ }
+
+ /// 接收到编码后的音频数据
+ /// - Parameter data: 编码后的音频数据
+ func onEncodedDataReceived(data: Data) {
+ // 保存编码数据到文件
+ recordingFile?.saveAudioData(data)
+
+ // 根据你的业务需求处理编码数据
+ // 例如:发送到蓝牙设备、保存到文件等
+ os_log("🎵 接收到编码音频数据: %d bytes", log: logger, type: .info, data.count)
+
+ // 修复条件绑定语句
+ guard let characteristic = callAudioCharacteristic,
+ let peripheral = peripheralDevice,
+ connectionState == BleConst.STATE_CONNECTED else {
+ os_log("通话音频特征未设置或设备未连接", log: logger, type: .error)
+ return
+ }
+
+ // 将编码音频数据加入到队列,按每次发送120字节,每次间隔60毫秒
+ addAudioDataToSendQueue(data: data)
+
+ // 启动音频发送定时器(如果尚未启动)
+ if !isAudioSending {
+ startAudioSendTimer()
+ }
+ }
+
+ /**
+ * 将音频数据添加到发送队列
+ * 只有当缓冲区达到120字节时才发送数据
+ * @param data 音频数据字节数组
+ */
+ private func addAudioDataToSendQueue(data: Data) {
+ audioQueueLock.lock()
+ defer { audioQueueLock.unlock() }
+
+ do {
+ // 将新数据添加到缓冲区
+ audioBuffer.append(contentsOf: data)
+
+ // 当缓冲区达到120字节时,发送数据
+ while audioBuffer.count >= AUDIO_CHUNK_SIZE {
+ // 取出120字节数据
+ let chunk = Data(audioBuffer.prefix(AUDIO_CHUNK_SIZE))
+ audioBuffer.removeFirst(AUDIO_CHUNK_SIZE)
+
+ // 将数据加入发送队列
+
+ audioDataQueue.append(chunk)
+
+ }
+
+ // os_log("音频数据已加入缓冲区,当前缓冲区大小: %d 字节", log: logger, type: .debug, audioBuffer.count)
+ } catch {
+ os_log("处理音频数据异常: %{public}@", log: logger, type: .error, error.localizedDescription)
+ }
+ }
+
+ /**
+ * 启动音频数据发送定时器
+ */
+ private func startAudioSendTimer() {
+ guard !isAudioSending else {
+ os_log("音频发送定时器已在运行", log: logger, type: .debug)
+ return
+ }
+
+ isAudioSending = true
+
+ // 在主队列中创建定时器
+ DispatchQueue.main.async { [weak self] in
+ guard let self = self else { return }
+
+ self.audioSendTimer = Timer.scheduledTimer(withTimeInterval: self.AUDIO_SEND_INTERVAL, repeats: true) { [weak self] _ in
+ self?.processAudioSendQueue()
+ }
+
+ os_log("音频发送定时器已启动", log: self.logger, type: .info)
+ }
+ }
+
+ /**
+ * 停止音频数据发送定时器
+ */
+ private func stopAudioSendTimer() {
+ isAudioSending = false
+
+ DispatchQueue.main.async { [weak self] in
+ self?.audioSendTimer?.invalidate()
+ self?.audioSendTimer = nil
+
+ guard let self = self else { return }
+ os_log("音频发送定时器已停止", log: self.logger, type: .info)
+ }
+ }
+
+ /**
+ * 处理音频发送队列
+ */
+ private func processAudioSendQueue() {
+ audioQueueLock.lock()
+ defer { audioQueueLock.unlock() }
+
+ guard !audioDataQueue.isEmpty else { return }
+
+ // 从队列中取出音频数据块
+ let audioChunk = audioDataQueue.removeFirst()
+
+ // 在后台队列中发送音频数据块
+ audioSendQueue.async { [weak self] in
+ self?.sendAudioChunk(audioChunk)
+ }
+ }
+
+ /**
+ * 发送音频数据块到蓝牙设备
+ * @param data 要发送的音频数据
+ */
+ private func sendAudioChunk(_ data: Data) {
+ guard let characteristic = callAudioCharacteristic,
+ let peripheral = peripheralDevice,
+ connectionState == BleConst.STATE_CONNECTED else {
+ os_log("通话音频特征未设置或设备未连接,无法发送音频数据", log: logger, type: .error)
+ return
+ }
+
+ // 发送音频数据块
+ peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
+ //判断是否发送成功
+ if peripheral.state == .connected {
+ os_log("🎵 发送音频数据块: %d bytes", log: logger, type: .debug, data.count)
+ } else {
+ os_log("🎵 发送音频数据块失败: %d bytes", log: logger, type: .debug, data.count)
+ }
+ }
}
// MARK: - CBCentralManagerDelegate
@@ -1392,12 +1624,12 @@ extension BleService: CBCentralManagerDelegate {
os_log("🔍 开始发现服务...", log: logger, type: .debug)
// 查找服务
- peripheral.discoverServices([BleConst.PRIMARY_SERVICE_UUID, BleConst.AUDIO_SERVICE_UUID])
+ peripheral.discoverServices([BleConst.PRIMARY_SERVICE_UUID, BleConst.AUDIO_SERVICE_UUID, BleConst.CALL_AUDIO_SERVICE_UUID])
// 确保Opus解码器处于活跃状态
- if opusProcessor?.isDecoding() != true {
+ // if opusProcessor?.isDecoding() != true {
startOpusDecoding()
- }
+ // }
}
public func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
@@ -1482,6 +1714,10 @@ extension BleService: CBPeripheralDelegate {
os_log("🔍 发现音频服务,开始发现音频特征...", log: logger, type: .debug)
// 音频服务,发现音频特征
peripheral.discoverCharacteristics([BleConst.RECEIVE_AUDIO_CHAR_UUID], for: service)
+ }else if service.uuid == BleConst.CALL_AUDIO_SERVICE_UUID {
+ os_log("🔍 发现通话音频服务,开始发现通话音频特征...", log: logger, type: .debug)
+ // 通话音频服务,发现通话音频特征
+ peripheral.discoverCharacteristics([BleConst.CALL_WRITE_AUDIO_CHAR_UUID], for: service)
}
}
}
@@ -1513,6 +1749,10 @@ extension BleService: CBPeripheralDelegate {
os_log("🎵 音频特征已设置,开始发现描述符...", log: logger, type: .info)
// 先发现描述符,再配置通知
peripheral.discoverDescriptors(for: characteristic)
+ }else if characteristic.uuid == BleConst.CALL_WRITE_AUDIO_CHAR_UUID {
+ callAudioCharacteristic = characteristic
+ os_log("🎵 通话音频特征已设置,开始发现描述符...", log: logger, type: .info)
+ // 先发现描述符,再配置通知
}
}
diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/RecordingFile.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/RecordingFile.swift
new file mode 100644
index 000000000..6b5824dfc
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/RecordingFile.swift
@@ -0,0 +1,135 @@
+import Foundation
+import os.log
+
+/// 音频录制文件管理类
+/// 负责创建音频文件并异步写入编码后的音频数据
+@available(iOS 13.0, *)
+class RecordingFile {
+ private var currentAudioFile: URL?
+ private var fileHandle: FileHandle?
+
+ // 用于异步写入的队列和线程
+ private let writeQueue = DispatchQueue(label: "com.yunqiinnovation.ble_service.recording_write", qos: .utility)
+ private var isWriting = false
+ private let writeLock = NSLock()
+
+ // 用于存储音频数据的缓冲区
+ private var totalBytesWritten = 0
+
+ var fileName = ""
+ private let logger = OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "RecordingFile")
+
+ /// 获取与Flutter getExternalStorageDirectories()一致的存储目录
+ /// 在iOS上,这相当于应用的Documents目录
+ private func getExternalStorageDirectory() -> URL? {
+ // 获取Documents目录,这部分与Flutter的getExternalStorageDirectories()在iOS上的行为一致
+ return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
+ }
+
+ /// 创建新的音频文件
+ /// 如果文件已存在则直接返回
+ internal func createFile() {
+ writeLock.lock()
+ defer { writeLock.unlock() }
+
+ if fileHandle != nil || currentAudioFile != nil {
+ return
+ }
+
+ // 创建新的音频文件
+ let dateFormatter = DateFormatter()
+ dateFormatter.dateFormat = "yyyyMMdd_HHmmss"
+ let timestamp = dateFormatter.string(from: Date())
+
+ // 获取与Flutter一致的外部存储目录
+ guard let externalStorageDirectory = getExternalStorageDirectory() else {
+ os_log("无法获取外部存储目录", log: logger, type: .error)
+ return
+ }
+
+ // 使用与Android端相同的文件命名格式
+ let filePath = externalStorageDirectory.appendingPathComponent("\(fileName)_\(timestamp).opus")
+ currentAudioFile = filePath
+
+ do {
+ // 创建文件
+ FileManager.default.createFile(atPath: filePath.path, contents: nil, attributes: nil)
+ fileHandle = try FileHandle(forWritingTo: filePath)
+ isWriting = true
+ os_log("创建文件: %@", log: logger, type: .info, filePath.path)
+ } catch {
+ os_log("创建文件失败: %@", log: logger, type: .error, error.localizedDescription)
+ currentAudioFile = nil
+ fileHandle = nil
+ }
+ }
+
+ /// 异步保存音频数据到文件
+ /// - Parameter buffer: 编码后的音频数据
+ internal func saveAudioData(_ buffer: Data) {
+ guard isWriting, fileHandle != nil else {
+ return
+ }
+
+ // 异步写入数据
+ writeQueue.async { [weak self] in
+ guard let self = self else { return }
+
+ do {
+ try self.fileHandle?.write(contentsOf: buffer)
+ self.totalBytesWritten += buffer.count
+ os_log("写入音频数据: %d bytes, 总计: %d bytes", log: self.logger, type: .debug, buffer.count, self.totalBytesWritten)
+ } catch {
+ os_log("写入音频数据失败: %@", log: self.logger, type: .error, error.localizedDescription)
+ }
+ }
+ }
+
+ /// 关闭文件并完成录制
+ internal func closeFile() {
+ writeLock.lock()
+ defer { writeLock.unlock() }
+
+ guard let fileHandle = fileHandle, let currentFile = currentAudioFile else {
+ return
+ }
+
+ isWriting = false
+
+ // 等待写入队列完成
+ writeQueue.sync {
+ do {
+ try fileHandle.close()
+
+ // 检查文件大小
+ let fileSize = try FileManager.default.attributesOfItem(atPath: currentFile.path)[.size] as? Int64 ?? 0
+
+ if fileSize <= 0 {
+ // 删除空文件
+ try FileManager.default.removeItem(at: currentFile)
+ os_log("音频文件过小已删除: %@", log: logger, type: .info, currentFile.path)
+ } else {
+ os_log("音频文件保存完成: %@, 大小: %lld bytes", log: logger, type: .info, currentFile.path, fileSize)
+ }
+ } catch {
+ os_log("关闭文件失败: %@", log: logger, type: .error, error.localizedDescription)
+ }
+ }
+
+ self.fileHandle = nil
+ self.currentAudioFile = nil
+ self.totalBytesWritten = 0
+ }
+
+ /// 获取当前录制文件路径
+ /// - Returns: 当前录制文件的路径,如果没有正在录制则返回nil
+ internal func getCurrentFilePath() -> String? {
+ return currentAudioFile?.path
+ }
+
+ /// 检查是否正在录制
+ /// - Returns: 如果正在录制返回true,否则返回false
+ internal func isRecording() -> Bool {
+ return isWriting && fileHandle != nil
+ }
+}
\ No newline at end of file
diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift
index e44bd6c61..4a664d583 100644
--- a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift
+++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift
@@ -236,6 +236,10 @@ extension SwiftBleServicePlugin: BleService.Callback {
}
}
+ public func onAudioDataReceived1(data: Data) {
+
+ }
+
public func onWakeupSignalReceived() {
if let eventSink = statusEventSink {
DispatchQueue.main.async {
diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftOpusAudioProcessor.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftOpusAudioProcessor.swift
index 1067a9211..5f4c4c69d 100644
--- a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftOpusAudioProcessor.swift
+++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftOpusAudioProcessor.swift
@@ -1,22 +1,46 @@
import Foundation
import AVFoundation
-import YbridOpus
+import opus
+import JLAudioUnitKit
@available(iOS 13.0, *)
class SwiftOpusAudioProcessor: NSObject {
+ /// 音频数据回调协议
protocol AudioDataCallback: AnyObject {
func onAudioDataReceived(data: Data)
+ func onAudioDataReceived1(data: Data)
+ func onEncodedDataReceived(data: Data) // 编码数据回调
}
+ // MARK: - 私有属性
+
+ // 状态标志
private var isDecodingActive = false
+ private var isEncodingActive = 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 = 640 // 为16kHz优化:40ms * 16000Hz = 640 samples,与Android参数统一
+ private let maxFrameSize: Int32 = 640 // 为16kHz优化:40ms * 16000Hz = 640 samples
+
+ // MARK: - JLOpusEncoder 编码器相关属性
+ private var jlOpusEncoder: JLOpusEncoder?
+ private var encoderFormat: JLOpusFormat?
+
+ // MARK: - PCM数据队列相关属性
+ /// PCM数据缓存队列
+ private var pcmDataQueue = Data()
+ /// 队列访问锁,确保线程安全
+ private let queueLock = NSLock()
+ /// 每次处理的数据块大小(字节)
+ private let chunkSize = 640
+ /// 异步处理队列
+ private var processingQueue: DispatchQueue?
+
+ // MARK: - 初始化和清理
override init() {
super.init()
@@ -26,6 +50,10 @@ class SwiftOpusAudioProcessor: NSObject {
cleanup()
}
+
+
+ // MARK: - 解码器管理
+
/// 线程安全的解码器初始化
private func initializeOpusDecoder() -> Bool {
objc_sync_enter(self)
@@ -58,12 +86,21 @@ class SwiftOpusAudioProcessor: NSObject {
}
}
+ // MARK: - 公共接口
+
+ /// 设置音频数据回调
+ /// - Parameter callback: 回调对象
func setCallback(_ callback: AudioDataCallback?) {
self.callback = callback
}
+ /// 启动Opus解码
+ /// - Parameters:
+ /// - sampleRate: 采样率
+ /// - channels: 声道数
+ /// - frameSize: 帧大小
+ /// - Returns: 是否启动成功
func startDecoding(sampleRate: Int32 = 16000, channels: Int32 = 1, frameSize: Int32 = 40) -> Bool {
- // frameSize参数必须与Android版本的packetSize保持一致,确保双平台解码行为一致
if isDecodingActive {
return true
}
@@ -76,10 +113,13 @@ class SwiftOpusAudioProcessor: NSObject {
}
isDecodingActive = true
+ print("Opus解码器启动成功 - 采样率: \(sampleRate)Hz, 声道: \(channels)")
return true
}
+ /// 停止Opus解码
+ /// - Returns: 是否停止成功
func stopDecoding() -> Bool {
if !isDecodingActive {
return false
@@ -87,10 +127,13 @@ class SwiftOpusAudioProcessor: NSObject {
isDecodingActive = false
destroyOpusDecoder()
+ print("Opus解码器已停止")
return true
}
+ /// 处理音频数据进行解码
+ /// - Parameter data: Opus编码的音频数据
func processAudioData(_ data: Data) {
guard isDecodingActive, let decoder = decoder, data.count > 0 else {
return
@@ -102,16 +145,13 @@ class SwiftOpusAudioProcessor: NSObject {
return
}
- // 检查最小数据包大小(Opus最小包通常至少几个字节)
guard data.count >= 3 else {
print("音频数据包太小: \(data.count) bytes,跳过处理")
return
}
- // 简单的 Opus 头部验证(检查是否是有效的 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
@@ -123,12 +163,11 @@ class SwiftOpusAudioProcessor: NSObject {
}
/// 改进的 Opus 解码方法,增强容错和线程安全
+ /// - Parameter packet: Opus数据包
private func decodeOpusPacket(_ packet: Data) {
- // 添加线程安全锁
objc_sync_enter(self)
defer { objc_sync_exit(self) }
- // 验证解码器状态
guard let decoder = decoder, isDecodingActive else {
print("解码器未初始化或已停止")
return
@@ -138,16 +177,13 @@ class SwiftOpusAudioProcessor: NSObject {
var pcmBuffer = [opus_int16](repeating: 0, count: maxSamples * Int(channels))
let decodedSamples = packet.withUnsafeBytes { packetPtr in
- // 确保指针有效
guard let uint8Ptr = packetPtr.bindMemory(to: UInt8.self).baseAddress else {
print("无法获取数据包指针")
return opus_int32(-1)
}
- // 添加异常捕获机制
var result: opus_int32 = -1
- // 使用 autoreleasepool 确保内存管理
autoreleasepool {
result = opus_decode(
decoder,
@@ -162,12 +198,11 @@ class SwiftOpusAudioProcessor: NSObject {
return result
}
- // 增强的错误处理:检查各种错误情况
+ // 增强的错误处理
if decodedSamples <= 0 {
let errorCode = decodedSamples
- print("Opus解码失败,错误代码: \(errorCode),重新初始化解码器")
+ print("Opus解码失败,错误代码: \(errorCode)")
- // 根据错误类型进行不同的处理
if errorCode == -1 { // OPUS_BAD_ARG
print("Opus解码参数错误,执行完全重置")
performCompleteReset()
@@ -184,18 +219,15 @@ class SwiftOpusAudioProcessor: NSObject {
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()
@@ -209,31 +241,28 @@ class SwiftOpusAudioProcessor: NSObject {
}
}
- // 重置解码器的简单方法
+ /// 重置解码器的简单方法
private func resetDecoder() {
print("执行简单解码器重置")
destroyOpusDecoder()
_ = initializeOpusDecoder()
}
- // 执行完全重置(包括停止和重启解码)
+ /// 执行完全重置(包括停止和重启解码)
private func performCompleteReset() {
print("执行完全解码器重置")
let wasActive = isDecodingActive
let currentSampleRate = self.sampleRate
let currentChannels = self.channels
- // 完全停止解码
if wasActive {
isDecodingActive = false
destroyOpusDecoder()
}
- // 重新初始化所有状态
self.sampleRate = currentSampleRate
self.channels = currentChannels
- // 如果之前是活跃状态,重新启动
if wasActive {
guard initializeOpusDecoder() else {
print("完全重置后重新初始化失败")
@@ -243,29 +272,312 @@ class SwiftOpusAudioProcessor: NSObject {
print("完全重置成功,解码器已重新启动")
}
}
-
+
+ /// 处理解码后的PCM音频数据
+ /// - Parameter pcmData: 解码后的PCM数据数组
private func processPCMData(_ pcmData: [opus_int16]) {
- // 转换为 Data
let data = Data(bytes: pcmData, count: pcmData.count * MemoryLayout.size)
- // 回调通知
+ guard !data.isEmpty else {
+ print("PCM数据为空")
+ return
+ }
+
+ print("Opus解码数据: \(data.count) bytes, 声道数: \(channels)")
+
+ if channels == 2 {
+ processStereoAudioData(data)
+ } else if channels == 1 {
+ DispatchQueue.main.async { [weak self] in
+ self?.callback?.onAudioDataReceived(data: data)
+ }
+ } else {
+ print("不支持的声道数: \(channels)")
+ }
+ }
+
+ /// 处理双声道音频数据,分离左右声道
+ /// - Parameter stereoData: 交错的双声道PCM数据
+ private func processStereoAudioData(_ stereoData: Data) {
+ let sampleCount = stereoData.count / 4 // 每个样本4字节(左右声道各2字节)
+
+ guard sampleCount > 0 else {
+ print("双声道数据样本数为0")
+ return
+ }
+
+ var leftBuffer = Data()
+ var rightBuffer = Data()
+
+ leftBuffer.reserveCapacity(sampleCount * 2)
+ rightBuffer.reserveCapacity(sampleCount * 2)
+
+ stereoData.withUnsafeBytes { bytes in
+ let uint8Ptr = bytes.bindMemory(to: UInt8.self)
+
+ for i in 0.. Bool {
return isDecodingActive
}
- func cleanup() {
- stopDecoding()
+ /// 获取编码器状态
+ /// - Returns: 是否正在编码
+ func isEncoding() -> Bool {
+ return isEncodingActive
}
- // MARK: - 公共接口
-
/// 获取当前配置信息
+ /// - Returns: 采样率和声道数
func getCurrentConfig() -> (sampleRate: Int32, channels: Int32) {
return (sampleRate, channels)
}
+
+ /// 获取编码器配置信息
+ /// - Returns: 编码器配置元组
+ func getEncoderConfig() -> (sampleRate: Int32, channels: Int32) {
+ return (sampleRate, channels)
+ }
+
+
+ /// 启动JLOpusEncoder编码(完善版本)
+ /// - Parameters:
+ /// - sampleRate: 采样率(默认16000Hz)
+ /// - channels: 声道数(默认1)
+ /// - frameRate: 帧长度(默认20ms)
+ /// - isHeader: 是否包含头部信息
+ /// - Returns: 是否启动成功
+ func startEncoding(sampleRate: Int32 = 16000,
+ channels: Int32 = 1,
+ frameRate: Int32 = 20,
+ isHeader: Bool = false) -> Bool {
+ if isEncodingActive {
+ return true
+ }
+
+ print("启动JLOpusEncoder编码 - 采样率: \(sampleRate)Hz, 声道: \(channels), 帧长度: \(frameRate)ms, 头部: \(isHeader)")
+
+ // 创建JLOpusFormat配置
+ encoderFormat = JLOpusFormat.defaultFormats()
+ encoderFormat?.sampleRate = Int32(sampleRate)
+ encoderFormat?.channels = Int32(channels)
+ encoderFormat?.frameDuration = Int32(frameRate)
+ encoderFormat?.hasDataHeader = isHeader
+
+ // 根据配置计算数据大小
+ if channels == 1 {
+ encoderFormat?.dataSize = frameRate == 20 ? 40 : 80 // 20ms=40bytes, 40ms=80bytes
+ } else {
+ encoderFormat?.dataSize = frameRate == 20 ? 80 : 160 // 双声道翻倍
+ }
+
+ guard let format = encoderFormat else {
+ print("编码器格式配置失败")
+ return false
+ }
+
+ // 初始化JLOpusEncoder
+ jlOpusEncoder = JLOpusEncoder(format: format, delegate: self)
+
+ guard jlOpusEncoder != nil else {
+ print("JLOpusEncoder初始化失败")
+ return false
+ }
+
+ isEncodingActive = true
+ print("JLOpusEncoder启动成功")
+
+ return true
+ }
+
+ /// 停止JLOpusEncoder编码(完善版本)
+ /// - Returns: 是否停止成功
+ func stopEncoding() -> Bool {
+ if !isEncodingActive {
+ return false
+ }
+
+ isEncodingActive = false
+
+ // 清空PCM数据队列
+ clearPCMQueue()
+
+ // 释放JLOpusEncoder资源
+ jlOpusEncoder?.opusOnRelease()
+ jlOpusEncoder = nil
+ encoderFormat = nil
+ processingQueue = nil
+
+ print("JLOpusEncoder已停止")
+
+ return true
+ }
+
+ /// 编码PCM音频数据
+ /// - Parameter pcmData: PCM音频数据
+ func encodePCMData(_ pcmData: Data) {
+ guard isEncodingActive, let encoder = jlOpusEncoder else {
+ print("编码器未启动或不可用")
+ return
+ }
+
+ guard !pcmData.isEmpty else {
+ print("PCM数据为空")
+ return
+ }
+
+ print("接收PCM数据 - 数据大小: \(pcmData.count) bytes")
+
+ // 将新数据加入队列
+ queueLock.lock()
+ pcmDataQueue.append(pcmData)
+ let currentQueueSize = pcmDataQueue.count
+ queueLock.unlock()
+
+ print("PCM数据已加入队列 - 当前队列大小: \(currentQueueSize) bytes")
+
+ // 异步处理队列中的数据
+ processQueuedData()
+ }
+
+ /// 处理队列中的PCM数据
+ private func processQueuedData() {
+ guard isEncodingActive, let encoder = jlOpusEncoder else {
+ return
+ }
+
+ // 使用专用队列进行异步处理
+ if processingQueue == nil {
+ processingQueue = DispatchQueue(label: "com.opus.processing", qos: .userInitiated)
+ }
+
+ processingQueue?.async { [weak self, weak encoder] in
+ guard let self = self, let encoder = encoder else {
+ print("编码器或处理器已释放")
+ return
+ }
+
+ while self.isEncodingActive {
+ var chunkData: Data?
+
+ // 从队列中取出数据
+ self.queueLock.lock()
+ if self.pcmDataQueue.count >= self.chunkSize {
+ // 取出640字节数据
+ chunkData = self.pcmDataQueue.subdata(in: 0.. 0 {
+ // 不足640字节,补齐静音数据
+ let availableBytes = self.pcmDataQueue.count
+ let silentBytesNeeded = self.chunkSize - availableBytes
+
+ // 创建静音数据(16位PCM静音为0)
+ let silentData = Data(repeating: 0, count: silentBytesNeeded)
+
+ // 组合实际数据和静音数据
+ chunkData = Data()
+ chunkData?.append(self.pcmDataQueue)
+ chunkData?.append(silentData)
+
+ // 清空队列
+ self.pcmDataQueue.removeAll()
+
+ print("数据不足640字节,已补齐静音数据 - 实际数据: \(availableBytes) bytes, 静音数据: \(silentBytesNeeded) bytes")
+ }
+ self.queueLock.unlock()
+
+ // 如果有数据需要编码
+ if let dataToEncode = chunkData {
+ guard self.isEncodingActive else {
+ print("编码已停止,退出处理循环")
+ break
+ }
+
+ // 编码数据块
+ encoder.opusEncode(dataToEncode)
+ print("已编码音频块 - 数据大小: \(dataToEncode.count) bytes")
+ } else {
+ // 队列为空,退出循环
+ break
+ }
+ }
+
+ print("队列处理完成")
+ }
+ }
+
+ /// 清空PCM数据队列
+ private func clearPCMQueue() {
+ queueLock.lock()
+ pcmDataQueue.removeAll()
+ queueLock.unlock()
+ print("PCM数据队列已清空")
+ }
+
+
+ /// 清理所有资源
+ func cleanup() {
+ stopDecoding()
+ stopEncoding()
+ }
+}
+
+// MARK: - JLOpusEncoderDelegate
+@available(iOS 13.0, *)
+extension SwiftOpusAudioProcessor: JLOpusEncoderDelegate {
+
+ /// JLOpusEncoder编码回调
+ /// - Parameters:
+ /// - encoder: 编码器实例
+ /// - data: 编码后的Opus数据
+ /// - error: 错误信息
+ func opusEncoder(_ encoder: JLOpusEncoder, data: Data?, error: (any Error)?) {
+ if let error = error {
+ print("Opus编码错误: \(error.localizedDescription)")
+ return
+ }
+
+ guard let opusData = data, !opusData.isEmpty else {
+ print("编码后的Opus数据为空")
+ return
+ }
+
+ print("Opus编码成功 - 数据大小: \(opusData.count) bytes")
+
+ // 回调编码后的数据到主线程
+ DispatchQueue.main.async { [weak self] in
+ self?.callback?.onEncodedDataReceived(data: opusData)
+ }
+ }
}
+
+
+
diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/opuse.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/opuse.swift
new file mode 100644
index 000000000..04e2fe871
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/opuse.swift
@@ -0,0 +1,85 @@
+import Foundation
+import opus
+
+class OpusAudioProcessor {
+ private var encoder: OpaquePointer?
+ private var decoder: OpaquePointer?
+
+ /**
+ * 初始化Opus编码器
+ * @param sampleRate 采样率 (8000, 12000, 16000, 24000, 48000)
+ * @param channels 声道数 (1 = 单声道, 2 = 立体声)
+ * @param application 应用类型 (OPUS_APPLICATION_VOIP, OPUS_APPLICATION_AUDIO, OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ */
+ func initializeEncoder(sampleRate: Int32, channels: Int32, application: Int32) -> Bool {
+ var error: Int32 = 0
+ encoder = opus_encoder_create(sampleRate, channels, application, &error)
+ return error == OPUS_OK
+ }
+
+ /**
+ * 初始化Opus解码器
+ * @param sampleRate 采样率
+ * @param channels 声道数
+ */
+ func initializeDecoder(sampleRate: Int32, channels: Int32) -> Bool {
+ var error: Int32 = 0
+ decoder = opus_decoder_create(sampleRate, channels, &error)
+ return error == OPUS_OK
+ }
+
+ /**
+ * 编码音频数据
+ * @param pcmData PCM音频数据
+ * @param frameSize 帧大小
+ * @param maxDataBytes 最大输出字节数
+ * @return 编码后的数据
+ */
+ func encode(pcmData: [Int16], frameSize: Int32, maxDataBytes: Int32) -> Data? {
+ guard let encoder = encoder else { return nil }
+
+ let outputBuffer = UnsafeMutablePointer.allocate(capacity: Int(maxDataBytes))
+ defer { outputBuffer.deallocate() }
+
+ let encodedBytes = opus_encode(encoder, pcmData, frameSize, outputBuffer, maxDataBytes)
+
+ if encodedBytes > 0 {
+ return Data(bytes: outputBuffer, count: Int(encodedBytes))
+ }
+ return nil
+ }
+
+ /**
+ * 解码音频数据
+ * @param encodedData 编码后的数据
+ * @param frameSize 帧大小
+ * @return 解码后的PCM数据
+ */
+ func decode(encodedData: Data, frameSize: Int32) -> [Int16]? {
+ guard let decoder = decoder else { return nil }
+
+ let outputBuffer = UnsafeMutablePointer.allocate(capacity: Int(frameSize * 2)) // 假设最多2声道
+ defer { outputBuffer.deallocate() }
+
+ let decodedSamples = encodedData.withUnsafeBytes { bytes in
+ opus_decode(decoder, bytes.bindMemory(to: UInt8.self).baseAddress, Int32(encodedData.count), outputBuffer, frameSize, 0)
+ }
+
+ if decodedSamples > 0 {
+ return Array(UnsafeBufferPointer(start: outputBuffer, count: Int(decodedSamples * 2)))
+ }
+ return nil
+ }
+
+ /**
+ * 清理资源
+ */
+ deinit {
+ if let encoder = encoder {
+ opus_encoder_destroy(encoder)
+ }
+ if let decoder = decoder {
+ opus_decoder_destroy(decoder)
+ }
+ }
+}
\ No newline at end of file
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/Info.plist b/local_plugins/ble_service/ios/ble_service/opus.xcframework/Info.plist
new file mode 100644
index 000000000..67bf2e3b8
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/opus.xcframework/Info.plist
@@ -0,0 +1,43 @@
+
+
+
+
+ AvailableLibraries
+
+
+ BinaryPath
+ opus.framework/opus
+ LibraryIdentifier
+ ios-x86_64-simulator
+ LibraryPath
+ opus.framework
+ SupportedArchitectures
+
+ x86_64
+
+ SupportedPlatform
+ ios
+ SupportedPlatformVariant
+ simulator
+
+
+ BinaryPath
+ opus.framework/opus
+ LibraryIdentifier
+ ios-arm64
+ LibraryPath
+ opus.framework
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ ios
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus.h b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus.h
new file mode 100644
index 000000000..5be73ddf4
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus.h
@@ -0,0 +1,981 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus.h
+ * @brief Opus reference implementation API
+ */
+
+#ifndef OPUS_H
+#define OPUS_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @mainpage Opus
+ *
+ * The Opus codec is designed for interactive speech and audio transmission over the Internet.
+ * It is designed by the IETF Codec Working Group and incorporates technology from
+ * Skype's SILK codec and Xiph.Org's CELT codec.
+ *
+ * The Opus codec is designed to handle a wide range of interactive audio applications,
+ * including Voice over IP, videoconferencing, in-game chat, and even remote live music
+ * performances. It can scale from low bit-rate narrowband speech to very high quality
+ * stereo music. Its main features are:
+
+ * @li Sampling rates from 8 to 48 kHz
+ * @li Bit-rates from 6 kb/s to 510 kb/s
+ * @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR)
+ * @li Audio bandwidth from narrowband to full-band
+ * @li Support for speech and music
+ * @li Support for mono and stereo
+ * @li Support for multichannel (up to 255 channels)
+ * @li Frame sizes from 2.5 ms to 60 ms
+ * @li Good loss robustness and packet loss concealment (PLC)
+ * @li Floating point and fixed-point implementation
+ *
+ * Documentation sections:
+ * @li @ref opus_encoder
+ * @li @ref opus_decoder
+ * @li @ref opus_repacketizer
+ * @li @ref opus_multistream
+ * @li @ref opus_libinfo
+ * @li @ref opus_custom
+ */
+
+/** @defgroup opus_encoder Opus Encoder
+ * @{
+ *
+ * @brief This page describes the process and functions used to encode Opus.
+ *
+ * Since Opus is a stateful codec, the encoding process starts with creating an encoder
+ * state. This can be done with:
+ *
+ * @code
+ * int error;
+ * OpusEncoder *enc;
+ * enc = opus_encoder_create(Fs, channels, application, &error);
+ * @endcode
+ *
+ * From this point, @c enc can be used for encoding an audio stream. An encoder state
+ * @b must @b not be used for more than one stream at the same time. Similarly, the encoder
+ * state @b must @b not be re-initialized for each frame.
+ *
+ * While opus_encoder_create() allocates memory for the state, it's also possible
+ * to initialize pre-allocated memory:
+ *
+ * @code
+ * int size;
+ * int error;
+ * OpusEncoder *enc;
+ * size = opus_encoder_get_size(channels);
+ * enc = malloc(size);
+ * error = opus_encoder_init(enc, Fs, channels, application);
+ * @endcode
+ *
+ * where opus_encoder_get_size() returns the required size for the encoder state. Note that
+ * future versions of this code may change the size, so no assuptions should be made about it.
+ *
+ * The encoder state is always continuous in memory and only a shallow copy is sufficient
+ * to copy it (e.g. memcpy())
+ *
+ * It is possible to change some of the encoder's settings using the opus_encoder_ctl()
+ * interface. All these settings already default to the recommended value, so they should
+ * only be changed when necessary. The most common settings one may want to change are:
+ *
+ * @code
+ * opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));
+ * opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
+ * opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type));
+ * @endcode
+ *
+ * where
+ *
+ * @arg bitrate is in bits per second (b/s)
+ * @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest
+ * @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC
+ *
+ * See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream.
+ *
+ * To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data:
+ * @code
+ * len = opus_encode(enc, audio_frame, frame_size, packet, max_packet);
+ * @endcode
+ *
+ * where
+ *
+ * - audio_frame is the audio data in opus_int16 (or float for opus_encode_float())
+ * - frame_size is the duration of the frame in samples (per channel)
+ * - packet is the byte array to which the compressed data is written
+ * - max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended).
+ * Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.
+ *
+ *
+ * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet.
+ * The return value can be negative, which indicates that an error has occurred. If the return value
+ * is 2 bytes or less, then the packet does not need to be transmitted (DTX).
+ *
+ * Once the encoder state if no longer needed, it can be destroyed with
+ *
+ * @code
+ * opus_encoder_destroy(enc);
+ * @endcode
+ *
+ * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(),
+ * then no action is required aside from potentially freeing the memory that was manually
+ * allocated for it (calling free(enc) for the example above)
+ *
+ */
+
+/** Opus encoder state.
+ * This contains the complete state of an Opus encoder.
+ * It is position independent and can be freely copied.
+ * @see opus_encoder_create,opus_encoder_init
+ */
+typedef struct OpusEncoder OpusEncoder;
+
+/** Gets the size of an OpusEncoder structure.
+ * @param[in] channels int: Number of channels.
+ * This must be 1 or 2.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);
+
+/**
+ */
+
+/** Allocates and initializes an encoder state.
+ * There are three coding modes:
+ *
+ * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice
+ * signals. It enhances the input signal by high-pass filtering and
+ * emphasizing formants and harmonics. Optionally it includes in-band
+ * forward error correction to protect against packet loss. Use this
+ * mode for typical VoIP applications. Because of the enhancement,
+ * even at high bitrates the output may sound different from the input.
+ *
+ * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most
+ * non-voice signals like music. Use this mode for music and mixed
+ * (music/voice) content, broadcast, and applications requiring less
+ * than 15 ms of coding delay.
+ *
+ * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that
+ * disables the speech-optimized mode in exchange for slightly reduced delay.
+ * This mode can only be set on an newly initialized or freshly reset encoder
+ * because it changes the codec delay.
+ *
+ * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution).
+ * @param [in] Fs opus_int32: Sampling rate of input signal (Hz)
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels int: Number of channels (1 or 2) in input signal
+ * @param [in] application int: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ * @param [out] error int*: @ref opus_errorcodes
+ * @note Regardless of the sampling rate and number channels selected, the Opus encoder
+ * can switch to a lower audio bandwidth or number of channels if the bitrate
+ * selected is too low. This also means that it is safe to always use 48 kHz stereo input
+ * and let the encoder optimize the encoding.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int application,
+ int *error
+);
+
+/** Initializes a previously allocated encoder state
+ * The memory pointed to by st must be at least the size returned by opus_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of malloc.
+ * @see opus_encoder_create(),opus_encoder_get_size()
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @param [in] st OpusEncoder*: Encoder state
+ * @param [in] Fs opus_int32: Sampling rate of input signal (Hz)
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels int: Number of channels (1 or 2) in input signal
+ * @param [in] application int: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ * @retval #OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_EXPORT int opus_encoder_init(
+ OpusEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int application
+) OPUS_ARG_NONNULL(1);
+
+/** Encodes an Opus frame.
+ * @param [in] st OpusEncoder*: Encoder state
+ * @param [in] pcm opus_int16*: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16)
+ * @param [in] frame_size int: Number of samples per channel in the
+ * input signal.
+ * This must be an Opus frame size for
+ * the encoder's sampling rate.
+ * For example, at 48 kHz the permitted
+ * values are 120, 240, 480, 960, 1920,
+ * and 2880.
+ * Passing in a duration of less than
+ * 10 ms (480 samples at 48 kHz) will
+ * prevent the encoder from using the LPC
+ * or hybrid modes.
+ * @param [out] data unsigned char*: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes opus_int32: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode(
+ OpusEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes an Opus frame from floating point input.
+ * @param [in] st OpusEncoder*: Encoder state
+ * @param [in] pcm float*: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0.
+ * Samples with a range beyond +/-1.0 are supported but will
+ * be clipped by decoders using the integer API and should
+ * only be used if it is known that the far end supports
+ * extended dynamic range.
+ * length is frame_size*channels*sizeof(float)
+ * @param [in] frame_size int: Number of samples per channel in the
+ * input signal.
+ * This must be an Opus frame size for
+ * the encoder's sampling rate.
+ * For example, at 48 kHz the permitted
+ * values are 120, 240, 480, 960, 1920,
+ * and 2880.
+ * Passing in a duration of less than
+ * 10 ms (480 samples at 48 kHz) will
+ * prevent the encoder from using the LPC
+ * or hybrid modes.
+ * @param [out] data unsigned char*: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes opus_int32: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float(
+ OpusEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Frees an OpusEncoder allocated by opus_encoder_create().
+ * @param[in] st OpusEncoder*: State to be freed.
+ */
+OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st);
+
+/** Perform a CTL function on an Opus encoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @param st OpusEncoder*: Encoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls or
+ * @ref opus_encoderctls.
+ * @see opus_genericctls
+ * @see opus_encoderctls
+ */
+OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+/**@}*/
+
+/** @defgroup opus_decoder Opus Decoder
+ * @{
+ *
+ * @brief This page describes the process and functions used to decode Opus.
+ *
+ * The decoding process also starts with creating a decoder
+ * state. This can be done with:
+ * @code
+ * int error;
+ * OpusDecoder *dec;
+ * dec = opus_decoder_create(Fs, channels, &error);
+ * @endcode
+ * where
+ * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000
+ * @li channels is the number of channels (1 or 2)
+ * @li error will hold the error code in case of failure (or #OPUS_OK on success)
+ * @li the return value is a newly created decoder state to be used for decoding
+ *
+ * While opus_decoder_create() allocates memory for the state, it's also possible
+ * to initialize pre-allocated memory:
+ * @code
+ * int size;
+ * int error;
+ * OpusDecoder *dec;
+ * size = opus_decoder_get_size(channels);
+ * dec = malloc(size);
+ * error = opus_decoder_init(dec, Fs, channels);
+ * @endcode
+ * where opus_decoder_get_size() returns the required size for the decoder state. Note that
+ * future versions of this code may change the size, so no assuptions should be made about it.
+ *
+ * The decoder state is always continuous in memory and only a shallow copy is sufficient
+ * to copy it (e.g. memcpy())
+ *
+ * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data:
+ * @code
+ * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0);
+ * @endcode
+ * where
+ *
+ * @li packet is the byte array containing the compressed data
+ * @li len is the exact number of bytes contained in the packet
+ * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float())
+ * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array
+ *
+ * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet.
+ * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio
+ * buffer is too small to hold the decoded audio.
+ *
+ * Opus is a stateful codec with overlapping blocks and as a result Opus
+ * packets are not coded independently of each other. Packets must be
+ * passed into the decoder serially and in the correct order for a correct
+ * decode. Lost packets can be replaced with loss concealment by calling
+ * the decoder with a null pointer and zero length for the missing packet.
+ *
+ * A single codec state may only be accessed from a single thread at
+ * a time and any required locking must be performed by the caller. Separate
+ * streams must be decoded with separate decoder states and can be decoded
+ * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK
+ * defined.
+ *
+ */
+
+/** Opus decoder state.
+ * This contains the complete state of an Opus decoder.
+ * It is position independent and can be freely copied.
+ * @see opus_decoder_create,opus_decoder_init
+ */
+typedef struct OpusDecoder OpusDecoder;
+
+/** Gets the size of an OpusDecoder structure.
+ * @param [in] channels int: Number of channels.
+ * This must be 1 or 2.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels);
+
+/** Allocates and initializes a decoder state.
+ * @param [in] Fs opus_int32: Sample rate to decode at (Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels int: Number of channels (1 or 2) to decode
+ * @param [out] error int*: #OPUS_OK Success or @ref opus_errorcodes
+ *
+ * Internally Opus stores data at 48000 Hz, so that should be the default
+ * value for Fs. However, the decoder can efficiently decode to buffers
+ * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use
+ * data at the full sample rate, or knows the compressed data doesn't
+ * use the full frequency range, it can request decoding at a reduced
+ * rate. Likewise, the decoder is capable of filling in either mono or
+ * interleaved stereo pcm buffers, at the caller's request.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create(
+ opus_int32 Fs,
+ int channels,
+ int *error
+);
+
+/** Initializes a previously allocated decoder state.
+ * The state must be at least the size returned by opus_decoder_get_size().
+ * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @param [in] st OpusDecoder*: Decoder state.
+ * @param [in] Fs opus_int32: Sampling rate to decode to (Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels int: Number of channels (1 or 2) to decode
+ * @retval #OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_EXPORT int opus_decoder_init(
+ OpusDecoder *st,
+ opus_int32 Fs,
+ int channels
+) OPUS_ARG_NONNULL(1);
+
+/** Decode an Opus packet.
+ * @param [in] st OpusDecoder*: Decoder state
+ * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len opus_int32: Number of bytes in payload*
+ * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(opus_int16)
+ * @param [in] frame_size Number of samples per channel of available space in \a pcm.
+ * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
+ * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+ * then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+ * FEC cases, frame_size must be a multiple of 2.5 ms.
+ * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be
+ * decoded. If no such data is available, the frame is decoded as if it were lost.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode(
+ OpusDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ opus_int16 *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode an Opus packet with floating point output.
+ * @param [in] st OpusDecoder*: Decoder state
+ * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len opus_int32: Number of bytes in payload
+ * @param [out] pcm float*: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(float)
+ * @param [in] frame_size Number of samples per channel of available space in \a pcm.
+ * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
+ * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+ * then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+ * FEC cases, frame_size must be a multiple of 2.5 ms.
+ * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be
+ * decoded. If no such data is available the frame is decoded as if it were lost.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float(
+ OpusDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ float *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on an Opus decoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @param st OpusDecoder*: Decoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls or
+ * @ref opus_decoderctls.
+ * @see opus_genericctls
+ * @see opus_decoderctls
+ */
+OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/** Frees an OpusDecoder allocated by opus_decoder_create().
+ * @param[in] st OpusDecoder*: State to be freed.
+ */
+OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
+
+/** Parse an opus packet into one or more frames.
+ * Opus_decode will perform this operation internally so most applications do
+ * not need to use this function.
+ * This function does not copy the frames, the returned pointers are pointers into
+ * the input packet.
+ * @param [in] data char*: Opus packet to be parsed
+ * @param [in] len opus_int32: size of data
+ * @param [out] out_toc char*: TOC pointer
+ * @param [out] frames char*[48] encapsulated frames
+ * @param [out] size opus_int16[48] sizes of the encapsulated frames
+ * @param [out] payload_offset int*: returns the position of the payload within the packet (in bytes)
+ * @returns number of frames
+ */
+OPUS_EXPORT int opus_packet_parse(
+ const unsigned char *data,
+ opus_int32 len,
+ unsigned char *out_toc,
+ const unsigned char *frames[48],
+ opus_int16 size[48],
+ int *payload_offset
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Gets the bandwidth of an Opus packet.
+ * @param [in] data char*: Opus packet
+ * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass)
+ * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass)
+ * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass)
+ * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass)
+ * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass)
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples per frame from an Opus packet.
+ * @param [in] data char*: Opus packet.
+ * This must contain at least one byte of
+ * data.
+ * @param [in] Fs opus_int32: Sampling rate in Hz.
+ * This must be a multiple of 400, or
+ * inaccurate results will be returned.
+ * @returns Number of samples per frame.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of channels from an Opus packet.
+ * @param [in] data char*: Opus packet
+ * @returns Number of channels
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of frames in an Opus packet.
+ * @param [in] packet char*: Opus packet
+ * @param [in] len opus_int32: Length of packet
+ * @returns Number of frames
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples of an Opus packet.
+ * @param [in] packet char*: Opus packet
+ * @param [in] len opus_int32: Length of packet
+ * @param [in] Fs opus_int32: Sampling rate in Hz.
+ * This must be a multiple of 400, or
+ * inaccurate results will be returned.
+ * @returns Number of samples
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples of an Opus packet.
+ * @param [in] dec OpusDecoder*: Decoder state
+ * @param [in] packet char*: Opus packet
+ * @param [in] len opus_int32: Length of packet
+ * @returns Number of samples
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+/** Applies soft-clipping to bring a float signal within the [-1,1] range. If
+ * the signal is already in that range, nothing is done. If there are values
+ * outside of [-1,1], then the signal is clipped as smoothly as possible to
+ * both fit in the range and avoid creating excessive distortion in the
+ * process.
+ * @param [in,out] pcm float*: Input PCM and modified PCM
+ * @param [in] frame_size int Number of samples per channel to process
+ * @param [in] channels int: Number of channels
+ * @param [in,out] softclip_mem float*: State memory for the soft clipping process (one float per channel, initialized to zero)
+ */
+OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem);
+
+
+/**@}*/
+
+/** @defgroup opus_repacketizer Repacketizer
+ * @{
+ *
+ * The repacketizer can be used to merge multiple Opus packets into a single
+ * packet or alternatively to split Opus packets that have previously been
+ * merged. Splitting valid Opus packets is always guaranteed to succeed,
+ * whereas merging valid packets only succeeds if all frames have the same
+ * mode, bandwidth, and frame size, and when the total duration of the merged
+ * packet is no more than 120 ms. The 120 ms limit comes from the
+ * specification and limits decoder memory requirements at a point where
+ * framing overhead becomes negligible.
+ *
+ * The repacketizer currently only operates on elementary Opus
+ * streams. It will not manipualte multistream packets successfully, except in
+ * the degenerate case where they consist of data from a single stream.
+ *
+ * The repacketizing process starts with creating a repacketizer state, either
+ * by calling opus_repacketizer_create() or by allocating the memory yourself,
+ * e.g.,
+ * @code
+ * OpusRepacketizer *rp;
+ * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size());
+ * if (rp != NULL)
+ * opus_repacketizer_init(rp);
+ * @endcode
+ *
+ * Then the application should submit packets with opus_repacketizer_cat(),
+ * extract new packets with opus_repacketizer_out() or
+ * opus_repacketizer_out_range(), and then reset the state for the next set of
+ * input packets via opus_repacketizer_init().
+ *
+ * For example, to split a sequence of packets into individual frames:
+ * @code
+ * unsigned char *data;
+ * int len;
+ * while (get_next_packet(&data, &len))
+ * {
+ * unsigned char out[1276];
+ * opus_int32 out_len;
+ * int nb_frames;
+ * int err;
+ * int i;
+ * err = opus_repacketizer_cat(rp, data, len);
+ * if (err != OPUS_OK)
+ * {
+ * release_packet(data);
+ * return err;
+ * }
+ * nb_frames = opus_repacketizer_get_nb_frames(rp);
+ * for (i = 0; i < nb_frames; i++)
+ * {
+ * out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out));
+ * if (out_len < 0)
+ * {
+ * release_packet(data);
+ * return (int)out_len;
+ * }
+ * output_next_packet(out, out_len);
+ * }
+ * opus_repacketizer_init(rp);
+ * release_packet(data);
+ * }
+ * @endcode
+ *
+ * Alternatively, to combine a sequence of frames into packets that each
+ * contain up to TARGET_DURATION_MS milliseconds of data:
+ * @code
+ * // The maximum number of packets with duration TARGET_DURATION_MS occurs
+ * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5)
+ * // packets.
+ * unsigned char *data[(TARGET_DURATION_MS*2/5)+1];
+ * opus_int32 len[(TARGET_DURATION_MS*2/5)+1];
+ * int nb_packets;
+ * unsigned char out[1277*(TARGET_DURATION_MS*2/2)];
+ * opus_int32 out_len;
+ * int prev_toc;
+ * nb_packets = 0;
+ * while (get_next_packet(data+nb_packets, len+nb_packets))
+ * {
+ * int nb_frames;
+ * int err;
+ * nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]);
+ * if (nb_frames < 1)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return nb_frames;
+ * }
+ * nb_frames += opus_repacketizer_get_nb_frames(rp);
+ * // If adding the next packet would exceed our target, or it has an
+ * // incompatible TOC sequence, output the packets we already have before
+ * // submitting it.
+ * // N.B., The nb_packets > 0 check ensures we've submitted at least one
+ * // packet since the last call to opus_repacketizer_init(). Otherwise a
+ * // single packet longer than TARGET_DURATION_MS would cause us to try to
+ * // output an (invalid) empty packet. It also ensures that prev_toc has
+ * // been set to a valid value. Additionally, len[nb_packets] > 0 is
+ * // guaranteed by the call to opus_packet_get_nb_frames() above, so the
+ * // reference to data[nb_packets][0] should be valid.
+ * if (nb_packets > 0 && (
+ * ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) ||
+ * opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames >
+ * TARGET_DURATION_MS*48))
+ * {
+ * out_len = opus_repacketizer_out(rp, out, sizeof(out));
+ * if (out_len < 0)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return (int)out_len;
+ * }
+ * output_next_packet(out, out_len);
+ * opus_repacketizer_init(rp);
+ * release_packets(data, nb_packets);
+ * data[0] = data[nb_packets];
+ * len[0] = len[nb_packets];
+ * nb_packets = 0;
+ * }
+ * err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]);
+ * if (err != OPUS_OK)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return err;
+ * }
+ * prev_toc = data[nb_packets][0];
+ * nb_packets++;
+ * }
+ * // Output the final, partial packet.
+ * if (nb_packets > 0)
+ * {
+ * out_len = opus_repacketizer_out(rp, out, sizeof(out));
+ * release_packets(data, nb_packets);
+ * if (out_len < 0)
+ * return (int)out_len;
+ * output_next_packet(out, out_len);
+ * }
+ * @endcode
+ *
+ * An alternate way of merging packets is to simply call opus_repacketizer_cat()
+ * unconditionally until it fails. At that point, the merged packet can be
+ * obtained with opus_repacketizer_out() and the input packet for which
+ * opus_repacketizer_cat() needs to be re-added to a newly reinitialized
+ * repacketizer state.
+ */
+
+typedef struct OpusRepacketizer OpusRepacketizer;
+
+/** Gets the size of an OpusRepacketizer structure.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void);
+
+/** (Re)initializes a previously allocated repacketizer state.
+ * The state must be at least the size returned by opus_repacketizer_get_size().
+ * This can be used for applications which use their own allocator instead of
+ * malloc().
+ * It must also be called to reset the queue of packets waiting to be
+ * repacketized, which is necessary if the maximum packet duration of 120 ms
+ * is reached or if you wish to submit packets with a different Opus
+ * configuration (coding mode, audio bandwidth, frame size, or channel count).
+ * Failure to do so will prevent a new packet from being added with
+ * opus_repacketizer_cat().
+ * @see opus_repacketizer_create
+ * @see opus_repacketizer_get_size
+ * @see opus_repacketizer_cat
+ * @param rp OpusRepacketizer*: The repacketizer state to
+ * (re)initialize.
+ * @returns A pointer to the same repacketizer state that was passed in.
+ */
+OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
+
+/** Allocates memory and initializes the new repacketizer with
+ * opus_repacketizer_init().
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void);
+
+/** Frees an OpusRepacketizer allocated by
+ * opus_repacketizer_create().
+ * @param[in] rp OpusRepacketizer*: State to be freed.
+ */
+OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp);
+
+/** Add a packet to the current repacketizer state.
+ * This packet must match the configuration of any packets already submitted
+ * for repacketization since the last call to opus_repacketizer_init().
+ * This means that it must have the same coding mode, audio bandwidth, frame
+ * size, and channel count.
+ * This can be checked in advance by examining the top 6 bits of the first
+ * byte of the packet, and ensuring they match the top 6 bits of the first
+ * byte of any previously submitted packet.
+ * The total duration of audio in the repacketizer state also must not exceed
+ * 120 ms, the maximum duration of a single packet, after adding this packet.
+ *
+ * The contents of the current repacketizer state can be extracted into new
+ * packets using opus_repacketizer_out() or opus_repacketizer_out_range().
+ *
+ * In order to add a packet with a different configuration or to add more
+ * audio beyond 120 ms, you must clear the repacketizer state by calling
+ * opus_repacketizer_init().
+ * If a packet is too large to add to the current repacketizer state, no part
+ * of it is added, even if it contains multiple frames, some of which might
+ * fit.
+ * If you wish to be able to add parts of such packets, you should first use
+ * another repacketizer to split the packet into pieces and add them
+ * individually.
+ * @see opus_repacketizer_out_range
+ * @see opus_repacketizer_out
+ * @see opus_repacketizer_init
+ * @param rp OpusRepacketizer*: The repacketizer state to which to
+ * add the packet.
+ * @param[in] data const unsigned char*: The packet data.
+ * The application must ensure
+ * this pointer remains valid
+ * until the next call to
+ * opus_repacketizer_init() or
+ * opus_repacketizer_destroy().
+ * @param len opus_int32: The number of bytes in the packet data.
+ * @returns An error code indicating whether or not the operation succeeded.
+ * @retval #OPUS_OK The packet's contents have been added to the repacketizer
+ * state.
+ * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence,
+ * the packet's TOC sequence was not compatible
+ * with previously submitted packets (because
+ * the coding mode, audio bandwidth, frame size,
+ * or channel count did not match), or adding
+ * this packet would increase the total amount of
+ * audio stored in the repacketizer state to more
+ * than 120 ms.
+ */
+OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+
+/** Construct a new packet from data previously submitted to the repacketizer
+ * state via opus_repacketizer_cat().
+ * @param rp OpusRepacketizer*: The repacketizer state from which to
+ * construct the new packet.
+ * @param begin int: The index of the first frame in the current
+ * repacketizer state to include in the output.
+ * @param end int: One past the index of the last frame in the
+ * current repacketizer state to include in the
+ * output.
+ * @param[out] data const unsigned char*: The buffer in which to
+ * store the output packet.
+ * @param maxlen opus_int32: The maximum number of bytes to store in
+ * the output buffer. In order to guarantee
+ * success, this should be at least
+ * 1276 for a single frame,
+ * or for multiple frames,
+ * 1277*(end-begin).
+ * However, 1*(end-begin) plus
+ * the size of all packet data submitted to
+ * the repacketizer since the last call to
+ * opus_repacketizer_init() or
+ * opus_repacketizer_create() is also
+ * sufficient, and possibly much smaller.
+ * @returns The total size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG [begin,end) was an invalid range of
+ * frames (begin < 0, begin >= end, or end >
+ * opus_repacketizer_get_nb_frames()).
+ * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+ * complete output packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Return the total number of frames contained in packet data submitted to
+ * the repacketizer state so far via opus_repacketizer_cat() since the last
+ * call to opus_repacketizer_init() or opus_repacketizer_create().
+ * This defines the valid range of packets that can be extracted with
+ * opus_repacketizer_out_range() or opus_repacketizer_out().
+ * @param rp OpusRepacketizer*: The repacketizer state containing the
+ * frames.
+ * @returns The total number of frames contained in the packet data submitted
+ * to the repacketizer state.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
+
+/** Construct a new packet from data previously submitted to the repacketizer
+ * state via opus_repacketizer_cat().
+ * This is a convenience routine that returns all the data submitted so far
+ * in a single packet.
+ * It is equivalent to calling
+ * @code
+ * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp),
+ * data, maxlen)
+ * @endcode
+ * @param rp OpusRepacketizer*: The repacketizer state from which to
+ * construct the new packet.
+ * @param[out] data const unsigned char*: The buffer in which to
+ * store the output packet.
+ * @param maxlen opus_int32: The maximum number of bytes to store in
+ * the output buffer. In order to guarantee
+ * success, this should be at least
+ * 1277*opus_repacketizer_get_nb_frames(rp).
+ * However,
+ * 1*opus_repacketizer_get_nb_frames(rp)
+ * plus the size of all packet data
+ * submitted to the repacketizer since the
+ * last call to opus_repacketizer_init() or
+ * opus_repacketizer_create() is also
+ * sufficient, and possibly much smaller.
+ * @returns The total size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+ * complete output packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1);
+
+/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence).
+ * @param[in,out] data const unsigned char*: The buffer containing the
+ * packet to pad.
+ * @param len opus_int32: The size of the packet.
+ * This must be at least 1.
+ * @param new_len opus_int32: The desired size of the packet after padding.
+ * This must be at least as large as len.
+ * @returns an error code
+ * @retval #OPUS_OK \a on success.
+ * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len);
+
+/** Remove all padding from a given Opus packet and rewrite the TOC sequence to
+ * minimize space usage.
+ * @param[in,out] data const unsigned char*: The buffer containing the
+ * packet to strip.
+ * @param len opus_int32: The size of the packet.
+ * This must be at least 1.
+ * @returns The new size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG \a len was less than 1.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len);
+
+/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence).
+ * @param[in,out] data const unsigned char*: The buffer containing the
+ * packet to pad.
+ * @param len opus_int32: The size of the packet.
+ * This must be at least 1.
+ * @param new_len opus_int32: The desired size of the packet after padding.
+ * This must be at least 1.
+ * @param nb_streams opus_int32: The number of streams (not channels) in the packet.
+ * This must be at least as large as len.
+ * @returns an error code
+ * @retval #OPUS_OK \a on success.
+ * @retval #OPUS_BAD_ARG \a len was less than 1.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams);
+
+/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to
+ * minimize space usage.
+ * @param[in,out] data const unsigned char*: The buffer containing the
+ * packet to strip.
+ * @param len opus_int32: The size of the packet.
+ * This must be at least 1.
+ * @param nb_streams opus_int32: The number of streams (not channels) in the packet.
+ * This must be at least 1.
+ * @returns The new size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams);
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_H */
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus_defines.h b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus_defines.h
new file mode 100644
index 000000000..315412dd1
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus_defines.h
@@ -0,0 +1,753 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus_defines.h
+ * @brief Opus reference implementation constants
+ */
+
+#ifndef OPUS_DEFINES_H
+#define OPUS_DEFINES_H
+
+#include "opus_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup opus_errorcodes Error codes
+ * @{
+ */
+/** No error @hideinitializer*/
+#define OPUS_OK 0
+/** One or more invalid/out of range arguments @hideinitializer*/
+#define OPUS_BAD_ARG -1
+/** Not enough bytes allocated in the buffer @hideinitializer*/
+#define OPUS_BUFFER_TOO_SMALL -2
+/** An internal error was detected @hideinitializer*/
+#define OPUS_INTERNAL_ERROR -3
+/** The compressed data passed is corrupted @hideinitializer*/
+#define OPUS_INVALID_PACKET -4
+/** Invalid/unsupported request number @hideinitializer*/
+#define OPUS_UNIMPLEMENTED -5
+/** An encoder or decoder structure is invalid or already freed @hideinitializer*/
+#define OPUS_INVALID_STATE -6
+/** Memory allocation has failed @hideinitializer*/
+#define OPUS_ALLOC_FAIL -7
+/**@}*/
+
+/** @cond OPUS_INTERNAL_DOC */
+/**Export control for opus functions */
+
+#ifndef OPUS_EXPORT
+# if defined(WIN32)
+# if defined(OPUS_BUILD) && defined(DLL_EXPORT)
+# define OPUS_EXPORT __declspec(dllexport)
+# else
+# define OPUS_EXPORT
+# endif
+# elif defined(__GNUC__) && defined(OPUS_BUILD)
+# define OPUS_EXPORT __attribute__ ((visibility ("default")))
+# else
+# define OPUS_EXPORT
+# endif
+#endif
+
+# if !defined(OPUS_GNUC_PREREQ)
+# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
+# define OPUS_GNUC_PREREQ(_maj,_min) \
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
+# else
+# define OPUS_GNUC_PREREQ(_maj,_min) 0
+# endif
+# endif
+
+#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if OPUS_GNUC_PREREQ(3,0)
+# define OPUS_RESTRICT __restrict__
+# elif (defined(_MSC_VER) && _MSC_VER >= 1400)
+# define OPUS_RESTRICT __restrict
+# else
+# define OPUS_RESTRICT
+# endif
+#else
+# define OPUS_RESTRICT restrict
+#endif
+
+#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if OPUS_GNUC_PREREQ(2,7)
+# define OPUS_INLINE __inline__
+# elif (defined(_MSC_VER))
+# define OPUS_INLINE __inline
+# else
+# define OPUS_INLINE
+# endif
+#else
+# define OPUS_INLINE inline
+#endif
+
+/**Warning attributes for opus functions
+ * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out
+ * some paranoid null checks. */
+#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
+# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
+#else
+# define OPUS_WARN_UNUSED_RESULT
+#endif
+#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
+# define OPUS_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x)))
+#else
+# define OPUS_ARG_NONNULL(_x)
+#endif
+
+/** These are the actual Encoder CTL ID numbers.
+ * They should not be used directly by applications.
+ * In general, SETs should be even and GETs should be odd.*/
+#define OPUS_SET_APPLICATION_REQUEST 4000
+#define OPUS_GET_APPLICATION_REQUEST 4001
+#define OPUS_SET_BITRATE_REQUEST 4002
+#define OPUS_GET_BITRATE_REQUEST 4003
+#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004
+#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005
+#define OPUS_SET_VBR_REQUEST 4006
+#define OPUS_GET_VBR_REQUEST 4007
+#define OPUS_SET_BANDWIDTH_REQUEST 4008
+#define OPUS_GET_BANDWIDTH_REQUEST 4009
+#define OPUS_SET_COMPLEXITY_REQUEST 4010
+#define OPUS_GET_COMPLEXITY_REQUEST 4011
+#define OPUS_SET_INBAND_FEC_REQUEST 4012
+#define OPUS_GET_INBAND_FEC_REQUEST 4013
+#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014
+#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015
+#define OPUS_SET_DTX_REQUEST 4016
+#define OPUS_GET_DTX_REQUEST 4017
+#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020
+#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021
+#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022
+#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023
+#define OPUS_SET_SIGNAL_REQUEST 4024
+#define OPUS_GET_SIGNAL_REQUEST 4025
+#define OPUS_GET_LOOKAHEAD_REQUEST 4027
+/* #define OPUS_RESET_STATE 4028 */
+#define OPUS_GET_SAMPLE_RATE_REQUEST 4029
+#define OPUS_GET_FINAL_RANGE_REQUEST 4031
+#define OPUS_GET_PITCH_REQUEST 4033
+#define OPUS_SET_GAIN_REQUEST 4034
+#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */
+#define OPUS_SET_LSB_DEPTH_REQUEST 4036
+#define OPUS_GET_LSB_DEPTH_REQUEST 4037
+#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039
+#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040
+#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041
+#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042
+#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043
+
+/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
+
+/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
+#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
+#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
+#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))
+#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))
+/** @endcond */
+
+/** @defgroup opus_ctlvalues Pre-defined values for CTL interface
+ * @see opus_genericctls, opus_encoderctls
+ * @{
+ */
+/* Values for the various encoder CTLs */
+#define OPUS_AUTO -1000 /**opus_int32: Allowed values: 0-10, inclusive.
+ *
+ * @hideinitializer */
+#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x)
+/** Gets the encoder's complexity configuration.
+ * @see OPUS_SET_COMPLEXITY
+ * @param[out] x opus_int32 *: Returns a value in the range 0-10,
+ * inclusive.
+ * @hideinitializer */
+#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the bitrate in the encoder.
+ * Rates from 500 to 512000 bits per second are meaningful, as well as the
+ * special values #OPUS_AUTO and #OPUS_BITRATE_MAX.
+ * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much
+ * rate as it can, which is useful for controlling the rate by adjusting the
+ * output buffer size.
+ * @see OPUS_GET_BITRATE
+ * @param[in] x opus_int32: Bitrate in bits per second. The default
+ * is determined based on the number of
+ * channels and the input sampling rate.
+ * @hideinitializer */
+#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x)
+/** Gets the encoder's bitrate configuration.
+ * @see OPUS_SET_BITRATE
+ * @param[out] x opus_int32 *: Returns the bitrate in bits per second.
+ * The default is determined based on the
+ * number of channels and the input
+ * sampling rate.
+ * @hideinitializer */
+#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x)
+
+/** Enables or disables variable bitrate (VBR) in the encoder.
+ * The configured bitrate may not be met exactly because frames must
+ * be an integer number of bytes in length.
+ * @see OPUS_GET_VBR
+ * @see OPUS_SET_VBR_CONSTRAINT
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - 0
- Hard CBR. For LPC/hybrid modes at very low bit-rate, this can
+ * cause noticeable quality degradation.
+ * - 1
- VBR (default). The exact type of VBR is controlled by
+ * #OPUS_SET_VBR_CONSTRAINT.
+ *
+ * @hideinitializer */
+#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x)
+/** Determine if variable bitrate (VBR) is enabled in the encoder.
+ * @see OPUS_SET_VBR
+ * @see OPUS_GET_VBR_CONSTRAINT
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - 0
- Hard CBR.
+ * - 1
- VBR (default). The exact type of VBR may be retrieved via
+ * #OPUS_GET_VBR_CONSTRAINT.
+ *
+ * @hideinitializer */
+#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x)
+
+/** Enables or disables constrained VBR in the encoder.
+ * This setting is ignored when the encoder is in CBR mode.
+ * @warning Only the MDCT mode of Opus currently heeds the constraint.
+ * Speech mode ignores it completely, hybrid mode may fail to obey it
+ * if the LPC layer uses more bitrate than the constraint would have
+ * permitted.
+ * @see OPUS_GET_VBR_CONSTRAINT
+ * @see OPUS_SET_VBR
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - 0
- Unconstrained VBR.
+ * - 1
- Constrained VBR (default). This creates a maximum of one
+ * frame of buffering delay assuming a transport with a
+ * serialization speed of the nominal bitrate.
+ *
+ * @hideinitializer */
+#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x)
+/** Determine if constrained VBR is enabled in the encoder.
+ * @see OPUS_SET_VBR_CONSTRAINT
+ * @see OPUS_GET_VBR
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - 0
- Unconstrained VBR.
+ * - 1
- Constrained VBR (default).
+ *
+ * @hideinitializer */
+#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures mono/stereo forcing in the encoder.
+ * This can force the encoder to produce packets encoded as either mono or
+ * stereo, regardless of the format of the input audio. This is useful when
+ * the caller knows that the input signal is currently a mono source embedded
+ * in a stereo stream.
+ * @see OPUS_GET_FORCE_CHANNELS
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - #OPUS_AUTO
- Not forced (default)
+ * - 1
- Forced mono
+ * - 2
- Forced stereo
+ *
+ * @hideinitializer */
+#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x)
+/** Gets the encoder's forced channel configuration.
+ * @see OPUS_SET_FORCE_CHANNELS
+ * @param[out] x opus_int32 *:
+ *
+ * - #OPUS_AUTO
- Not forced (default)
+ * - 1
- Forced mono
+ * - 2
- Forced stereo
+ *
+ * @hideinitializer */
+#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the maximum bandpass that the encoder will select automatically.
+ * Applications should normally use this instead of #OPUS_SET_BANDWIDTH
+ * (leaving that set to the default, #OPUS_AUTO). This allows the
+ * application to set an upper bound based on the type of input it is
+ * providing, but still gives the encoder the freedom to reduce the bandpass
+ * when the bitrate becomes too low, for better overall quality.
+ * @see OPUS_GET_MAX_BANDWIDTH
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - OPUS_BANDWIDTH_NARROWBAND
- 4 kHz passband
+ * - OPUS_BANDWIDTH_MEDIUMBAND
- 6 kHz passband
+ * - OPUS_BANDWIDTH_WIDEBAND
- 8 kHz passband
+ * - OPUS_BANDWIDTH_SUPERWIDEBAND
- 12 kHz passband
+ * - OPUS_BANDWIDTH_FULLBAND
- 20 kHz passband (default)
+ *
+ * @hideinitializer */
+#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x)
+
+/** Gets the encoder's configured maximum allowed bandpass.
+ * @see OPUS_SET_MAX_BANDWIDTH
+ * @param[out] x opus_int32 *: Allowed values:
+ *
+ * - #OPUS_BANDWIDTH_NARROWBAND
- 4 kHz passband
+ * - #OPUS_BANDWIDTH_MEDIUMBAND
- 6 kHz passband
+ * - #OPUS_BANDWIDTH_WIDEBAND
- 8 kHz passband
+ * - #OPUS_BANDWIDTH_SUPERWIDEBAND
- 12 kHz passband
+ * - #OPUS_BANDWIDTH_FULLBAND
- 20 kHz passband (default)
+ *
+ * @hideinitializer */
+#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Sets the encoder's bandpass to a specific value.
+ * This prevents the encoder from automatically selecting the bandpass based
+ * on the available bitrate. If an application knows the bandpass of the input
+ * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH
+ * instead, which still gives the encoder the freedom to reduce the bandpass
+ * when the bitrate becomes too low, for better overall quality.
+ * @see OPUS_GET_BANDWIDTH
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - #OPUS_AUTO
- (default)
+ * - #OPUS_BANDWIDTH_NARROWBAND
- 4 kHz passband
+ * - #OPUS_BANDWIDTH_MEDIUMBAND
- 6 kHz passband
+ * - #OPUS_BANDWIDTH_WIDEBAND
- 8 kHz passband
+ * - #OPUS_BANDWIDTH_SUPERWIDEBAND
- 12 kHz passband
+ * - #OPUS_BANDWIDTH_FULLBAND
- 20 kHz passband
+ *
+ * @hideinitializer */
+#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x)
+
+/** Configures the type of signal being encoded.
+ * This is a hint which helps the encoder's mode selection.
+ * @see OPUS_GET_SIGNAL
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - #OPUS_AUTO
- (default)
+ * - #OPUS_SIGNAL_VOICE
- Bias thresholds towards choosing LPC or Hybrid modes.
+ * - #OPUS_SIGNAL_MUSIC
- Bias thresholds towards choosing MDCT modes.
+ *
+ * @hideinitializer */
+#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured signal type.
+ * @see OPUS_SET_SIGNAL
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - #OPUS_AUTO
- (default)
+ * - #OPUS_SIGNAL_VOICE
- Bias thresholds towards choosing LPC or Hybrid modes.
+ * - #OPUS_SIGNAL_MUSIC
- Bias thresholds towards choosing MDCT modes.
+ *
+ * @hideinitializer */
+#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x)
+
+
+/** Configures the encoder's intended application.
+ * The initial value is a mandatory argument to the encoder_create function.
+ * @see OPUS_GET_APPLICATION
+ * @param[in] x opus_int32: Returns one of the following values:
+ *
+ * - #OPUS_APPLICATION_VOIP
+ * - Process signal for improved speech intelligibility.
+ * - #OPUS_APPLICATION_AUDIO
+ * - Favor faithfulness to the original input.
+ * - #OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ * - Configure the minimum possible coding delay by disabling certain modes
+ * of operation.
+ *
+ * @hideinitializer */
+#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured application.
+ * @see OPUS_SET_APPLICATION
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - #OPUS_APPLICATION_VOIP
+ * - Process signal for improved speech intelligibility.
+ * - #OPUS_APPLICATION_AUDIO
+ * - Favor faithfulness to the original input.
+ * - #OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ * - Configure the minimum possible coding delay by disabling certain modes
+ * of operation.
+ *
+ * @hideinitializer */
+#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the total samples of delay added by the entire codec.
+ * This can be queried by the encoder and then the provided number of samples can be
+ * skipped on from the start of the decoder's output to provide time aligned input
+ * and output. From the perspective of a decoding application the real data begins this many
+ * samples late.
+ *
+ * The decoder contribution to this delay is identical for all decoders, but the
+ * encoder portion of the delay may vary from implementation to implementation,
+ * version to version, or even depend on the encoder's initial configuration.
+ * Applications needing delay compensation should call this CTL rather than
+ * hard-coding a value.
+ * @param[out] x opus_int32 *: Number of lookahead samples
+ * @hideinitializer */
+#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of inband forward error correction (FEC).
+ * @note This is only applicable to the LPC layer
+ * @see OPUS_GET_INBAND_FEC
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - 0
- Disable inband FEC (default).
+ * - 1
- Enable inband FEC.
+ *
+ * @hideinitializer */
+#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
+/** Gets encoder's configured use of inband forward error correction.
+ * @see OPUS_SET_INBAND_FEC
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - 0
- Inband FEC disabled (default).
+ * - 1
- Inband FEC enabled.
+ *
+ * @hideinitializer */
+#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's expected packet loss percentage.
+ * Higher values trigger progressively more loss resistant behavior in the encoder
+ * at the expense of quality at a given bitrate in the absence of packet loss, but
+ * greater quality under loss.
+ * @see OPUS_GET_PACKET_LOSS_PERC
+ * @param[in] x opus_int32: Loss percentage in the range 0-100, inclusive (default: 0).
+ * @hideinitializer */
+#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured packet loss percentage.
+ * @see OPUS_SET_PACKET_LOSS_PERC
+ * @param[out] x opus_int32 *: Returns the configured loss percentage
+ * in the range 0-100, inclusive (default: 0).
+ * @hideinitializer */
+#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of discontinuous transmission (DTX).
+ * @note This is only applicable to the LPC layer
+ * @see OPUS_GET_DTX
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - 0
- Disable DTX (default).
+ * - 1
- Enabled DTX.
+ *
+ * @hideinitializer */
+#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x)
+/** Gets encoder's configured use of discontinuous transmission.
+ * @see OPUS_SET_DTX
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - 0
- DTX disabled (default).
+ * - 1
- DTX enabled.
+ *
+ * @hideinitializer */
+#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x)
+/** Configures the depth of signal being encoded.
+ *
+ * This is a hint which helps the encoder identify silence and near-silence.
+ * It represents the number of significant bits of linear intensity below
+ * which the signal contains ignorable quantization or other noise.
+ *
+ * For example, OPUS_SET_LSB_DEPTH(14) would be an appropriate setting
+ * for G.711 u-law input. OPUS_SET_LSB_DEPTH(16) would be appropriate
+ * for 16-bit linear pcm input with opus_encode_float().
+ *
+ * When using opus_encode() instead of opus_encode_float(), or when libopus
+ * is compiled for fixed-point, the encoder uses the minimum of the value
+ * set here and the value 16.
+ *
+ * @see OPUS_GET_LSB_DEPTH
+ * @param[in] x opus_int32: Input precision in bits, between 8 and 24
+ * (default: 24).
+ * @hideinitializer */
+#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured signal depth.
+ * @see OPUS_SET_LSB_DEPTH
+ * @param[out] x opus_int32 *: Input precision in bits, between 8 and
+ * 24 (default: 24).
+ * @hideinitializer */
+#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of variable duration frames.
+ * When variable duration is enabled, the encoder is free to use a shorter frame
+ * size than the one requested in the opus_encode*() call.
+ * It is then the user's responsibility
+ * to verify how much audio was encoded by checking the ToC byte of the encoded
+ * packet. The part of the audio that was not encoded needs to be resent to the
+ * encoder for the next call. Do not use this option unless you really
+ * know what you are doing.
+ * @see OPUS_GET_EXPERT_FRAME_DURATION
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - OPUS_FRAMESIZE_ARG
- Select frame size from the argument (default).
+ * - OPUS_FRAMESIZE_2_5_MS
- Use 2.5 ms frames.
+ * - OPUS_FRAMESIZE_5_MS
- Use 5 ms frames.
+ * - OPUS_FRAMESIZE_10_MS
- Use 10 ms frames.
+ * - OPUS_FRAMESIZE_20_MS
- Use 20 ms frames.
+ * - OPUS_FRAMESIZE_40_MS
- Use 40 ms frames.
+ * - OPUS_FRAMESIZE_60_MS
- Use 60 ms frames.
+ * - OPUS_FRAMESIZE_VARIABLE
- Optimize the frame size dynamically.
+ *
+ * @hideinitializer */
+#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured use of variable duration frames.
+ * @see OPUS_SET_EXPERT_FRAME_DURATION
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - OPUS_FRAMESIZE_ARG
- Select frame size from the argument (default).
+ * - OPUS_FRAMESIZE_2_5_MS
- Use 2.5 ms frames.
+ * - OPUS_FRAMESIZE_5_MS
- Use 5 ms frames.
+ * - OPUS_FRAMESIZE_10_MS
- Use 10 ms frames.
+ * - OPUS_FRAMESIZE_20_MS
- Use 20 ms frames.
+ * - OPUS_FRAMESIZE_40_MS
- Use 40 ms frames.
+ * - OPUS_FRAMESIZE_60_MS
- Use 60 ms frames.
+ * - OPUS_FRAMESIZE_VARIABLE
- Optimize the frame size dynamically.
+ *
+ * @hideinitializer */
+#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x)
+
+/** If set to 1, disables almost all use of prediction, making frames almost
+ * completely independent. This reduces quality.
+ * @see OPUS_GET_PREDICTION_DISABLED
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - 0
- Enable prediction (default).
+ * - 1
- Disable prediction.
+ *
+ * @hideinitializer */
+#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured prediction status.
+ * @see OPUS_SET_PREDICTION_DISABLED
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - 0
- Prediction enabled (default).
+ * - 1
- Prediction disabled.
+ *
+ * @hideinitializer */
+#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_genericctls Generic CTLs
+ *
+ * These macros are used with the \c opus_decoder_ctl and
+ * \c opus_encoder_ctl calls to generate a particular
+ * request.
+ *
+ * When called on an \c OpusDecoder they apply to that
+ * particular decoder instance. When called on an
+ * \c OpusEncoder they apply to the corresponding setting
+ * on that encoder instance, if present.
+ *
+ * Some usage examples:
+ *
+ * @code
+ * int ret;
+ * opus_int32 pitch;
+ * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch));
+ * if (ret == OPUS_OK) return ret;
+ *
+ * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);
+ * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE);
+ *
+ * opus_int32 enc_bw, dec_bw;
+ * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw));
+ * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw));
+ * if (enc_bw != dec_bw) {
+ * printf("packet bandwidth mismatch!\n");
+ * }
+ * @endcode
+ *
+ * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls
+ * @{
+ */
+
+/** Resets the codec state to be equivalent to a freshly initialized state.
+ * This should be called when switching streams in order to prevent
+ * the back to back decoding from giving different results from
+ * one at a time decoding.
+ * @hideinitializer */
+#define OPUS_RESET_STATE 4028
+
+/** Gets the final state of the codec's entropy coder.
+ * This is used for testing purposes,
+ * The encoder and decoder state should be identical after coding a payload
+ * (assuming no data corruption or software bugs)
+ *
+ * @param[out] x opus_uint32 *: Entropy coder state
+ *
+ * @hideinitializer */
+#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x)
+
+/** Gets the encoder's configured bandpass or the decoder's last bandpass.
+ * @see OPUS_SET_BANDWIDTH
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - #OPUS_AUTO
- (default)
+ * - #OPUS_BANDWIDTH_NARROWBAND
- 4 kHz passband
+ * - #OPUS_BANDWIDTH_MEDIUMBAND
- 6 kHz passband
+ * - #OPUS_BANDWIDTH_WIDEBAND
- 8 kHz passband
+ * - #OPUS_BANDWIDTH_SUPERWIDEBAND
- 12 kHz passband
+ * - #OPUS_BANDWIDTH_FULLBAND
- 20 kHz passband
+ *
+ * @hideinitializer */
+#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the sampling rate the encoder or decoder was initialized with.
+ * This simply returns the Fs value passed to opus_encoder_init()
+ * or opus_decoder_init().
+ * @param[out] x opus_int32 *: Sampling rate of encoder or decoder.
+ * @hideinitializer
+ */
+#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_decoderctls Decoder related CTLs
+ * @see opus_genericctls, opus_encoderctls, opus_decoder
+ * @{
+ */
+
+/** Configures decoder gain adjustment.
+ * Scales the decoded output by a factor specified in Q8 dB units.
+ * This has a maximum range of -32768 to 32767 inclusive, and returns
+ * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment.
+ * This setting survives decoder reset.
+ *
+ * gain = pow(10, x/(20.0*256))
+ *
+ * @param[in] x opus_int32: Amount to scale PCM signal by in Q8 dB units.
+ * @hideinitializer */
+#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x)
+/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN
+ *
+ * @param[out] x opus_int32 *: Amount to scale PCM signal by in Q8 dB units.
+ * @hideinitializer */
+#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the duration (in samples) of the last packet successfully decoded or concealed.
+ * @param[out] x opus_int32 *: Number of samples (at current sampling rate).
+ * @hideinitializer */
+#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the pitch of the last decoded frame, if available.
+ * This can be used for any post-processing algorithm requiring the use of pitch,
+ * e.g. time stretching/shortening. If the last frame was not voiced, or if the
+ * pitch was not coded in the frame, then zero is returned.
+ *
+ * This CTL is only implemented for decoder instances.
+ *
+ * @param[out] x opus_int32 *: pitch period at 48 kHz (or 0 if not available)
+ *
+ * @hideinitializer */
+#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_libinfo Opus library information functions
+ * @{
+ */
+
+/** Converts an opus error code into a human readable string.
+ *
+ * @param[in] error int: Error number
+ * @returns Error string
+ */
+OPUS_EXPORT const char *opus_strerror(int error);
+
+/** Gets the libopus version string.
+ *
+ * Applications may look for the substring "-fixed" in the version string to
+ * determine whether they have a fixed-point or floating-point build at
+ * runtime.
+ *
+ * @returns Version string
+ */
+OPUS_EXPORT const char *opus_get_version_string(void);
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_DEFINES_H */
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus_multistream.h b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus_multistream.h
new file mode 100644
index 000000000..3622e009f
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus_multistream.h
@@ -0,0 +1,660 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus_multistream.h
+ * @brief Opus reference implementation multistream API
+ */
+
+#ifndef OPUS_MULTISTREAM_H
+#define OPUS_MULTISTREAM_H
+
+#include "opus.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @cond OPUS_INTERNAL_DOC */
+
+/** Macros to trigger compilation errors when the wrong types are provided to a
+ * CTL. */
+/**@{*/
+#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr)))
+#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr)))
+/**@}*/
+
+/** These are the actual encoder and decoder CTL ID numbers.
+ * They should not be used directly by applications.
+ * In general, SETs should be even and GETs should be odd.*/
+/**@{*/
+#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120
+#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122
+/**@}*/
+
+/** @endcond */
+
+/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs
+ *
+ * These are convenience macros that are specific to the
+ * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl()
+ * interface.
+ * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and
+ * @ref opus_decoderctls may be applied to a multistream encoder or decoder as
+ * well.
+ * In addition, you may retrieve the encoder or decoder state for an specific
+ * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or
+ * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually.
+ */
+/**@{*/
+
+/** Gets the encoder state for an individual stream of a multistream encoder.
+ * @param[in] x opus_int32: The index of the stream whose encoder you
+ * wish to retrieve.
+ * This must be non-negative and less than
+ * the streams parameter used
+ * to initialize the encoder.
+ * @param[out] y OpusEncoder**: Returns a pointer to the given
+ * encoder state.
+ * @retval OPUS_BAD_ARG The index of the requested stream was out of range.
+ * @hideinitializer
+ */
+#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y)
+
+/** Gets the decoder state for an individual stream of a multistream decoder.
+ * @param[in] x opus_int32: The index of the stream whose decoder you
+ * wish to retrieve.
+ * This must be non-negative and less than
+ * the streams parameter used
+ * to initialize the decoder.
+ * @param[out] y OpusDecoder**: Returns a pointer to the given
+ * decoder state.
+ * @retval OPUS_BAD_ARG The index of the requested stream was out of range.
+ * @hideinitializer
+ */
+#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y)
+
+/**@}*/
+
+/** @defgroup opus_multistream Opus Multistream API
+ * @{
+ *
+ * The multistream API allows individual Opus streams to be combined into a
+ * single packet, enabling support for up to 255 channels. Unlike an
+ * elementary Opus stream, the encoder and decoder must negotiate the channel
+ * configuration before the decoder can successfully interpret the data in the
+ * packets produced by the encoder. Some basic information, such as packet
+ * duration, can be computed without any special negotiation.
+ *
+ * The format for multistream Opus packets is defined in
+ * RFC 7845
+ * and is based on the self-delimited Opus framing described in Appendix B of
+ * RFC 6716.
+ * Normal Opus packets are just a degenerate case of multistream Opus packets,
+ * and can be encoded or decoded with the multistream API by setting
+ * streams to 1 when initializing the encoder or
+ * decoder.
+ *
+ * Multistream Opus streams can contain up to 255 elementary Opus streams.
+ * These may be either "uncoupled" or "coupled", indicating that the decoder
+ * is configured to decode them to either 1 or 2 channels, respectively.
+ * The streams are ordered so that all coupled streams appear at the
+ * beginning.
+ *
+ * A mapping table defines which decoded channel i
+ * should be used for each input/output (I/O) channel j. This table is
+ * typically provided as an unsigned char array.
+ * Let i = mapping[j] be the index for I/O channel j.
+ * If i < 2*coupled_streams, then I/O channel j is
+ * encoded as the left channel of stream (i/2) if i
+ * is even, or as the right channel of stream (i/2) if
+ * i is odd. Otherwise, I/O channel j is encoded as
+ * mono in stream (i - coupled_streams), unless it has the special
+ * value 255, in which case it is omitted from the encoding entirely (the
+ * decoder will reproduce it as silence). Each value i must either
+ * be the special value 255 or be less than streams + coupled_streams.
+ *
+ * The output channels specified by the encoder
+ * should use the
+ * Vorbis
+ * channel ordering. A decoder may wish to apply an additional permutation
+ * to the mapping the encoder used to achieve a different output channel
+ * order (e.g. for outputing in WAV order).
+ *
+ * Each multistream packet contains an Opus packet for each stream, and all of
+ * the Opus packets in a single multistream packet must have the same
+ * duration. Therefore the duration of a multistream packet can be extracted
+ * from the TOC sequence of the first stream, which is located at the
+ * beginning of the packet, just like an elementary Opus stream:
+ *
+ * @code
+ * int nb_samples;
+ * int nb_frames;
+ * nb_frames = opus_packet_get_nb_frames(data, len);
+ * if (nb_frames < 1)
+ * return nb_frames;
+ * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames;
+ * @endcode
+ *
+ * The general encoding and decoding process proceeds exactly the same as in
+ * the normal @ref opus_encoder and @ref opus_decoder APIs.
+ * See their documentation for an overview of how to use the corresponding
+ * multistream functions.
+ */
+
+/** Opus multistream encoder state.
+ * This contains the complete state of a multistream Opus encoder.
+ * It is position independent and can be freely copied.
+ * @see opus_multistream_encoder_create
+ * @see opus_multistream_encoder_init
+ */
+typedef struct OpusMSEncoder OpusMSEncoder;
+
+/** Opus multistream decoder state.
+ * This contains the complete state of a multistream Opus decoder.
+ * It is position independent and can be freely copied.
+ * @see opus_multistream_decoder_create
+ * @see opus_multistream_decoder_init
+ */
+typedef struct OpusMSDecoder OpusMSDecoder;
+
+/**\name Multistream encoder functions */
+/**@{*/
+
+/** Gets the size of an OpusMSEncoder structure.
+ * @param streams int: The total number of streams to encode from the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams int: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (streams +
+ * coupled_streams) must be no
+ * more than 255.
+ * @returns The size in bytes on success, or a negative error code
+ * (see @ref opus_errorcodes) on error.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size(
+ int streams,
+ int coupled_streams
+);
+
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_surround_encoder_get_size(
+ int channels,
+ int mapping_family
+);
+
+
+/** Allocates and initializes a multistream encoder state.
+ * Call opus_multistream_encoder_destroy() to release
+ * this object when finished.
+ * @param Fs opus_int32: Sampling rate of the input signal (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels int: Number of channels in the input signal.
+ * This must be at most 255.
+ * It may be greater than the number of
+ * coded channels (streams +
+ * coupled_streams).
+ * @param streams int: The total number of streams to encode from the
+ * input.
+ * This must be no more than the number of channels.
+ * @param coupled_streams int: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (streams +
+ * coupled_streams) must be no
+ * more than the number of input channels.
+ * @param[in] mapping const unsigned char[channels]: Mapping from
+ * encoded channels to input channels, as described in
+ * @ref opus_multistream. As an extra constraint, the
+ * multistream encoder does not allow encoding coupled
+ * streams for which one channel is unused since this
+ * is never a good idea.
+ * @param application int: The target encoder application.
+ * This must be one of the following:
+ *
+ * - #OPUS_APPLICATION_VOIP
+ * - Process signal for improved speech intelligibility.
+ * - #OPUS_APPLICATION_AUDIO
+ * - Favor faithfulness to the original input.
+ * - #OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ * - Configure the minimum possible coding delay by disabling certain modes
+ * of operation.
+ *
+ * @param[out] error int *: Returns #OPUS_OK on success, or an error
+ * code (see @ref opus_errorcodes) on
+ * failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+/** Initialize a previously allocated multistream encoder state.
+ * The memory pointed to by \a st must be at least the size returned by
+ * opus_multistream_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of
+ * malloc.
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @see opus_multistream_encoder_create
+ * @see opus_multistream_encoder_get_size
+ * @param st OpusMSEncoder*: Multistream encoder state to initialize.
+ * @param Fs opus_int32: Sampling rate of the input signal (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels int: Number of channels in the input signal.
+ * This must be at most 255.
+ * It may be greater than the number of
+ * coded channels (streams +
+ * coupled_streams).
+ * @param streams int: The total number of streams to encode from the
+ * input.
+ * This must be no more than the number of channels.
+ * @param coupled_streams int: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (streams +
+ * coupled_streams) must be no
+ * more than the number of input channels.
+ * @param[in] mapping const unsigned char[channels]: Mapping from
+ * encoded channels to input channels, as described in
+ * @ref opus_multistream. As an extra constraint, the
+ * multistream encoder does not allow encoding coupled
+ * streams for which one channel is unused since this
+ * is never a good idea.
+ * @param application int: The target encoder application.
+ * This must be one of the following:
+ *
+ * - #OPUS_APPLICATION_VOIP
+ * - Process signal for improved speech intelligibility.
+ * - #OPUS_APPLICATION_AUDIO
+ * - Favor faithfulness to the original input.
+ * - #OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ * - Configure the minimum possible coding delay by disabling certain modes
+ * of operation.
+ *
+ * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
+ * on failure.
+ */
+OPUS_EXPORT int opus_multistream_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+OPUS_EXPORT int opus_multistream_surround_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+/** Encodes a multistream Opus frame.
+ * @param st OpusMSEncoder*: Multistream encoder state.
+ * @param[in] pcm const opus_int16*: The input signal as interleaved
+ * samples.
+ * This must contain
+ * frame_size*channels
+ * samples.
+ * @param frame_size int: Number of samples per channel in the input
+ * signal.
+ * This must be an Opus frame size for the
+ * encoder's sampling rate.
+ * For example, at 48 kHz the permitted values
+ * are 120, 240, 480, 960, 1920, and 2880.
+ * Passing in a duration of less than 10 ms
+ * (480 samples at 48 kHz) will prevent the
+ * encoder from using the LPC or hybrid modes.
+ * @param[out] data unsigned char*: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes opus_int32: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode(
+ OpusMSEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes a multistream Opus frame from floating point input.
+ * @param st OpusMSEncoder*: Multistream encoder state.
+ * @param[in] pcm const float*: The input signal as interleaved
+ * samples with a normal range of
+ * +/-1.0.
+ * Samples with a range beyond +/-1.0
+ * are supported but will be clipped by
+ * decoders using the integer API and
+ * should only be used if it is known
+ * that the far end supports extended
+ * dynamic range.
+ * This must contain
+ * frame_size*channels
+ * samples.
+ * @param frame_size int: Number of samples per channel in the input
+ * signal.
+ * This must be an Opus frame size for the
+ * encoder's sampling rate.
+ * For example, at 48 kHz the permitted values
+ * are 120, 240, 480, 960, 1920, and 2880.
+ * Passing in a duration of less than 10 ms
+ * (480 samples at 48 kHz) will prevent the
+ * encoder from using the LPC or hybrid modes.
+ * @param[out] data unsigned char*: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes opus_int32: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float(
+ OpusMSEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Frees an OpusMSEncoder allocated by
+ * opus_multistream_encoder_create().
+ * @param st OpusMSEncoder*: Multistream encoder state to be freed.
+ */
+OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st);
+
+/** Perform a CTL function on a multistream Opus encoder.
+ *
+ * Generally the request and subsequent arguments are generated by a
+ * convenience macro.
+ * @param st OpusMSEncoder*: Multistream encoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls,
+ * @ref opus_encoderctls, or @ref opus_multistream_ctls.
+ * @see opus_genericctls
+ * @see opus_encoderctls
+ * @see opus_multistream_ctls
+ */
+OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/**@}*/
+
+/**\name Multistream decoder functions */
+/**@{*/
+
+/** Gets the size of an OpusMSDecoder structure.
+ * @param streams int: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams int: Number streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (streams +
+ * coupled_streams) must be no
+ * more than 255.
+ * @returns The size in bytes on success, or a negative error code
+ * (see @ref opus_errorcodes) on error.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size(
+ int streams,
+ int coupled_streams
+);
+
+/** Allocates and initializes a multistream decoder state.
+ * Call opus_multistream_decoder_destroy() to release
+ * this object when finished.
+ * @param Fs opus_int32: Sampling rate to decode at (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels int: Number of channels to output.
+ * This must be at most 255.
+ * It may be different from the number of coded
+ * channels (streams +
+ * coupled_streams).
+ * @param streams int: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams int: Number of streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (streams +
+ * coupled_streams) must be no
+ * more than 255.
+ * @param[in] mapping const unsigned char[channels]: Mapping from
+ * coded channels to output channels, as described in
+ * @ref opus_multistream.
+ * @param[out] error int *: Returns #OPUS_OK on success, or an error
+ * code (see @ref opus_errorcodes) on
+ * failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+/** Intialize a previously allocated decoder state object.
+ * The memory pointed to by \a st must be at least the size returned by
+ * opus_multistream_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of
+ * malloc.
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @see opus_multistream_decoder_create
+ * @see opus_multistream_deocder_get_size
+ * @param st OpusMSEncoder*: Multistream encoder state to initialize.
+ * @param Fs opus_int32: Sampling rate to decode at (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels int: Number of channels to output.
+ * This must be at most 255.
+ * It may be different from the number of coded
+ * channels (streams +
+ * coupled_streams).
+ * @param streams int: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams int: Number of streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (streams +
+ * coupled_streams) must be no
+ * more than 255.
+ * @param[in] mapping const unsigned char[channels]: Mapping from
+ * coded channels to output channels, as described in
+ * @ref opus_multistream.
+ * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
+ * on failure.
+ */
+OPUS_EXPORT int opus_multistream_decoder_init(
+ OpusMSDecoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+/** Decode a multistream Opus packet.
+ * @param st OpusMSDecoder*: Multistream decoder state.
+ * @param[in] data const unsigned char*: Input payload.
+ * Use a NULL
+ * pointer to indicate packet
+ * loss.
+ * @param len opus_int32: Number of bytes in payload.
+ * @param[out] pcm opus_int16*: Output signal, with interleaved
+ * samples.
+ * This must contain room for
+ * frame_size*channels
+ * samples.
+ * @param frame_size int: The number of samples per channel of
+ * available space in \a pcm.
+ * If this is less than the maximum packet duration
+ * (120 ms; 5760 for 48kHz), this function will not be capable
+ * of decoding some packets. In the case of PLC (data==NULL)
+ * or FEC (decode_fec=1), then frame_size needs to be exactly
+ * the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the
+ * next incoming packet. For the PLC and FEC cases, frame_size
+ * must be a multiple of 2.5 ms.
+ * @param decode_fec int: Flag (0 or 1) to request that any in-band
+ * forward error correction data be decoded.
+ * If no such data is available, the frame is
+ * decoded as if it were lost.
+ * @returns Number of samples decoded on success or a negative error code
+ * (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ opus_int16 *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode a multistream Opus packet with floating point output.
+ * @param st OpusMSDecoder*: Multistream decoder state.
+ * @param[in] data const unsigned char*: Input payload.
+ * Use a NULL
+ * pointer to indicate packet
+ * loss.
+ * @param len opus_int32: Number of bytes in payload.
+ * @param[out] pcm opus_int16*: Output signal, with interleaved
+ * samples.
+ * This must contain room for
+ * frame_size*channels
+ * samples.
+ * @param frame_size int: The number of samples per channel of
+ * available space in \a pcm.
+ * If this is less than the maximum packet duration
+ * (120 ms; 5760 for 48kHz), this function will not be capable
+ * of decoding some packets. In the case of PLC (data==NULL)
+ * or FEC (decode_fec=1), then frame_size needs to be exactly
+ * the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the
+ * next incoming packet. For the PLC and FEC cases, frame_size
+ * must be a multiple of 2.5 ms.
+ * @param decode_fec int: Flag (0 or 1) to request that any in-band
+ * forward error correction data be decoded.
+ * If no such data is available, the frame is
+ * decoded as if it were lost.
+ * @returns Number of samples decoded on success or a negative error code
+ * (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ float *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on a multistream Opus decoder.
+ *
+ * Generally the request and subsequent arguments are generated by a
+ * convenience macro.
+ * @param st OpusMSDecoder*: Multistream decoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls,
+ * @ref opus_decoderctls, or @ref opus_multistream_ctls.
+ * @see opus_genericctls
+ * @see opus_decoderctls
+ * @see opus_multistream_ctls
+ */
+OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/** Frees an OpusMSDecoder allocated by
+ * opus_multistream_decoder_create().
+ * @param st OpusMSDecoder: Multistream decoder state to be freed.
+ */
+OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st);
+
+/**@}*/
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_MULTISTREAM_H */
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus_types.h b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus_types.h
new file mode 100644
index 000000000..b28e03aea
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Headers/opus_types.h
@@ -0,0 +1,159 @@
+/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */
+/* Modified by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/* opus_types.h based on ogg_types.h from libogg */
+
+/**
+ @file opus_types.h
+ @brief Opus reference implementation types
+*/
+#ifndef OPUS_TYPES_H
+#define OPUS_TYPES_H
+
+/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */
+#if (defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H))
+#include
+
+ typedef int16_t opus_int16;
+ typedef uint16_t opus_uint16;
+ typedef int32_t opus_int32;
+ typedef uint32_t opus_uint32;
+#elif defined(_WIN32)
+
+# if defined(__CYGWIN__)
+# include <_G_config.h>
+ typedef _G_int32_t opus_int32;
+ typedef _G_uint32_t opus_uint32;
+ typedef _G_int16 opus_int16;
+ typedef _G_uint16 opus_uint16;
+# elif defined(__MINGW32__)
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+# elif defined(__MWERKS__)
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+# else
+ /* MSVC/Borland */
+ typedef __int32 opus_int32;
+ typedef unsigned __int32 opus_uint32;
+ typedef __int16 opus_int16;
+ typedef unsigned __int16 opus_uint16;
+# endif
+
+#elif defined(__MACOS__)
+
+# include
+ typedef SInt16 opus_int16;
+ typedef UInt16 opus_uint16;
+ typedef SInt32 opus_int32;
+ typedef UInt32 opus_uint32;
+
+#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
+
+# include
+ typedef int16_t opus_int16;
+ typedef u_int16_t opus_uint16;
+ typedef int32_t opus_int32;
+ typedef u_int32_t opus_uint32;
+
+#elif defined(__BEOS__)
+
+ /* Be */
+# include
+ typedef int16 opus_int16;
+ typedef u_int16 opus_uint16;
+ typedef int32_t opus_int32;
+ typedef u_int32_t opus_uint32;
+
+#elif defined (__EMX__)
+
+ /* OS/2 GCC */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined (DJGPP)
+
+ /* DJGPP */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined(R5900)
+
+ /* PS2 EE */
+ typedef int opus_int32;
+ typedef unsigned opus_uint32;
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+
+#elif defined(__SYMBIAN32__)
+
+ /* Symbian GCC */
+ typedef signed short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef signed int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
+
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef long opus_int32;
+ typedef unsigned long opus_uint32;
+
+#elif defined(CONFIG_TI_C6X)
+
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#else
+
+ /* Give up, take a reasonable guess */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#endif
+
+#define opus_int int /* used for counters etc; at least 16 bits */
+#define opus_int64 long long
+#define opus_int8 signed char
+
+#define opus_uint unsigned int /* used for counters etc; at least 16 bits */
+#define opus_uint64 unsigned long long
+#define opus_uint8 unsigned char
+
+#endif /* OPUS_TYPES_H */
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Info.plist b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Info.plist
new file mode 100644
index 000000000..99c5c68af
Binary files /dev/null and b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Info.plist differ
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Modules/module.modulemap b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Modules/module.modulemap
new file mode 100644
index 000000000..bb7631ab4
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/Modules/module.modulemap
@@ -0,0 +1,6 @@
+framework module opus {
+ umbrella header "opus.h"
+
+ export *
+ module * { export * }
+}
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/opus b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/opus
new file mode 100755
index 000000000..e645bd726
Binary files /dev/null and b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-arm64/opus.framework/opus differ
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus.h b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus.h
new file mode 100644
index 000000000..5be73ddf4
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus.h
@@ -0,0 +1,981 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus.h
+ * @brief Opus reference implementation API
+ */
+
+#ifndef OPUS_H
+#define OPUS_H
+
+#include "opus_types.h"
+#include "opus_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @mainpage Opus
+ *
+ * The Opus codec is designed for interactive speech and audio transmission over the Internet.
+ * It is designed by the IETF Codec Working Group and incorporates technology from
+ * Skype's SILK codec and Xiph.Org's CELT codec.
+ *
+ * The Opus codec is designed to handle a wide range of interactive audio applications,
+ * including Voice over IP, videoconferencing, in-game chat, and even remote live music
+ * performances. It can scale from low bit-rate narrowband speech to very high quality
+ * stereo music. Its main features are:
+
+ * @li Sampling rates from 8 to 48 kHz
+ * @li Bit-rates from 6 kb/s to 510 kb/s
+ * @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR)
+ * @li Audio bandwidth from narrowband to full-band
+ * @li Support for speech and music
+ * @li Support for mono and stereo
+ * @li Support for multichannel (up to 255 channels)
+ * @li Frame sizes from 2.5 ms to 60 ms
+ * @li Good loss robustness and packet loss concealment (PLC)
+ * @li Floating point and fixed-point implementation
+ *
+ * Documentation sections:
+ * @li @ref opus_encoder
+ * @li @ref opus_decoder
+ * @li @ref opus_repacketizer
+ * @li @ref opus_multistream
+ * @li @ref opus_libinfo
+ * @li @ref opus_custom
+ */
+
+/** @defgroup opus_encoder Opus Encoder
+ * @{
+ *
+ * @brief This page describes the process and functions used to encode Opus.
+ *
+ * Since Opus is a stateful codec, the encoding process starts with creating an encoder
+ * state. This can be done with:
+ *
+ * @code
+ * int error;
+ * OpusEncoder *enc;
+ * enc = opus_encoder_create(Fs, channels, application, &error);
+ * @endcode
+ *
+ * From this point, @c enc can be used for encoding an audio stream. An encoder state
+ * @b must @b not be used for more than one stream at the same time. Similarly, the encoder
+ * state @b must @b not be re-initialized for each frame.
+ *
+ * While opus_encoder_create() allocates memory for the state, it's also possible
+ * to initialize pre-allocated memory:
+ *
+ * @code
+ * int size;
+ * int error;
+ * OpusEncoder *enc;
+ * size = opus_encoder_get_size(channels);
+ * enc = malloc(size);
+ * error = opus_encoder_init(enc, Fs, channels, application);
+ * @endcode
+ *
+ * where opus_encoder_get_size() returns the required size for the encoder state. Note that
+ * future versions of this code may change the size, so no assuptions should be made about it.
+ *
+ * The encoder state is always continuous in memory and only a shallow copy is sufficient
+ * to copy it (e.g. memcpy())
+ *
+ * It is possible to change some of the encoder's settings using the opus_encoder_ctl()
+ * interface. All these settings already default to the recommended value, so they should
+ * only be changed when necessary. The most common settings one may want to change are:
+ *
+ * @code
+ * opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));
+ * opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
+ * opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type));
+ * @endcode
+ *
+ * where
+ *
+ * @arg bitrate is in bits per second (b/s)
+ * @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest
+ * @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC
+ *
+ * See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream.
+ *
+ * To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data:
+ * @code
+ * len = opus_encode(enc, audio_frame, frame_size, packet, max_packet);
+ * @endcode
+ *
+ * where
+ *
+ * - audio_frame is the audio data in opus_int16 (or float for opus_encode_float())
+ * - frame_size is the duration of the frame in samples (per channel)
+ * - packet is the byte array to which the compressed data is written
+ * - max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended).
+ * Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.
+ *
+ *
+ * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet.
+ * The return value can be negative, which indicates that an error has occurred. If the return value
+ * is 2 bytes or less, then the packet does not need to be transmitted (DTX).
+ *
+ * Once the encoder state if no longer needed, it can be destroyed with
+ *
+ * @code
+ * opus_encoder_destroy(enc);
+ * @endcode
+ *
+ * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(),
+ * then no action is required aside from potentially freeing the memory that was manually
+ * allocated for it (calling free(enc) for the example above)
+ *
+ */
+
+/** Opus encoder state.
+ * This contains the complete state of an Opus encoder.
+ * It is position independent and can be freely copied.
+ * @see opus_encoder_create,opus_encoder_init
+ */
+typedef struct OpusEncoder OpusEncoder;
+
+/** Gets the size of an OpusEncoder structure.
+ * @param[in] channels int: Number of channels.
+ * This must be 1 or 2.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);
+
+/**
+ */
+
+/** Allocates and initializes an encoder state.
+ * There are three coding modes:
+ *
+ * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice
+ * signals. It enhances the input signal by high-pass filtering and
+ * emphasizing formants and harmonics. Optionally it includes in-band
+ * forward error correction to protect against packet loss. Use this
+ * mode for typical VoIP applications. Because of the enhancement,
+ * even at high bitrates the output may sound different from the input.
+ *
+ * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most
+ * non-voice signals like music. Use this mode for music and mixed
+ * (music/voice) content, broadcast, and applications requiring less
+ * than 15 ms of coding delay.
+ *
+ * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that
+ * disables the speech-optimized mode in exchange for slightly reduced delay.
+ * This mode can only be set on an newly initialized or freshly reset encoder
+ * because it changes the codec delay.
+ *
+ * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution).
+ * @param [in] Fs opus_int32: Sampling rate of input signal (Hz)
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels int: Number of channels (1 or 2) in input signal
+ * @param [in] application int: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ * @param [out] error int*: @ref opus_errorcodes
+ * @note Regardless of the sampling rate and number channels selected, the Opus encoder
+ * can switch to a lower audio bandwidth or number of channels if the bitrate
+ * selected is too low. This also means that it is safe to always use 48 kHz stereo input
+ * and let the encoder optimize the encoding.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int application,
+ int *error
+);
+
+/** Initializes a previously allocated encoder state
+ * The memory pointed to by st must be at least the size returned by opus_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of malloc.
+ * @see opus_encoder_create(),opus_encoder_get_size()
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @param [in] st OpusEncoder*: Encoder state
+ * @param [in] Fs opus_int32: Sampling rate of input signal (Hz)
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels int: Number of channels (1 or 2) in input signal
+ * @param [in] application int: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ * @retval #OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_EXPORT int opus_encoder_init(
+ OpusEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int application
+) OPUS_ARG_NONNULL(1);
+
+/** Encodes an Opus frame.
+ * @param [in] st OpusEncoder*: Encoder state
+ * @param [in] pcm opus_int16*: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16)
+ * @param [in] frame_size int: Number of samples per channel in the
+ * input signal.
+ * This must be an Opus frame size for
+ * the encoder's sampling rate.
+ * For example, at 48 kHz the permitted
+ * values are 120, 240, 480, 960, 1920,
+ * and 2880.
+ * Passing in a duration of less than
+ * 10 ms (480 samples at 48 kHz) will
+ * prevent the encoder from using the LPC
+ * or hybrid modes.
+ * @param [out] data unsigned char*: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes opus_int32: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode(
+ OpusEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes an Opus frame from floating point input.
+ * @param [in] st OpusEncoder*: Encoder state
+ * @param [in] pcm float*: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0.
+ * Samples with a range beyond +/-1.0 are supported but will
+ * be clipped by decoders using the integer API and should
+ * only be used if it is known that the far end supports
+ * extended dynamic range.
+ * length is frame_size*channels*sizeof(float)
+ * @param [in] frame_size int: Number of samples per channel in the
+ * input signal.
+ * This must be an Opus frame size for
+ * the encoder's sampling rate.
+ * For example, at 48 kHz the permitted
+ * values are 120, 240, 480, 960, 1920,
+ * and 2880.
+ * Passing in a duration of less than
+ * 10 ms (480 samples at 48 kHz) will
+ * prevent the encoder from using the LPC
+ * or hybrid modes.
+ * @param [out] data unsigned char*: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes opus_int32: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float(
+ OpusEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Frees an OpusEncoder allocated by opus_encoder_create().
+ * @param[in] st OpusEncoder*: State to be freed.
+ */
+OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st);
+
+/** Perform a CTL function on an Opus encoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @param st OpusEncoder*: Encoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls or
+ * @ref opus_encoderctls.
+ * @see opus_genericctls
+ * @see opus_encoderctls
+ */
+OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+/**@}*/
+
+/** @defgroup opus_decoder Opus Decoder
+ * @{
+ *
+ * @brief This page describes the process and functions used to decode Opus.
+ *
+ * The decoding process also starts with creating a decoder
+ * state. This can be done with:
+ * @code
+ * int error;
+ * OpusDecoder *dec;
+ * dec = opus_decoder_create(Fs, channels, &error);
+ * @endcode
+ * where
+ * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000
+ * @li channels is the number of channels (1 or 2)
+ * @li error will hold the error code in case of failure (or #OPUS_OK on success)
+ * @li the return value is a newly created decoder state to be used for decoding
+ *
+ * While opus_decoder_create() allocates memory for the state, it's also possible
+ * to initialize pre-allocated memory:
+ * @code
+ * int size;
+ * int error;
+ * OpusDecoder *dec;
+ * size = opus_decoder_get_size(channels);
+ * dec = malloc(size);
+ * error = opus_decoder_init(dec, Fs, channels);
+ * @endcode
+ * where opus_decoder_get_size() returns the required size for the decoder state. Note that
+ * future versions of this code may change the size, so no assuptions should be made about it.
+ *
+ * The decoder state is always continuous in memory and only a shallow copy is sufficient
+ * to copy it (e.g. memcpy())
+ *
+ * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data:
+ * @code
+ * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0);
+ * @endcode
+ * where
+ *
+ * @li packet is the byte array containing the compressed data
+ * @li len is the exact number of bytes contained in the packet
+ * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float())
+ * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array
+ *
+ * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet.
+ * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio
+ * buffer is too small to hold the decoded audio.
+ *
+ * Opus is a stateful codec with overlapping blocks and as a result Opus
+ * packets are not coded independently of each other. Packets must be
+ * passed into the decoder serially and in the correct order for a correct
+ * decode. Lost packets can be replaced with loss concealment by calling
+ * the decoder with a null pointer and zero length for the missing packet.
+ *
+ * A single codec state may only be accessed from a single thread at
+ * a time and any required locking must be performed by the caller. Separate
+ * streams must be decoded with separate decoder states and can be decoded
+ * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK
+ * defined.
+ *
+ */
+
+/** Opus decoder state.
+ * This contains the complete state of an Opus decoder.
+ * It is position independent and can be freely copied.
+ * @see opus_decoder_create,opus_decoder_init
+ */
+typedef struct OpusDecoder OpusDecoder;
+
+/** Gets the size of an OpusDecoder structure.
+ * @param [in] channels int: Number of channels.
+ * This must be 1 or 2.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels);
+
+/** Allocates and initializes a decoder state.
+ * @param [in] Fs opus_int32: Sample rate to decode at (Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels int: Number of channels (1 or 2) to decode
+ * @param [out] error int*: #OPUS_OK Success or @ref opus_errorcodes
+ *
+ * Internally Opus stores data at 48000 Hz, so that should be the default
+ * value for Fs. However, the decoder can efficiently decode to buffers
+ * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use
+ * data at the full sample rate, or knows the compressed data doesn't
+ * use the full frequency range, it can request decoding at a reduced
+ * rate. Likewise, the decoder is capable of filling in either mono or
+ * interleaved stereo pcm buffers, at the caller's request.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create(
+ opus_int32 Fs,
+ int channels,
+ int *error
+);
+
+/** Initializes a previously allocated decoder state.
+ * The state must be at least the size returned by opus_decoder_get_size().
+ * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @param [in] st OpusDecoder*: Decoder state.
+ * @param [in] Fs opus_int32: Sampling rate to decode to (Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels int: Number of channels (1 or 2) to decode
+ * @retval #OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_EXPORT int opus_decoder_init(
+ OpusDecoder *st,
+ opus_int32 Fs,
+ int channels
+) OPUS_ARG_NONNULL(1);
+
+/** Decode an Opus packet.
+ * @param [in] st OpusDecoder*: Decoder state
+ * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len opus_int32: Number of bytes in payload*
+ * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(opus_int16)
+ * @param [in] frame_size Number of samples per channel of available space in \a pcm.
+ * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
+ * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+ * then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+ * FEC cases, frame_size must be a multiple of 2.5 ms.
+ * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be
+ * decoded. If no such data is available, the frame is decoded as if it were lost.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode(
+ OpusDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ opus_int16 *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode an Opus packet with floating point output.
+ * @param [in] st OpusDecoder*: Decoder state
+ * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len opus_int32: Number of bytes in payload
+ * @param [out] pcm float*: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(float)
+ * @param [in] frame_size Number of samples per channel of available space in \a pcm.
+ * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
+ * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+ * then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+ * FEC cases, frame_size must be a multiple of 2.5 ms.
+ * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be
+ * decoded. If no such data is available the frame is decoded as if it were lost.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float(
+ OpusDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ float *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on an Opus decoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @param st OpusDecoder*: Decoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls or
+ * @ref opus_decoderctls.
+ * @see opus_genericctls
+ * @see opus_decoderctls
+ */
+OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/** Frees an OpusDecoder allocated by opus_decoder_create().
+ * @param[in] st OpusDecoder*: State to be freed.
+ */
+OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
+
+/** Parse an opus packet into one or more frames.
+ * Opus_decode will perform this operation internally so most applications do
+ * not need to use this function.
+ * This function does not copy the frames, the returned pointers are pointers into
+ * the input packet.
+ * @param [in] data char*: Opus packet to be parsed
+ * @param [in] len opus_int32: size of data
+ * @param [out] out_toc char*: TOC pointer
+ * @param [out] frames char*[48] encapsulated frames
+ * @param [out] size opus_int16[48] sizes of the encapsulated frames
+ * @param [out] payload_offset int*: returns the position of the payload within the packet (in bytes)
+ * @returns number of frames
+ */
+OPUS_EXPORT int opus_packet_parse(
+ const unsigned char *data,
+ opus_int32 len,
+ unsigned char *out_toc,
+ const unsigned char *frames[48],
+ opus_int16 size[48],
+ int *payload_offset
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Gets the bandwidth of an Opus packet.
+ * @param [in] data char*: Opus packet
+ * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass)
+ * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass)
+ * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass)
+ * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass)
+ * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass)
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples per frame from an Opus packet.
+ * @param [in] data char*: Opus packet.
+ * This must contain at least one byte of
+ * data.
+ * @param [in] Fs opus_int32: Sampling rate in Hz.
+ * This must be a multiple of 400, or
+ * inaccurate results will be returned.
+ * @returns Number of samples per frame.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of channels from an Opus packet.
+ * @param [in] data char*: Opus packet
+ * @returns Number of channels
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of frames in an Opus packet.
+ * @param [in] packet char*: Opus packet
+ * @param [in] len opus_int32: Length of packet
+ * @returns Number of frames
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples of an Opus packet.
+ * @param [in] packet char*: Opus packet
+ * @param [in] len opus_int32: Length of packet
+ * @param [in] Fs opus_int32: Sampling rate in Hz.
+ * This must be a multiple of 400, or
+ * inaccurate results will be returned.
+ * @returns Number of samples
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples of an Opus packet.
+ * @param [in] dec OpusDecoder*: Decoder state
+ * @param [in] packet char*: Opus packet
+ * @param [in] len opus_int32: Length of packet
+ * @returns Number of samples
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+/** Applies soft-clipping to bring a float signal within the [-1,1] range. If
+ * the signal is already in that range, nothing is done. If there are values
+ * outside of [-1,1], then the signal is clipped as smoothly as possible to
+ * both fit in the range and avoid creating excessive distortion in the
+ * process.
+ * @param [in,out] pcm float*: Input PCM and modified PCM
+ * @param [in] frame_size int Number of samples per channel to process
+ * @param [in] channels int: Number of channels
+ * @param [in,out] softclip_mem float*: State memory for the soft clipping process (one float per channel, initialized to zero)
+ */
+OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem);
+
+
+/**@}*/
+
+/** @defgroup opus_repacketizer Repacketizer
+ * @{
+ *
+ * The repacketizer can be used to merge multiple Opus packets into a single
+ * packet or alternatively to split Opus packets that have previously been
+ * merged. Splitting valid Opus packets is always guaranteed to succeed,
+ * whereas merging valid packets only succeeds if all frames have the same
+ * mode, bandwidth, and frame size, and when the total duration of the merged
+ * packet is no more than 120 ms. The 120 ms limit comes from the
+ * specification and limits decoder memory requirements at a point where
+ * framing overhead becomes negligible.
+ *
+ * The repacketizer currently only operates on elementary Opus
+ * streams. It will not manipualte multistream packets successfully, except in
+ * the degenerate case where they consist of data from a single stream.
+ *
+ * The repacketizing process starts with creating a repacketizer state, either
+ * by calling opus_repacketizer_create() or by allocating the memory yourself,
+ * e.g.,
+ * @code
+ * OpusRepacketizer *rp;
+ * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size());
+ * if (rp != NULL)
+ * opus_repacketizer_init(rp);
+ * @endcode
+ *
+ * Then the application should submit packets with opus_repacketizer_cat(),
+ * extract new packets with opus_repacketizer_out() or
+ * opus_repacketizer_out_range(), and then reset the state for the next set of
+ * input packets via opus_repacketizer_init().
+ *
+ * For example, to split a sequence of packets into individual frames:
+ * @code
+ * unsigned char *data;
+ * int len;
+ * while (get_next_packet(&data, &len))
+ * {
+ * unsigned char out[1276];
+ * opus_int32 out_len;
+ * int nb_frames;
+ * int err;
+ * int i;
+ * err = opus_repacketizer_cat(rp, data, len);
+ * if (err != OPUS_OK)
+ * {
+ * release_packet(data);
+ * return err;
+ * }
+ * nb_frames = opus_repacketizer_get_nb_frames(rp);
+ * for (i = 0; i < nb_frames; i++)
+ * {
+ * out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out));
+ * if (out_len < 0)
+ * {
+ * release_packet(data);
+ * return (int)out_len;
+ * }
+ * output_next_packet(out, out_len);
+ * }
+ * opus_repacketizer_init(rp);
+ * release_packet(data);
+ * }
+ * @endcode
+ *
+ * Alternatively, to combine a sequence of frames into packets that each
+ * contain up to TARGET_DURATION_MS milliseconds of data:
+ * @code
+ * // The maximum number of packets with duration TARGET_DURATION_MS occurs
+ * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5)
+ * // packets.
+ * unsigned char *data[(TARGET_DURATION_MS*2/5)+1];
+ * opus_int32 len[(TARGET_DURATION_MS*2/5)+1];
+ * int nb_packets;
+ * unsigned char out[1277*(TARGET_DURATION_MS*2/2)];
+ * opus_int32 out_len;
+ * int prev_toc;
+ * nb_packets = 0;
+ * while (get_next_packet(data+nb_packets, len+nb_packets))
+ * {
+ * int nb_frames;
+ * int err;
+ * nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]);
+ * if (nb_frames < 1)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return nb_frames;
+ * }
+ * nb_frames += opus_repacketizer_get_nb_frames(rp);
+ * // If adding the next packet would exceed our target, or it has an
+ * // incompatible TOC sequence, output the packets we already have before
+ * // submitting it.
+ * // N.B., The nb_packets > 0 check ensures we've submitted at least one
+ * // packet since the last call to opus_repacketizer_init(). Otherwise a
+ * // single packet longer than TARGET_DURATION_MS would cause us to try to
+ * // output an (invalid) empty packet. It also ensures that prev_toc has
+ * // been set to a valid value. Additionally, len[nb_packets] > 0 is
+ * // guaranteed by the call to opus_packet_get_nb_frames() above, so the
+ * // reference to data[nb_packets][0] should be valid.
+ * if (nb_packets > 0 && (
+ * ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) ||
+ * opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames >
+ * TARGET_DURATION_MS*48))
+ * {
+ * out_len = opus_repacketizer_out(rp, out, sizeof(out));
+ * if (out_len < 0)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return (int)out_len;
+ * }
+ * output_next_packet(out, out_len);
+ * opus_repacketizer_init(rp);
+ * release_packets(data, nb_packets);
+ * data[0] = data[nb_packets];
+ * len[0] = len[nb_packets];
+ * nb_packets = 0;
+ * }
+ * err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]);
+ * if (err != OPUS_OK)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return err;
+ * }
+ * prev_toc = data[nb_packets][0];
+ * nb_packets++;
+ * }
+ * // Output the final, partial packet.
+ * if (nb_packets > 0)
+ * {
+ * out_len = opus_repacketizer_out(rp, out, sizeof(out));
+ * release_packets(data, nb_packets);
+ * if (out_len < 0)
+ * return (int)out_len;
+ * output_next_packet(out, out_len);
+ * }
+ * @endcode
+ *
+ * An alternate way of merging packets is to simply call opus_repacketizer_cat()
+ * unconditionally until it fails. At that point, the merged packet can be
+ * obtained with opus_repacketizer_out() and the input packet for which
+ * opus_repacketizer_cat() needs to be re-added to a newly reinitialized
+ * repacketizer state.
+ */
+
+typedef struct OpusRepacketizer OpusRepacketizer;
+
+/** Gets the size of an OpusRepacketizer structure.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void);
+
+/** (Re)initializes a previously allocated repacketizer state.
+ * The state must be at least the size returned by opus_repacketizer_get_size().
+ * This can be used for applications which use their own allocator instead of
+ * malloc().
+ * It must also be called to reset the queue of packets waiting to be
+ * repacketized, which is necessary if the maximum packet duration of 120 ms
+ * is reached or if you wish to submit packets with a different Opus
+ * configuration (coding mode, audio bandwidth, frame size, or channel count).
+ * Failure to do so will prevent a new packet from being added with
+ * opus_repacketizer_cat().
+ * @see opus_repacketizer_create
+ * @see opus_repacketizer_get_size
+ * @see opus_repacketizer_cat
+ * @param rp OpusRepacketizer*: The repacketizer state to
+ * (re)initialize.
+ * @returns A pointer to the same repacketizer state that was passed in.
+ */
+OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
+
+/** Allocates memory and initializes the new repacketizer with
+ * opus_repacketizer_init().
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void);
+
+/** Frees an OpusRepacketizer allocated by
+ * opus_repacketizer_create().
+ * @param[in] rp OpusRepacketizer*: State to be freed.
+ */
+OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp);
+
+/** Add a packet to the current repacketizer state.
+ * This packet must match the configuration of any packets already submitted
+ * for repacketization since the last call to opus_repacketizer_init().
+ * This means that it must have the same coding mode, audio bandwidth, frame
+ * size, and channel count.
+ * This can be checked in advance by examining the top 6 bits of the first
+ * byte of the packet, and ensuring they match the top 6 bits of the first
+ * byte of any previously submitted packet.
+ * The total duration of audio in the repacketizer state also must not exceed
+ * 120 ms, the maximum duration of a single packet, after adding this packet.
+ *
+ * The contents of the current repacketizer state can be extracted into new
+ * packets using opus_repacketizer_out() or opus_repacketizer_out_range().
+ *
+ * In order to add a packet with a different configuration or to add more
+ * audio beyond 120 ms, you must clear the repacketizer state by calling
+ * opus_repacketizer_init().
+ * If a packet is too large to add to the current repacketizer state, no part
+ * of it is added, even if it contains multiple frames, some of which might
+ * fit.
+ * If you wish to be able to add parts of such packets, you should first use
+ * another repacketizer to split the packet into pieces and add them
+ * individually.
+ * @see opus_repacketizer_out_range
+ * @see opus_repacketizer_out
+ * @see opus_repacketizer_init
+ * @param rp OpusRepacketizer*: The repacketizer state to which to
+ * add the packet.
+ * @param[in] data const unsigned char*: The packet data.
+ * The application must ensure
+ * this pointer remains valid
+ * until the next call to
+ * opus_repacketizer_init() or
+ * opus_repacketizer_destroy().
+ * @param len opus_int32: The number of bytes in the packet data.
+ * @returns An error code indicating whether or not the operation succeeded.
+ * @retval #OPUS_OK The packet's contents have been added to the repacketizer
+ * state.
+ * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence,
+ * the packet's TOC sequence was not compatible
+ * with previously submitted packets (because
+ * the coding mode, audio bandwidth, frame size,
+ * or channel count did not match), or adding
+ * this packet would increase the total amount of
+ * audio stored in the repacketizer state to more
+ * than 120 ms.
+ */
+OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+
+/** Construct a new packet from data previously submitted to the repacketizer
+ * state via opus_repacketizer_cat().
+ * @param rp OpusRepacketizer*: The repacketizer state from which to
+ * construct the new packet.
+ * @param begin int: The index of the first frame in the current
+ * repacketizer state to include in the output.
+ * @param end int: One past the index of the last frame in the
+ * current repacketizer state to include in the
+ * output.
+ * @param[out] data const unsigned char*: The buffer in which to
+ * store the output packet.
+ * @param maxlen opus_int32: The maximum number of bytes to store in
+ * the output buffer. In order to guarantee
+ * success, this should be at least
+ * 1276 for a single frame,
+ * or for multiple frames,
+ * 1277*(end-begin).
+ * However, 1*(end-begin) plus
+ * the size of all packet data submitted to
+ * the repacketizer since the last call to
+ * opus_repacketizer_init() or
+ * opus_repacketizer_create() is also
+ * sufficient, and possibly much smaller.
+ * @returns The total size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG [begin,end) was an invalid range of
+ * frames (begin < 0, begin >= end, or end >
+ * opus_repacketizer_get_nb_frames()).
+ * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+ * complete output packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Return the total number of frames contained in packet data submitted to
+ * the repacketizer state so far via opus_repacketizer_cat() since the last
+ * call to opus_repacketizer_init() or opus_repacketizer_create().
+ * This defines the valid range of packets that can be extracted with
+ * opus_repacketizer_out_range() or opus_repacketizer_out().
+ * @param rp OpusRepacketizer*: The repacketizer state containing the
+ * frames.
+ * @returns The total number of frames contained in the packet data submitted
+ * to the repacketizer state.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
+
+/** Construct a new packet from data previously submitted to the repacketizer
+ * state via opus_repacketizer_cat().
+ * This is a convenience routine that returns all the data submitted so far
+ * in a single packet.
+ * It is equivalent to calling
+ * @code
+ * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp),
+ * data, maxlen)
+ * @endcode
+ * @param rp OpusRepacketizer*: The repacketizer state from which to
+ * construct the new packet.
+ * @param[out] data const unsigned char*: The buffer in which to
+ * store the output packet.
+ * @param maxlen opus_int32: The maximum number of bytes to store in
+ * the output buffer. In order to guarantee
+ * success, this should be at least
+ * 1277*opus_repacketizer_get_nb_frames(rp).
+ * However,
+ * 1*opus_repacketizer_get_nb_frames(rp)
+ * plus the size of all packet data
+ * submitted to the repacketizer since the
+ * last call to opus_repacketizer_init() or
+ * opus_repacketizer_create() is also
+ * sufficient, and possibly much smaller.
+ * @returns The total size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+ * complete output packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1);
+
+/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence).
+ * @param[in,out] data const unsigned char*: The buffer containing the
+ * packet to pad.
+ * @param len opus_int32: The size of the packet.
+ * This must be at least 1.
+ * @param new_len opus_int32: The desired size of the packet after padding.
+ * This must be at least as large as len.
+ * @returns an error code
+ * @retval #OPUS_OK \a on success.
+ * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len);
+
+/** Remove all padding from a given Opus packet and rewrite the TOC sequence to
+ * minimize space usage.
+ * @param[in,out] data const unsigned char*: The buffer containing the
+ * packet to strip.
+ * @param len opus_int32: The size of the packet.
+ * This must be at least 1.
+ * @returns The new size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG \a len was less than 1.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len);
+
+/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence).
+ * @param[in,out] data const unsigned char*: The buffer containing the
+ * packet to pad.
+ * @param len opus_int32: The size of the packet.
+ * This must be at least 1.
+ * @param new_len opus_int32: The desired size of the packet after padding.
+ * This must be at least 1.
+ * @param nb_streams opus_int32: The number of streams (not channels) in the packet.
+ * This must be at least as large as len.
+ * @returns an error code
+ * @retval #OPUS_OK \a on success.
+ * @retval #OPUS_BAD_ARG \a len was less than 1.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams);
+
+/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to
+ * minimize space usage.
+ * @param[in,out] data const unsigned char*: The buffer containing the
+ * packet to strip.
+ * @param len opus_int32: The size of the packet.
+ * This must be at least 1.
+ * @param nb_streams opus_int32: The number of streams (not channels) in the packet.
+ * This must be at least 1.
+ * @returns The new size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams);
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_H */
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus_defines.h b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus_defines.h
new file mode 100644
index 000000000..315412dd1
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus_defines.h
@@ -0,0 +1,753 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus_defines.h
+ * @brief Opus reference implementation constants
+ */
+
+#ifndef OPUS_DEFINES_H
+#define OPUS_DEFINES_H
+
+#include "opus_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup opus_errorcodes Error codes
+ * @{
+ */
+/** No error @hideinitializer*/
+#define OPUS_OK 0
+/** One or more invalid/out of range arguments @hideinitializer*/
+#define OPUS_BAD_ARG -1
+/** Not enough bytes allocated in the buffer @hideinitializer*/
+#define OPUS_BUFFER_TOO_SMALL -2
+/** An internal error was detected @hideinitializer*/
+#define OPUS_INTERNAL_ERROR -3
+/** The compressed data passed is corrupted @hideinitializer*/
+#define OPUS_INVALID_PACKET -4
+/** Invalid/unsupported request number @hideinitializer*/
+#define OPUS_UNIMPLEMENTED -5
+/** An encoder or decoder structure is invalid or already freed @hideinitializer*/
+#define OPUS_INVALID_STATE -6
+/** Memory allocation has failed @hideinitializer*/
+#define OPUS_ALLOC_FAIL -7
+/**@}*/
+
+/** @cond OPUS_INTERNAL_DOC */
+/**Export control for opus functions */
+
+#ifndef OPUS_EXPORT
+# if defined(WIN32)
+# if defined(OPUS_BUILD) && defined(DLL_EXPORT)
+# define OPUS_EXPORT __declspec(dllexport)
+# else
+# define OPUS_EXPORT
+# endif
+# elif defined(__GNUC__) && defined(OPUS_BUILD)
+# define OPUS_EXPORT __attribute__ ((visibility ("default")))
+# else
+# define OPUS_EXPORT
+# endif
+#endif
+
+# if !defined(OPUS_GNUC_PREREQ)
+# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
+# define OPUS_GNUC_PREREQ(_maj,_min) \
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
+# else
+# define OPUS_GNUC_PREREQ(_maj,_min) 0
+# endif
+# endif
+
+#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if OPUS_GNUC_PREREQ(3,0)
+# define OPUS_RESTRICT __restrict__
+# elif (defined(_MSC_VER) && _MSC_VER >= 1400)
+# define OPUS_RESTRICT __restrict
+# else
+# define OPUS_RESTRICT
+# endif
+#else
+# define OPUS_RESTRICT restrict
+#endif
+
+#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if OPUS_GNUC_PREREQ(2,7)
+# define OPUS_INLINE __inline__
+# elif (defined(_MSC_VER))
+# define OPUS_INLINE __inline
+# else
+# define OPUS_INLINE
+# endif
+#else
+# define OPUS_INLINE inline
+#endif
+
+/**Warning attributes for opus functions
+ * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out
+ * some paranoid null checks. */
+#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
+# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
+#else
+# define OPUS_WARN_UNUSED_RESULT
+#endif
+#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
+# define OPUS_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x)))
+#else
+# define OPUS_ARG_NONNULL(_x)
+#endif
+
+/** These are the actual Encoder CTL ID numbers.
+ * They should not be used directly by applications.
+ * In general, SETs should be even and GETs should be odd.*/
+#define OPUS_SET_APPLICATION_REQUEST 4000
+#define OPUS_GET_APPLICATION_REQUEST 4001
+#define OPUS_SET_BITRATE_REQUEST 4002
+#define OPUS_GET_BITRATE_REQUEST 4003
+#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004
+#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005
+#define OPUS_SET_VBR_REQUEST 4006
+#define OPUS_GET_VBR_REQUEST 4007
+#define OPUS_SET_BANDWIDTH_REQUEST 4008
+#define OPUS_GET_BANDWIDTH_REQUEST 4009
+#define OPUS_SET_COMPLEXITY_REQUEST 4010
+#define OPUS_GET_COMPLEXITY_REQUEST 4011
+#define OPUS_SET_INBAND_FEC_REQUEST 4012
+#define OPUS_GET_INBAND_FEC_REQUEST 4013
+#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014
+#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015
+#define OPUS_SET_DTX_REQUEST 4016
+#define OPUS_GET_DTX_REQUEST 4017
+#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020
+#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021
+#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022
+#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023
+#define OPUS_SET_SIGNAL_REQUEST 4024
+#define OPUS_GET_SIGNAL_REQUEST 4025
+#define OPUS_GET_LOOKAHEAD_REQUEST 4027
+/* #define OPUS_RESET_STATE 4028 */
+#define OPUS_GET_SAMPLE_RATE_REQUEST 4029
+#define OPUS_GET_FINAL_RANGE_REQUEST 4031
+#define OPUS_GET_PITCH_REQUEST 4033
+#define OPUS_SET_GAIN_REQUEST 4034
+#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */
+#define OPUS_SET_LSB_DEPTH_REQUEST 4036
+#define OPUS_GET_LSB_DEPTH_REQUEST 4037
+#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039
+#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040
+#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041
+#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042
+#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043
+
+/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
+
+/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
+#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
+#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
+#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))
+#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))
+/** @endcond */
+
+/** @defgroup opus_ctlvalues Pre-defined values for CTL interface
+ * @see opus_genericctls, opus_encoderctls
+ * @{
+ */
+/* Values for the various encoder CTLs */
+#define OPUS_AUTO -1000 /**opus_int32: Allowed values: 0-10, inclusive.
+ *
+ * @hideinitializer */
+#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x)
+/** Gets the encoder's complexity configuration.
+ * @see OPUS_SET_COMPLEXITY
+ * @param[out] x opus_int32 *: Returns a value in the range 0-10,
+ * inclusive.
+ * @hideinitializer */
+#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the bitrate in the encoder.
+ * Rates from 500 to 512000 bits per second are meaningful, as well as the
+ * special values #OPUS_AUTO and #OPUS_BITRATE_MAX.
+ * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much
+ * rate as it can, which is useful for controlling the rate by adjusting the
+ * output buffer size.
+ * @see OPUS_GET_BITRATE
+ * @param[in] x opus_int32: Bitrate in bits per second. The default
+ * is determined based on the number of
+ * channels and the input sampling rate.
+ * @hideinitializer */
+#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x)
+/** Gets the encoder's bitrate configuration.
+ * @see OPUS_SET_BITRATE
+ * @param[out] x opus_int32 *: Returns the bitrate in bits per second.
+ * The default is determined based on the
+ * number of channels and the input
+ * sampling rate.
+ * @hideinitializer */
+#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x)
+
+/** Enables or disables variable bitrate (VBR) in the encoder.
+ * The configured bitrate may not be met exactly because frames must
+ * be an integer number of bytes in length.
+ * @see OPUS_GET_VBR
+ * @see OPUS_SET_VBR_CONSTRAINT
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - 0
- Hard CBR. For LPC/hybrid modes at very low bit-rate, this can
+ * cause noticeable quality degradation.
+ * - 1
- VBR (default). The exact type of VBR is controlled by
+ * #OPUS_SET_VBR_CONSTRAINT.
+ *
+ * @hideinitializer */
+#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x)
+/** Determine if variable bitrate (VBR) is enabled in the encoder.
+ * @see OPUS_SET_VBR
+ * @see OPUS_GET_VBR_CONSTRAINT
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - 0
- Hard CBR.
+ * - 1
- VBR (default). The exact type of VBR may be retrieved via
+ * #OPUS_GET_VBR_CONSTRAINT.
+ *
+ * @hideinitializer */
+#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x)
+
+/** Enables or disables constrained VBR in the encoder.
+ * This setting is ignored when the encoder is in CBR mode.
+ * @warning Only the MDCT mode of Opus currently heeds the constraint.
+ * Speech mode ignores it completely, hybrid mode may fail to obey it
+ * if the LPC layer uses more bitrate than the constraint would have
+ * permitted.
+ * @see OPUS_GET_VBR_CONSTRAINT
+ * @see OPUS_SET_VBR
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - 0
- Unconstrained VBR.
+ * - 1
- Constrained VBR (default). This creates a maximum of one
+ * frame of buffering delay assuming a transport with a
+ * serialization speed of the nominal bitrate.
+ *
+ * @hideinitializer */
+#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x)
+/** Determine if constrained VBR is enabled in the encoder.
+ * @see OPUS_SET_VBR_CONSTRAINT
+ * @see OPUS_GET_VBR
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - 0
- Unconstrained VBR.
+ * - 1
- Constrained VBR (default).
+ *
+ * @hideinitializer */
+#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures mono/stereo forcing in the encoder.
+ * This can force the encoder to produce packets encoded as either mono or
+ * stereo, regardless of the format of the input audio. This is useful when
+ * the caller knows that the input signal is currently a mono source embedded
+ * in a stereo stream.
+ * @see OPUS_GET_FORCE_CHANNELS
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - #OPUS_AUTO
- Not forced (default)
+ * - 1
- Forced mono
+ * - 2
- Forced stereo
+ *
+ * @hideinitializer */
+#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x)
+/** Gets the encoder's forced channel configuration.
+ * @see OPUS_SET_FORCE_CHANNELS
+ * @param[out] x opus_int32 *:
+ *
+ * - #OPUS_AUTO
- Not forced (default)
+ * - 1
- Forced mono
+ * - 2
- Forced stereo
+ *
+ * @hideinitializer */
+#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the maximum bandpass that the encoder will select automatically.
+ * Applications should normally use this instead of #OPUS_SET_BANDWIDTH
+ * (leaving that set to the default, #OPUS_AUTO). This allows the
+ * application to set an upper bound based on the type of input it is
+ * providing, but still gives the encoder the freedom to reduce the bandpass
+ * when the bitrate becomes too low, for better overall quality.
+ * @see OPUS_GET_MAX_BANDWIDTH
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - OPUS_BANDWIDTH_NARROWBAND
- 4 kHz passband
+ * - OPUS_BANDWIDTH_MEDIUMBAND
- 6 kHz passband
+ * - OPUS_BANDWIDTH_WIDEBAND
- 8 kHz passband
+ * - OPUS_BANDWIDTH_SUPERWIDEBAND
- 12 kHz passband
+ * - OPUS_BANDWIDTH_FULLBAND
- 20 kHz passband (default)
+ *
+ * @hideinitializer */
+#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x)
+
+/** Gets the encoder's configured maximum allowed bandpass.
+ * @see OPUS_SET_MAX_BANDWIDTH
+ * @param[out] x opus_int32 *: Allowed values:
+ *
+ * - #OPUS_BANDWIDTH_NARROWBAND
- 4 kHz passband
+ * - #OPUS_BANDWIDTH_MEDIUMBAND
- 6 kHz passband
+ * - #OPUS_BANDWIDTH_WIDEBAND
- 8 kHz passband
+ * - #OPUS_BANDWIDTH_SUPERWIDEBAND
- 12 kHz passband
+ * - #OPUS_BANDWIDTH_FULLBAND
- 20 kHz passband (default)
+ *
+ * @hideinitializer */
+#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Sets the encoder's bandpass to a specific value.
+ * This prevents the encoder from automatically selecting the bandpass based
+ * on the available bitrate. If an application knows the bandpass of the input
+ * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH
+ * instead, which still gives the encoder the freedom to reduce the bandpass
+ * when the bitrate becomes too low, for better overall quality.
+ * @see OPUS_GET_BANDWIDTH
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - #OPUS_AUTO
- (default)
+ * - #OPUS_BANDWIDTH_NARROWBAND
- 4 kHz passband
+ * - #OPUS_BANDWIDTH_MEDIUMBAND
- 6 kHz passband
+ * - #OPUS_BANDWIDTH_WIDEBAND
- 8 kHz passband
+ * - #OPUS_BANDWIDTH_SUPERWIDEBAND
- 12 kHz passband
+ * - #OPUS_BANDWIDTH_FULLBAND
- 20 kHz passband
+ *
+ * @hideinitializer */
+#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x)
+
+/** Configures the type of signal being encoded.
+ * This is a hint which helps the encoder's mode selection.
+ * @see OPUS_GET_SIGNAL
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - #OPUS_AUTO
- (default)
+ * - #OPUS_SIGNAL_VOICE
- Bias thresholds towards choosing LPC or Hybrid modes.
+ * - #OPUS_SIGNAL_MUSIC
- Bias thresholds towards choosing MDCT modes.
+ *
+ * @hideinitializer */
+#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured signal type.
+ * @see OPUS_SET_SIGNAL
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - #OPUS_AUTO
- (default)
+ * - #OPUS_SIGNAL_VOICE
- Bias thresholds towards choosing LPC or Hybrid modes.
+ * - #OPUS_SIGNAL_MUSIC
- Bias thresholds towards choosing MDCT modes.
+ *
+ * @hideinitializer */
+#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x)
+
+
+/** Configures the encoder's intended application.
+ * The initial value is a mandatory argument to the encoder_create function.
+ * @see OPUS_GET_APPLICATION
+ * @param[in] x opus_int32: Returns one of the following values:
+ *
+ * - #OPUS_APPLICATION_VOIP
+ * - Process signal for improved speech intelligibility.
+ * - #OPUS_APPLICATION_AUDIO
+ * - Favor faithfulness to the original input.
+ * - #OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ * - Configure the minimum possible coding delay by disabling certain modes
+ * of operation.
+ *
+ * @hideinitializer */
+#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured application.
+ * @see OPUS_SET_APPLICATION
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - #OPUS_APPLICATION_VOIP
+ * - Process signal for improved speech intelligibility.
+ * - #OPUS_APPLICATION_AUDIO
+ * - Favor faithfulness to the original input.
+ * - #OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ * - Configure the minimum possible coding delay by disabling certain modes
+ * of operation.
+ *
+ * @hideinitializer */
+#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the total samples of delay added by the entire codec.
+ * This can be queried by the encoder and then the provided number of samples can be
+ * skipped on from the start of the decoder's output to provide time aligned input
+ * and output. From the perspective of a decoding application the real data begins this many
+ * samples late.
+ *
+ * The decoder contribution to this delay is identical for all decoders, but the
+ * encoder portion of the delay may vary from implementation to implementation,
+ * version to version, or even depend on the encoder's initial configuration.
+ * Applications needing delay compensation should call this CTL rather than
+ * hard-coding a value.
+ * @param[out] x opus_int32 *: Number of lookahead samples
+ * @hideinitializer */
+#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of inband forward error correction (FEC).
+ * @note This is only applicable to the LPC layer
+ * @see OPUS_GET_INBAND_FEC
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - 0
- Disable inband FEC (default).
+ * - 1
- Enable inband FEC.
+ *
+ * @hideinitializer */
+#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
+/** Gets encoder's configured use of inband forward error correction.
+ * @see OPUS_SET_INBAND_FEC
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - 0
- Inband FEC disabled (default).
+ * - 1
- Inband FEC enabled.
+ *
+ * @hideinitializer */
+#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's expected packet loss percentage.
+ * Higher values trigger progressively more loss resistant behavior in the encoder
+ * at the expense of quality at a given bitrate in the absence of packet loss, but
+ * greater quality under loss.
+ * @see OPUS_GET_PACKET_LOSS_PERC
+ * @param[in] x opus_int32: Loss percentage in the range 0-100, inclusive (default: 0).
+ * @hideinitializer */
+#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured packet loss percentage.
+ * @see OPUS_SET_PACKET_LOSS_PERC
+ * @param[out] x opus_int32 *: Returns the configured loss percentage
+ * in the range 0-100, inclusive (default: 0).
+ * @hideinitializer */
+#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of discontinuous transmission (DTX).
+ * @note This is only applicable to the LPC layer
+ * @see OPUS_GET_DTX
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - 0
- Disable DTX (default).
+ * - 1
- Enabled DTX.
+ *
+ * @hideinitializer */
+#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x)
+/** Gets encoder's configured use of discontinuous transmission.
+ * @see OPUS_SET_DTX
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - 0
- DTX disabled (default).
+ * - 1
- DTX enabled.
+ *
+ * @hideinitializer */
+#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x)
+/** Configures the depth of signal being encoded.
+ *
+ * This is a hint which helps the encoder identify silence and near-silence.
+ * It represents the number of significant bits of linear intensity below
+ * which the signal contains ignorable quantization or other noise.
+ *
+ * For example, OPUS_SET_LSB_DEPTH(14) would be an appropriate setting
+ * for G.711 u-law input. OPUS_SET_LSB_DEPTH(16) would be appropriate
+ * for 16-bit linear pcm input with opus_encode_float().
+ *
+ * When using opus_encode() instead of opus_encode_float(), or when libopus
+ * is compiled for fixed-point, the encoder uses the minimum of the value
+ * set here and the value 16.
+ *
+ * @see OPUS_GET_LSB_DEPTH
+ * @param[in] x opus_int32: Input precision in bits, between 8 and 24
+ * (default: 24).
+ * @hideinitializer */
+#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured signal depth.
+ * @see OPUS_SET_LSB_DEPTH
+ * @param[out] x opus_int32 *: Input precision in bits, between 8 and
+ * 24 (default: 24).
+ * @hideinitializer */
+#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of variable duration frames.
+ * When variable duration is enabled, the encoder is free to use a shorter frame
+ * size than the one requested in the opus_encode*() call.
+ * It is then the user's responsibility
+ * to verify how much audio was encoded by checking the ToC byte of the encoded
+ * packet. The part of the audio that was not encoded needs to be resent to the
+ * encoder for the next call. Do not use this option unless you really
+ * know what you are doing.
+ * @see OPUS_GET_EXPERT_FRAME_DURATION
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - OPUS_FRAMESIZE_ARG
- Select frame size from the argument (default).
+ * - OPUS_FRAMESIZE_2_5_MS
- Use 2.5 ms frames.
+ * - OPUS_FRAMESIZE_5_MS
- Use 5 ms frames.
+ * - OPUS_FRAMESIZE_10_MS
- Use 10 ms frames.
+ * - OPUS_FRAMESIZE_20_MS
- Use 20 ms frames.
+ * - OPUS_FRAMESIZE_40_MS
- Use 40 ms frames.
+ * - OPUS_FRAMESIZE_60_MS
- Use 60 ms frames.
+ * - OPUS_FRAMESIZE_VARIABLE
- Optimize the frame size dynamically.
+ *
+ * @hideinitializer */
+#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured use of variable duration frames.
+ * @see OPUS_SET_EXPERT_FRAME_DURATION
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - OPUS_FRAMESIZE_ARG
- Select frame size from the argument (default).
+ * - OPUS_FRAMESIZE_2_5_MS
- Use 2.5 ms frames.
+ * - OPUS_FRAMESIZE_5_MS
- Use 5 ms frames.
+ * - OPUS_FRAMESIZE_10_MS
- Use 10 ms frames.
+ * - OPUS_FRAMESIZE_20_MS
- Use 20 ms frames.
+ * - OPUS_FRAMESIZE_40_MS
- Use 40 ms frames.
+ * - OPUS_FRAMESIZE_60_MS
- Use 60 ms frames.
+ * - OPUS_FRAMESIZE_VARIABLE
- Optimize the frame size dynamically.
+ *
+ * @hideinitializer */
+#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x)
+
+/** If set to 1, disables almost all use of prediction, making frames almost
+ * completely independent. This reduces quality.
+ * @see OPUS_GET_PREDICTION_DISABLED
+ * @param[in] x opus_int32: Allowed values:
+ *
+ * - 0
- Enable prediction (default).
+ * - 1
- Disable prediction.
+ *
+ * @hideinitializer */
+#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured prediction status.
+ * @see OPUS_SET_PREDICTION_DISABLED
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - 0
- Prediction enabled (default).
+ * - 1
- Prediction disabled.
+ *
+ * @hideinitializer */
+#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_genericctls Generic CTLs
+ *
+ * These macros are used with the \c opus_decoder_ctl and
+ * \c opus_encoder_ctl calls to generate a particular
+ * request.
+ *
+ * When called on an \c OpusDecoder they apply to that
+ * particular decoder instance. When called on an
+ * \c OpusEncoder they apply to the corresponding setting
+ * on that encoder instance, if present.
+ *
+ * Some usage examples:
+ *
+ * @code
+ * int ret;
+ * opus_int32 pitch;
+ * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch));
+ * if (ret == OPUS_OK) return ret;
+ *
+ * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);
+ * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE);
+ *
+ * opus_int32 enc_bw, dec_bw;
+ * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw));
+ * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw));
+ * if (enc_bw != dec_bw) {
+ * printf("packet bandwidth mismatch!\n");
+ * }
+ * @endcode
+ *
+ * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls
+ * @{
+ */
+
+/** Resets the codec state to be equivalent to a freshly initialized state.
+ * This should be called when switching streams in order to prevent
+ * the back to back decoding from giving different results from
+ * one at a time decoding.
+ * @hideinitializer */
+#define OPUS_RESET_STATE 4028
+
+/** Gets the final state of the codec's entropy coder.
+ * This is used for testing purposes,
+ * The encoder and decoder state should be identical after coding a payload
+ * (assuming no data corruption or software bugs)
+ *
+ * @param[out] x opus_uint32 *: Entropy coder state
+ *
+ * @hideinitializer */
+#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x)
+
+/** Gets the encoder's configured bandpass or the decoder's last bandpass.
+ * @see OPUS_SET_BANDWIDTH
+ * @param[out] x opus_int32 *: Returns one of the following values:
+ *
+ * - #OPUS_AUTO
- (default)
+ * - #OPUS_BANDWIDTH_NARROWBAND
- 4 kHz passband
+ * - #OPUS_BANDWIDTH_MEDIUMBAND
- 6 kHz passband
+ * - #OPUS_BANDWIDTH_WIDEBAND
- 8 kHz passband
+ * - #OPUS_BANDWIDTH_SUPERWIDEBAND
- 12 kHz passband
+ * - #OPUS_BANDWIDTH_FULLBAND
- 20 kHz passband
+ *
+ * @hideinitializer */
+#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the sampling rate the encoder or decoder was initialized with.
+ * This simply returns the Fs value passed to opus_encoder_init()
+ * or opus_decoder_init().
+ * @param[out] x opus_int32 *: Sampling rate of encoder or decoder.
+ * @hideinitializer
+ */
+#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_decoderctls Decoder related CTLs
+ * @see opus_genericctls, opus_encoderctls, opus_decoder
+ * @{
+ */
+
+/** Configures decoder gain adjustment.
+ * Scales the decoded output by a factor specified in Q8 dB units.
+ * This has a maximum range of -32768 to 32767 inclusive, and returns
+ * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment.
+ * This setting survives decoder reset.
+ *
+ * gain = pow(10, x/(20.0*256))
+ *
+ * @param[in] x opus_int32: Amount to scale PCM signal by in Q8 dB units.
+ * @hideinitializer */
+#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x)
+/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN
+ *
+ * @param[out] x opus_int32 *: Amount to scale PCM signal by in Q8 dB units.
+ * @hideinitializer */
+#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the duration (in samples) of the last packet successfully decoded or concealed.
+ * @param[out] x opus_int32 *: Number of samples (at current sampling rate).
+ * @hideinitializer */
+#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the pitch of the last decoded frame, if available.
+ * This can be used for any post-processing algorithm requiring the use of pitch,
+ * e.g. time stretching/shortening. If the last frame was not voiced, or if the
+ * pitch was not coded in the frame, then zero is returned.
+ *
+ * This CTL is only implemented for decoder instances.
+ *
+ * @param[out] x opus_int32 *: pitch period at 48 kHz (or 0 if not available)
+ *
+ * @hideinitializer */
+#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_libinfo Opus library information functions
+ * @{
+ */
+
+/** Converts an opus error code into a human readable string.
+ *
+ * @param[in] error int: Error number
+ * @returns Error string
+ */
+OPUS_EXPORT const char *opus_strerror(int error);
+
+/** Gets the libopus version string.
+ *
+ * Applications may look for the substring "-fixed" in the version string to
+ * determine whether they have a fixed-point or floating-point build at
+ * runtime.
+ *
+ * @returns Version string
+ */
+OPUS_EXPORT const char *opus_get_version_string(void);
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_DEFINES_H */
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus_multistream.h b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus_multistream.h
new file mode 100644
index 000000000..3622e009f
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus_multistream.h
@@ -0,0 +1,660 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus_multistream.h
+ * @brief Opus reference implementation multistream API
+ */
+
+#ifndef OPUS_MULTISTREAM_H
+#define OPUS_MULTISTREAM_H
+
+#include "opus.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @cond OPUS_INTERNAL_DOC */
+
+/** Macros to trigger compilation errors when the wrong types are provided to a
+ * CTL. */
+/**@{*/
+#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr)))
+#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr)))
+/**@}*/
+
+/** These are the actual encoder and decoder CTL ID numbers.
+ * They should not be used directly by applications.
+ * In general, SETs should be even and GETs should be odd.*/
+/**@{*/
+#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120
+#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122
+/**@}*/
+
+/** @endcond */
+
+/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs
+ *
+ * These are convenience macros that are specific to the
+ * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl()
+ * interface.
+ * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and
+ * @ref opus_decoderctls may be applied to a multistream encoder or decoder as
+ * well.
+ * In addition, you may retrieve the encoder or decoder state for an specific
+ * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or
+ * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually.
+ */
+/**@{*/
+
+/** Gets the encoder state for an individual stream of a multistream encoder.
+ * @param[in] x opus_int32: The index of the stream whose encoder you
+ * wish to retrieve.
+ * This must be non-negative and less than
+ * the streams parameter used
+ * to initialize the encoder.
+ * @param[out] y OpusEncoder**: Returns a pointer to the given
+ * encoder state.
+ * @retval OPUS_BAD_ARG The index of the requested stream was out of range.
+ * @hideinitializer
+ */
+#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y)
+
+/** Gets the decoder state for an individual stream of a multistream decoder.
+ * @param[in] x opus_int32: The index of the stream whose decoder you
+ * wish to retrieve.
+ * This must be non-negative and less than
+ * the streams parameter used
+ * to initialize the decoder.
+ * @param[out] y OpusDecoder**: Returns a pointer to the given
+ * decoder state.
+ * @retval OPUS_BAD_ARG The index of the requested stream was out of range.
+ * @hideinitializer
+ */
+#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y)
+
+/**@}*/
+
+/** @defgroup opus_multistream Opus Multistream API
+ * @{
+ *
+ * The multistream API allows individual Opus streams to be combined into a
+ * single packet, enabling support for up to 255 channels. Unlike an
+ * elementary Opus stream, the encoder and decoder must negotiate the channel
+ * configuration before the decoder can successfully interpret the data in the
+ * packets produced by the encoder. Some basic information, such as packet
+ * duration, can be computed without any special negotiation.
+ *
+ * The format for multistream Opus packets is defined in
+ * RFC 7845
+ * and is based on the self-delimited Opus framing described in Appendix B of
+ * RFC 6716.
+ * Normal Opus packets are just a degenerate case of multistream Opus packets,
+ * and can be encoded or decoded with the multistream API by setting
+ * streams to 1 when initializing the encoder or
+ * decoder.
+ *
+ * Multistream Opus streams can contain up to 255 elementary Opus streams.
+ * These may be either "uncoupled" or "coupled", indicating that the decoder
+ * is configured to decode them to either 1 or 2 channels, respectively.
+ * The streams are ordered so that all coupled streams appear at the
+ * beginning.
+ *
+ * A mapping table defines which decoded channel i
+ * should be used for each input/output (I/O) channel j. This table is
+ * typically provided as an unsigned char array.
+ * Let i = mapping[j] be the index for I/O channel j.
+ * If i < 2*coupled_streams, then I/O channel j is
+ * encoded as the left channel of stream (i/2) if i
+ * is even, or as the right channel of stream (i/2) if
+ * i is odd. Otherwise, I/O channel j is encoded as
+ * mono in stream (i - coupled_streams), unless it has the special
+ * value 255, in which case it is omitted from the encoding entirely (the
+ * decoder will reproduce it as silence). Each value i must either
+ * be the special value 255 or be less than streams + coupled_streams.
+ *
+ * The output channels specified by the encoder
+ * should use the
+ * Vorbis
+ * channel ordering. A decoder may wish to apply an additional permutation
+ * to the mapping the encoder used to achieve a different output channel
+ * order (e.g. for outputing in WAV order).
+ *
+ * Each multistream packet contains an Opus packet for each stream, and all of
+ * the Opus packets in a single multistream packet must have the same
+ * duration. Therefore the duration of a multistream packet can be extracted
+ * from the TOC sequence of the first stream, which is located at the
+ * beginning of the packet, just like an elementary Opus stream:
+ *
+ * @code
+ * int nb_samples;
+ * int nb_frames;
+ * nb_frames = opus_packet_get_nb_frames(data, len);
+ * if (nb_frames < 1)
+ * return nb_frames;
+ * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames;
+ * @endcode
+ *
+ * The general encoding and decoding process proceeds exactly the same as in
+ * the normal @ref opus_encoder and @ref opus_decoder APIs.
+ * See their documentation for an overview of how to use the corresponding
+ * multistream functions.
+ */
+
+/** Opus multistream encoder state.
+ * This contains the complete state of a multistream Opus encoder.
+ * It is position independent and can be freely copied.
+ * @see opus_multistream_encoder_create
+ * @see opus_multistream_encoder_init
+ */
+typedef struct OpusMSEncoder OpusMSEncoder;
+
+/** Opus multistream decoder state.
+ * This contains the complete state of a multistream Opus decoder.
+ * It is position independent and can be freely copied.
+ * @see opus_multistream_decoder_create
+ * @see opus_multistream_decoder_init
+ */
+typedef struct OpusMSDecoder OpusMSDecoder;
+
+/**\name Multistream encoder functions */
+/**@{*/
+
+/** Gets the size of an OpusMSEncoder structure.
+ * @param streams int: The total number of streams to encode from the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams int: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (streams +
+ * coupled_streams) must be no
+ * more than 255.
+ * @returns The size in bytes on success, or a negative error code
+ * (see @ref opus_errorcodes) on error.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size(
+ int streams,
+ int coupled_streams
+);
+
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_surround_encoder_get_size(
+ int channels,
+ int mapping_family
+);
+
+
+/** Allocates and initializes a multistream encoder state.
+ * Call opus_multistream_encoder_destroy() to release
+ * this object when finished.
+ * @param Fs opus_int32: Sampling rate of the input signal (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels int: Number of channels in the input signal.
+ * This must be at most 255.
+ * It may be greater than the number of
+ * coded channels (streams +
+ * coupled_streams).
+ * @param streams int: The total number of streams to encode from the
+ * input.
+ * This must be no more than the number of channels.
+ * @param coupled_streams int: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (streams +
+ * coupled_streams) must be no
+ * more than the number of input channels.
+ * @param[in] mapping const unsigned char[channels]: Mapping from
+ * encoded channels to input channels, as described in
+ * @ref opus_multistream. As an extra constraint, the
+ * multistream encoder does not allow encoding coupled
+ * streams for which one channel is unused since this
+ * is never a good idea.
+ * @param application int: The target encoder application.
+ * This must be one of the following:
+ *
+ * - #OPUS_APPLICATION_VOIP
+ * - Process signal for improved speech intelligibility.
+ * - #OPUS_APPLICATION_AUDIO
+ * - Favor faithfulness to the original input.
+ * - #OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ * - Configure the minimum possible coding delay by disabling certain modes
+ * of operation.
+ *
+ * @param[out] error int *: Returns #OPUS_OK on success, or an error
+ * code (see @ref opus_errorcodes) on
+ * failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+/** Initialize a previously allocated multistream encoder state.
+ * The memory pointed to by \a st must be at least the size returned by
+ * opus_multistream_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of
+ * malloc.
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @see opus_multistream_encoder_create
+ * @see opus_multistream_encoder_get_size
+ * @param st OpusMSEncoder*: Multistream encoder state to initialize.
+ * @param Fs opus_int32: Sampling rate of the input signal (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels int: Number of channels in the input signal.
+ * This must be at most 255.
+ * It may be greater than the number of
+ * coded channels (streams +
+ * coupled_streams).
+ * @param streams int: The total number of streams to encode from the
+ * input.
+ * This must be no more than the number of channels.
+ * @param coupled_streams int: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (streams +
+ * coupled_streams) must be no
+ * more than the number of input channels.
+ * @param[in] mapping const unsigned char[channels]: Mapping from
+ * encoded channels to input channels, as described in
+ * @ref opus_multistream. As an extra constraint, the
+ * multistream encoder does not allow encoding coupled
+ * streams for which one channel is unused since this
+ * is never a good idea.
+ * @param application int: The target encoder application.
+ * This must be one of the following:
+ *
+ * - #OPUS_APPLICATION_VOIP
+ * - Process signal for improved speech intelligibility.
+ * - #OPUS_APPLICATION_AUDIO
+ * - Favor faithfulness to the original input.
+ * - #OPUS_APPLICATION_RESTRICTED_LOWDELAY
+ * - Configure the minimum possible coding delay by disabling certain modes
+ * of operation.
+ *
+ * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
+ * on failure.
+ */
+OPUS_EXPORT int opus_multistream_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+OPUS_EXPORT int opus_multistream_surround_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+/** Encodes a multistream Opus frame.
+ * @param st OpusMSEncoder*: Multistream encoder state.
+ * @param[in] pcm const opus_int16*: The input signal as interleaved
+ * samples.
+ * This must contain
+ * frame_size*channels
+ * samples.
+ * @param frame_size int: Number of samples per channel in the input
+ * signal.
+ * This must be an Opus frame size for the
+ * encoder's sampling rate.
+ * For example, at 48 kHz the permitted values
+ * are 120, 240, 480, 960, 1920, and 2880.
+ * Passing in a duration of less than 10 ms
+ * (480 samples at 48 kHz) will prevent the
+ * encoder from using the LPC or hybrid modes.
+ * @param[out] data unsigned char*: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes opus_int32: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode(
+ OpusMSEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes a multistream Opus frame from floating point input.
+ * @param st OpusMSEncoder*: Multistream encoder state.
+ * @param[in] pcm const float*: The input signal as interleaved
+ * samples with a normal range of
+ * +/-1.0.
+ * Samples with a range beyond +/-1.0
+ * are supported but will be clipped by
+ * decoders using the integer API and
+ * should only be used if it is known
+ * that the far end supports extended
+ * dynamic range.
+ * This must contain
+ * frame_size*channels
+ * samples.
+ * @param frame_size int: Number of samples per channel in the input
+ * signal.
+ * This must be an Opus frame size for the
+ * encoder's sampling rate.
+ * For example, at 48 kHz the permitted values
+ * are 120, 240, 480, 960, 1920, and 2880.
+ * Passing in a duration of less than 10 ms
+ * (480 samples at 48 kHz) will prevent the
+ * encoder from using the LPC or hybrid modes.
+ * @param[out] data unsigned char*: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes opus_int32: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float(
+ OpusMSEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Frees an OpusMSEncoder allocated by
+ * opus_multistream_encoder_create().
+ * @param st OpusMSEncoder*: Multistream encoder state to be freed.
+ */
+OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st);
+
+/** Perform a CTL function on a multistream Opus encoder.
+ *
+ * Generally the request and subsequent arguments are generated by a
+ * convenience macro.
+ * @param st OpusMSEncoder*: Multistream encoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls,
+ * @ref opus_encoderctls, or @ref opus_multistream_ctls.
+ * @see opus_genericctls
+ * @see opus_encoderctls
+ * @see opus_multistream_ctls
+ */
+OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/**@}*/
+
+/**\name Multistream decoder functions */
+/**@{*/
+
+/** Gets the size of an OpusMSDecoder structure.
+ * @param streams int: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams int: Number streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (streams +
+ * coupled_streams) must be no
+ * more than 255.
+ * @returns The size in bytes on success, or a negative error code
+ * (see @ref opus_errorcodes) on error.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size(
+ int streams,
+ int coupled_streams
+);
+
+/** Allocates and initializes a multistream decoder state.
+ * Call opus_multistream_decoder_destroy() to release
+ * this object when finished.
+ * @param Fs opus_int32: Sampling rate to decode at (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels int: Number of channels to output.
+ * This must be at most 255.
+ * It may be different from the number of coded
+ * channels (streams +
+ * coupled_streams).
+ * @param streams int: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams int: Number of streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (streams +
+ * coupled_streams) must be no
+ * more than 255.
+ * @param[in] mapping const unsigned char[channels]: Mapping from
+ * coded channels to output channels, as described in
+ * @ref opus_multistream.
+ * @param[out] error int *: Returns #OPUS_OK on success, or an error
+ * code (see @ref opus_errorcodes) on
+ * failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+/** Intialize a previously allocated decoder state object.
+ * The memory pointed to by \a st must be at least the size returned by
+ * opus_multistream_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of
+ * malloc.
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @see opus_multistream_decoder_create
+ * @see opus_multistream_deocder_get_size
+ * @param st OpusMSEncoder*: Multistream encoder state to initialize.
+ * @param Fs opus_int32: Sampling rate to decode at (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels int: Number of channels to output.
+ * This must be at most 255.
+ * It may be different from the number of coded
+ * channels (streams +
+ * coupled_streams).
+ * @param streams int: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams int: Number of streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (streams +
+ * coupled_streams) must be no
+ * more than 255.
+ * @param[in] mapping const unsigned char[channels]: Mapping from
+ * coded channels to output channels, as described in
+ * @ref opus_multistream.
+ * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
+ * on failure.
+ */
+OPUS_EXPORT int opus_multistream_decoder_init(
+ OpusMSDecoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+/** Decode a multistream Opus packet.
+ * @param st OpusMSDecoder*: Multistream decoder state.
+ * @param[in] data const unsigned char*: Input payload.
+ * Use a NULL
+ * pointer to indicate packet
+ * loss.
+ * @param len opus_int32: Number of bytes in payload.
+ * @param[out] pcm opus_int16*: Output signal, with interleaved
+ * samples.
+ * This must contain room for
+ * frame_size*channels
+ * samples.
+ * @param frame_size int: The number of samples per channel of
+ * available space in \a pcm.
+ * If this is less than the maximum packet duration
+ * (120 ms; 5760 for 48kHz), this function will not be capable
+ * of decoding some packets. In the case of PLC (data==NULL)
+ * or FEC (decode_fec=1), then frame_size needs to be exactly
+ * the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the
+ * next incoming packet. For the PLC and FEC cases, frame_size
+ * must be a multiple of 2.5 ms.
+ * @param decode_fec int: Flag (0 or 1) to request that any in-band
+ * forward error correction data be decoded.
+ * If no such data is available, the frame is
+ * decoded as if it were lost.
+ * @returns Number of samples decoded on success or a negative error code
+ * (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ opus_int16 *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode a multistream Opus packet with floating point output.
+ * @param st OpusMSDecoder*: Multistream decoder state.
+ * @param[in] data const unsigned char*: Input payload.
+ * Use a NULL
+ * pointer to indicate packet
+ * loss.
+ * @param len opus_int32: Number of bytes in payload.
+ * @param[out] pcm opus_int16*: Output signal, with interleaved
+ * samples.
+ * This must contain room for
+ * frame_size*channels
+ * samples.
+ * @param frame_size int: The number of samples per channel of
+ * available space in \a pcm.
+ * If this is less than the maximum packet duration
+ * (120 ms; 5760 for 48kHz), this function will not be capable
+ * of decoding some packets. In the case of PLC (data==NULL)
+ * or FEC (decode_fec=1), then frame_size needs to be exactly
+ * the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the
+ * next incoming packet. For the PLC and FEC cases, frame_size
+ * must be a multiple of 2.5 ms.
+ * @param decode_fec int: Flag (0 or 1) to request that any in-band
+ * forward error correction data be decoded.
+ * If no such data is available, the frame is
+ * decoded as if it were lost.
+ * @returns Number of samples decoded on success or a negative error code
+ * (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ float *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on a multistream Opus decoder.
+ *
+ * Generally the request and subsequent arguments are generated by a
+ * convenience macro.
+ * @param st OpusMSDecoder*: Multistream decoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls,
+ * @ref opus_decoderctls, or @ref opus_multistream_ctls.
+ * @see opus_genericctls
+ * @see opus_decoderctls
+ * @see opus_multistream_ctls
+ */
+OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/** Frees an OpusMSDecoder allocated by
+ * opus_multistream_decoder_create().
+ * @param st OpusMSDecoder: Multistream decoder state to be freed.
+ */
+OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st);
+
+/**@}*/
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_MULTISTREAM_H */
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus_types.h b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus_types.h
new file mode 100644
index 000000000..b28e03aea
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Headers/opus_types.h
@@ -0,0 +1,159 @@
+/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */
+/* Modified by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/* opus_types.h based on ogg_types.h from libogg */
+
+/**
+ @file opus_types.h
+ @brief Opus reference implementation types
+*/
+#ifndef OPUS_TYPES_H
+#define OPUS_TYPES_H
+
+/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */
+#if (defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H))
+#include
+
+ typedef int16_t opus_int16;
+ typedef uint16_t opus_uint16;
+ typedef int32_t opus_int32;
+ typedef uint32_t opus_uint32;
+#elif defined(_WIN32)
+
+# if defined(__CYGWIN__)
+# include <_G_config.h>
+ typedef _G_int32_t opus_int32;
+ typedef _G_uint32_t opus_uint32;
+ typedef _G_int16 opus_int16;
+ typedef _G_uint16 opus_uint16;
+# elif defined(__MINGW32__)
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+# elif defined(__MWERKS__)
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+# else
+ /* MSVC/Borland */
+ typedef __int32 opus_int32;
+ typedef unsigned __int32 opus_uint32;
+ typedef __int16 opus_int16;
+ typedef unsigned __int16 opus_uint16;
+# endif
+
+#elif defined(__MACOS__)
+
+# include
+ typedef SInt16 opus_int16;
+ typedef UInt16 opus_uint16;
+ typedef SInt32 opus_int32;
+ typedef UInt32 opus_uint32;
+
+#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
+
+# include
+ typedef int16_t opus_int16;
+ typedef u_int16_t opus_uint16;
+ typedef int32_t opus_int32;
+ typedef u_int32_t opus_uint32;
+
+#elif defined(__BEOS__)
+
+ /* Be */
+# include
+ typedef int16 opus_int16;
+ typedef u_int16 opus_uint16;
+ typedef int32_t opus_int32;
+ typedef u_int32_t opus_uint32;
+
+#elif defined (__EMX__)
+
+ /* OS/2 GCC */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined (DJGPP)
+
+ /* DJGPP */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined(R5900)
+
+ /* PS2 EE */
+ typedef int opus_int32;
+ typedef unsigned opus_uint32;
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+
+#elif defined(__SYMBIAN32__)
+
+ /* Symbian GCC */
+ typedef signed short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef signed int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
+
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef long opus_int32;
+ typedef unsigned long opus_uint32;
+
+#elif defined(CONFIG_TI_C6X)
+
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#else
+
+ /* Give up, take a reasonable guess */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#endif
+
+#define opus_int int /* used for counters etc; at least 16 bits */
+#define opus_int64 long long
+#define opus_int8 signed char
+
+#define opus_uint unsigned int /* used for counters etc; at least 16 bits */
+#define opus_uint64 unsigned long long
+#define opus_uint8 unsigned char
+
+#endif /* OPUS_TYPES_H */
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Info.plist b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Info.plist
new file mode 100644
index 000000000..99c5c68af
Binary files /dev/null and b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Info.plist differ
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Modules/module.modulemap b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Modules/module.modulemap
new file mode 100644
index 000000000..bb7631ab4
--- /dev/null
+++ b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/Modules/module.modulemap
@@ -0,0 +1,6 @@
+framework module opus {
+ umbrella header "opus.h"
+
+ export *
+ module * { export * }
+}
diff --git a/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/opus b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/opus
new file mode 100755
index 000000000..a4123a551
Binary files /dev/null and b/local_plugins/ble_service/ios/ble_service/opus.xcframework/ios-x86_64-simulator/opus.framework/opus differ
diff --git a/local_plugins/chat_api/ios/chat_api/Package.swift b/local_plugins/chat_api/ios/chat_api/Package.swift
index 8f7b3378a..6772cc3c9 100644
--- a/local_plugins/chat_api/ios/chat_api/Package.swift
+++ b/local_plugins/chat_api/ios/chat_api/Package.swift
@@ -13,7 +13,7 @@ let package = Package(
.library(name: "chat-api", targets: ["chat_api"])
],
dependencies: [
- .package(url: "https://github.com/MacPaw/OpenAI.git", from: "0.4.3"),
+ .package(url: "https://github.com/MacPaw/OpenAI.git", exact: "0.4.3"),
.package(url: "https://github.com/modelcontextprotocol/swift-sdk.git", from: "0.9.0"),
.package(path: "../../../location_service/ios/location_service"),
.package(path: "../../../qq_music/ios/qq_music"),