Equalizer (nativ), Dolby-Atmos-Zugang und Auto-Wiedergabe bei Kopfhoerern

- Native Bruecke AudioEffectsBridge.kt: Equalizer + BassBoost + Virtualizer
  auf der Audio-Session des Players, inkl. System-Klangeffekt-Panel
- Dart-Seite AudioEffects: Presets, Baender, Bass/Immersiv, persistiert
- EqualizerScreen nach Vorlage inkl. Drehregler (CustomPainter)
- Auto-Wiedergabe bei verbundenen Kopfhoerern (Klinke + Bluetooth)
- MODIFY_AUDIO_SETTINGS im Manifest
- Einstellungen: neuer Bereich "Ton"

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011snPXPafPC5i87o68H14W7
This commit is contained in:
2026-08-20 18:35:06 +02:00
co-authored by Claude Opus 5
parent 7aa98864aa
commit 1325badf90
13 changed files with 1020 additions and 1 deletions
+29
View File
@@ -1,10 +1,12 @@
import 'dart:async';
import 'package:audio_service/audio_service.dart';
import 'package:audio_session/audio_session.dart';
import 'package:just_audio/just_audio.dart';
import '../library/database.dart';
import '../services/cache_manager.dart';
import '../services/navidrome_service.dart';
import 'headphone_autoplay.dart';
import 'sleep_timer.dart';
/// Entscheidet, ob eine gespeicherte Wiedergabeposition beim Laden
@@ -37,6 +39,10 @@ class MeloAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
final NavidromeService _nav = NavidromeService();
int? _lastCountedIndex;
/// Wiedergabe automatisch starten, sobald Kopfhörer verbunden werden.
/// Wird von den App-Einstellungen gesetzt.
bool autoPlayOnHeadphones = false;
MeloAudioHandler({required this.db}) {
_cache = CacheManager();
_cache.init();
@@ -71,6 +77,8 @@ class MeloAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
}
});
_watchHeadphones();
// Ermittelte Dauer nachtragen
_player.durationStream.listen((duration) {
final item = mediaItem.value;
@@ -80,6 +88,27 @@ class MeloAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
});
}
/// Startet die Wiedergabe, wenn Kopfhörer verbunden werden und der Nutzer
/// das in den Einstellungen erlaubt hat.
Future<void> _watchHeadphones() async {
final session = await AudioSession.instance;
session.devicesChangedEventStream.listen((event) {
final added = event.devicesAdded.map((d) => d.type).toSet();
if (shouldAutoPlay(
added: added,
enabled: autoPlayOnHeadphones,
hasQueue: queue.value.isNotEmpty,
playing: _player.playing,
)) {
play();
}
});
}
/// Audio-Session des Players — die Klangeffekte hängen daran.
Stream<int?> get androidAudioSessionIdStream =>
_player.androidAudioSessionIdStream;
/// Ersetzt die Warteschlange und startet ab [startIndex].
/// Auto-Caching: Streame von Server + speichere lokal gleichzeitig.
Future<void> loadPlaylist(List<MediaItem> items, {int startIndex = 0}) async {