From 17105a640bf5107bd5d333b9b4d097c14a3949a2 Mon Sep 17 00:00:00 2001 From: olivier2 Date: Sun, 25 Feb 2024 11:26:06 -0500 Subject: [PATCH] fix(android): audio issue when screen is off and broadcast audio session id (#1221 & #1247) * this change fixes the garbled audio on my Pixel 6a while the screen is off. Not familiar with libmpv, but seems to favor audiotrack audio output over opensles. KRTirtho/spotube#571 * get audio session id, send it to AudioTrack in libmpv, broadcast it to other apps. Fixes KRTirtho/spotube#1221 --------- Co-authored-by: Kingkor Roy Tirtho --- .../audio_player/mk_state_player.dart | 46 ++++++++++++++++++- pubspec.yaml | 1 + 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/lib/services/audio_player/mk_state_player.dart b/lib/services/audio_player/mk_state_player.dart index a556afecc..04df71110 100644 --- a/lib/services/audio_player/mk_state_player.dart +++ b/lib/services/audio_player/mk_state_player.dart @@ -1,8 +1,11 @@ import 'dart:async'; - +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:catcher_2/catcher_2.dart'; import 'package:collection/collection.dart'; import 'package:media_kit/media_kit.dart'; +import 'package:flutter_broadcasts/flutter_broadcasts.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:audio_session/audio_session.dart'; // ignore: implementation_imports import 'package:spotube/services/audio_player/playback_state.dart'; @@ -14,6 +17,13 @@ class MkPlayerWithState extends Player { final StreamController _shuffleStream; final StreamController _loopModeStream; + static const String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME"; + static const String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION"; + static const String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION = + "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"; + static const String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION = + "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"; + late final List _subscriptions; bool _shuffled; @@ -21,6 +31,9 @@ class MkPlayerWithState extends Player { Playlist? _playlist; List? _tempMedias; + int _androidAudioSessionId = 0; + String _packageName = ""; + AndroidAudioManager? _androidAudioManager; MkPlayerWithState({super.configuration}) : _playerStateStream = StreamController.broadcast(), @@ -64,6 +77,34 @@ class MkPlayerWithState extends Player { Catcher2.reportCheckedError('[MediaKitError] \n$event', null); }), ]; + PackageInfo.fromPlatform().then((packageInfo) { + _packageName = packageInfo.packageName; + }); + if (DesktopTools.platform.isAndroid) { + _androidAudioManager = AndroidAudioManager(); + AudioSession.instance.then((s) async { + _androidAudioSessionId = + await _androidAudioManager!.generateAudioSessionId(); + notifyAudioSessionUpdate(true); + + nativePlayer.setProperty( + "audiotrack-session-id", _androidAudioSessionId.toString()); + nativePlayer.setProperty("ao", "audiotrack,opensles,"); + }); + } + } + + Future notifyAudioSessionUpdate(bool active) async { + if (DesktopTools.platform.isAndroid) { + sendBroadcast(BroadcastMessage( + name: active + ? ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION + : ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION, + data: { + EXTRA_AUDIO_SESSION: _androidAudioSessionId, + EXTRA_PACKAGE_NAME: _packageName + })); + } } bool get shuffled => _shuffled; @@ -140,10 +181,11 @@ class MkPlayerWithState extends Player { } @override - Future dispose() { + Future dispose() async { for (var element in _subscriptions) { element.cancel(); } + await notifyAudioSessionUpdate(false); return super.dispose(); } diff --git a/pubspec.yaml b/pubspec.yaml index 9bacf6dd3..53da7ba7f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -124,6 +124,7 @@ dependencies: app_links: ^3.5.0 win32_registry: ^1.1.2 flutter_sharing_intent: ^1.1.0 + flutter_broadcasts: ^0.4.0 freezed_annotation: ^2.4.1 dev_dependencies: