Browse Source

向下兼容16版本

newdev_shunjiawei
fdp 1 year ago
parent
commit
982ee11e7c
  1. 2
      ios/Flutter/AppFrameworkInfo.plist
  2. 4
      ios/Podfile
  3. 4
      ios/Podfile.lock
  4. 6
      ios/Runner.xcodeproj/project.pbxproj
  5. 7
      ios/Runner/Info.plist
  6. 10
      lib/data/services/speech_impl/azure_asr_service.dart
  7. 19
      lib/modules/translation/controllers/translation_controller.dart
  8. 17
      lib/modules/translation/views/translation_view.dart
  9. 2
      local_plugins/agent_service/ios/agent_service/Package.swift
  10. 2
      local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift
  11. 2
      local_plugins/azure_speech/ios/azure_speech/Package.swift
  12. 124
      local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift
  13. 19
      local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift
  14. 3
      local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureTtsHelper.swift
  15. 2
      local_plugins/ble_service/ios/ble_service/Package.swift
  16. 2
      local_plugins/chat_storage/ios/chat_storage/Package.swift
  17. 2
      local_plugins/classic_bluetooth/ios/classic_bluetooth.podspec
  18. 2
      local_plugins/music_service/ios/music_service/Package.swift
  19. 2
      local_plugins/realtime/ios/realtime/Package.swift

2
ios/Flutter/AppFrameworkInfo.plist

@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>18.0</string>
<string>16.0</string>
</dict>
</plist>

4
ios/Podfile

@ -1,5 +1,5 @@
# Define a global platform for your project
platform :ios, '18.0'
platform :ios, '16.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
@ -44,7 +44,7 @@ post_install do |installer|
# Ensure all pods use the same iOS deployment target
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '18.0'
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '16.0'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',

4
ios/Podfile.lock

@ -177,7 +177,7 @@ SPEC CHECKSUMS:
AMapLocation: 5248aec2455ebb5d104b367813c946430a2ee033
AMapNavi: fceb4715f9a3b5a25f330facebee2aa2bdba42dd
audio_waveforms: a6dde7fe7c0ea05f06ffbdb0f7c1b2b2ba6cedcf
classic_bluetooth: c146e1618e867a47fa7ab79a3bf262e7d69d557d
classic_bluetooth: 29f392f1ab7c52862a9ef036c94f2713b02e0c50
FBAEMKit: e34530df538b8eb8aeb53c35867715ba6c63ef0c
FBSDKCoreKit: d3f479a69127acebb1c6aad91c1a33907bcf6c2f
FBSDKCoreKit_Basics: 017b6dc2a1862024815a8229e75661e627ac1e29
@ -207,6 +207,6 @@ SPEC CHECKSUMS:
WechatOpenSDK-XCFramework: 36fb2bea0754266c17184adf4963d7e6ff98b69f
wifi_iot: f645260a2be8608517b2a9bf4c39b98e97003acc
PODFILE CHECKSUM: 517ecd5ce5153c9609017e05f4e64ab72605e805
PODFILE CHECKSUM: e69e629768e642fde97676ea149350c61d57751e
COCOAPODS: 1.16.2

6
ios/Runner.xcodeproj/project.pbxproj

@ -530,7 +530,7 @@
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Deep Voice";
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -722,7 +722,7 @@
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Deep Voice";
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -748,7 +748,7 @@
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Deep Voice";
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",

7
ios/Runner/Info.plist

@ -72,6 +72,13 @@
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>需要蓝牙权限用于连接和管理音频设备</string>
<key>NSBluetoothPeripheralUsageDescription</key>

10
lib/data/services/speech_impl/azure_asr_service.dart

@ -81,11 +81,11 @@ class AzureAsrService extends GetxService implements AsrService {
try {
final List<String> languages =
supportedLanguages ?? _defaultSupportedLanguages;
// 检查是否需要重新初始化
if (_isInitialized) {
await dispose();
}
//底层会初始化前释放
// // 检查是否需要重新初始化
// if (_isInitialized) {
// await dispose();
// }
// 设置音频源类型
_audioSourceType = useExternalAudio

19
lib/modules/translation/controllers/translation_controller.dart

@ -121,13 +121,18 @@ class TranslationController extends GetxController {
// 监听识别结果
if (activeSpeaker.value != 0) {
isPlayback = false;
final recognitionStream =
await _asrService.startContinuousRecognition(_audioSourceType);
if (id == 1) {
await _asrService.restoreOriginalAudioState();
} else {
await _asrService.disableBluetoothAudio();
}
await _asrService.startContinuousRecognition(_audioSourceType);
lastActiveSpeaker.value = id;
} else {
if (fTFTranslationResult != '' && !isPlayback) {
isPlayback = true;
print("松开走了着");
await _ttsService.setAudioOutputDevice(lastActiveSpeaker.value);
await Future.delayed(const Duration(milliseconds: 1300));
await playTranslatedText(fTFTranslationResult!);
@ -141,9 +146,11 @@ class TranslationController extends GetxController {
}
// 禁用蓝牙音频
void disableBluetoothAudio() => _asrService.disableBluetoothAudio();
Future<void> disableBluetoothAudio() async =>
await _asrService.disableBluetoothAudio();
//恢复原始音频状态
void restoreOriginalAudioState() => _asrService.restoreOriginalAudioState();
Future<void> restoreOriginalAudioState() async =>
await _asrService.restoreOriginalAudioState();
// 兼容旧版视图的计算属性
Rx<TranslationItem?> get currentItem {
@ -337,6 +344,7 @@ class TranslationController extends GetxController {
_translationDebounceTimer?.cancel();
scrollController.dispose();
restoreOtherServices();
_asrService.dispose();
super.onClose();
}
@ -477,9 +485,8 @@ class TranslationController extends GetxController {
if (!isRecognizing.value) return;
try {
restoreOriginalAudioState();
await _asrService.stopContinuousRecognition();
await _asrService.restoreOriginalAudioState();
isRecognizing.value = false;
// 如果当前有中间结果,将其作为最终结果处理

17
lib/modules/translation/views/translation_view.dart

@ -109,7 +109,6 @@ class TranslationView extends GetView<TranslationController> {
)),
centerTitle: true,
actions: [
Obx(() {
if (controller.isRecording.value) {
// 录音中:显示红色计时器样式,点击可停止录音
@ -305,7 +304,8 @@ class TranslationView extends GetView<TranslationController> {
itemCount: itemCount,
itemBuilder: (context, index) {
// 如果是最后一项且有更多历史记录,显示加载指示器(reverse模式下)
if (index == controller.translationHistory.length && controller.hasMoreHistory.value) {
if (index == controller.translationHistory.length &&
controller.hasMoreHistory.value) {
return _buildLoadMoreIndicator();
}
@ -313,7 +313,8 @@ class TranslationView extends GetView<TranslationController> {
final historyIndex = controller.translationHistory.length - 1 - index;
// 检查索引是否有效(reverse模式下的索引验证)
if (historyIndex < 0 || historyIndex >= controller.translationHistory.length) {
if (historyIndex < 0 ||
historyIndex >= controller.translationHistory.length) {
return const SizedBox.shrink();
}
@ -460,8 +461,6 @@ class TranslationView extends GetView<TranslationController> {
child: Obx(() {
// 同时模式显示双按钮
if (controller.currentMode.value == 'faceToFace') {
controller.startRecognition();
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@ -592,11 +591,6 @@ class TranslationView extends GetView<TranslationController> {
// 设置300ms延迟防止误触
_holdTimer = Timer(const Duration(milliseconds: 200), () {
if (activeSpeaker == 0) {
if (speakerId == 1) {
controller.restoreOriginalAudioState();
} else {
controller.disableBluetoothAudio();
}
controller.setActiveSpeaker(speakerId);
}
});
@ -802,7 +796,8 @@ class TranslationView extends GetView<TranslationController> {
child: GestureDetector(
onTap: () => controller.loadMoreHistory(),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: Colors.red[50],
borderRadius: BorderRadius.circular(20),

2
local_plugins/agent_service/ios/agent_service/Package.swift

@ -3,7 +3,7 @@ import PackageDescription
let package = Package(
name: "agent_service",
platforms: [.iOS("18.0")],
platforms: [.iOS("16.0")],
products: [
.library(name: "agent-service", targets: ["agent_service"])
],

2
local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift

@ -324,7 +324,7 @@ class AgentServiceImpl: NSObject {
} else {
AudioSessionHub.shared.begin(.voice)
}
print("ai启动语音=\(audioSourceType)=\(useBle)")
guard let success = azureAsrHelper?.startContinuousRecognition(
// callback: self,
audioSourceType: audioSourceType

2
local_plugins/azure_speech/ios/azure_speech/Package.swift

@ -3,7 +3,7 @@ import PackageDescription
let package = Package(
name: "azure_speech",
platforms: [.iOS("18.0")],
platforms: [.iOS("16.0")],
products: [
.library(name: "azure-speech", targets: ["azure_speech"])
],

124
local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift

@ -149,7 +149,7 @@ public class AzureAsrHelper: NSObject {
return false
}
// 启动音频处理
audioStream?.startAudioInput()
audioStream?.startAudioInput(audioSourceType: audioSourceType)
// 开始连续识别
try recognizer?.startContinuousRecognition()
@ -172,7 +172,6 @@ public class AzureAsrHelper: NSObject {
* @return 是否成功停止
*/
public func stopContinuousRecognition() -> Bool {
print("stopContinuousRecognition")
guard speechConfig != nil else {
os_log("语音服务未初始化", log: log, type: .error)
return false
@ -238,7 +237,7 @@ public class AzureAsrHelper: NSObject {
recognizer = nil
speechConfig = nil
audioConfig = nil
audioStream = nil
// 确保状态被重置
_isContinuousRecognitionActive = false
//externalAudioStream = nil
@ -249,6 +248,7 @@ public class AzureAsrHelper: NSObject {
audioConfig = nil
recognizer = nil
speechConfig = nil
audioStream = nil
}
}
@ -302,7 +302,7 @@ public class AzureAsrHelper: NSObject {
if (audioStream == nil) {
// 创建外部音频拉流对象
// 明确指定使用外部音频源(推流模式)
audioStream = AudioStream(audioSourceType: audioSourceType)
audioStream = AudioStream()
audioStream?.initAudioRecord()
}
@ -328,28 +328,29 @@ public class AzureAsrHelper: NSObject {
return false
}
guard let recognizer = recognizer else { return false}
// 识别中事件
recognizer.addRecognizingEventHandler { [weak self] (sender, event) in
guard let self = self else { return }
print("识别中事件:")
let result = event.result
let detectedLanguage = self.getDetectedLanguage(from: result)
// os_log("识别中: %{public}@", log: self.log, type: .info, result.text ?? "")
// 直接在当前线程调用回调
// 正在识别事件
recognizer.addRecognizingEventHandler { [weak self] (_, event) in
guard let self = self else { return }
let result = event.result
let detectedLanguage = self.detectLanguage(from: result)
print("识别中事件: \(detectedLanguage)")
DispatchQueue.main.async {
callback.onRecognizing(result.text ?? "", detectedLanguage)
}
// 识别完成事件
recognizer.addRecognizedEventHandler { [weak self] (sender, event) in
guard let self = self else { return }
print("识别完成事件:")
let result = event.result
if result.reason == SPXResultReason.recognizedSpeech {
let detectedLanguage = self.getDetectedLanguage(from: result)
// 直接在当前线程调用回调
}
// 识别完成事件
recognizer.addRecognizedEventHandler { [weak self] (_, event) in
guard let self = self else { return }
let result = event.result
if result.reason == .recognizedSpeech {
let detectedLanguage = self.detectLanguage(from: result)
print("识别完成事件: \(detectedLanguage)")
DispatchQueue.main.async {
callback.onResult(result.text ?? "", detectedLanguage)
}
}
}
// 会话开始事件
recognizer.addSessionStartedEventHandler { (sender, event) in
@ -381,7 +382,16 @@ public class AzureAsrHelper: NSObject {
}
return true
}
// 提取的辅助方法
private func detectLanguage(from result: SPXSpeechRecognitionResult) -> String {
if isAutoDetectLanguage {
let langResult = try SPXAutoDetectSourceLanguageResult(result)
return langResult.language ?? ""
} else {
return currentLanguage
}
}
/**
* 获取检测到的语言
*/
@ -399,6 +409,7 @@ public class AzureAsrHelper: NSObject {
// 尝试另一种方式获取语言
do {
let langResult = try SPXAutoDetectSourceLanguageResult(result)
print("获取检测到的语言")
return langResult.language ?? ""
} catch {
return ""
@ -490,24 +501,26 @@ public class AzureAsrHelper: NSObject {
private let writeQueue = LinkedBlockingQueue<Data>()
private var audioEngine: AVAudioEngine?
private var audioFormat: AVAudioFormat?
private let audioSourceType: AudioSourceType // 添加引用
private let audioSession = AVAudioSession.sharedInstance()
private var audioSourceType = AudioSourceType.microphone
private var isRunning = false
public var isWriting = false
private let bufferSize: Int = 4096
private let writeThread = DispatchQueue(label: "audio.stream.writer")
init(audioSourceType: AudioSourceType) {
self.audioSourceType = audioSourceType
}
private var writeThread: DispatchQueue?
private var currentRoute: AudioOutputRoute?
/**
* 初始化
*/
public func initAudioRecord() {
print("初始化了")
audioFormat = getOptimalAudioFormat()
pushAudioStream = SPXPushAudioInputStream()
isRunning=true
// 创建新的写线程
writeThread = DispatchQueue(label: "audio.stream.writer")
startWriteThread()
self.setAudioOutputRoute(.receiver)
}
/// 获取最佳音频格式 (iOS 通常支持标准采样率)
@ -523,8 +536,9 @@ public class AzureAsrHelper: NSObject {
/**
* 开始音频输入
*/
public func startAudioInput() {
public func startAudioInput(audioSourceType: AudioSourceType = .microphone) {
isWriting=true
self.audioSourceType = audioSourceType;
print("startAudioInput=audioSourceType\(audioSourceType)")
switch audioSourceType {
case .microphone:
@ -538,10 +552,11 @@ public class AzureAsrHelper: NSObject {
* 开启音频写入线程
*/
public func startWriteThread() {
writeThread.async { [weak self] in
writeThread?.async { [weak self] in
guard let self = self else { return }
while self.isRunning {
print("是否写入: \(self.isWriting)")
if !self.isWriting {
usleep(10_000)
continue
@ -549,7 +564,7 @@ public class AzureAsrHelper: NSObject {
guard let dataToWrite = self.writeQueue.take() else { continue }
//print("写入数据长度: \(dataToWrite.count)")
print("写入数据长度: \(dataToWrite.count)")
self.pushAudioStream?.write(dataToWrite)
}
}
@ -565,14 +580,13 @@ public class AzureAsrHelper: NSObject {
if audioSourceType != .external {
return
}
print("外部data=\(data)")
// 放入队列,由写线程写入
writeQueue.put(data)
}
private func runMicrophoneCapture() {
do {
//self.setAudioOutputRoute(.speaker)
audioEngine = AVAudioEngine()
guard let inputNode = audioEngine?.inputNode else {
throw NSError(domain: "AudioSetup", code: 1)
@ -622,8 +636,10 @@ public class AzureAsrHelper: NSObject {
}
}
try audioEngine?.start()
// 重新激活
try audioSession.setActive(true, options: [.notifyOthersOnDeactivation])
try audioEngine?.start()
} catch {
print("麦克风启动失败: \(error)")
}
@ -664,23 +680,27 @@ public class AzureAsrHelper: NSObject {
if audioSourceType == .external {
//pushAudioData(data: Data())
audioEngine?.stop()
audioEngine?.inputNode.removeTap(onBus: 0)
audioEngine?.pause()
//audioEngine?.inputNode.removeTap(onBus: 0)
}
}
public func stopAudioCapture() {
guard isWriting==true else { return }
print("stopContinuousRecognition")
isWriting=false
audioEngine?.stop()
audioEngine?.pause()
audioEngine?.inputNode.removeTap(onBus: 0)
writeThread.async {
writeThread?.async {
self.writeQueue.close()
}
}
public func releaseAudioResources() {
print("释放了")
stopAudioCapture()
audioEngine?.stop()
writeThread = nil
audioEngine?.inputNode.removeTap(onBus: 0)
isRunning=false
audioEngine = nil
}
@ -692,13 +712,18 @@ public class AzureAsrHelper: NSObject {
case bluetooth
}
public func setAudioOutputRoute(_ route: AudioOutputRoute) {
let audioSession = AVAudioSession.sharedInstance()
guard currentRoute != route else { return }
print("setAudioOutputRoute")
do {
isWriting=false
try audioEngine?.stop()
//
if self.isWriting {
print("当前正在识别")
try audioEngine?.pause()
// 先停用以避免冲突
try audioSession.setActive(false)
}
switch route {
case .speaker:
// 使用扬声器时必须用videoChat模式
@ -728,12 +753,17 @@ public class AzureAsrHelper: NSObject {
try audioSession.overrideOutputAudioPort(.none)
// 不需要override,系统自动路由
}
self.currentRoute = route
if self.isWriting {
// 重新激活
try audioSession.setActive(true, options: [.notifyOthersOnDeactivation])
try audioEngine?.start()
isWriting=true
writeThread?.async {
self.writeQueue.close()
}
}
} catch {
print("路由切换失败: \(error)")
}

19
local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift

@ -185,6 +185,7 @@ import os.log
)
result(success)
case "stopContinuousRecognition":
let success = azureAsrHelper.stopContinuousRecognition()
currentAsrCallback = nil
result(success)
@ -277,16 +278,16 @@ import os.log
}
case "disableBluetoothAudio":
print("disableBluetoothAudio")
azureAsrHelper.disableBluetoothAudio();
azureTtsHelper.setAudioOutputDevice()
azureAsrHelper.disableBluetoothAudio();
azureTtsHelper.stop()
result(true)
case "restoreOriginalAudioState":
print("restoreOriginalAudioState")
azureAsrHelper.restoreOriginalAudioState();
azureTtsHelper.setAudioOutputDevice()
azureAsrHelper.restoreOriginalAudioState();
azureTtsHelper.stop()
result(true)
default:
@ -369,18 +370,18 @@ 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) {
// 强制使用耳机
azureAsrHelper.restoreOriginalAudioState();
azureTtsHelper.setAudioOutputDevice()
//azureTtsHelper.setAudioOutputDevice()
}
@ -405,7 +406,7 @@ private class AsrCallbackWrapper: AzureAsrHelper.ContinuousRecognizeCallback {
plugin?.sendAsrEvent([
"type": "result",
"text": text,
"language": detectedLanguage
"detectedLanguage": detectedLanguage
])
}
@ -413,7 +414,7 @@ private class AsrCallbackWrapper: AzureAsrHelper.ContinuousRecognizeCallback {
plugin?.sendAsrEvent([
"type": "recognizing",
"text": recognizing,
"language": detectedLanguage
"detectedLanguage": detectedLanguage
])
}

3
local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureTtsHelper.swift

@ -308,9 +308,10 @@ public class AzureTtsHelper: NSObject, ITtsService {
// 重新创建合成器以应用新设备
if isInitialized {
print(" 重新创建合成器以应用新设备")
recreateSynthesizer()
}
// 如果之前正在播放,恢复播放
if wasSpeaking, let lastText = lastSpokenText {
speakOnce(lastText)

2
local_plugins/ble_service/ios/ble_service/Package.swift

@ -3,7 +3,7 @@ import PackageDescription
let package = Package(
name: "ble_service",
platforms: [.iOS("18.0")],
platforms: [.iOS("16.0")],
products: [
.library(name: "ble-service", targets: ["ble_service"])
],

2
local_plugins/chat_storage/ios/chat_storage/Package.swift

@ -3,7 +3,7 @@ import PackageDescription
let package = Package(
name: "chat_storage",
platforms: [.iOS("18.0")],
platforms: [.iOS("16.0")],
products: [
.library(name: "chat-storage", targets: ["chat_storage"])
],

2
local_plugins/classic_bluetooth/ios/classic_bluetooth.podspec

@ -13,7 +13,7 @@ Pod::Spec.new do |s|
s.author = { 'YunQi Innovation' => 'support@yunqiinnovation.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.ios.deployment_target = '18.0'
s.ios.deployment_target = '16.0'
s.dependency 'Flutter'
s.swift_version = '5.0'

2
local_plugins/music_service/ios/music_service/Package.swift

@ -3,7 +3,7 @@ import PackageDescription
let package = Package(
name: "music_service",
platforms: [.iOS("18.0")],
platforms: [.iOS("16.0")],
products: [
.library(name: "music-service", targets: ["music_service"])
],

2
local_plugins/realtime/ios/realtime/Package.swift

@ -3,7 +3,7 @@ import PackageDescription
let package = Package(
name: "realtime",
platforms: [.iOS("18.0")],
platforms: [.iOS("16.0")],
products: [
.library(name: "realtime", targets: ["realtime"])
],

Loading…
Cancel
Save