I have HLS stream. When I trying insert VAST tag into stream :
- exoplayer not show AD with any errors and warnings in logcat
- exoplayer throwing exception, and after re-init with HlsMediaSource.Factory(..) works well
How i build ExoPlayer instance:
private fun initPlayer() {
adsLoader = ImaAdsLoader.Builder(requireContext())
.setAdEventListener { adEvent ->
// SOME LISTENER
}
.build()
val httpDataSource = DefaultHttpDataSource.Factory().createDataSource().apply {
setRequestProperty("Referer", "*some referer*")
}
// Set up the factory for media sources, passing the ads loader and ad view providers.
val httpDataSourceFactory = DataSource.Factory { httpDataSource }
val mediaSourceFactory: MediaSource.Factory =
DefaultMediaSourceFactory(httpDataSourceFactory)
.setLocalAdInsertionComponents(
{ unusedAdTagUri: MediaItem.AdsConfiguration? -> adsLoader }
) { //some view for ad
binding.unsafe.adView
}
// some buffering settings
val loadControlBuilder = DefaultLoadControl.Builder()
loadControlBuilder.setBufferDurationsMs(
AppConstants.Player.PLAYER_BUFFER_DURATION,
AppConstants.Player.PLAYER_BUFFER_DURATION,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS
)
// init player
playerInstance =
ExoPlayer.Builder(
requireContext(),
DefaultRenderersFactory(requireContext()),
mediaSourceFactory,
DefaultTrackSelector(requireContext()),
loadControlBuilder.build(),
DefaultBandwidthMeter.Builder(requireContext()).build(),
DefaultAnalyticsCollector(Clock.DEFAULT)
).setSeekBackIncrementMs(AppConstants.Player.PLAYER_SEEK_FORWARD)
.setSeekForwardIncrementMs(AppConstants.Player.PLAYER_SEEK_FORWARD)
.build()
}
How i setup my player for HLS stream:
private fun setupExoPlayer(source: String, adLink: String? = null) {
if (playerInstance == null) initPlayer()
binding {
player.playerView.player = playerInstance
adsLoader?.setPlayer(playerInstance)
player.playerView.subtitleView?.visibility = View.GONE
}
val adsConfig = adLink?.let { MediaItem.AdsConfiguration.Builder(Uri.parse(adLink)).build() }
val mediaItem = MediaItem.Builder()
.setUri(source)
.setAdsConfiguration(adsConfig)
.build()
val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
val hlsMediaSource: HlsMediaSource = HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(mediaItem)
playerInstance?.apply {
setMediaSource(hlsMediaSource)
prepare()
addListener(playerErrorHandler) // adding some listeners here
playWhenReady = true
}
}
How i insert AD VAST tag after some playing time, difference in setMediaSource or setMediaItem of this source:
private fun injectAdIntoExoPlayer(adLink: String) {
val adsConfig = MediaItem.AdsConfiguration.Builder(Uri.parse(adLink)).build()
val mediaItemWithAd = playerInstance?.currentMediaItem?.buildUpon()?.setAdsConfiguration(
adsConfig
)?.build()
mediaItemWithAd?.let {
val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
val hlsMediaSource: HlsMediaSource = HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(mediaItemWithAd)
// - first case behavior (not showing ad !!!)
playerInstance?.setMediaSource(hlsMediaSource)
// - second case behavior (showing ad !!!)
// playerInstance?.setMediaItem(hlsMediaSource.mediaItem)
}
}
In second case behaviour exoplayer throws this. Same exceptions I have when init player without HlsMediaSource factory:
E/LoadTask: Unexpected exception loading stream
java.lang.ArrayIndexOutOfBoundsException: size=9400 offset=0 byteCount=-940
at com.android.okhttp.okio.Util.checkOffsetAndCount(Util.java:30)
at com.android.okhttp.okio.RealBufferedSource$1.read(RealBufferedSource.java:368)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.readInternal(DefaultHttpDataSource.java:768)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.read(DefaultHttpDataSource.java:478)
at com.google.android.exoplayer2.upstream.StatsDataSource.read(StatsDataSource.java:92)
at com.google.android.exoplayer2.extractor.DefaultExtractorInput.readFromUpstream(DefaultExtractorInput.java:291)
at com.google.android.exoplayer2.extractor.DefaultExtractorInput.read(DefaultExtractorInput.java:68)
at com.google.android.exoplayer2.extractor.ts.TsExtractor.fillBufferWithAtLeastOnePacket(TsExtractor.java:433)
at com.google.android.exoplayer2.extractor.ts.TsExtractor.read(TsExtractor.java:323)
at com.google.android.exoplayer2.source.hls.BundledHlsMediaChunkExtractor.read(BundledHlsMediaChunkExtractor.java:67)
at com.google.android.exoplayer2.source.hls.HlsMediaChunk.feedDataToExtractor(HlsMediaChunk.java:473)
at com.google.android.exoplayer2.source.hls.HlsMediaChunk.loadMedia(HlsMediaChunk.java:437)
at com.google.android.exoplayer2.source.hls.HlsMediaChunk.load(HlsMediaChunk.java:394)
at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:412)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
E/LoadTask: Unexpected exception loading stream
java.lang.ArrayIndexOutOfBoundsException: size=8192 offset=0 byteCount=-33
at com.android.okhttp.okio.Util.checkOffsetAndCount(Util.java:30)
at com.android.okhttp.okio.RealBufferedSource$1.read(RealBufferedSource.java:368)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.readInternal(DefaultHttpDataSource.java:768)
at com.google.android.exoplayer2.upstream.DefaultHttpDataSource.read(DefaultHttpDataSource.java:478)
at com.google.android.exoplayer2.upstream.StatsDataSource.read(StatsDataSource.java:92)
at com.google.android.exoplayer2.upstream.DataSourceInputStream.read(DataSourceInputStream.java:80)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:288)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:351)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:180)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:172)
at java.io.BufferedReader.read(BufferedReader.java:193)
at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.checkPlaylistHeader(HlsPlaylistParser.java:296)
at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.parse(HlsPlaylistParser.java:259)
at com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistParser.parse(HlsPlaylistParser.java:68)
at com.google.android.exoplayer2.upstream.ParsingLoadable.load(ParsingLoadable.java:176)
at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:412)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
So i need inject my AD Vast tag with exoplayer:extension-ima dependency without handling player error and reiniting with setMediaSource method and without my AD link