Migrate to one isolate audio service.
This commit is contained in:
parent
7312fdd10c
commit
7474afd7b8
|
@ -4,4 +4,4 @@ distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||||
distributionSha256Sum=abc10bcedb58806e8654210f96031db541bcd2d6fc3161e81cb0572d6a15e821
|
#distributionSha256Sum=abc10bcedb58806e8654210f96031db541bcd2d6fc3161e81cb0572d6a15e821
|
||||||
|
|
|
@ -303,8 +303,9 @@ class LastPosition extends StatelessWidget {
|
||||||
.onSurface
|
.onSurface
|
||||||
.withOpacity(0.12))),
|
.withOpacity(0.12))),
|
||||||
textColor: data ? Colors.white : null,
|
textColor: data ? Colors.white : null,
|
||||||
onPressed: () =>
|
onPressed: () => {}
|
||||||
audio.setSkipSilence(skipSilence: !data))),
|
//audio.setSkipSilence(skipSilence: !data)
|
||||||
|
)),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Selector<AudioPlayerNotifier, bool>(
|
Selector<AudioPlayerNotifier, bool>(
|
||||||
selector: (_, audio) => audio.boostVolume,
|
selector: (_, audio) => audio.boostVolume,
|
||||||
|
@ -328,8 +329,9 @@ class LastPosition extends StatelessWidget {
|
||||||
.onSurface
|
.onSurface
|
||||||
.withOpacity(0.12))),
|
.withOpacity(0.12))),
|
||||||
textColor: data ? Colors.white : null,
|
textColor: data ? Colors.white : null,
|
||||||
onPressed: () =>
|
onPressed: () => {}
|
||||||
audio.setBoostVolume(boostVolume: !data))),
|
// audio.setBoostVolume(boostVolume: !data)
|
||||||
|
)),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
FutureBuilder<PlayHistory>(
|
FutureBuilder<PlayHistory>(
|
||||||
future: getPosition(episode),
|
future: getPosition(episode),
|
||||||
|
@ -1336,13 +1338,7 @@ class _ControlPanelState extends State<ControlPanel>
|
||||||
AudioProcessingState
|
AudioProcessingState
|
||||||
.buffering ||
|
.buffering ||
|
||||||
data.audioState ==
|
data.audioState ==
|
||||||
AudioProcessingState
|
AudioProcessingState.loading
|
||||||
.connecting ||
|
|
||||||
data.audioState ==
|
|
||||||
AudioProcessingState.none ||
|
|
||||||
data.audioState ==
|
|
||||||
AudioProcessingState
|
|
||||||
.skippingToNext
|
|
||||||
? context.s.buffering
|
? context.s.buffering
|
||||||
: '',
|
: '',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:math' as math;
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
import 'package:audio_session/audio_session.dart';
|
import 'package:audio_session/audio_session.dart';
|
||||||
|
@ -179,18 +179,19 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void addListener(VoidCallback listener) async {
|
void addListener(VoidCallback listener) async {
|
||||||
super.addListener(listener);
|
await _initAudioData();
|
||||||
_initAudioData();
|
final _audioHandler = await AudioService.init(
|
||||||
_audioHandler = await AudioService.init(
|
|
||||||
builder: () => CustomAudioHandler(),
|
builder: () => CustomAudioHandler(),
|
||||||
config: AudioServiceConfig(
|
config: AudioServiceConfig(
|
||||||
androidNotificationChannelName: 'Tsacdop',
|
androidNotificationChannelName: 'Tsacdop',
|
||||||
androidNotificationIcon: 'drawable/ic_notification',
|
androidNotificationIcon: 'drawable/ic_notification',
|
||||||
androidEnableQueue: true,
|
androidEnableQueue: true,
|
||||||
androidStopForegroundOnPause: true,
|
androidStopForegroundOnPause: true,
|
||||||
|
preloadArtwork: false,
|
||||||
fastForwardInterval: Duration(seconds: _fastForwardSeconds),
|
fastForwardInterval: Duration(seconds: _fastForwardSeconds),
|
||||||
rewindInterval: Duration(seconds: _rewindSeconds)),
|
rewindInterval: Duration(seconds: _rewindSeconds)),
|
||||||
);
|
);
|
||||||
|
super.addListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Audio playing state.
|
/// Audio playing state.
|
||||||
|
@ -249,6 +250,9 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
_skipSilence = await _skipSilenceStorage.getBool(defaultValue: false);
|
_skipSilence = await _skipSilenceStorage.getBool(defaultValue: false);
|
||||||
_boostVolume = await _boostVolumeStorage.getBool(defaultValue: false);
|
_boostVolume = await _boostVolumeStorage.getBool(defaultValue: false);
|
||||||
_volumeGain = await _volumeGainStorage.getInt(defaultValue: 3000);
|
_volumeGain = await _volumeGainStorage.getInt(defaultValue: 3000);
|
||||||
|
_fastForwardSeconds =
|
||||||
|
await _fastForwardSecondsStorage.getInt(defaultValue: 30);
|
||||||
|
_rewindSeconds = await _rewindSecondsStorage.getInt(defaultValue: 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _savePlayerHeight() async {
|
Future _savePlayerHeight() async {
|
||||||
|
@ -446,11 +450,11 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
//Check autoplay setting, if true only add one episode, else add playlist.
|
//Check autoplay setting, if true only add one episode, else add playlist.
|
||||||
await _getAutoPlay();
|
await _getAutoPlay();
|
||||||
if (_autoPlay) {
|
if (_autoPlay) {
|
||||||
for (var episode in playlist.episodes) {
|
await _audioHandler.addQueueItems(
|
||||||
await _audioHandler.addQueueItem(episode.toMediaItem());
|
([for (var episode in playlist.episodes) episode.toMediaItem()]));
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
await _audioHandler.addQueueItem(playlist.episodes[index].toMediaItem());
|
await _audioHandler
|
||||||
|
.addQueueItems([playlist.episodes[index].toMediaItem()]);
|
||||||
}
|
}
|
||||||
//Check auto sleep timer setting
|
//Check auto sleep timer setting
|
||||||
await _getAutoSleepTimer();
|
await _getAutoSleepTimer();
|
||||||
|
@ -487,40 +491,40 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
// 'setBoostVolume', [_boostVolume, _volumeGain]);
|
// 'setBoostVolume', [_boostVolume, _volumeGain]);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
await _audioHandler.play();
|
_audioHandler.play();
|
||||||
_audioHandler.mediaItem
|
|
||||||
.where((event) => event != null)
|
_audioHandler.mediaItem.where((event) => event != null).listen(
|
||||||
.listen((item) async {
|
(item) async {
|
||||||
var episode = await _dbHelper.getRssItemWithMediaId(item.id);
|
var episode = await _dbHelper.getRssItemWithMediaId(item.id);
|
||||||
if (episode == null) {
|
if (episode == null) {
|
||||||
episode = _playFromSearchList.firstWhere((e) => e.mediaId == item.id,
|
episode = _playFromSearchList.firstWhere((e) => e.mediaId == item.id,
|
||||||
orElse: () => null);
|
orElse: () => null);
|
||||||
}
|
|
||||||
_backgroundAudioDuration = item.duration?.inMilliseconds ?? 0;
|
|
||||||
if (episode != null) {
|
|
||||||
_episode = episode;
|
|
||||||
_backgroundAudioDuration = item.duration.inMilliseconds ?? 0;
|
|
||||||
if (position > 0 &&
|
|
||||||
_backgroundAudioDuration > 0 &&
|
|
||||||
_episode.enclosureUrl == _playlist.episodeList[index]) {
|
|
||||||
await AudioService.seekTo(Duration(milliseconds: position));
|
|
||||||
position = 0;
|
|
||||||
}
|
}
|
||||||
notifyListeners();
|
if (episode != null) {
|
||||||
} else {
|
_episode = episode;
|
||||||
AudioService.skipToNext();
|
_backgroundAudioDuration = item.duration.inMilliseconds ?? 0;
|
||||||
}
|
if (position > 0 &&
|
||||||
});
|
_backgroundAudioDuration > 0 &&
|
||||||
|
_episode.enclosureUrl == _playlist.episodeList[index]) {
|
||||||
|
await _audioHandler.seek(Duration(milliseconds: position));
|
||||||
|
position = 0;
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
} else {
|
||||||
|
_audioHandler.skipToNext();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
_audioHandler.playbackState
|
_audioHandler.playbackState
|
||||||
.distinct()
|
|
||||||
.where((event) => event != null)
|
.where((event) => event != null)
|
||||||
.listen((event) async {
|
.listen((event) async {
|
||||||
|
print(event.toString());
|
||||||
_current = DateTime.now();
|
_current = DateTime.now();
|
||||||
_audioState = event.processingState;
|
_audioState = event.processingState;
|
||||||
_playing = event?.playing;
|
_playing = event?.playing;
|
||||||
_currentSpeed = event.speed;
|
_currentSpeed = event.speed;
|
||||||
_currentPosition = event.position.inMilliseconds ?? 0;
|
_currentPosition = event.updatePosition.inMilliseconds ?? 0;
|
||||||
|
|
||||||
if (_audioState == AudioProcessingState.completed) {
|
if (_audioState == AudioProcessingState.completed) {
|
||||||
if (_switchValue > 0) _switchValue = 0;
|
if (_switchValue > 0) _switchValue = 0;
|
||||||
}
|
}
|
||||||
|
@ -570,23 +574,12 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
}
|
}
|
||||||
//_episode = null;
|
//_episode = null;
|
||||||
}
|
}
|
||||||
});
|
if (event is Map && event['duration'] != null) {
|
||||||
|
_backgroundAudioDuration = event['duration'].inMilliseconds;
|
||||||
//double s = _currentSpeed ?? 1.0;
|
notifyListeners();
|
||||||
var getPosition = 0;
|
}
|
||||||
Timer.periodic(Duration(milliseconds: 500), (timer) {
|
if (event is Map && event['position'] != null) {
|
||||||
var s = _currentSpeed ?? 1.0;
|
_backgroundAudioPosition = event['position'].inMilliseconds;
|
||||||
if (_noSlide) {
|
|
||||||
if (_playing && !buffering) {
|
|
||||||
getPosition = _currentPosition +
|
|
||||||
((DateTime.now().difference(_current).inMilliseconds) * s)
|
|
||||||
.toInt();
|
|
||||||
_backgroundAudioPosition =
|
|
||||||
math.min(getPosition, _backgroundAudioDuration);
|
|
||||||
} else {
|
|
||||||
_backgroundAudioPosition = _currentPosition ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_backgroundAudioDuration != null &&
|
if (_backgroundAudioDuration != null &&
|
||||||
_backgroundAudioDuration != 0 &&
|
_backgroundAudioDuration != 0 &&
|
||||||
_backgroundAudioPosition != null) {
|
_backgroundAudioPosition != null) {
|
||||||
|
@ -595,19 +588,46 @@ class AudioPlayerNotifier extends ChangeNotifier {
|
||||||
} else {
|
} else {
|
||||||
_seekSliderValue = 0;
|
_seekSliderValue = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_backgroundAudioPosition > 0 &&
|
|
||||||
_backgroundAudioPosition < _backgroundAudioDuration) {
|
|
||||||
_lastPosition = _backgroundAudioPosition;
|
|
||||||
_playerStateStorage.savePlayerState(
|
|
||||||
_playlist.id, _episode.enclosureUrl, _lastPosition);
|
|
||||||
}
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
if (_audioState == AudioProcessingState.completed) {
|
|
||||||
timer.cancel();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//double s = _currentSpeed ?? 1.0;
|
||||||
|
// var getPosition = 0;
|
||||||
|
// Timer.periodic(Duration(milliseconds: 500), (timer) {
|
||||||
|
// var s = _currentSpeed ?? 1.0;
|
||||||
|
// if (_noSlide) {
|
||||||
|
// if (_playing && !buffering) {
|
||||||
|
// getPosition = _currentPosition +
|
||||||
|
// ((DateTime.now().difference(_current).inMilliseconds) * s)
|
||||||
|
// .toInt();
|
||||||
|
// _backgroundAudioPosition =
|
||||||
|
// math.min(getPosition, _backgroundAudioDuration);
|
||||||
|
// } else {
|
||||||
|
// _backgroundAudioPosition = _currentPosition ?? 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (_backgroundAudioDuration != null &&
|
||||||
|
// _backgroundAudioDuration != 0 &&
|
||||||
|
// _backgroundAudioPosition != null) {
|
||||||
|
// _seekSliderValue =
|
||||||
|
// _backgroundAudioPosition / _backgroundAudioDuration ?? 0;
|
||||||
|
// } else {
|
||||||
|
// _seekSliderValue = 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (_backgroundAudioPosition > 0 &&
|
||||||
|
// _backgroundAudioPosition < _backgroundAudioDuration) {
|
||||||
|
// _lastPosition = _backgroundAudioPosition;
|
||||||
|
// _playerStateStorage.savePlayerState(
|
||||||
|
// _playlist.id, _episode.enclosureUrl, _lastPosition);
|
||||||
|
// }
|
||||||
|
// notifyListeners();
|
||||||
|
// }
|
||||||
|
// if (_audioState == AudioProcessingState.completed) {
|
||||||
|
// timer.cancel();
|
||||||
|
// }
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queue management.
|
/// Queue management.
|
||||||
|
@ -972,32 +992,36 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
final cacheStorage = KeyValueStorage(cacheMaxKey);
|
final cacheStorage = KeyValueStorage(cacheMaxKey);
|
||||||
final layoutStorage = KeyValueStorage(notificationLayoutKey);
|
final layoutStorage = KeyValueStorage(notificationLayoutKey);
|
||||||
final AudioPlayer _player = AudioPlayer();
|
final AudioPlayer _player = AudioPlayer();
|
||||||
AudioSession _session;
|
|
||||||
bool _playing;
|
|
||||||
bool _interrupted = false;
|
bool _interrupted = false;
|
||||||
|
int _layoutIndex;
|
||||||
bool _stopAtEnd;
|
bool _stopAtEnd;
|
||||||
int _cacheMax;
|
int _cacheMax;
|
||||||
bool _isQueue;
|
bool _isQueue = false;
|
||||||
int _index = 0;
|
|
||||||
|
|
||||||
bool get hasNext => queue.value.length > 0;
|
bool get hasNext => queue.value.length > 0;
|
||||||
MediaItem get currentMediaItem => mediaItem.value;
|
MediaItem get currentMediaItem => mediaItem.value;
|
||||||
bool get playing => playbackState.value.playing;
|
bool get playing => playbackState.value.playing;
|
||||||
|
|
||||||
// MediaItem get _currentMediaItem => hasNext ? _queue[_index] : null;
|
// MediaItem get _currentMediaItem => hasNext ? _queue[_index] : null;
|
||||||
BehaviorSubject<Map<String, dynamic>> customEvent;
|
BehaviorSubject<Map<String, dynamic>> customEvent =
|
||||||
|
BehaviorSubject.seeded({});
|
||||||
|
|
||||||
CustomAudioHandler() {
|
CustomAudioHandler() {
|
||||||
_player.currentIndexStream
|
_handleInterruption();
|
||||||
.listen((index) => mediaItem.add(queue.value[index]));
|
_player.currentIndexStream.listen(
|
||||||
_player.playbackEventStream.listen((event) {
|
(index) {
|
||||||
|
if (queue.value.isNotEmpty) {
|
||||||
|
mediaItem.add(queue.value[index]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
_player.playbackEventStream.listen((event) async {
|
||||||
|
if (_layoutIndex == null) {
|
||||||
|
_layoutIndex = await layoutStorage.getInt();
|
||||||
|
}
|
||||||
playbackState.add(playbackState.value.copyWith(
|
playbackState.add(playbackState.value.copyWith(
|
||||||
controls: [
|
controls: _getControls(_layoutIndex),
|
||||||
MediaControl.skipToPrevious,
|
androidCompactActionIndices: [0, 1, 2],
|
||||||
playing ? MediaControl.pause : MediaControl.play,
|
|
||||||
MediaControl.skipToNext,
|
|
||||||
],
|
|
||||||
androidCompactActionIndices: [0, 1, 3],
|
|
||||||
systemActions: {
|
systemActions: {
|
||||||
MediaAction.seek,
|
MediaAction.seek,
|
||||||
MediaAction.seekForward,
|
MediaAction.seekForward,
|
||||||
|
@ -1016,33 +1040,51 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
speed: _player.speed,
|
speed: _player.speed,
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
_configureSession();
|
|
||||||
|
_player.positionStream.listen((event) {
|
||||||
|
customEvent.add({'position': event});
|
||||||
|
});
|
||||||
|
|
||||||
|
_player.durationStream.listen((event) {
|
||||||
|
log(event.toString());
|
||||||
|
mediaItem.add(mediaItem.value.copyWith(duration: _player.duration));
|
||||||
|
customEvent.add({'duration': event});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _configureSession() async {
|
Future<void> addQueueItems(List<MediaItem> items) async {
|
||||||
_session = await AudioSession.instance;
|
super.addQueueItems(items);
|
||||||
await _session.configure(AudioSessionConfiguration.speech());
|
await _player.setAudioSource(
|
||||||
_handleInterruption(_session);
|
ConcatenatingAudioSource(
|
||||||
|
useLazyPreparation: true,
|
||||||
|
shuffleOrder: DefaultShuffleOrder(),
|
||||||
|
children: [
|
||||||
|
for (var item in items) AudioSource.uri(Uri.parse(item.id)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleInterruption(AudioSession session) async {
|
void _handleInterruption() async {
|
||||||
|
final session = await AudioSession.instance;
|
||||||
|
await session.configure(AudioSessionConfiguration.speech());
|
||||||
session.interruptionEventStream.listen((event) {
|
session.interruptionEventStream.listen((event) {
|
||||||
if (event.begin) {
|
if (event.begin) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case AudioInterruptionType.pause:
|
case AudioInterruptionType.pause:
|
||||||
if (_playing) {
|
if (playing) {
|
||||||
pause();
|
pause();
|
||||||
_interrupted = true;
|
_interrupted = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AudioInterruptionType.duck:
|
case AudioInterruptionType.duck:
|
||||||
if (_playing) {
|
if (playing) {
|
||||||
pause();
|
pause();
|
||||||
_interrupted = true;
|
_interrupted = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AudioInterruptionType.unknown:
|
case AudioInterruptionType.unknown:
|
||||||
if (_playing) {
|
if (playing) {
|
||||||
pause();
|
pause();
|
||||||
_interrupted = true;
|
_interrupted = true;
|
||||||
}
|
}
|
||||||
|
@ -1051,12 +1093,12 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
} else {
|
} else {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case AudioInterruptionType.pause:
|
case AudioInterruptionType.pause:
|
||||||
if (!_playing && _interrupted) {
|
if (!playing && _interrupted) {
|
||||||
play();
|
play();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AudioInterruptionType.duck:
|
case AudioInterruptionType.duck:
|
||||||
if (!_playing && _interrupted) {
|
if (!playing && _interrupted) {
|
||||||
play();
|
play();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1067,19 +1109,19 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
session.becomingNoisyEventStream.listen((_) {
|
session.becomingNoisyEventStream.listen((_) {
|
||||||
if (_playing) pause();
|
if (playing) pause();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handlePlaybackCompleted() async {
|
// void _handlePlaybackCompleted() async {
|
||||||
if (hasNext) {
|
// if (hasNext) {
|
||||||
skipToNext();
|
// skipToNext();
|
||||||
} else {
|
// } else {
|
||||||
_player.stop();
|
// _player.stop();
|
||||||
removeQueueItemAt(0);
|
// removeQueueItemAt(0);
|
||||||
stop();
|
// stop();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
void playPause() {
|
void playPause() {
|
||||||
if (playbackState.value.playing) {
|
if (playbackState.value.playing) {
|
||||||
|
@ -1090,24 +1132,29 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> skipToNext() async {
|
Future<void> skipToNext() async {
|
||||||
customEvent.add({'mediaItem': currentMediaItem.title});
|
if (_isQueue && queue.value.length > 0) {
|
||||||
if (_isQueue) {
|
removeQueueItemAt(0);
|
||||||
if (queue.value.length > 0) {
|
|
||||||
removeQueueItemAt(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (queue.value.length == 0 || _stopAtEnd) {
|
if (queue.value.length == 0 || _stopAtEnd) {
|
||||||
await Future.delayed(Duration(milliseconds: 200));
|
await Future.delayed(Duration(milliseconds: 200));
|
||||||
await stop();
|
await stop();
|
||||||
} else {
|
} else {
|
||||||
super.skipToNext();
|
await super.skipToNext();
|
||||||
var duration = await _player.durationFuture;
|
// _updateDuration();
|
||||||
if (duration != null) {
|
|
||||||
mediaItem.add(currentMediaItem.copyWith(duration: duration));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// _updateDuration() async {
|
||||||
|
// var duration = await _player.durationFuture;
|
||||||
|
// if (duration != null) {
|
||||||
|
// mediaItem.add(currentMediaItem.copyWith(duration: duration));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
_setMediaItem(MediaItem item) {
|
||||||
|
mediaItem.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> play() async {
|
Future<void> play() async {
|
||||||
if (playing == null) {
|
if (playing == null) {
|
||||||
// _cacheMax = await cacheStorage.getInt(
|
// _cacheMax = await cacheStorage.getInt(
|
||||||
|
@ -1116,41 +1163,42 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
// await cacheStorage.saveInt((200 * 1024 * 1024).toInt());
|
// await cacheStorage.saveInt((200 * 1024 * 1024).toInt());
|
||||||
// _cacheMax = 200 * 1024 * 1024;
|
// _cacheMax = 200 * 1024 * 1024;
|
||||||
// }
|
// }
|
||||||
await _player.setUrl(queue.value[_index].id);
|
await super.play();
|
||||||
var duration = await _player.durationFuture;
|
_player.play();
|
||||||
if (duration != null) {
|
|
||||||
mediaItem.add(currentMediaItem.copyWith(duration: duration));
|
|
||||||
}
|
|
||||||
_playFromStart();
|
_playFromStart();
|
||||||
|
// _updateDuration();
|
||||||
} else {
|
} else {
|
||||||
_session.setActive(true);
|
// _session.setActive(true);
|
||||||
|
super.play();
|
||||||
await _player.play();
|
await _player.play();
|
||||||
await _seekRelative(Duration(seconds: -3));
|
await _seekRelative(Duration(seconds: -3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _playFromStart() async {
|
Future<void> _playFromStart() async {
|
||||||
_playing = true;
|
// _session.setActive(true);
|
||||||
_session.setActive(true);
|
|
||||||
if (currentMediaItem.extras['skipSecondsStart'] > 0 ||
|
if (currentMediaItem.extras['skipSecondsStart'] > 0 ||
|
||||||
currentMediaItem.extras['skipSecondsEnd'] > 0) {
|
currentMediaItem.extras['skipSecondsEnd'] > 0) {
|
||||||
_player
|
_player
|
||||||
.seek(Duration(seconds: mediaItem.value.extras['skipSecondsStart']));
|
.seek(Duration(seconds: mediaItem.value.extras['skipSecondsStart']));
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
_player.play();
|
|
||||||
} catch (e) {
|
|
||||||
playbackState.add(playbackState.value
|
|
||||||
.copyWith(processingState: AudioProcessingState.error));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> pause() async {
|
Future<void> pause() async {
|
||||||
_player.pause();
|
await _player.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> seekTo(Duration position) async {
|
Future<void> seek(Duration position) async {
|
||||||
await _player.seek(position);
|
await _player.seek(position);
|
||||||
|
super.seek(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> fastForward() async {
|
||||||
|
_seekRelative(AudioService.config.fastForwardInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> rewind() async {
|
||||||
|
_seekRelative(-AudioService.config.rewindInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onClick(MediaButton button) async {
|
Future<void> onClick(MediaButton button) async {
|
||||||
|
@ -1174,7 +1222,7 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
Future<void> _seekRelative(Duration offset) async {
|
Future<void> _seekRelative(Duration offset) async {
|
||||||
var newPosition = playbackState.value.position + offset;
|
var newPosition = playbackState.value.position + offset;
|
||||||
if (newPosition < Duration.zero) newPosition = Duration.zero;
|
if (newPosition < Duration.zero) newPosition = Duration.zero;
|
||||||
seekTo(newPosition);
|
seek(newPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> stop() async {
|
Future<void> stop() async {
|
||||||
|
@ -1198,17 +1246,14 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
queue.add(queue.value..insert(index, item));
|
queue.add(queue.value..insert(index, item));
|
||||||
// await _player.setUrl(mediaItem.id, cacheMax: _cacheMax);
|
// await _player.setUrl(mediaItem.id, cacheMax: _cacheMax);
|
||||||
await _player.setUrl(item.id);
|
await _player.setUrl(item.id);
|
||||||
mediaItem.add(item);
|
super.play();
|
||||||
var duration = await _player.durationFuture ?? Duration.zero;
|
// _updateDuration();
|
||||||
mediaItem.add(mediaItem.value.copyWith(duration: duration));
|
|
||||||
_playFromStart();
|
_playFromStart();
|
||||||
//onPlay();
|
|
||||||
} else {
|
} else {
|
||||||
queue.add(queue.value..insert(index, item));
|
queue.add(queue.value..insert(index, item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future customAction(funtion, argument) async {
|
Future customAction(funtion, argument) async {
|
||||||
switch (funtion) {
|
switch (funtion) {
|
||||||
case 'stopAtEnd':
|
case 'stopAtEnd':
|
||||||
|
@ -1242,24 +1287,16 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
|
|
||||||
Future _changeQueue(List<MediaItem> newQueue) async {
|
Future _changeQueue(List<MediaItem> newQueue) async {
|
||||||
await _player.stop();
|
await _player.stop();
|
||||||
customEvent.add({'mediaItem': currentMediaItem.title});
|
|
||||||
queue.add(newQueue);
|
queue.add(newQueue);
|
||||||
_index = 0;
|
await super.play();
|
||||||
await _player.setUrl(currentMediaItem.id);
|
|
||||||
var duration = await _player.durationFuture ?? Duration.zero;
|
|
||||||
mediaItem.add(currentMediaItem.copyWith(duration: duration));
|
|
||||||
_playFromStart();
|
_playFromStart();
|
||||||
|
// _updateDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _changeIndex(int index) async {
|
Future _changeIndex(int index) async {
|
||||||
await _player.stop();
|
await super.skipToQueueItem(index);
|
||||||
customEvent.add({'mediaItem': currentMediaItem.title});
|
|
||||||
_index = index;
|
|
||||||
mediaItem.add(currentMediaItem);
|
|
||||||
await _player.setUrl(currentMediaItem.id);
|
|
||||||
var duration = await _player.durationFuture ?? Duration.zero;
|
|
||||||
mediaItem.add(currentMediaItem.copyWith(duration: duration));
|
|
||||||
_playFromStart();
|
_playFromStart();
|
||||||
|
// _updateDuration();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future _setSkipSilence(bool boo) async {
|
// Future _setSkipSilence(bool boo) async {
|
||||||
|
@ -1301,7 +1338,7 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
return [
|
return [
|
||||||
_playing ? pauseControl : playControl,
|
playing ? pauseControl : playControl,
|
||||||
forwardControl,
|
forwardControl,
|
||||||
skipToNextControl,
|
skipToNextControl,
|
||||||
stopControl
|
stopControl
|
||||||
|
@ -1309,7 +1346,7 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
return [
|
return [
|
||||||
_playing ? pauseControl : playControl,
|
playing ? pauseControl : playControl,
|
||||||
rewindControl,
|
rewindControl,
|
||||||
skipToNextControl,
|
skipToNextControl,
|
||||||
stopControl
|
stopControl
|
||||||
|
@ -1318,7 +1355,7 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
case 2:
|
case 2:
|
||||||
return [
|
return [
|
||||||
rewindControl,
|
rewindControl,
|
||||||
_playing ? pauseControl : playControl,
|
playing ? pauseControl : playControl,
|
||||||
forwardControl,
|
forwardControl,
|
||||||
stopControl
|
stopControl
|
||||||
];
|
];
|
||||||
|
@ -1326,7 +1363,7 @@ class CustomAudioHandler extends BaseAudioHandler
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return [
|
return [
|
||||||
_playing ? pauseControl : playControl,
|
playing ? pauseControl : playControl,
|
||||||
forwardControl,
|
forwardControl,
|
||||||
skipToNextControl,
|
skipToNextControl,
|
||||||
stopControl
|
stopControl
|
||||||
|
|
50
pubspec.yaml
50
pubspec.yaml
|
@ -13,43 +13,42 @@ dependencies:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
auto_animated: ^3.0.0
|
auto_animated: ^3.0.0
|
||||||
audio_session: ^0.1.0
|
audio_session: ^0.1.0
|
||||||
cached_network_image: ^2.5.1
|
cached_network_image: ^3.0.0
|
||||||
color_thief_flutter: ^1.0.2
|
color_thief_flutter: ^1.0.2
|
||||||
confetti: ^0.5.5
|
confetti: ^0.5.5
|
||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
connectivity: ^3.0.2
|
connectivity: ^3.0.3
|
||||||
crypto: ^3.0.0
|
crypto: ^3.0.1
|
||||||
device_info: ^2.0.0
|
device_info: ^2.0.0
|
||||||
dio: ^3.0.10
|
|
||||||
dio_cookie_manager: ^1.0.0
|
dio_cookie_manager: ^1.0.0
|
||||||
|
dio: ^3.0.10
|
||||||
extended_nested_scroll_view: ^3.0.0
|
extended_nested_scroll_view: ^3.0.0
|
||||||
effective_dart: ^1.3.1
|
effective_dart: ^1.3.1
|
||||||
equatable: ^1.2.5
|
feature_discovery: ^0.14.0
|
||||||
feature_discovery: ^0.13.0+2
|
file_picker: ^3.0.1
|
||||||
file_picker: ^2.1.4
|
|
||||||
flutter_html: ^0.11.1
|
flutter_html: ^0.11.1
|
||||||
fluttertoast: ^4.0.1
|
fluttertoast: ^4.0.1
|
||||||
flutter_isolate: ^1.0.0+14
|
flutter_isolate: ^2.0.0
|
||||||
flutter_linkify: ^4.0.2
|
flutter_linkify: ^4.1.0
|
||||||
flutter_file_dialog: ^1.0.0
|
flutter_file_dialog: ^2.0.0
|
||||||
flare_flutter: ^2.0.6
|
flare_flutter: ^3.0.0
|
||||||
fl_chart: ^0.12.2
|
fl_chart: ^0.12.2
|
||||||
line_icons: ^1.3.2
|
line_icons: ^2.0.1
|
||||||
flutter_media_metadata: ^0.0.3+2
|
flutter_media_metadata: ^0.1.0
|
||||||
marquee: ^1.7.0
|
marquee: ^2.0.0
|
||||||
google_fonts: ^2.0.0
|
google_fonts: ^2.0.0
|
||||||
image: ^3.0.1
|
image: ^3.0.2
|
||||||
intl: ^0.17.0
|
intl: ^0.17.0
|
||||||
json_serializable: ^3.5.1
|
json_serializable: ^4.1.0
|
||||||
json_annotation: ^3.1.1
|
json_annotation: ^4.0.1
|
||||||
permission_handler: ^5.0.1
|
permission_handler: ^6.1.1
|
||||||
provider: ^4.3.2
|
provider: ^5.0.0
|
||||||
sqflite: ^2.0.0+2
|
sqflite: ^2.0.0+3
|
||||||
state_notifier: ^0.6.0
|
state_notifier: ^0.7.0
|
||||||
tuple: ^1.0.3
|
tuple: ^2.0.0
|
||||||
url_launcher: ^5.7.10
|
url_launcher: ^6.0.3
|
||||||
workmanager: ^0.2.3
|
workmanager: ^0.2.3
|
||||||
wc_flutter_share: ^0.2.2
|
wc_flutter_share: ^0.4.0
|
||||||
just_audio: ^0.7.3
|
just_audio: ^0.7.3
|
||||||
audio_service:
|
audio_service:
|
||||||
git:
|
git:
|
||||||
|
@ -67,6 +66,7 @@ dependencies:
|
||||||
url: https://github.com/stonega/webfeed.git
|
url: https://github.com/stonega/webfeed.git
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
|
equatable: ^2.0.0
|
||||||
path_provider: ^2.0.1
|
path_provider: ^2.0.1
|
||||||
http_parser: ^4.0.0
|
http_parser: ^4.0.0
|
||||||
cookie_jar: ^2.0.0
|
cookie_jar: ^2.0.0
|
||||||
|
@ -75,7 +75,7 @@ dependency_overrides:
|
||||||
flutter_cache_manager: ^3.0.1
|
flutter_cache_manager: ^3.0.1
|
||||||
rxdart: ^0.26.0
|
rxdart: ^0.26.0
|
||||||
shared_preferences: 2.0.0
|
shared_preferences: 2.0.0
|
||||||
plugin_platform_interface: ^1.0.1
|
plugin_platform_interface: ^2.0.0
|
||||||
convert: ^3.0.0
|
convert: ^3.0.0
|
||||||
xml: ^5.0.2
|
xml: ^5.0.2
|
||||||
linkify:
|
linkify:
|
||||||
|
|
Loading…
Reference in New Issue