import 'package:flutter/material.dart'; import 'package:audio_service/audio_service.dart'; import 'playback_service.dart'; import 'audio_service.dart' as local_audio; class AudioPlayerHandler extends BaseAudioHandler { final PlaybackService _playback = PlaybackService(); late final local_audio.AudioService _localAudio; // ⭐ 切歌锁,防止重复命令 bool _switchingTrack = false; AudioPlayerHandler() { _localAudio = local_audio.AudioService(); // ⭐ 唯一状态来源:media_kit 的 playing 流 _playback.player.stream.playing.listen((playing) { debugPrint('🎵 [stream] playing changed: $playing'); _updatePlaybackState(playing: playing); }); // ⭐ 播放完成 → 触发下一首(不直接广播状态) _playback.player.stream.completed.listen((_) { debugPrint('🎵 [stream] completed, auto next'); _localAudio.next(); // 触发切歌,playing 流会自然变化 // 不调用 _updatePlaybackState() }); // ⭐ 歌曲变化 → 更新媒体信息(独立于播放状态) // 这里用 duration 变化作为“歌曲已切换”的信号 _playback.player.stream.duration.listen((duration) { if (duration.inMilliseconds > 0) { _syncMediaItem(); } }); } // ============================================================ // 状态同步链(只能由 playing 流触发) // ============================================================ void _updatePlaybackState({bool? playing}) { final isPlaying = playing ?? _playback.player.state.playing; debugPrint('🎵 _updatePlaybackState: isPlaying=$isPlaying'); final controls = [ MediaControl.skipToPrevious, if (isPlaying) MediaControl.pause else MediaControl.play, MediaControl.skipToNext, ]; debugPrint('🎵 controls: ${controls.map((c) => c.action).join(', ')}'); playbackState.add(PlaybackState( controls: controls, processingState: AudioProcessingState.ready, playing: isPlaying, androidCompactActionIndices: const [0, 1, 2], updateTime: DateTime.now(), )); } // ============================================================ // 媒体信息同步链(独立于播放状态) // ============================================================ void _syncMediaItem() { final song = _localAudio.currentSong; if (song != null) { debugPrint('🎵 [sync] media item: ${song.title}'); mediaItem.add(MediaItem( id: song.id, title: song.title, artist: song.artist, duration: _playback.player.state.duration, )); } } void updateNotification({ required String id, required String title, required String artist, }) { mediaItem.add(MediaItem( id: id, title: title, artist: artist, duration: _playback.player.state.duration, )); _updatePlaybackState(); } // ============================================================ // 控制命令(只发命令,不宣布状态) // ============================================================ @override Future play() async { debugPrint('🎵 [audio_service] play() called'); await _playback.resume(); // ⭐ 不调用 _updatePlaybackState() // 等待 playing 流触发 } @override Future pause() async { debugPrint('🎵 [audio_service] pause() called'); await _playback.pause(); // ⭐ 不调用 _updatePlaybackState() } @override Future stop() async { debugPrint('🎵 [audio_service] stop() called'); await _playback.stop(); // ⭐ 不调用 _updatePlaybackState() } @override Future seek(Duration position) async { debugPrint('🎵 [audio_service] seek() called: $position'); await _playback.seek(position); } @override Future skipToNext() async { if (_switchingTrack) { debugPrint('🎵 skipToNext ignored: already switching'); return; } _switchingTrack = true; try { debugPrint('🎵 [audio_service] skipToNext() called'); await _localAudio.next(); // ⭐ 不调用 _updatePlaybackState() // playing 流和 duration 流会自然触发状态更新 } finally { // ⭐ 用真实状态释放锁,不用时间 await Future.delayed(const Duration(milliseconds: 50)); _switchingTrack = false; } } @override Future skipToPrevious() async { if (_switchingTrack) { debugPrint('🎵 skipToPrevious ignored: already switching'); return; } _switchingTrack = true; try { debugPrint('🎵 [audio_service] skipToPrevious() called'); await _localAudio.previous(); } finally { await Future.delayed(const Duration(milliseconds: 50)); _switchingTrack = false; } } // ============================================================ // click():薄路由层,不操作播放器 // ============================================================ @override Future click([MediaButton button = MediaButton.media]) async { debugPrint('🎵 [audio_service] click(): ${button.name} (index: ${button.index})'); // ⭐ 用 button.name 判断,不用 index final name = button.name.toLowerCase(); // 路由到标准方法 if (name.contains('next') || name == 'next') { await skipToNext(); return; } if (name.contains('previous') || name == 'previous') { await skipToPrevious(); return; } if (name.contains('pause')) { await pause(); return; } if (name.contains('play') || name.contains('media')) { await play(); return; } // fallback: 根据当前播放状态 toggle debugPrint('🎵 → fallback toggle'); if (_playback.player.state.playing) { await pause(); } else { await play(); } } }