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

191 lines
7.3 KiB

import Foundation
import AVFoundation
/// 统一音频会话管理类
/// 用于统一管理所有组件的音频会话配置
@objc class AudioSessionManager: NSObject {
// MARK: - 单例实现
@objc static let shared = AudioSessionManager()
// 音频会话
private let audioSession = AVAudioSession.sharedInstance()
// 是否已经配置过音频会话
private var isConfigured = false
// 当前配置类型
private var currentCategory: AVAudioSession.Category = .playAndRecord
private var currentMode: AVAudioSession.Mode = .default
private var currentOptions: AVAudioSession.CategoryOptions = [.allowBluetooth, .allowBluetoothA2DP]
// 私有初始化方法,确保只能通过shared访问
private override init() {
super.init()
NSLog("[AudioSessionManager] 音频会话管理器已初始化")
}
// MARK: - 音频会话配置
/// 在应用启动时调用一次性配置方法
/// - Parameters:
/// - category: 音频会话类别
/// - mode: 音频会话模式
/// - options: 音频会话选项
/// - Returns: 是否配置成功
@objc func initialConfiguration(category: AVAudioSession.Category = .playAndRecord,
mode: AVAudioSession.Mode = .default,
options: AVAudioSession.CategoryOptions = [.allowBluetooth, .allowBluetoothA2DP]) -> Bool {
if isConfigured {
NSLog("[AudioSessionManager] 音频会话已经配置过,忽略初始化请求")
return true
}
do {
NSLog("[AudioSessionManager] 执行一次性音频会话配置: \(category)")
try audioSession.setCategory(category, mode: mode, options: options)
try audioSession.setActive(true)
// 记录当前配置
currentCategory = category
currentMode = mode
currentOptions = options
isConfigured = true
return true
} catch {
NSLog("[AudioSessionManager] 一次性配置音频会话失败: \(error.localizedDescription)")
return false
}
}
/// 配置音频会话,适用于语音识别和合成
@objc func configureForVoiceProcessing() throws {
if !applyConfigurationIfNeeded(category: .playAndRecord,
mode: .spokenAudio,
options: [.allowBluetooth, .allowBluetoothA2DP, .duckOthers]) {
NSLog("[AudioSessionManager] 使用已存在的音频会话配置,跳过语音处理模式配置")
}
}
/// 配置音频会话,适用于蓝牙耳机连接和监听
@objc func configureForBluetoothHeadset() throws {
if !applyConfigurationIfNeeded(category: .playAndRecord,
mode: .default,
options: [.allowBluetooth, .allowBluetoothA2DP]) {
NSLog("[AudioSessionManager] 使用已存在的音频会话配置,跳过蓝牙耳机模式配置")
}
}
/// 配置音频会话,适用于媒体播放和蓝牙媒体按钮
@objc func configureForMediaPlayback() throws {
if !applyConfigurationIfNeeded(category: .playback,
mode: .default,
options: [.allowBluetooth, .allowBluetoothA2DP]) {
NSLog("[AudioSessionManager] 使用已存在的音频会话配置,跳过媒体播放模式配置")
}
}
/// 配置自定义音频会话
@objc func configure(category: AVAudioSession.Category,
mode: AVAudioSession.Mode,
options: AVAudioSession.CategoryOptions) throws {
if !applyConfigurationIfNeeded(category: category, mode: mode, options: options) {
NSLog("[AudioSessionManager] 使用已存在的音频会话配置,跳过自定义模式配置")
}
}
/// 内部方法:如果尚未配置,应用新的配置
private func applyConfigurationIfNeeded(category: AVAudioSession.Category,
mode: AVAudioSession.Mode,
options: AVAudioSession.CategoryOptions) -> Bool {
// 如果已经配置过,不再重复配置
if isConfigured {
return false
}
do {
NSLog("[AudioSessionManager] 应用音频会话配置: \(category)")
try audioSession.setCategory(category, mode: mode, options: options)
try audioSession.setActive(true)
// 记录当前配置
currentCategory = category
currentMode = mode
currentOptions = options
isConfigured = true
return true
} catch {
NSLog("[AudioSessionManager] 配置音频会话失败: \(error.localizedDescription)")
return false
}
}
/// 获取当前音频会话的配置信息
@objc func getCurrentConfiguration() -> [String: Any] {
return [
"isConfigured": isConfigured,
"category": "\(currentCategory)",
"mode": "\(currentMode)"
]
}
/// 仅在特殊情况下使用:强制重新配置音频会话
@objc func forceReconfigure() -> Bool {
isConfigured = false
do {
NSLog("[AudioSessionManager] 强制重新配置音频会话")
try audioSession.setCategory(currentCategory, mode: currentMode, options: currentOptions)
try audioSession.setActive(true)
isConfigured = true
return true
} catch {
NSLog("[AudioSessionManager] 强制重新配置失败: \(error.localizedDescription)")
return false
}
}
/// 激活音频会话(如果已配置)
@objc func activateSession() throws {
if isConfigured {
try audioSession.setActive(true)
} else {
NSLog("[AudioSessionManager] 警告: 尝试激活未配置的音频会话")
// 应用默认配置并激活
try applyConfigurationIfNeeded(category: .playAndRecord,
mode: .default,
options: [.allowBluetooth, .allowBluetoothA2DP])
}
}
/// 停用音频会话(保留配置)
@objc func deactivateSession() throws {
try audioSession.setActive(false, options: .notifyOthersOnDeactivation)
}
/// 获取当前音频会话路由描述
@objc func getCurrentRoute() -> AVAudioSessionRouteDescription {
return audioSession.currentRoute
}
/// 添加路由变化监听器
@objc func addRouteChangeListener(_ observer: Any, selector: Selector) {
NotificationCenter.default.addObserver(
observer,
selector: selector,
name: AVAudioSession.routeChangeNotification,
object: nil
)
}
/// 移除路由变化监听器
@objc func removeRouteChangeListener(_ observer: Any) {
NotificationCenter.default.removeObserver(
observer,
name: AVAudioSession.routeChangeNotification,
object: nil
)
}
}