|
|
@ -541,11 +541,19 @@ public class AudioSessionHub { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private func performVolumeControlWithMPVolumeView(action: VolumeControlAction, value: Float?, completion: @escaping (Bool, String) -> Void) { |
|
|
private func performVolumeControlWithMPVolumeView(action: VolumeControlAction, value: Float?, completion: @escaping (Bool, String) -> Void) { |
|
|
// 创建更大的 frame,有助于子视图正确初始化 |
|
|
// 确保在有音频会话的情况下进行音量控制 |
|
|
|
|
|
do { |
|
|
|
|
|
try audioSession.setActive(true) |
|
|
|
|
|
// 设置为播放类别,这样音量控制才能生效 |
|
|
|
|
|
try audioSession.setCategory(.playback, mode: .default, options: []) |
|
|
|
|
|
} catch { |
|
|
|
|
|
os_log("设置音频会话失败: %{public}@", log: logger, type: .error, error.localizedDescription) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
let volumeView = MPVolumeView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) |
|
|
let volumeView = MPVolumeView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) |
|
|
volumeView.showsVolumeSlider = true |
|
|
volumeView.showsVolumeSlider = true |
|
|
volumeView.showsRouteButton = false |
|
|
volumeView.showsRouteButton = false |
|
|
volumeView.alpha = 0.01 // 几乎透明 |
|
|
volumeView.alpha = 0.01 |
|
|
|
|
|
|
|
|
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, |
|
|
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, |
|
|
let window = windowScene.windows.first else { |
|
|
let window = windowScene.windows.first else { |
|
|
@ -557,71 +565,63 @@ public class AudioSessionHub { |
|
|
volumeView.setNeedsLayout() |
|
|
volumeView.setNeedsLayout() |
|
|
volumeView.layoutIfNeeded() |
|
|
volumeView.layoutIfNeeded() |
|
|
|
|
|
|
|
|
var retryCount = 0 |
|
|
// 增加延迟时间,确保滑块完全初始化 |
|
|
let maxRetries = 5 |
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { |
|
|
|
|
|
func findSliderRecursively(in view: UIView) -> UISlider? { |
|
|
func attemptVolumeControl() { |
|
|
if let slider = view as? UISlider { |
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { |
|
|
return slider |
|
|
os_log("尝试第 %d 次音量控制", log: self.logger, type: .debug, retryCount + 1) |
|
|
} |
|
|
|
|
|
for subview in view.subviews { |
|
|
// 递归查找滑块 |
|
|
if let foundSlider = findSliderRecursively(in: subview) { |
|
|
func findSliderRecursively(in view: UIView) -> UISlider? { |
|
|
return foundSlider |
|
|
if let slider = view as? UISlider { |
|
|
|
|
|
return slider |
|
|
|
|
|
} |
|
|
|
|
|
for subview in view.subviews { |
|
|
|
|
|
if let foundSlider = findSliderRecursively(in: subview) { |
|
|
|
|
|
return foundSlider |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
return nil |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
return nil |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if let slider = findSliderRecursively(in: volumeView) { |
|
|
|
|
|
let currentValue = slider.value |
|
|
|
|
|
let newValue: Float |
|
|
|
|
|
|
|
|
if let slider = findSliderRecursively(in: volumeView) { |
|
|
switch action { |
|
|
let currentValue = slider.value |
|
|
case .increase: |
|
|
let newValue: Float |
|
|
newValue = min(currentValue + 0.1, 1.0) // 改回0.1避免变化过大 |
|
|
|
|
|
case .decrease: |
|
|
switch action { |
|
|
newValue = max(currentValue - 0.1, 0.0) |
|
|
case .increase: |
|
|
case .mute: |
|
|
newValue = min(currentValue + 0.2, 1.0) // 从 0.1 改为 0.2 (20%) |
|
|
newValue = 0.0 |
|
|
case .decrease: |
|
|
case .setMax: |
|
|
newValue = max(currentValue - 0.2, 0.0) // 从 0.1 改为 0.2 (20%) |
|
|
newValue = 1.0 |
|
|
case .mute: |
|
|
case .setValue(let val): |
|
|
newValue = 0.0 |
|
|
newValue = max(0.0, min(val, 1.0)) |
|
|
case .setMax: |
|
|
} |
|
|
newValue = 1.0 |
|
|
|
|
|
case .setValue(let val): |
|
|
os_log("设置音量从 %.2f 到 %.2f", log: self.logger, type: .info, currentValue, newValue) |
|
|
newValue = max(0.0, min(val, 1.0)) |
|
|
|
|
|
} |
|
|
// 模拟用户触摸操作 |
|
|
|
|
|
slider.setValue(newValue, animated: true) |
|
|
os_log("设置音量从 %.2f 到 %.2f", log: self.logger, type: .info, currentValue, newValue) |
|
|
slider.sendActions(for: .touchDown) |
|
|
|
|
|
slider.sendActions(for: .valueChanged) |
|
|
|
|
|
slider.sendActions(for: .touchUpInside) |
|
|
|
|
|
|
|
|
|
|
|
// 再次确认设置 |
|
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { |
|
|
slider.value = newValue |
|
|
slider.value = newValue |
|
|
slider.sendActions(for: .valueChanged) |
|
|
slider.sendActions(for: .valueChanged) |
|
|
slider.sendActions(for: .touchUpInside) |
|
|
|
|
|
|
|
|
|
|
|
let message = self.getVolumeActionMessage(action: action) |
|
|
|
|
|
completion(true, message) |
|
|
|
|
|
volumeView.removeFromSuperview() |
|
|
|
|
|
} else { |
|
|
|
|
|
retryCount += 1 |
|
|
|
|
|
if retryCount < maxRetries { |
|
|
|
|
|
os_log("音量控制重试 %d/%d", log: self.logger, type: .debug, retryCount, maxRetries) |
|
|
|
|
|
attemptVolumeControl() |
|
|
|
|
|
} else { |
|
|
|
|
|
os_log("所有重试都失败,使用备选方案", log: self.logger, type: .error) |
|
|
|
|
|
volumeView.removeFromSuperview() |
|
|
|
|
|
|
|
|
|
|
|
// 备选方案:至少记录当前音量状态 |
|
|
|
|
|
let currentVolume = self.audioSession.outputVolume |
|
|
|
|
|
let message = "音量控制请求已处理(当前音量: \(Int(currentVolume * 100))%)" |
|
|
|
|
|
completion(true, message) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let message = self.getVolumeActionMessage(action: action) |
|
|
|
|
|
completion(true, message) |
|
|
|
|
|
volumeView.removeFromSuperview() |
|
|
|
|
|
} else { |
|
|
|
|
|
os_log("无法找到音量滑块", log: self.logger, type: .error) |
|
|
|
|
|
volumeView.removeFromSuperview() |
|
|
|
|
|
|
|
|
|
|
|
// 提供用户友好的反馈 |
|
|
|
|
|
let message = "音量控制需要在播放音频时才能生效,请先播放音频后再调整音量" |
|
|
|
|
|
completion(false, message) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
attemptVolumeControl() |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private func getVolumeActionMessage(action: VolumeControlAction) -> String { |
|
|
private func getVolumeActionMessage(action: VolumeControlAction) -> String { |
|
|
|