Add new audio plugin.

This commit is contained in:
stonega 2021-05-02 00:02:12 +08:00
parent 7474afd7b8
commit 9ff8f84892
4 changed files with 88 additions and 174 deletions

View File

@ -8,7 +8,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<application android:name="io.flutter.app.FlutterApplication" android:label="Tsacdop" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:networkSecurityConfig="@xml/network_security_config"> <application android:name="io.flutter.app.FlutterApplication" android:label="Tsacdop" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:networkSecurityConfig="@xml/network_security_config">
<activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> <activity android:name="com.ryanheise.audioservice.AudioServiceActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
<meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/LaunchTheme" /> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/LaunchTheme" />
<meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/normal_background" /> <meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/normal_background" />
<intent-filter> <intent-filter>

View File

@ -303,9 +303,8 @@ 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,
@ -329,9 +328,8 @@ 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),

View File

@ -75,6 +75,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
KeyValueStorage(markListenedAfterSkipKey); KeyValueStorage(markListenedAfterSkipKey);
final _playlistsStorgae = KeyValueStorage(playlistsAllKey); final _playlistsStorgae = KeyValueStorage(playlistsAllKey);
final _playerStateStorage = KeyValueStorage(playerStateKey); final _playerStateStorage = KeyValueStorage(playerStateKey);
final cacheStorage = KeyValueStorage(cacheMaxKey);
/// Playing episdoe. /// Playing episdoe.
EpisodeBrief _episode; EpisodeBrief _episode;
@ -175,13 +176,18 @@ class AudioPlayerNotifier extends ChangeNotifier {
List<EpisodeBrief> _playFromSearchList = []; List<EpisodeBrief> _playFromSearchList = [];
AudioHandler _audioHandler; AudioHandler _audioHandler;
AudioSession _session;
StreamSubscription<MediaItem> _mediaitemSubscription;
StreamSubscription<PlaybackState> _playbackStateSubscription;
StreamSubscription<dynamic> _customEventSubscription;
@override @override
void addListener(VoidCallback listener) async { void addListener(VoidCallback listener) async {
await _initAudioData(); await _initAudioData();
final _audioHandler = await AudioService.init( final cacheMax =
builder: () => CustomAudioHandler(), await cacheStorage.getInt(defaultValue: (1024 * 1024 * 200).toInt());
_audioHandler = await AudioService.init(
builder: () => CustomAudioHandler(cacheMax),
config: AudioServiceConfig( config: AudioServiceConfig(
androidNotificationChannelName: 'Tsacdop', androidNotificationChannelName: 'Tsacdop',
androidNotificationIcon: 'drawable/ic_notification', androidNotificationIcon: 'drawable/ic_notification',
@ -194,6 +200,14 @@ class AudioPlayerNotifier extends ChangeNotifier {
super.addListener(listener); super.addListener(listener);
} }
@override
void dispose() {
_mediaitemSubscription?.cancel();
_playbackStateSubscription?.cancel();
_customEventSubscription?.cancel();
super.dispose();
}
/// Audio playing state. /// Audio playing state.
AudioProcessingState get audioState => _audioState; AudioProcessingState get audioState => _audioState;
int get backgroundAudioDuration => _backgroundAudioDuration; int get backgroundAudioDuration => _backgroundAudioDuration;
@ -482,18 +496,20 @@ class AudioPlayerNotifier extends ChangeNotifier {
/// Set slipsilence. /// Set slipsilence.
if (_skipSilence) { if (_skipSilence) {
// await _audioHandler.customAction('setSkipSilence', {'': skipSilence}); await _audioHandler
.customAction('setSkipSilence', {'skipSilence': skipSilence});
} }
/// Set boostValome. /// Set boostValome.
// if (_boostVolume) { if (_boostVolume) {
// await _audioHandler.customAction( await _audioHandler.customAction(
// 'setBoostVolume', [_boostVolume, _volumeGain]); 'setBoostVolume', {'boostVolume': _boostVolume, 'gain': _volumeGain});
// } }
_audioHandler.play(); _audioHandler.play();
_audioHandler.mediaItem.where((event) => event != null).listen( _mediaitemSubscription =
_audioHandler.mediaItem.where((event) => event != null).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) {
@ -502,7 +518,7 @@ class AudioPlayerNotifier extends ChangeNotifier {
} }
if (episode != null) { if (episode != null) {
_episode = episode; _episode = episode;
_backgroundAudioDuration = item.duration.inMilliseconds ?? 0; _backgroundAudioDuration = item.duration?.inMilliseconds ?? 0;
if (position > 0 && if (position > 0 &&
_backgroundAudioDuration > 0 && _backgroundAudioDuration > 0 &&
_episode.enclosureUrl == _playlist.episodeList[index]) { _episode.enclosureUrl == _playlist.episodeList[index]) {
@ -516,10 +532,9 @@ class AudioPlayerNotifier extends ChangeNotifier {
}, },
); );
_audioHandler.playbackState _playbackStateSubscription = _audioHandler.playbackState
.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;
@ -541,11 +556,12 @@ class AudioPlayerNotifier extends ChangeNotifier {
notifyListeners(); notifyListeners();
}); });
_audioHandler.customEvent.distinct().listen((event) async { _customEventSubscription =
if (event is String) { _audioHandler.customEvent.distinct().listen((event) async {
if (event is Map && event['removePlayed'] != null) {
if (_playlist.isQueue && if (_playlist.isQueue &&
_queue.isNotEmpty && _queue.isNotEmpty &&
_queue.episodes.first.title == event) { _queue.episodes.first.title == event['removePlayed']) {
_queue.delFromPlaylist(_episode); _queue.delFromPlaylist(_episode);
updatePlaylist(_queue, updateEpisodes: false); updatePlaylist(_queue, updateEpisodes: false);
} }
@ -574,10 +590,6 @@ class AudioPlayerNotifier extends ChangeNotifier {
} }
//_episode = null; //_episode = null;
} }
if (event is Map && event['duration'] != null) {
_backgroundAudioDuration = event['duration'].inMilliseconds;
notifyListeners();
}
if (event is Map && event['position'] != null) { if (event is Map && event['position'] != null) {
_backgroundAudioPosition = event['position'].inMilliseconds; _backgroundAudioPosition = event['position'].inMilliseconds;
if (_backgroundAudioDuration != null && if (_backgroundAudioDuration != null &&
@ -591,43 +603,6 @@ class AudioPlayerNotifier extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
}); });
//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.
@ -904,30 +879,31 @@ class AudioPlayerNotifier extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
/// Set skip silence. // Set skip silence.
// Future<void> setSkipSilence({@required bool skipSilence}) async { Future<void> setSkipSilence({@required bool skipSilence}) async {
// await AudioService.customAction('setSkipSilence', skipSilence); await _audioHandler
// _skipSilence = skipSilence; .customAction('setSkipSilence', {'skipSilence': skipSilence});
// await _skipSilenceStorage.saveBool(_skipSilence); _skipSilence = skipSilence;
// notifyListeners(); await _skipSilenceStorage.saveBool(_skipSilence);
// } notifyListeners();
}
set setVolumeGain(int volumeGain) { set setVolumeGain(int volumeGain) {
_volumeGain = volumeGain; _volumeGain = volumeGain;
if (_playerRunning && _boostVolume) { if (_playerRunning && _boostVolume) {
// setBoostVolume(boostVolume: _boostVolume, gain: _volumeGain); setBoostVolume(boostVolume: _boostVolume, gain: _volumeGain);
} }
notifyListeners(); notifyListeners();
_volumeGainStorage.saveInt(volumeGain); _volumeGainStorage.saveInt(volumeGain);
} }
// Future<void> setBoostVolume({@required bool boostVolume, int gain}) async { Future<void> setBoostVolume({@required bool boostVolume, int gain}) async {
// await _audioHandler.customAction( await _audioHandler.customAction(
// 'setBoostVolume', [boostVolume, _volumeGain]); 'setBoostVolume', {'boostVolume': boostVolume, 'gain': _volumeGain});
// _boostVolume = boostVolume; _boostVolume = boostVolume;
// notifyListeners(); notifyListeners();
// await _boostVolumeStorage.saveBool(boostVolume); await _boostVolumeStorage.saveBool(boostVolume);
// } }
//Set sleep timer //Set sleep timer
void sleepTimer(int mins) { void sleepTimer(int mins) {
@ -994,25 +970,29 @@ class CustomAudioHandler extends BaseAudioHandler
final AudioPlayer _player = AudioPlayer(); final AudioPlayer _player = AudioPlayer();
bool _interrupted = false; bool _interrupted = false;
int _layoutIndex; int _layoutIndex;
bool _stopAtEnd; bool _stopAtEnd = false;
int _cacheMax;
bool _isQueue = false; bool _isQueue = false;
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;
BehaviorSubject<Map<String, dynamic>> customEvent = BehaviorSubject<Map<String, dynamic>> customEvent =
BehaviorSubject.seeded({}); BehaviorSubject.seeded({});
CustomAudioHandler() { CustomAudioHandler(int cacheMax) {
_player.cacheMax = cacheMax;
_handleInterruption(); _handleInterruption();
_player.currentIndexStream.listen( _player.currentIndexStream.listen(
(index) { (index) {
log(index.toString());
if (queue.value.isNotEmpty) { if (queue.value.isNotEmpty) {
mediaItem.add(queue.value[index]); mediaItem.add(queue.value[index]);
} }
if (_isQueue && index == 1) {
customEvent.add({'removePlayed': queue.value.first.title});
}
}, },
); );
_player.playbackEventStream.listen((event) async { _player.playbackEventStream.listen((event) async {
@ -1036,6 +1016,7 @@ class CustomAudioHandler extends BaseAudioHandler
}[_player.processingState], }[_player.processingState],
playing: _player.playing, playing: _player.playing,
updatePosition: _player.position, updatePosition: _player.position,
queueIndex: _player.currentIndex,
bufferedPosition: _player.bufferedPosition, bufferedPosition: _player.bufferedPosition,
speed: _player.speed, speed: _player.speed,
)); ));
@ -1046,9 +1027,7 @@ class CustomAudioHandler extends BaseAudioHandler
}); });
_player.durationStream.listen((event) { _player.durationStream.listen((event) {
log(event.toString());
mediaItem.add(mediaItem.value.copyWith(duration: _player.duration)); mediaItem.add(mediaItem.value.copyWith(duration: _player.duration));
customEvent.add({'duration': event});
}); });
} }
@ -1059,7 +1038,11 @@ class CustomAudioHandler extends BaseAudioHandler
useLazyPreparation: true, useLazyPreparation: true,
shuffleOrder: DefaultShuffleOrder(), shuffleOrder: DefaultShuffleOrder(),
children: [ children: [
for (var item in items) AudioSource.uri(Uri.parse(item.id)), for (var item in items)
ClippingAudioSource(
start: Duration(seconds: item.extras['skipSecondsStart']),
// end: Duration(seconds: item.extras['skipSecondsEnd']),
child: AudioSource.uri(Uri.parse(item.id))),
], ],
), ),
); );
@ -1113,16 +1096,6 @@ class CustomAudioHandler extends BaseAudioHandler
}); });
} }
// void _handlePlaybackCompleted() async {
// if (hasNext) {
// skipToNext();
// } else {
// _player.stop();
// removeQueueItemAt(0);
// stop();
// }
// }
void playPause() { void playPause() {
if (playbackState.value.playing) { if (playbackState.value.playing) {
pause(); pause();
@ -1132,56 +1105,32 @@ class CustomAudioHandler extends BaseAudioHandler
} }
Future<void> skipToNext() async { Future<void> skipToNext() async {
if (_isQueue && 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 {
await super.skipToNext(); await super.skipToNext();
// _updateDuration(); _player.seekToNext();
if (_isQueue && queue.value.isNotEmpty) {
removeQueueItemAt(0);
}
} }
} }
// _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(
// defaultValue: (200 * 1024 * 1024).toInt());
// if (_cacheMax == 0) {
// await cacheStorage.saveInt((200 * 1024 * 1024).toInt());
// _cacheMax = 200 * 1024 * 1024;
// }
await super.play(); await super.play();
_player.play(); _player.play();
_playFromStart();
// _updateDuration();
} else { } else {
// _session.setActive(true);
super.play(); super.play();
await _player.play(); await _player.play();
await _seekRelative(Duration(seconds: -3)); await _seekRelative(Duration(seconds: -3));
} }
} }
Future<void> _playFromStart() async { Future<void> removeQueueItemAt(int index) async {
// _session.setActive(true); queue.add(queue.value..removeAt(index));
if (currentMediaItem.extras['skipSecondsStart'] > 0 || super.removeQueueItemAt(index);
currentMediaItem.extras['skipSecondsEnd'] > 0) {
_player
.seek(Duration(seconds: mediaItem.value.extras['skipSecondsStart']));
}
} }
Future<void> pause() async { Future<void> pause() async {
@ -1240,15 +1189,9 @@ class CustomAudioHandler extends BaseAudioHandler
Future<void> _addQueueItemAt(MediaItem item, int index) async { Future<void> _addQueueItemAt(MediaItem item, int index) async {
if (index == 0 && _isQueue) { if (index == 0 && _isQueue) {
await _player.stop();
queue.add(queue.value..removeAt(0));
queue.add(queue.value..removeWhere((i) => i.id == item.id)); queue.add(queue.value..removeWhere((i) => i.id == item.id));
queue.add(queue.value..insert(index, item)); queue.add(queue.value..insert(index, item));
// await _player.setUrl(mediaItem.id, cacheMax: _cacheMax); skipToNext();
await _player.setUrl(item.id);
super.play();
// _updateDuration();
_playFromStart();
} else { } else {
queue.add(queue.value..insert(index, item)); queue.add(queue.value..insert(index, item));
} }
@ -1266,10 +1209,10 @@ class CustomAudioHandler extends BaseAudioHandler
await _player.setSpeed(argument['speed']); await _player.setSpeed(argument['speed']);
break; break;
case 'setSkipSilence': case 'setSkipSilence':
// await _skipSilence(argument); await _setSkipSilence(argument['skipSilence']);
break; break;
case 'setBoostVolume': case 'setBoostVolume':
// await _setBoostVolume(argument[0], argument[1]); await _setBoostVolume(argument['boostVolume'], argument['gain']);
break; break;
case 'setIsQueue': case 'setIsQueue':
_isQueue = argument['isQueue']; _isQueue = argument['isQueue'];
@ -1288,51 +1231,20 @@ class CustomAudioHandler extends BaseAudioHandler
Future _changeQueue(List<MediaItem> newQueue) async { Future _changeQueue(List<MediaItem> newQueue) async {
await _player.stop(); await _player.stop();
queue.add(newQueue); queue.add(newQueue);
await super.play(); play();
_playFromStart();
// _updateDuration();
} }
Future _changeIndex(int index) async { Future _changeIndex(int index) async {
await super.skipToQueueItem(index); await super.skipToQueueItem(index);
_playFromStart();
// _updateDuration();
} }
// Future _setSkipSilence(bool boo) async { Future _setSkipSilence(bool boo) async {
// await _audioPlayer.setSkipSilence(boo); await _player.setSkipSilence(boo);
// var duration = await _audioPlayer.durationFuture ?? Duration.zero; }
// AudioServiceBackground.setMediaItem(mediaItem.copyWith(duration: duration));
// }
// Future _setBoostVolume(bool boo, int gain) async { Future _setBoostVolume(bool boo, int gain) async {
// await _audioPlayer.setBoostVolume(boo, gain: gain); await _player.setBoostVolume(boo, gain);
// } }
// Future<void> _setState({
// AudioProcessingState processingState,
// Duration position,
// Duration bufferedPosition,
// }) async {
// if (position == null) {
// position = _player.playbackEvent.position;
// }
// final index = await layoutStorage.getInt(defaultValue: 0);
// await playbackState.add(
// controls: _getControls(index),
// systemActions: [
// MediaAction.seekTo,
// MediaAction.seekForward,
// MediaAction.seekBackward,
// ],
// processingState:
// processingState ?? AudioServiceBackground.state.processingState,
// playing: _playing ?? false,
// position: position,
// bufferedPosition: bufferedPosition ?? position,
// speed: _audioPlayer.speed,
// );
// }
List<MediaControl> _getControls(int index) { List<MediaControl> _getControls(int index) {
switch (index) { switch (index) {

View File

@ -49,7 +49,11 @@ dependencies:
url_launcher: ^6.0.3 url_launcher: ^6.0.3
workmanager: ^0.2.3 workmanager: ^0.2.3
wc_flutter_share: ^0.4.0 wc_flutter_share: ^0.4.0
just_audio: ^0.7.3 just_audio:
git:
url: https://github.com/stonega/just_audio_origin.git
ref: update
path: just_audio
audio_service: audio_service:
git: git:
url: https://github.com/ryanheise/audio_service.git url: https://github.com/ryanheise/audio_service.git