// lib/services/audio_service.dart import 'dart:async'; import 'package:flutter/material.dart'; import 'package:media_kit/media_kit.dart'; import 'playback_service.dart'; // ============================================================ // 播放模式 // ============================================================ enum PlayMode { sequential, // 顺序循环 repeatOne, // 单曲循环 shuffle, // 随机播放 } // ============================================================ // 歌曲模型 // ============================================================ class Song { final String id; final String title; final String artist; final String? url; Song({ required this.id, required this.title, required this.artist, this.url, }); } // ============================================================ // AudioService - 播放状态管理与 UI 数据源 // ============================================================ class AudioService extends ChangeNotifier { // ---------- 单例 ---------- static final AudioService _instance = AudioService._internal(); factory AudioService() => _instance; AudioService._internal(); // ---------- 播放状态 ---------- Song? _currentSong; bool _isPlaying = false; Duration _position = Duration.zero; Duration _duration = Duration.zero; Duration _bufferedPosition = Duration.zero; // ---------- 播放模式 ---------- PlayMode _playMode = PlayMode.sequential; // ---------- 播放队列 ---------- List _queue = []; int _currentIndex = -1; // ---------- 随机播放相关 ---------- List _shuffledIndices = []; int _shuffledIndex = -1; // ---------- 监听控制 ---------- bool _listening = false; final List _subscriptions = []; // ---------- Getter ---------- Song? get currentSong => _currentSong; bool get isPlaying => _isPlaying; Duration get position => _position; Duration get duration => _duration; Duration get bufferedPosition => _bufferedPosition; PlayMode get playMode => _playMode; List get queue => List.unmodifiable(_queue); int get currentIndex => _currentIndex; bool get hasQueue => _queue.isNotEmpty; // ---------- 播放模式图标 ---------- IconData get playModeIcon { switch (_playMode) { case PlayMode.sequential: return Icons.repeat; case PlayMode.repeatOne: return Icons.repeat_one; case PlayMode.shuffle: return Icons.shuffle; } } // ---------- 播放模式切换 ---------- void togglePlayMode() { switch (_playMode) { case PlayMode.sequential: _playMode = PlayMode.repeatOne; break; case PlayMode.repeatOne: _playMode = PlayMode.shuffle; break; case PlayMode.shuffle: _playMode = PlayMode.sequential; break; } notifyListeners(); } // ---------- 设置播放队列 ---------- void setQueue(List queue, {int startIndex = 0}) { if (queue.isEmpty) { _clearQueue(); return; } _queue = List.from(queue); _currentIndex = startIndex.clamp(0, _queue.length - 1); // 初始化随机播放索引 _shuffledIndices = List.generate(_queue.length, (i) => i); _shuffledIndices.shuffle(); _shuffledIndex = _shuffledIndices.indexOf(_currentIndex); if (_shuffledIndex == -1) { _shuffledIndex = 0; _currentIndex = _shuffledIndices[0]; } // 播放当前歌曲 _playCurrent(); } // ---------- 清空队列 ---------- void _clearQueue() { _queue.clear(); _currentIndex = -1; _shuffledIndices.clear(); _shuffledIndex = -1; stopPlay(); } // ---------- 播放指定歌曲(外部入口) ---------- Future playSong(Song song) async { // 如果当前队列不包含这首歌,替换队列 if (_queue.isEmpty || _queue[_currentIndex].id != song.id) { setQueue([song], startIndex: 0); } else { // 如果已经在队列中,直接播放 _playCurrent(); } } // ---------- 播放当前索引歌曲 ---------- void _playCurrent() { if (_currentIndex < 0 || _currentIndex >= _queue.length) { stopPlay(); return; } final song = _queue[_currentIndex]; _currentSong = song; _position = Duration.zero; _duration = Duration.zero; _bufferedPosition = Duration.zero; _startListening(); notifyListeners(); if (song.url == null || song.url!.isEmpty) { return; } // 由 PlaybackService 实际播放,状态由流更新 PlaybackService().play(song.url!); } // ---------- 播放下一首 ---------- void next() { if (_queue.isEmpty) return; // 随机模式 if (_playMode == PlayMode.shuffle) { if (_shuffledIndices.isEmpty) return; final nextIdx = (_shuffledIndex + 1) % _shuffledIndices.length; _shuffledIndex = nextIdx; _currentIndex = _shuffledIndices[nextIdx]; _playCurrent(); return; } // 顺序/单曲模式 final nextIdx = (_currentIndex + 1) % _queue.length; _currentIndex = nextIdx; _playCurrent(); } // ---------- 播放上一首 ---------- void previous() { if (_queue.isEmpty) return; // 随机模式 if (_playMode == PlayMode.shuffle) { if (_shuffledIndices.isEmpty) return; final prevIdx = (_shuffledIndex - 1) % _shuffledIndices.length; if (prevIdx < 0) { _shuffledIndex = _shuffledIndices.length - 1; } else { _shuffledIndex = prevIdx; } _currentIndex = _shuffledIndices[_shuffledIndex]; _playCurrent(); return; } // 顺序/单曲模式 final prevIdx = (_currentIndex - 1) % _queue.length; if (prevIdx < 0) { _currentIndex = _queue.length - 1; } else { _currentIndex = prevIdx; } _playCurrent(); } // ---------- 播放/暂停切换 ---------- void togglePlay() { if (_currentSong == null) return; if (_isPlaying) { PlaybackService().pause(); } else { PlaybackService().resume(); } // 状态由 player.stream.playing 更新 } // ---------- 停止播放 ---------- void stopPlay() { _currentSong = null; _isPlaying = false; _position = Duration.zero; _duration = Duration.zero; _bufferedPosition = Duration.zero; _stopListening(); notifyListeners(); } // ---------- Seek ---------- void seekTo(Duration position) { PlaybackService().seek(position); _position = position; notifyListeners(); } // ---------- 处理播放结束 ---------- void _onPlaybackCompleted() { if (_queue.isEmpty) return; // 单曲循环模式 if (_playMode == PlayMode.repeatOne) { _playCurrent(); return; } // 其他模式:播放下一首 next(); } void clearQueue() { _queue.clear(); _currentIndex = -1; _shuffledIndices.clear(); _shuffledIndex = -1; stopPlay(); notifyListeners(); } // ---------- 监听 media_kit 状态 ---------- void _startListening() { if (_listening) return; _listening = true; final player = PlaybackService().player; _subscriptions.add( player.stream.playing.listen((playing) { if (_isPlaying != playing) { _isPlaying = playing; notifyListeners(); } }), ); _subscriptions.add( player.stream.position.listen((position) { if (_position != position) { _position = position; notifyListeners(); } }), ); _subscriptions.add( player.stream.duration.listen((duration) { if (_duration != duration) { _duration = duration; notifyListeners(); } }), ); _subscriptions.add( player.stream.buffer.listen((buffer) { if (_bufferedPosition != buffer) { _bufferedPosition = buffer; notifyListeners(); } }), ); // ✅ 播放结束监听 _subscriptions.add( player.stream.completed.listen((_) { _onPlaybackCompleted(); }), ); } void _stopListening() { _listening = false; for (final subscription in _subscriptions) { subscription.cancel(); } _subscriptions.clear(); } // ---------- 资源释放 ---------- void dispose() { _stopListening(); PlaybackService().dispose(); super.dispose(); } }