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 a34ee7790..e55663cc4 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 @@ -18,7 +18,7 @@ import ble_service // 日志标签 private let tag = "AzureSpeechPlugin" // 日志对象 - private let log = OSLog(subsystem: "com.azure.speech", category: "AzureSpeechPlugin") + internal let log = OSLog(subsystem: "com.azure.speech", category: "AzureSpeechPlugin") // MARK: - 防抖相关(iOS 原生层) // 函数级注释:用于限制 startContinuousRecognition/stopContinuousRecognition 在极短时间内的重复触发 @@ -269,7 +269,7 @@ private func sendAstEvent(_ event: [String: Any]) { * @param wavData WAV格式的音频数据 * @return 纯PCM音频数据,如果提取失败则返回空Data */ - private func extractPcmFromWav(_ wavData: Data) -> Data { + internal func extractPcmFromWav(_ wavData: Data) -> Data { // WAV文件头最小长度为44字节 guard wavData.count >= 44 else { os_log("WAV数据长度不足,无法解析文件头", log: log, type: .error) @@ -1011,15 +1011,15 @@ private class AstEventCallback: IntegratedSpeechTranslationService.ServiceEventC public func onSynthesisAudioGenerated(text: String, audioData: Data) { guard let plugin = plugin else { return } - plugin.os_log("语音合成音频生成,文本=%@,音频数据大小=%d", log: plugin.log, type: .info, text, audioData.count) + os_log("语音合成音频生成,文本=%@,音频数据大小=%d", log: plugin.log, type: .info, text, audioData.count) // Azure TTS返回的是RIFF WAV格式,需要去除文件头提取PCM数据 let pcmData = plugin.extractPcmFromWav(audioData) if !pcmData.isEmpty { - plugin.os_log("提取PCM数据,大小=%d字节", log: plugin.log, type: .info, pcmData.count) + os_log("提取PCM数据,大小=%d字节", log: plugin.log, type: .info, pcmData.count) BleService.shared.writeExternalAudioData(data: pcmData) } else { - plugin.os_log("提取PCM数据失败,音频数据可能不是WAV格式", log: plugin.log, type: .error) + os_log("提取PCM数据失败,音频数据可能不是WAV格式", log: plugin.log, type: .error) } // plugin?.sendAsrEvent([ diff --git a/local_plugins/music_service/ios/music_service/Sources/music_service/MusicService.swift b/local_plugins/music_service/ios/music_service/Sources/music_service/MusicService.swift index 52d1c4228..40bcfbc9e 100644 --- a/local_plugins/music_service/ios/music_service/Sources/music_service/MusicService.swift +++ b/local_plugins/music_service/ios/music_service/Sources/music_service/MusicService.swift @@ -52,10 +52,24 @@ public class MusicService: NSObject { // MARK: - 音频会话设置 private func setupAudioSession() { do { - try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.allowAirPlay, .allowBluetooth]) + // 设置音频会话类别,添加 mixWithOthers 选项以确保通知正常显示 + try AVAudioSession.sharedInstance().setCategory( + .playback, + mode: .default, + options: [.allowAirPlay, .allowBluetooth, .mixWithOthers] + ) try AVAudioSession.sharedInstance().setActive(true) + print("🎵 [MusicService] ✅ 音频会话设置成功") } catch { - print("设置音频会话失败: \(error)") + print("🎵 [MusicService] ❌ 设置音频会话失败: \(error)") + // 尝试备用配置 + do { + try AVAudioSession.sharedInstance().setCategory(.playback) + try AVAudioSession.sharedInstance().setActive(true) + print("🎵 [MusicService] ✅ 使用备用音频会话配置") + } catch { + print("🎵 [MusicService] ❌ 备用音频会话配置也失败: \(error)") + } } } @@ -570,30 +584,51 @@ public class MusicService: NSObject { private func setupRemoteCommandCenter() { let commandCenter = MPRemoteCommandCenter.shared() - commandCenter.playCommand.addTarget { [unowned self] _ in - self.resume() + // 清除之前的目标,避免重复添加 + commandCenter.playCommand.removeTarget(nil) + commandCenter.pauseCommand.removeTarget(nil) + commandCenter.nextTrackCommand.removeTarget(nil) + commandCenter.previousTrackCommand.removeTarget(nil) + commandCenter.stopCommand.removeTarget(nil) + + // 启用命令 + commandCenter.playCommand.isEnabled = true + commandCenter.pauseCommand.isEnabled = true + commandCenter.nextTrackCommand.isEnabled = true + commandCenter.previousTrackCommand.isEnabled = true + commandCenter.stopCommand.isEnabled = true + + commandCenter.playCommand.addTarget { [weak self] _ in + print("🎵 [RemoteCommand] 播放命令触发") + self?.resume() return .success } - commandCenter.pauseCommand.addTarget { [unowned self] _ in - self.pause() + commandCenter.pauseCommand.addTarget { [weak self] _ in + print("🎵 [RemoteCommand] 暂停命令触发") + self?.pause() return .success } - commandCenter.nextTrackCommand.addTarget { [unowned self] _ in - self.next() + commandCenter.nextTrackCommand.addTarget { [weak self] _ in + print("🎵 [RemoteCommand] 下一首命令触发") + self?.next() return .success } - commandCenter.previousTrackCommand.addTarget { [unowned self] _ in - self.previous() + commandCenter.previousTrackCommand.addTarget { [weak self] _ in + print("🎵 [RemoteCommand] 上一首命令触发") + self?.previous() return .success } - commandCenter.stopCommand.addTarget { [unowned self] _ in - self.stop() + commandCenter.stopCommand.addTarget { [weak self] _ in + print("🎵 [RemoteCommand] 停止命令触发") + self?.stop() return .success } + + print("🎵 [MusicService] ✅ 远程控制中心设置完成") } private func updateNowPlayingInfo(song: [String: Any]) { @@ -641,7 +676,11 @@ public class MusicService: NSObject { nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = Double(currentPosition) / 1000.0 nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = isPlaying ? 1.0 : 0.0 - MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo + // 确保在主线程更新 + DispatchQueue.main.async { + MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo + print("🎵 [MusicService] ✅ 媒体会话进度已更新: \(currentPosition/1000)s/\(duration/1000)s") + } } /// 启用媒体会话回调 @@ -714,9 +753,15 @@ public class MusicService: NSObject { /// 更新媒体会话播放状态 public func updateMediaSessionPlaybackState(isPlaying: Bool) { self.isPlaying = isPlaying - var nowPlayingInfo = MPNowPlayingInfoCenter.default().nowPlayingInfo ?? [:] - nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = isPlaying ? 1.0 : 0.0 - MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo + + // 确保在主线程更新 + DispatchQueue.main.async { + var nowPlayingInfo = MPNowPlayingInfoCenter.default().nowPlayingInfo ?? [:] + nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = isPlaying ? 1.0 : 0.0 + MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo + + print("🎵 [MusicService] ✅ 媒体会话播放状态已更新: \(isPlaying ? "播放中" : "已暂停")") + } if isPlaying { startProgressTimer()