From 30b63e01ce2cbc5588d393e39f318c92312b9d43 Mon Sep 17 00:00:00 2001 From: Hans Vandenwijngaerden Date: Thu, 12 Sep 2024 12:40:06 +0000 Subject: [PATCH 1/5] Migrate to ExoPlayer to Media3 --- just_audio/android/build.gradle | 11 ++- .../com/ryanheise/just_audio/AudioPlayer.java | 73 +++++++++---------- 2 files changed, 41 insertions(+), 43 deletions(-) diff --git a/just_audio/android/build.gradle b/just_audio/android/build.gradle index 4d3fcbbbc..2739d2652 100644 --- a/just_audio/android/build.gradle +++ b/just_audio/android/build.gradle @@ -48,11 +48,10 @@ android { } dependencies { - def exoplayer_version = "2.18.7" - implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version" - implementation "com.google.android.exoplayer:exoplayer-dash:$exoplayer_version" - implementation "com.google.android.exoplayer:exoplayer-hls:$exoplayer_version" - implementation "com.google.android.exoplayer:exoplayer-smoothstreaming:$exoplayer_version" + def exoplayer_version = "1.0.2" + implementation "androidx.media3:media3-exoplayer:$exoplayer_version" + implementation "androidx.media3:media3-exoplayer-dash:$exoplayer_version" + implementation "androidx.media3:media3-exoplayer-hls:$exoplayer_version" + implementation "androidx.media3:media3-exoplayer-smoothstreaming:$exoplayer_version" } } - diff --git a/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java b/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java index 5adf351f0..ad3410647 100644 --- a/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java +++ b/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java @@ -8,43 +8,42 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.DefaultLivePlaybackSpeedControl; -import com.google.android.exoplayer2.DefaultLoadControl; -import com.google.android.exoplayer2.DefaultRenderersFactory; -import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.LivePlaybackSpeedControl; -import com.google.android.exoplayer2.LoadControl; -import com.google.android.exoplayer2.MediaItem; -import com.google.android.exoplayer2.PlaybackException; -import com.google.android.exoplayer2.PlaybackParameters; -import com.google.android.exoplayer2.Player; -import com.google.android.exoplayer2.Player.PositionInfo; -import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.Timeline; -import com.google.android.exoplayer2.Tracks; -import com.google.android.exoplayer2.audio.AudioAttributes; -import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; -import com.google.android.exoplayer2.metadata.Metadata; -import com.google.android.exoplayer2.metadata.MetadataOutput; -import com.google.android.exoplayer2.metadata.icy.IcyHeaders; -import com.google.android.exoplayer2.metadata.icy.IcyInfo; -import com.google.android.exoplayer2.source.ClippingMediaSource; -import com.google.android.exoplayer2.source.ConcatenatingMediaSource; -import com.google.android.exoplayer2.source.MediaSource; -import com.google.android.exoplayer2.source.ProgressiveMediaSource; -import com.google.android.exoplayer2.source.ShuffleOrder; -import com.google.android.exoplayer2.source.ShuffleOrder.DefaultShuffleOrder; -import com.google.android.exoplayer2.source.SilenceMediaSource; -import com.google.android.exoplayer2.source.TrackGroup; -import com.google.android.exoplayer2.source.dash.DashMediaSource; -import com.google.android.exoplayer2.source.hls.HlsMediaSource; -import com.google.android.exoplayer2.trackselection.TrackSelectionArray; -import com.google.android.exoplayer2.upstream.DataSource; -import com.google.android.exoplayer2.upstream.DefaultDataSource; -import com.google.android.exoplayer2.upstream.DefaultHttpDataSource; -import com.google.android.exoplayer2.util.MimeTypes; -import com.google.android.exoplayer2.util.Util; +import androidx.media3.common.C; +import androidx.media3.exoplayer.DefaultLivePlaybackSpeedControl; +import androidx.media3.exoplayer.DefaultLoadControl; +import androidx.media3.exoplayer.DefaultRenderersFactory; +import androidx.media3.exoplayer.ExoPlaybackException; +import androidx.media3.exoplayer.LivePlaybackSpeedControl; +import androidx.media3.exoplayer.LoadControl; +import androidx.media3.common.MediaItem; +import androidx.media3.common.PlaybackException; +import androidx.media3.common.PlaybackParameters; +import androidx.media3.common.Player; +import androidx.media3.common.Player.PositionInfo; +import androidx.media3.exoplayer.ExoPlayer; +import androidx.media3.common.Timeline; +import androidx.media3.common.Tracks; +import androidx.media3.common.AudioAttributes; +import androidx.media3.extractor.DefaultExtractorsFactory; +import androidx.media3.common.Metadata; +import androidx.media3.exoplayer.metadata.MetadataOutput; +import androidx.media3.extractor.metadata.icy.IcyHeaders; +import androidx.media3.extractor.metadata.icy.IcyInfo; +import androidx.media3.exoplayer.source.ClippingMediaSource; +import androidx.media3.exoplayer.source.ConcatenatingMediaSource; +import androidx.media3.exoplayer.source.MediaSource; +import androidx.media3.exoplayer.source.ProgressiveMediaSource; +import androidx.media3.exoplayer.source.ShuffleOrder; +import androidx.media3.exoplayer.source.ShuffleOrder.DefaultShuffleOrder; +import androidx.media3.exoplayer.source.SilenceMediaSource; +import androidx.media3.common.TrackGroup; +import androidx.media3.exoplayer.dash.DashMediaSource; +import androidx.media3.exoplayer.hls.HlsMediaSource; +import androidx.media3.datasource.DataSource; +import androidx.media3.datasource.DefaultDataSource; +import androidx.media3.datasource.DefaultHttpDataSource; +import androidx.media3.common.MimeTypes; +import androidx.media3.common.util.Util; import io.flutter.Log; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.EventChannel; From 0afcf69953d9b7bc66773ac8ad63ad51d3947d13 Mon Sep 17 00:00:00 2001 From: Hans Vandenwijngaerden Date: Thu, 12 Sep 2024 12:41:32 +0000 Subject: [PATCH 2/5] Update version number --- just_audio/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/just_audio/pubspec.yaml b/just_audio/pubspec.yaml index 517110717..bc8987a81 100644 --- a/just_audio/pubspec.yaml +++ b/just_audio/pubspec.yaml @@ -1,6 +1,6 @@ name: just_audio description: A feature-rich audio player for Flutter. Loop, clip and concatenate any sound from any source (asset/file/URL/stream) in a variety of audio formats with gapless playback. -version: 0.9.40 +version: 0.9.41 repository: https://github.com/ryanheise/just_audio/tree/minor/just_audio issue_tracker: https://github.com/ryanheise/just_audio/issues topics: From 8552ae207cd131aa3c0de10d6b3d6f926f331592 Mon Sep 17 00:00:00 2001 From: Hans Vandenwijngaerden Date: Thu, 12 Sep 2024 12:45:20 +0000 Subject: [PATCH 3/5] Update changelog --- just_audio/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/just_audio/CHANGELOG.md b/just_audio/CHANGELOG.md index 394865daf..7e4d9467d 100644 --- a/just_audio/CHANGELOG.md +++ b/just_audio/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.41 + +* Migrate from ExoPlayer to Media3 + ## 0.9.40 * Fix JDK 21 compile error. From 7be5aef6431de3ce2db1e54bafcefe7b61420eb6 Mon Sep 17 00:00:00 2001 From: Hans Vandenwijngaerden Date: Fri, 13 Sep 2024 21:50:48 +1000 Subject: [PATCH 4/5] Correct changelog entry, add GitHub username --- just_audio/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/just_audio/CHANGELOG.md b/just_audio/CHANGELOG.md index 7e4d9467d..99831146d 100644 --- a/just_audio/CHANGELOG.md +++ b/just_audio/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.9.41 -* Migrate from ExoPlayer to Media3 +* Migrate from ExoPlayer to Media3 (@hansvdwd) ## 0.9.40 From 150fd3a3366d366a1cf8a077aeffca105a6ab04f Mon Sep 17 00:00:00 2001 From: Ryan Heise Date: Mon, 16 Dec 2024 01:29:52 +1100 Subject: [PATCH 5/5] Migrate to media3 ExoPlayer 1.4.1 on Android. --- just_audio/CHANGELOG.md | 1 + just_audio/android/build.gradle | 10 +- .../com/ryanheise/just_audio/AudioPlayer.java | 118 +++++++++++------- 3 files changed, 78 insertions(+), 51 deletions(-) diff --git a/just_audio/CHANGELOG.md b/just_audio/CHANGELOG.md index 550615a52..82772b432 100644 --- a/just_audio/CHANGELOG.md +++ b/just_audio/CHANGELOG.md @@ -1,6 +1,7 @@ ## 0.9.43 * Fix NPE in load on iOS/macOS. +* Migrate to media3 ExoPlayer 1.4.1 on Android. ## 0.9.42 diff --git a/just_audio/android/build.gradle b/just_audio/android/build.gradle index 10795e2fd..59bfa6fcf 100644 --- a/just_audio/android/build.gradle +++ b/just_audio/android/build.gradle @@ -48,11 +48,11 @@ android { } dependencies { - def exoplayer_version = "2.18.7" - implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version" - implementation "com.google.android.exoplayer:exoplayer-dash:$exoplayer_version" - implementation "com.google.android.exoplayer:exoplayer-hls:$exoplayer_version" - implementation "com.google.android.exoplayer:exoplayer-smoothstreaming:$exoplayer_version" + def exoplayer_version = "1.4.1" + implementation "androidx.media3:media3-exoplayer:$exoplayer_version" + implementation "androidx.media3:media3-exoplayer-dash:$exoplayer_version" + implementation "androidx.media3:media3-exoplayer-hls:$exoplayer_version" + implementation "androidx.media3:media3-exoplayer-smoothstreaming:$exoplayer_version" } } diff --git a/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java b/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java index dc8a8e66e..590bab34a 100644 --- a/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java +++ b/just_audio/android/src/main/java/com/ryanheise/just_audio/AudioPlayer.java @@ -8,43 +8,46 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.DefaultLivePlaybackSpeedControl; -import com.google.android.exoplayer2.DefaultLoadControl; -import com.google.android.exoplayer2.DefaultRenderersFactory; -import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.LivePlaybackSpeedControl; -import com.google.android.exoplayer2.LoadControl; -import com.google.android.exoplayer2.MediaItem; -import com.google.android.exoplayer2.PlaybackException; -import com.google.android.exoplayer2.PlaybackParameters; -import com.google.android.exoplayer2.Player; -import com.google.android.exoplayer2.Player.PositionInfo; -import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.Timeline; -import com.google.android.exoplayer2.Tracks; -import com.google.android.exoplayer2.audio.AudioAttributes; -import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; -import com.google.android.exoplayer2.metadata.Metadata; -import com.google.android.exoplayer2.metadata.MetadataOutput; -import com.google.android.exoplayer2.metadata.icy.IcyHeaders; -import com.google.android.exoplayer2.metadata.icy.IcyInfo; -import com.google.android.exoplayer2.source.ClippingMediaSource; -import com.google.android.exoplayer2.source.ConcatenatingMediaSource; -import com.google.android.exoplayer2.source.MediaSource; -import com.google.android.exoplayer2.source.ProgressiveMediaSource; -import com.google.android.exoplayer2.source.ShuffleOrder; -import com.google.android.exoplayer2.source.ShuffleOrder.DefaultShuffleOrder; -import com.google.android.exoplayer2.source.SilenceMediaSource; -import com.google.android.exoplayer2.source.TrackGroup; -import com.google.android.exoplayer2.source.dash.DashMediaSource; -import com.google.android.exoplayer2.source.hls.HlsMediaSource; -import com.google.android.exoplayer2.trackselection.TrackSelectionArray; -import com.google.android.exoplayer2.upstream.DataSource; -import com.google.android.exoplayer2.upstream.DefaultDataSource; -import com.google.android.exoplayer2.upstream.DefaultHttpDataSource; -import com.google.android.exoplayer2.util.MimeTypes; -import com.google.android.exoplayer2.util.Util; +import androidx.media3.common.C; +import androidx.media3.exoplayer.DefaultLivePlaybackSpeedControl; +import androidx.media3.exoplayer.DefaultLoadControl; +import androidx.media3.exoplayer.ExoPlaybackException; +import androidx.media3.exoplayer.LivePlaybackSpeedControl; +import androidx.media3.exoplayer.LoadControl; +import androidx.media3.common.MediaItem; +import androidx.media3.common.PlaybackException; +import androidx.media3.common.PlaybackParameters; +import androidx.media3.common.Player; +import androidx.media3.common.Player.PositionInfo; +import androidx.media3.exoplayer.ExoPlayer; +import androidx.media3.common.Timeline; +import androidx.media3.common.Tracks; +import androidx.media3.common.TrackSelectionParameters; +import androidx.media3.common.TrackSelectionParameters.AudioOffloadPreferences; +import androidx.media3.common.AudioAttributes; +import androidx.media3.extractor.DefaultExtractorsFactory; +import androidx.media3.common.Metadata; +import androidx.media3.exoplayer.metadata.MetadataOutput; +import androidx.media3.extractor.metadata.icy.IcyHeaders; +import androidx.media3.extractor.metadata.icy.IcyInfo; +import androidx.media3.exoplayer.source.ClippingMediaSource; // Deprecated +// For some reason, this import triggers the [deprecation] warning, despite the +// warnings being suppressed at each use. +// import androidx.media3.exoplayer.source.ConcatenatingMediaSource; // Deprecated +import androidx.media3.exoplayer.source.MediaSource; // Deprecated +import androidx.media3.exoplayer.source.ProgressiveMediaSource; // Deprecated +import androidx.media3.exoplayer.source.ShuffleOrder; +import androidx.media3.exoplayer.source.ShuffleOrder.DefaultShuffleOrder; +import androidx.media3.exoplayer.source.SilenceMediaSource; // Deprecated +import androidx.media3.common.TrackGroup; +import androidx.media3.exoplayer.dash.DashMediaSource; // Deprecated +import androidx.media3.exoplayer.hls.HlsMediaSource; // Deprecated +import androidx.media3.exoplayer.trackselection.TrackSelectionArray; +import androidx.media3.datasource.DataSource; +import androidx.media3.datasource.DefaultDataSource; +import androidx.media3.datasource.DefaultHttpDataSource; +import androidx.media3.common.MimeTypes; +import androidx.media3.common.util.Util; import io.flutter.Log; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.EventChannel; @@ -556,10 +559,13 @@ private ShuffleOrder createShuffleOrder(int length, Integer firstIndex) { return new DefaultShuffleOrder(shuffleIndices, random.nextLong()); } - private ConcatenatingMediaSource concatenating(final Object index) { - return (ConcatenatingMediaSource)mediaSources.get((String)index); + + @SuppressWarnings("deprecation") + private androidx.media3.exoplayer.source.ConcatenatingMediaSource concatenating(final Object index) { + return (androidx.media3.exoplayer.source.ConcatenatingMediaSource)mediaSources.get((String)index); } + @SuppressWarnings("deprecation") private void setShuffleOrder(final Object json) { Map map = (Map)json; String id = mapGet(map, "id"); @@ -567,7 +573,7 @@ private void setShuffleOrder(final Object json) { if (mediaSource == null) return; switch ((String)mapGet(map, "type")) { case "concatenating": - ConcatenatingMediaSource concatenatingMediaSource = (ConcatenatingMediaSource)mediaSource; + androidx.media3.exoplayer.source.ConcatenatingMediaSource concatenatingMediaSource = (androidx.media3.exoplayer.source.ConcatenatingMediaSource)mediaSource; concatenatingMediaSource.setShuffleOrder(decodeShuffleOrder(mapGet(map, "shuffleOrder"))); List children = mapGet(map, "children"); for (Object child : children) { @@ -610,6 +616,7 @@ private DefaultExtractorsFactory buildExtractorsFactory(Map options) { return extractorsFactory; } + @SuppressWarnings("deprecation") private MediaSource decodeAudioSource(final Object json) { Map map = (Map)json; String id = (String)map.get("id"); @@ -640,7 +647,7 @@ private MediaSource decodeAudioSource(final Object json) { .createMediaSource(); case "concatenating": MediaSource[] mediaSources = getAudioSourcesArray(map.get("children")); - return new ConcatenatingMediaSource( + return new androidx.media3.exoplayer.source.ConcatenatingMediaSource( false, // isAtomic (Boolean)map.get("useLazyPreparation"), decodeShuffleOrder(mapGet(map, "shuffleOrder")), @@ -658,7 +665,7 @@ private MediaSource decodeAudioSource(final Object json) { for (int i = 0; i < looperChildren.length; i++) { looperChildren[i] = looperChild; } - return new ConcatenatingMediaSource(looperChildren); + return new androidx.media3.exoplayer.source.ConcatenatingMediaSource(looperChildren); default: throw new IllegalArgumentException("Unknown AudioSource type: " + map.get("type")); } @@ -765,11 +772,30 @@ private void ensurePlayerInitialized() { if (livePlaybackSpeedControl != null) { builder.setLivePlaybackSpeedControl(livePlaybackSpeedControl); } - if (offloadSchedulingEnabled) { - builder.setRenderersFactory(new DefaultRenderersFactory(context).setEnableAudioOffload(true)); - } player = builder.build(); - player.experimentalSetOffloadSchedulingEnabled(offloadSchedulingEnabled); + // The latest ExoPlayer enables offload scheduling by default but + // it doesn't support gapless playback below SDK level 33 or speec + // changing. To maintain backwards compatibility within just_audio, + // we set gapless playback and speed changing support as required, + // and let ExoPlayer choose whether it can enable offload + // scheduling depending on device support. If the app passes in + // androidOffloadSchedulingEnabled: true, we simply remove these + // requirements which may prevent gapless and speed changing from + // working, but will allow offload to work. A future release may + // expose more parameters to the app concerning offloading + // preferences. + player.setTrackSelectionParameters( + player.getTrackSelectionParameters() + .buildUpon() + .setAudioOffloadPreferences( + new AudioOffloadPreferences.Builder() + .setIsGaplessSupportRequired(!offloadSchedulingEnabled) + .setIsSpeedChangeSupportRequired(!offloadSchedulingEnabled) + .setAudioOffloadMode(AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_ENABLED) + .build() + ) + .build() + ); setAudioSessionId(player.getAudioSessionId()); player.addListener(this); }