mucke/lib/system/audio/audio_player_impl.dart
2020-12-20 16:21:48 +01:00

244 lines
8.2 KiB
Dart

import 'package:just_audio/just_audio.dart' as ja;
import 'package:rxdart/rxdart.dart';
import '../../domain/entities/loop_mode.dart';
import '../../domain/entities/queue_item.dart';
import '../../domain/entities/shuffle_mode.dart';
import '../models/loop_mode_model.dart';
import '../models/playback_event_model.dart';
import '../models/queue_item_model.dart';
import '../models/song_model.dart';
import 'audio_player_contract.dart';
import 'queue_generator.dart';
class AudioPlayerImpl implements AudioPlayer {
AudioPlayerImpl(this._audioPlayer, this._queueGenerator) {
_audioPlayer.currentIndexStream.listen((event) {
print('currentIndex: $event');
_currentIndexSubject.add(event);
if (_queueSubject.value != null) {
_currentSongSubject.add(_queueSubject.value[event].song);
}
});
_audioPlayer.playingStream.listen((event) => _playingSubject.add(event));
_audioPlayer.playbackEventStream.listen((event) {
_playbackEventSubject.add(PlaybackEventModel.fromJAPlaybackEvent(event));
});
_audioPlayer.positionStream.listen((event) {
_positionSubject.add(event);
});
_audioPlayer.loopModeStream.listen((event) {
_loopModeSubject.add(event.toEntity());
});
_queueSubject.listen((event) {
if (_currentIndexSubject.value != null) {
_currentSongSubject.add(event[_currentIndexSubject.value].song);
}
});
}
final ja.AudioPlayer _audioPlayer;
ja.ConcatenatingAudioSource _audioSource;
final QueueGenerator _queueGenerator;
List<SongModel> _inputQueue;
List<QueueItemModel> _queue;
final BehaviorSubject<int> _currentIndexSubject = BehaviorSubject();
final BehaviorSubject<SongModel> _currentSongSubject = BehaviorSubject();
final BehaviorSubject<PlaybackEventModel> _playbackEventSubject = BehaviorSubject();
final BehaviorSubject<bool> _playingSubject = BehaviorSubject();
final BehaviorSubject<Duration> _positionSubject = BehaviorSubject();
final BehaviorSubject<List<QueueItemModel>> _queueSubject = BehaviorSubject();
final BehaviorSubject<ShuffleMode> _shuffleModeSubject = BehaviorSubject.seeded(ShuffleMode.none);
final BehaviorSubject<LoopMode> _loopModeSubject = BehaviorSubject();
@override
ValueStream<int> get currentIndexStream => _currentIndexSubject.stream;
@override
ValueStream<SongModel> get currentSongStream => _currentSongSubject.stream;
@override
ValueStream<PlaybackEventModel> get playbackEventStream => _playbackEventSubject.stream;
@override
ValueStream<Duration> get positionStream => _positionSubject.stream;
@override
ValueStream<bool> get playingStream => _playingSubject.stream;
@override
ValueStream<List<QueueItemModel>> get queueStream => _queueSubject.stream;
@override
ValueStream<ShuffleMode> get shuffleModeStream => _shuffleModeSubject.stream;
@override
ValueStream<LoopMode> get loopModeStream => _loopModeSubject.stream;
@override
Future<void> dispose() async {
await _currentIndexSubject.close();
await _currentSongSubject.close();
await _playbackEventSubject.close();
await _positionSubject.close();
await _queueSubject.close();
await _shuffleModeSubject.close();
await _loopModeSubject.close();
await _audioPlayer.dispose();
}
@override
Future<void> loadQueue({List<QueueItemModel> queue, int startIndex = 0}) async {
if (queue == null || queue.isEmpty ) {
return;
}
if (startIndex >= queue.length) {
print('$startIndex >= ${queue.length}');
return;
}
_audioSource = _queueGenerator.songModelsToAudioSource([queue[startIndex].song]);
await _audioPlayer.setAudioSource(_audioSource);
// await _audioPlayer.load();
final songModelQueue = queue.map((e) => e.song).toList();
_queueSubject.add(queue);
final completeAudioSource = _queueGenerator.songModelsToAudioSource(songModelQueue);
_audioSource.insertAll(0, completeAudioSource.children.sublist(0, startIndex));
_audioSource.addAll(
completeAudioSource.children.sublist(startIndex + 1, completeAudioSource.length),
);
}
@override
Future<void> pause() async {
await _audioPlayer.pause();
}
@override
Future<void> play() async {
await _audioPlayer.play();
}
@override
Future<void> playSongList(List<SongModel> songs, int startIndex) async {
_inputQueue = songs;
final firstSong = songs[startIndex];
_queueSubject.add([QueueItemModel(firstSong, originalIndex: startIndex)]);
_audioSource = _queueGenerator.songModelsToAudioSource([firstSong]);
await _audioPlayer.setAudioSource(_audioSource);
_audioPlayer.play();
_queue = await _queueGenerator.generateQueue(_shuffleModeSubject.value, songs, startIndex);
final songModelQueue = _queue.map((e) => e.song).toList();
_queueSubject.add(_queue);
final int splitIndex = _shuffleModeSubject.value == ShuffleMode.none ? startIndex : 0;
final newQueue = _queueGenerator.songModelsToAudioSource(songModelQueue);
await _audioSource.insertAll(0, newQueue.children.sublist(0, splitIndex));
_audioSource.addAll(newQueue.children.sublist(splitIndex + 1, newQueue.length));
}
@override
Future<void> seekToNext() async {
await _audioPlayer.seekToNext();
}
@override
Future<void> seekToPrevious() async {
await _audioPlayer.seekToPrevious();
}
@override
Future<void> setIndex(int index) async {
await _audioPlayer.seek(const Duration(seconds: 0), index: index);
}
@override
Future<void> stop() async {
_audioPlayer.stop();
}
@override
Future<void> addToQueue(SongModel song) async {
await _audioSource.add(ja.AudioSource.uri(Uri.file(song.path)));
_queue.add(QueueItemModel(song, originalIndex: -1, type: QueueItemType.added));
_queueSubject.add(_queue);
}
@override
Future<void> moveQueueItem(int oldIndex, int newIndex) async {
final QueueItemModel queueItem = _queue.removeAt(oldIndex);
final index = newIndex < oldIndex ? newIndex : newIndex - 1;
_queue.insert(index, queueItem);
_queueSubject.add(_queue);
await _audioSource.move(oldIndex, index);
}
@override
Future<void> removeQueueIndex(int index) async {
_queue.removeAt(index);
_queueSubject.add(_queue);
await _audioSource.removeAt(index);
}
@override
Future<void> setShuffleMode(ShuffleMode shuffleMode, bool updateQueue) async {
if (shuffleMode == null) return;
_shuffleModeSubject.add(shuffleMode);
if (updateQueue) {
final QueueItem currentQueueItem = _queue[_currentIndexSubject.value];
final int index = currentQueueItem.originalIndex;
_queue = await _queueGenerator.generateQueue(shuffleMode, _inputQueue, index);
// TODO: maybe refactor _queue to a subject and listen for changes
final songModelQueue = _queue.map((e) => e.song).toList();
_queueSubject.add(_queue);
final newQueue = _queueGenerator.songModelsToAudioSource(songModelQueue);
_updateQueue(newQueue, currentQueueItem);
}
}
@override
Future<void> setLoopMode(LoopMode loopMode) async {
if (loopMode == null) return;
await _audioPlayer.setLoopMode(loopMode.toJA());
}
Future<void> _updateQueue(ja.ConcatenatingAudioSource newQueue, QueueItem currentQueueItem) async {
final int index = currentQueueItem.originalIndex;
_audioSource.removeRange(0, _currentIndexSubject.value);
_audioSource.removeRange(1, _audioSource.length);
if (_shuffleModeSubject.value == ShuffleMode.none) {
switch (currentQueueItem.type) {
case QueueItemType.added:
case QueueItemType.standard:
await _audioSource.insertAll(0, newQueue.children.sublist(0, index));
_audioSource.addAll(newQueue.children.sublist(index + 1));
break;
case QueueItemType.predecessor:
await _audioSource.insertAll(0, newQueue.children.sublist(0, index));
_audioSource.addAll(newQueue.children.sublist(index));
break;
case QueueItemType.successor:
await _audioSource.insertAll(0, newQueue.children.sublist(0, index + 1));
_audioSource.addAll(newQueue.children.sublist(index + 1));
break;
}
_currentIndexSubject.add(index);
} else {
_audioSource.addAll(newQueue.children.sublist(1));
}
}
}