Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gapless playback broken in ExoPlayer >= 2.12.0 #7994

Closed
ashutoshgngwr opened this issue Sep 26, 2020 · 11 comments
Closed

Gapless playback broken in ExoPlayer >= 2.12.0 #7994

ashutoshgngwr opened this issue Sep 26, 2020 · 11 comments
Assignees

Comments

@ashutoshgngwr
Copy link

ashutoshgngwr commented Sep 26, 2020

When reporting a bug:

[REQUIRED] Issue description

After upgrading to ExoPlayer 2.12.0, the sounds (MP3) that used to play gapless, now have a noticeable gap in them.

I am not sure if this is a bug or an intended change. I went through the release notes and didn't find any changes that should cause this behaviour.

[REQUIRED] Reproduction steps

I (or rather the Dependabot) simply bumped the ExoPlayer in my application which relies heavily on gapless playback.

  1. Issue is easily reproducible. Clone the app repository and bump the version of ExoPlayer to 2.12.0 in app/build.gradle
  2. Play Moderate Rain from the list and notice the gap in playback after about 20 seconds
  3. Downgrade ExoPlayer from 2.12.0 to 2.11.8 in app/build.gradle
  4. Play Moderate Rain again from the list, but now the gap is gone

[REQUIRED] Link to test content

https://github.com/ashutoshgngwr/noice/raw/master/app/src/main/assets/moderate_rain.mp3

[REQUIRED] A full bug report captured from the device

I don't think this is needed here? Please let me know otherwise

[REQUIRED] Version of ExoPlayer being used

2.12.0

[REQUIRED] Device(s) and version(s) of Android being used

Xiaomi Mi A3 with Android 10 and HUAWEI P Smart with Android 9

@krocard
Copy link
Contributor

krocard commented Sep 28, 2020

I have unsuccessfully tried to reproduce the issue on my Pixel 3 XL running Android 10:

With Noice

git clone https://github.com/ashutoshgngwr/noice.git && cd noice
git revert 89ad85a3210338d4c1a23fedcabefdb232f96677 # restore ExoPlayer 2.12.0
./gradlew installPlaystoreDebug
# open noice and play "Moderate rain"

I could not hear any gap when "Moderate rain" loops around.

Noice code

I looked at https://github.com/ashutoshgngwr/noice/blob/809f131480bd4ef483988aedbfda5aa100183066/app/src/main/java/com/github/ashutoshgngwr/noice/sound/player/strategy/LocalPlaybackStrategy.kt#L41
which seems to be where Noice initialize it's player.
The code init code is quite simple, maybe the issue comes from the fading? I have not looked into it.

With our demo application

We would much prefer to reproduce the issue with our demo app. This allows us to be sure the issue comes from ExoPlayer itself if not the app using it.
Here is how to test it:

git clone https://github.com/google/ExoPlayer.git --branch 2.12.0 && cd ExoPlayer
# Set REPEAT_MODE_ONE in the demo player
sed -ie '/setPlayWhenReady/i\
      player.setRepeatMode(Player.REPEAT_MODE_ONE);
      ' demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java
git diff
ANDROID_SDK_ROOT=~/Android/Sdk ./gradlew demo:installNoDecoderExtensionsDebug
adb shell am start -a com.google.android.exoplayer.demo.action.VIEW -d https://raw.githubusercontent.com/ashutoshgngwr/noice/master/app/src/main/assets/moderate_rain.mp3

As with Noice, I could not hear any gap when looping around.

We need your help

Could you please try to reproduce on your devices with our demo application? This would tremendously help to figure out were the issue comes from.
If you reproduce with the demo app on your devices, the issue could come from a change in how MediaCodec format change are handled.

@krocard krocard self-assigned this Sep 28, 2020
@ashutoshgngwr
Copy link
Author

@krocard I'll get on this ASAP.

@ashutoshgngwr
Copy link
Author

ashutoshgngwr commented Sep 28, 2020

@krocard I am able to reproduce this on my device with the given sound sample on the demo application.

Edit: trynoice/android-app@89ad85a is a revert commit that downgrades ExoPlayer back to 2.11.8 from 2.12.0 which explains why you were having trouble reproducing the issue. Sorry for the incomplete information.

PS, you can reproduce it on the commit tagged 0.11.0 (trynoice/android-app@8ebdfaf) which uses ExoPlayer 2.12.0. You can then check out the tag 0.11.1 (trynoice/android-app@dd90b86) which reverts ExoPayer back to 2.11.8.

@krocard
Copy link
Contributor

krocard commented Oct 7, 2020

@ashutoshgngwr I have tested trynoice/android-app@8ebdfaf and can confirm that there are no gap on my device (Pixel 3).

@krocard I am able to reproduce this on my device with the given sound sample on the demo application.

If you can reproduce with our demo app on your device, then this is definitely a device specific issue.

The only thing I can think off that could break gapless in some devices are the changes made to MediaCodec format change propagation.

@Samrobbo do you think gapless audio loop could be broken by your Format propagation changes?

@krocard krocard assigned Samrobbo and unassigned krocard Oct 7, 2020
@ashutoshgngwr
Copy link
Author

ashutoshgngwr commented Oct 8, 2020

@krocard PS I can also reproduce this on an Android 9 Google APIs emulator image.

@krocard krocard assigned krocard and unassigned Samrobbo Oct 8, 2020
@krocard
Copy link
Contributor

krocard commented Oct 8, 2020

+ @lcf87 For visibility as he has done some gapless test recently.

@krocard
Copy link
Contributor

krocard commented Oct 8, 2020

I have been able to reproduce the issue on Android 8 emulator using the step #7994 (comment) section "With our demo application"

@krocard
Copy link
Contributor

krocard commented Oct 8, 2020

The issue is that flush is called twice (by applyAudioProcessorPlaybackParametersAndSkipSilence), first at
https://github.com/google/ExoPlayer/blob/r2.12.0/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java#L799 (not expected)
and then again at
https://github.com/google/ExoPlayer/blob/r2.12.0/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java#L717 (expected)

The unexpected call is because startMediaTimeUsNeedsSync was set to true by handleDiscontinuity called at the end of MediaCodecRenderer.onProcessedOutputBuffer.

@krocard
Copy link
Contributor

krocard commented Oct 15, 2020

This is taking longer than expected.

Last week, I could reproduce the issue with our gapless sweep setup on the emulator (2 gapless tracks back to back instead of a loop). So I looked into it and found weird inconsistency between platform (see hash differences bellow) which I thought caused the bug. See folded block bellow.
Nevertheless, today I realize that I can no longer hear a gap in the gapless sweep setup on any platform. So either a patch fixed it or my setup last week was corrupted in some way (possible as I had left over changes in my test patch stack).

So I need to start over in the gapless loop setup.

Click to see the weird inconsistencies in hash that is probably not causing the issue.

Tracking what is written to the AudioTrack as such:

  ByteArrayOutputStream written = new ByteArrayOutputStream();
  private int writeNonBlockingV21(AudioTrack audioTrack, ByteBuffer buffer, int size) {
    int before = buffer.position();
    int ret = audioTrack.write(buffer, size, AudioTrack.WRITE_NON_BLOCKING);
    if (ret > 0) written.write(buffer.array(), before, ret);
}

And then playing 2 gapless tracks in succession (fraunhofer gapless sweep). Dumping the content when stopping the AT

Android 27 emulator
AudioTrack: Written (1764440B) hash=1160723638

Android 29 emulator
D AudioTrack: Written (1764440B) hash=896480250

Android 29 pixel 3 XL
D AudioTrack: Written (1764440B) hash=1248743548

So the number of bytes written is always the same, but the hash is not (the hash algorithm is the same tough).

Additionally, the track transition (configuration = pendingConfiguration) always occur while a different number of bytes have been written in the audioTrack. But I think this is normal and caused by the AudioSink internal buffering.

I wonder if this is due to some emulator decoder issue. Decoding is supposed to be exact though as far as I know.

@krocard
Copy link
Contributor

krocard commented Oct 15, 2020

I am also trying to adapt our current gapless test (https://github.com/google/ExoPlayer/blob/dev-v2/library/core/src/test/java/com/google/android/exoplayer2/e2etest/EndToEndGaplessTest.java) to test a gapless loop.
Nevertheless I have not figure out a way to have ExoPlayer only play the media twice instead of forever.

@ojw28
Copy link
Contributor

ojw28 commented Apr 1, 2021

Let's use #8594 for tracking this issue. Closing as a duplicate.

@ojw28 ojw28 closed this as completed Apr 1, 2021
@ojw28 ojw28 added the duplicate label Apr 1, 2021
@google google locked and limited conversation to collaborators Jun 1, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants