81 lines
2.9 KiB
Dart
81 lines
2.9 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:audio_session/audio_session.dart';
|
|
import 'package:hgdj/hj_page/short_video/view/video_player_base_logic.dart';
|
|
import 'package:hgdj/tools_base/debug_log.dart';
|
|
import 'package:hgdj/tools_base/event_bus/event_bus_util.dart';
|
|
import 'package:hgdj/tools_base/event_bus/events.dart';
|
|
|
|
/// 监听音频环境变化,自动暂停所有视频播放,防止音频通过手机外放泄露隐私:
|
|
/// 1. 耳机 / 蓝牙断开(音频切回外放)
|
|
/// 2. 来电、微信通话等其他 App 抢占音频(中断)
|
|
class HeadphoneMonitor {
|
|
HeadphoneMonitor._();
|
|
static final HeadphoneMonitor instance = HeadphoneMonitor._();
|
|
|
|
/// 断开后会导致音频切回外放的「私密」输出设备类型(移除时需暂停)
|
|
static const _privateOutputTypes = {
|
|
AudioDeviceType.bluetoothA2dp,
|
|
AudioDeviceType.bluetoothSco,
|
|
AudioDeviceType.wiredHeadset,
|
|
AudioDeviceType.wiredHeadphones,
|
|
AudioDeviceType.usbAudio,
|
|
};
|
|
|
|
bool _started = false;
|
|
StreamSubscription? _noisySub;
|
|
StreamSubscription? _interruptSub;
|
|
StreamSubscription? _deviceSub;
|
|
|
|
Future<void> start() async {
|
|
if (_started) return;
|
|
_started = true;
|
|
try {
|
|
final session = await AudioSession.instance;
|
|
await session.configure(const AudioSessionConfiguration.music());
|
|
// 耳机拔出 / 蓝牙断开(音频切回外放)
|
|
_noisySub = session.becomingNoisyEventStream.listen((_) {
|
|
debugLog('耳机断开 → 自动暂停所有播放');
|
|
pauseAll();
|
|
});
|
|
// 兜底:部分机型(华为/荣耀等)蓝牙断开不发 becomingNoisy 广播,改用更底层的设备移除回调兜底
|
|
_deviceSub = session.devicesChangedEventStream.listen((event) {
|
|
final unplugged = event.devicesRemoved
|
|
.any((d) => d.isOutput && _privateOutputTypes.contains(d.type));
|
|
if (unplugged) {
|
|
debugLog('音频输出设备移除(蓝牙/耳机) → 自动暂停所有播放');
|
|
pauseAll();
|
|
}
|
|
});
|
|
// 来电 / 微信通话等抢占音频(中断)→ 暂停;duck(短促提示音降音量)不处理
|
|
_interruptSub = session.interruptionEventStream.listen((event) {
|
|
if (event.begin && event.type != AudioInterruptionType.duck) {
|
|
debugLog('音频被打断(来电/通话等) → 自动暂停所有播放');
|
|
pauseAll();
|
|
}
|
|
});
|
|
} catch (e) {
|
|
_started = false;
|
|
debugLog('HeadphoneMonitor.start error: $e');
|
|
}
|
|
}
|
|
|
|
/// 暂停所有正在播放的视频(长视频/直播/简单播放器/短视频列表)
|
|
void pauseAll() {
|
|
// 长视频详情页 / 直播 / 简单播放器(统一走 eventBus)
|
|
eventBus.emit(PauseVideoEvent());
|
|
// 短视频列表页
|
|
VideoPlayerBaseLogic.pauseAll();
|
|
}
|
|
|
|
void dispose() {
|
|
_noisySub?.cancel();
|
|
_noisySub = null;
|
|
_interruptSub?.cancel();
|
|
_interruptSub = null;
|
|
_deviceSub?.cancel();
|
|
_deviceSub = null;
|
|
_started = false;
|
|
}
|
|
}
|