Reputation: 133
I have problem with [audio_service][1] of Dart's package inside Flutter. It has trouble in reading the duration of current MediaItem. As written in its official documentation [here][2], we are asked to create a new MediaItem to store the copied duration. If we don't do it, then we won't be able to maintain the progress bar when [audio_service][1] is playing the song. I meant, if it has no duration value of the song, it will break the progress bar if user tap on Pause button or Stop button.
Now, I thought another alternative in order to keep duration data.
I used [flutter_ffmpeg][3], and one of its package to read duration in String. Then use these codes to convert String into Duration:
Future<MediaItem> addDuration(File myAudio) async {
late final MediaItem songInfo;
String duration = "";
await readAudio(myAudio).then((value) => duration = value);
durSong = parseDuration(duration);
songInfo.copyWith(duration: durSong);
log("Duration is $durSong");
log("The current duration for ${songInfo.title} is ${songInfo.duration}");
return songInfo;
}
Future<String> readAudio(File audio) async {
final FlutterFFprobe durReader = FlutterFFprobe();
String duration = "";
await durReader.getMediaInformation(audio.path).then((value) => duration = value.getMediaProperties()!["duration"]);
return duration;
}
Duration parseDuration(String s) {
int hours = 0;
int minutes = 0;
int micros;
List<String> parts = s.split(':');
if (parts.length > 2) {
hours = int.parse(parts[parts.length - 3]);
}
if (parts.length > 1) {
minutes = int.parse(parts[parts.length - 2]);
}
micros = (double.parse(parts[parts.length - 1]) * 1000000).round();
return Duration(hours: hours, minutes: minutes, microseconds: micros);
}
Upvotes: 1
Views: 572
Reputation: 133
I found out where I went wrong. Actually, we just need to add these code inside init() function:
_player.durationStream.listen((duration) {
var index = _player.currentIndex;
if (index != null && duration != null) {
final newQueue = queue.value;
final oldMediaItem = newQueue[index];
final newMediaItem = oldMediaItem.copyWith(duration: duration);
newQueue[index] = newMediaItem;
mediaItem.add(newMediaItem);
}
});
@override
Future<void> setShuffleMode(AudioServiceShuffleMode shuffleMode) async {
final enabled = shuffleMode == AudioServiceShuffleMode.all;
if (enabled) {
await _player.shuffle();
await _player.setShuffleModeEnabled(true);
_player.durationStream.listen((duration) {
var index = _player.currentIndex;
if (index != null && duration != null) {
final newQueue = queue.value;
final oldMediaItem = newQueue[index];
final newMediaItem = oldMediaItem.copyWith(duration: duration);
newQueue[index] = newMediaItem;
mediaItem.add(newMediaItem);
playbackState.add(playbackState.value.copyWith(
shuffleMode: shuffleMode,
updatePosition: _player.position,
bufferedPosition: _player.bufferedPosition,
));
}
});
} else {
shuffleMode = AudioServiceShuffleMode.none;
await _player.setShuffleModeEnabled(false);
_player.durationStream.listen((duration) {
var index = _player.currentIndex;
if (index != null && duration != null) {
final newQueue = queue.value;
final oldMediaItem = newQueue[index];
final newMediaItem = oldMediaItem.copyWith(duration: duration);
newQueue[index] = newMediaItem;
mediaItem.add(newMediaItem);
playbackState.add(playbackState.value.copyWith(
shuffleMode: shuffleMode,
updatePosition: _player.position,
bufferedPosition: _player.bufferedPosition,
));
}
});
}
}
I don't need to read the duration value using library flutter_ffmpeg, I just need to add that code inside init()
function and replace the original function setShuffleMode. I think I have to erase my below comment for alternative way which is so much harder than this answer. Well, thank you anyway.
Upvotes: 0
Reputation: 133
Okay, I think I know the answer.
Duration type of data in Dart cannot be uploaded into Firestore and must be converted into Timestamp format. So, the only way for me to store the Duration data is to keep the String value of the return value in this function readAudio(File audio)
.
Future<String> readAudio(File audio) async {
final FlutterFFprobe durReader = FlutterFFprobe();
String duration = "";
await durReader.getMediaInformation(audio.path).then((value) => duration = value.getMediaProperties()!["duration"]);
return duration; //this data
}
parseDuration(String s)
.
Duration parseDuration(String s) {
int hours = 0;
int minutes = 0;
int micros;
List<String> parts = s.split(':');
if (parts.length > 2) {
hours = int.parse(parts[parts.length - 3]);
}
if (parts.length > 1) {
minutes = int.parse(parts[parts.length - 2]);
}
micros = (double.parse(parts[parts.length - 1]) * 1000000).round();
return Duration(hours: hours, minutes: minutes, microseconds: micros);
}
example_playlist.dart
[inside github repository], doesn't have an example if the song has no Duration value.
Upvotes: 0