androidx / media

Jetpack Media3 support libraries for media use cases, including ExoPlayer, an extensible media player for Android
Apache License 2.0
1.35k stars 320 forks source link

How to dynamically change the audio url using media3 exoplayer? #1430

Open allenxu-passion opened 3 weeks ago

allenxu-passion commented 3 weeks ago

I use media3 exoplayer to develop a music playback APP. Since the audio URL will become invalid, I need to request a new URL and replace it after it expires.

As follows

val upstreamFactory = ResolvingDataSource.Factory(
    DefaultHttpDataSource.Factory()
) {
    // replace url here when needed
    dataSpec -> dataSpec.withUri(dataSpec.uri)
  }
val myDataSourceFactory = CacheDataSource.Factory()
    .setCache(myLocalCache)
    .setUpstreamDataSourceFactory(upstreamFactory)
    .setCacheWriteDataSinkFactory(null)
    .setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR)
val myMediaSourceFactory = DefaultMediaSourceFactory(this).setDataSourceFactory(myDataSourceFactory)
ExoPlayer.Builder(this).apply {
    setMediaSourceFactory(myMediaSourceFactory)
}.build()

When the url is invalid, replace it with a new url through ResolvingDataSource. But there is a problem. When the URL is replaced, the player will stop playing after a while.

There's no obvious error logs. In DefaultHttpDataSource, the open(DataSpec dataSpec) method is executed and the connection is established. I guess CacheDataSource did a check and found that the two URLs were different or the container meta information was different, so it stopped. I'm not sure.

Is there a solution?

allenxu-passion commented 3 weeks ago

I use CacheDataSource because I need to implement download functionality.

tianyif commented 3 weeks ago

Hi @allenxu-passion,

Thanks for reporting! Just want to get problem clarified - does the player stop when playing the downloaded media or when playing from the upstream?

allenxu-passion commented 3 weeks ago

@tianyif Thanks for attention. The problem occurs when these two situations (downloaded and upstream) occur at the same time. I tried to simulate the situation where the url become invalid:

  1. Use one URL for downloading and another URL for online playback, and both are started at the same time. After 3 to 5 seconds, the player gets stuck, looping for 4 to 5 seconds of audio several times, and then stops.
  2. If half of the audio is downloaded and the first half is played normally, when it reaches the undownloaded position, upstream uses another URL request. At this time, the above situation will also occur and the player will get stuck.
  3. If I do not use CacheDataSource and only use upstream, then there is no problem in replacing the url through ResolvingDataSource. So my guess is that CacheDataSource sensed the url change and verified the address or audio data, causing the error.

When debugging, I sometimes get the following log, I'm not sure if it's related.

E  Audio sink error androidx.media3.exoplayer.audio.AudioSink$UnexpectedDiscontinuityException: Unexpected audio track timestamp discontinuity: expected 1000123379500, got 1000125248707 
    at androidx.media3.exoplayer.audio.DefaultAudioSink.handleBuffer(DefaultAudioSink.java:994) 
    at androidx.media3.exoplayer.audio.MediaCodecAudioRenderer.processOutputBuffer(MediaCodecAudioRenderer.java:744) 
    at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.drainOutputBuffer(MediaCodecRenderer.java:2010) 
    at androidx.media3.exoplayer.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:827) 
    at androidx.media3.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:1112) 
    at androidx.media3.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:544) 
    at android.os.Handler.dispatchMessage(Handler.java:103) 
    at android.os.Looper.loop(Looper.java:237) 
    at android.os.HandlerThread.run(HandlerThread.java:67)

Thanks and expect a reply.