import 'dart:math'; import 'package:audio_service/audio_service.dart'; import 'package:logging/logging.dart'; import '../../domain/entities/loop_mode.dart'; import '../../domain/entities/playback_event.dart'; import '../../domain/entities/shuffle_mode.dart'; import '../datasources/music_data_source_contract.dart'; import '../models/playback_event_model.dart'; import '../models/queue_item_model.dart'; import '../models/song_model.dart'; import 'audio_player_contract.dart'; import 'stream_constants.dart'; class MyAudioHandler extends BaseAudioHandler { MyAudioHandler(this._musicDataSource, this._audioPlayer) { _audioPlayer.queueStream.listen((event) { _handleSetQueue(event); }); _audioPlayer.currentSongStream.listen((songModel) { mediaItemSubject.add(songModel.toMediaItem()); }); _audioPlayer.playbackEventStream.listen((event) { _handlePlaybackEvent(event); }); _audioPlayer.shuffleModeStream.listen((shuffleMode) { _musicDataSource.setShuffleMode(shuffleMode); customEventSubject.add({SHUFFLE_MODE: shuffleMode}); }); _audioPlayer.loopModeStream.listen((event) { _musicDataSource.setLoopMode(event); }); _initAudioPlayer(); } Future _initAudioPlayer() async { if (_musicDataSource.loopModeStream != null) { _audioPlayer.setLoopMode(await _musicDataSource.loopModeStream.first); } if (_musicDataSource.shuffleModeStream != null) { _audioPlayer.setShuffleMode(await _musicDataSource.shuffleModeStream.first, false); } if (_musicDataSource.queueStream != null && _musicDataSource.currentIndexStream != null) { _audioPlayer.loadQueue( queue: await _musicDataSource.queueStream.first, startIndex: await _musicDataSource.currentIndexStream.first, ); } } final AudioPlayer _audioPlayer; final MusicDataSource _musicDataSource; static final _log = Logger('AudioHandler'); @override Future stop() async { await _audioPlayer.stop(); await _audioPlayer.dispose(); await super.stop(); } @override Future play() async { _audioPlayer.play(); } @override Future pause() async { await _audioPlayer.pause(); } @override Future skipToNext() async { _audioPlayer.seekToNext(); } @override Future skipToPrevious() async { _audioPlayer.seekToPrevious(); } @override Future addQueueItem(MediaItem mediaItem) async { _audioPlayer.addToQueue(SongModel.fromMediaItem(mediaItem)); } @override Future customAction(String name, Map arguments) async { switch (name) { case PLAY_WITH_CONTEXT: final context = arguments['CONTEXT'] as List; final index = arguments['INDEX'] as int; return playWithContext(context, index); case APP_LIFECYCLE_RESUMED: return onAppLifecycleResumed(); case SET_SHUFFLE_MODE: return setCustomShuffleMode(arguments['SHUFFLE_MODE'] as ShuffleMode); case SET_LOOP_MODE: return setCustomLoopMode(arguments['LOOP_MODE'] as LoopMode); case SHUFFLE_ALL: return shuffleAll(); case MOVE_QUEUE_ITEM: return moveQueueItem(arguments['OLD_INDEX'] as int, arguments['NEW_INDEX'] as int); case REMOVE_QUEUE_ITEM: return removeQueueIndex(arguments as int); default: } } Future playWithContext(List context, int index) async { final songs = []; for (final path in context) { final song = await _musicDataSource.getSongByPath(path); songs.add(song); } _audioPlayer.playSongList(songs, index); } Future onAppLifecycleResumed() async { // customEventSubject.add({SHUFFLE_MODE: shuffleMode}); // customEventSubject.add({KEY_INDEX: playbackIndex}); } Future setCustomShuffleMode(ShuffleMode mode) async { _audioPlayer.setShuffleMode(mode, true); } Future setCustomLoopMode(LoopMode mode) async { _audioPlayer.setLoopMode(mode); } Future shuffleAll() async { _audioPlayer.setShuffleMode(ShuffleMode.plus, false); final List songs = await _musicDataSource.getSongs(); final rng = Random(); final index = rng.nextInt(songs.length); _audioPlayer.playSongList(songs, index); } Future moveQueueItem(int oldIndex, int newIndex) async { _audioPlayer.moveQueueItem(oldIndex, newIndex); } Future removeQueueIndex(int index) async { _audioPlayer.removeQueueIndex(index); } void _handleSetQueue(List queue) { _musicDataSource.setQueue(queue); final mediaItems = queue.map((e) => e.song.toMediaItem()).toList(); queueSubject.add(mediaItems); } void _handlePlaybackEvent(PlaybackEventModel pe) { if (pe.index != null) { _musicDataSource.setCurrentIndex(pe.index); customEventSubject.add({KEY_INDEX: pe.index}); } if (pe.processingState == ProcessingState.ready) { if (_audioPlayer.playingStream.value) { playbackStateSubject.add(playbackState.value.copyWith( controls: [MediaControl.skipToPrevious, MediaControl.pause, MediaControl.skipToNext], playing: true, processingState: AudioProcessingState.ready, updatePosition: pe.updatePosition, )); } else { playbackStateSubject.add(playbackState.value.copyWith( controls: [MediaControl.skipToPrevious, MediaControl.play, MediaControl.skipToNext], processingState: AudioProcessingState.ready, updatePosition: pe.updatePosition, playing: false, )); } } } }