Can we retrieve the same updated media item with added Duration in Dart [Flutter] which is derived from Cloud Firestore?

Issue

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);
  }

My use case is I created server app and client app. Server app is used to process, retrieve the duration value using plugin flutter_ffmpeg and store it in MediaItem and then upload it to Cloud Firestore and Storage. Client app is used to retrieve data from Cloud Firestore and Storage.

I updated the media item according to [official documentation][2]. I intended to use the updated songs so I don’t need to add duration again to current media item.

My question is:

Can the data included inside media item have the same duration value after being downloaded from Cloud Firestore? I meant, do we need to add Duration value again in the same song??? Or the Duration value is already stored within the song?

[1]: https://pub.dev/packages/audio_service

[2]: https://github.com/ryanheise/audio_service/wiki/FAQ#how-do-i-update-an-existing-mediaitem

[3]: https://pub.dev/packages/flutter_ffmpeg

Solution

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);
      }
    });

I should also add these inside function setShuffleMode()

@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.

Answered By – Wege

Answer Checked By – Willingham (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *