mucke/lib/system/datasources/audio_manager.dart

108 lines
2.9 KiB
Dart
Raw Normal View History

2020-04-06 22:33:26 +02:00
import 'dart:async';
import 'package:audio_service/audio_service.dart';
2020-04-10 20:12:26 +02:00
import '../../domain/entities/playback_state.dart' as entity;
import '../models/playback_state_model.dart';
2020-04-06 22:33:26 +02:00
import '../models/song_model.dart';
import 'audio_manager_contract.dart';
2020-04-11 20:23:02 +02:00
import 'audio_player_task.dart';
2020-04-06 22:33:26 +02:00
2020-04-10 20:12:26 +02:00
typedef Conversion<S, T> = T Function(S);
2020-04-06 22:33:26 +02:00
class AudioManagerImpl implements AudioManager {
2020-04-10 20:12:26 +02:00
final Stream<MediaItem> _currentMediaItemStream =
AudioService.currentMediaItemStream;
final Stream<PlaybackState> _sourcePlaybackStateStream =
AudioService.playbackStateStream;
@override
Stream<SongModel> get currentSongStream =>
_filterStream<MediaItem, SongModel>(
_currentMediaItemStream,
(MediaItem mi) => SongModel.fromMediaItem(mi),
);
2020-04-09 17:50:28 +02:00
@override
2020-04-10 20:12:26 +02:00
Stream<entity.PlaybackState> get playbackStateStream => _filterStream(
_sourcePlaybackStateStream,
(PlaybackState ps) => PlaybackStateModel.fromASPlaybackState(ps),
);
2020-04-09 17:50:28 +02:00
2020-04-11 20:23:02 +02:00
@override
Stream<int> get currentPositionStream => _position().distinct();
2020-04-06 22:33:26 +02:00
@override
Future<void> playSong(int index, List<SongModel> songList) async {
2020-04-09 17:50:28 +02:00
await _startAudioService();
2020-04-06 22:33:26 +02:00
final List<MediaItem> queue = songList.map((s) => s.toMediaItem()).toList();
2020-05-09 19:52:43 +02:00
// await AudioService.customAction(SET_QUEUE, listofids);
2020-05-09 19:52:43 +02:00
await AudioService.addQueueItem(queue[index]);
2020-04-06 22:33:26 +02:00
AudioService.playFromMediaId(queue[index].id);
}
2020-04-09 17:50:28 +02:00
2020-04-10 20:12:26 +02:00
@override
Future<void> play() async {
await AudioService.play();
}
@override
Future<void> pause() async {
await AudioService.pause();
}
2020-04-09 17:50:28 +02:00
Future<void> _startAudioService() async {
2020-06-03 21:17:08 +02:00
if (!AudioService.running) {
2020-04-09 17:50:28 +02:00
await AudioService.start(
backgroundTaskEntrypoint: _backgroundTaskEntrypoint,
2020-06-03 21:17:08 +02:00
androidEnableQueue: true,
2020-04-09 17:50:28 +02:00
);
}
}
2020-04-10 20:12:26 +02:00
Stream<T> _filterStream<S, T>(Stream<S> stream, Conversion<S, T> fn) async* {
T lastItem;
await for (final S item in stream) {
final T newItem = fn(item);
if (newItem != lastItem) {
lastItem = newItem;
yield newItem;
}
}
}
2020-04-11 20:23:02 +02:00
Stream<int> _position() async* {
2020-06-03 21:17:08 +02:00
PlaybackState state;
Duration updateTime;
Duration statePosition;
2020-04-11 20:23:02 +02:00
// should this class get an init method for this?
_sourcePlaybackStateStream.listen((currentState) {
2020-06-03 21:17:08 +02:00
state = currentState;
2020-04-11 20:23:02 +02:00
updateTime = currentState?.updateTime;
statePosition = currentState?.position;
});
while (true) {
if (statePosition != null && updateTime != null && state != null) {
2020-06-03 21:17:08 +02:00
if (state.playing) {
yield statePosition.inMilliseconds +
(DateTime.now().millisecondsSinceEpoch - updateTime.inMilliseconds);
2020-04-11 20:23:02 +02:00
} else {
2020-06-03 21:17:08 +02:00
yield statePosition.inMilliseconds;
2020-04-11 20:23:02 +02:00
}
} else {
yield 0;
}
await Future.delayed(const Duration(milliseconds: 200));
}
}
2020-04-09 17:50:28 +02:00
}
void _backgroundTaskEntrypoint() {
AudioServiceBackground.run(() => AudioPlayerTask());
2020-04-06 22:33:26 +02:00
}