Skip to content

Instantly share code, notes, and snippets.

@CristianMG
Created December 30, 2019 10:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save CristianMG/d4d4f3e15d089697b72e1ba599f309ca to your computer and use it in GitHub Desktop.
Save CristianMG/d4d4f3e15d089697b72e1ba599f309ca to your computer and use it in GitHub Desktop.
package com.cristianmg.newplayerivoox.player.ads
import android.net.Uri
import android.os.Looper
import com.cristianmg.newplayerivoox.player.Track
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.C.TIME_END_OF_SOURCE
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.source.ads.AdPlaybackState
import com.google.android.exoplayer2.source.ads.AdsLoader
import com.google.android.exoplayer2.source.ads.AdsMediaSource
import com.google.android.exoplayer2.upstream.DataSpec
import com.google.android.exoplayer2.util.Assertions
import com.google.android.exoplayer2.util.MimeTypes
import timber.log.Timber
import java.io.IOException
class FixedAdsLoader(
private val relatedTrack: Track
) : AdsLoader, Player.EventListener {
private var player: Player? = null
private var supportedMimeTypes: List<String> = mutableListOf()
private var eventListener: AdsLoader.EventListener? = null
private var adPlaybackState: AdPlaybackState? = null
override fun start(
eventListener: AdsLoader.EventListener,
adViewProvider: AdsLoader.AdViewProvider?
) {
Assertions.checkState(
player != null, "Set player using adsLoader.setPlayer before preparing the player."
)
this.eventListener = eventListener
player?.addListener(this)
val midRollPosition = relatedTrack.getDuration() * 1000 / 2
adPlaybackState = AdPlaybackState(0, midRollPosition, TIME_END_OF_SOURCE)
adPlaybackState = adPlaybackState?.withAdUri(
0,
0,
Uri.parse("https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3")
)
updateAdPlaybackState()
}
override fun stop() {
if (player == null)
return
}
override fun onIsPlayingChanged(isPlaying: Boolean) {
Timber.d("${player?.isPlayingAd} /// ${player?.currentAdGroupIndex} /// ${player?.currentAdIndexInAdGroup}")
}
override fun setPlayer(player: Player?) {
Assertions.checkState(Looper.getMainLooper() == Looper.myLooper())
Assertions.checkState(
player == null || player.applicationLooper == Looper.getMainLooper()
)
this.player = player
}
override fun handlePrepareError(
adGroupIndex: Int,
adIndexInAdGroup: Int,
exception: IOException?
) {
Timber.e("AdgroupIndex adGroupIndex:$adGroupIndex adIndexInAdGroup:$adIndexInAdGroup exception: $exception")
if (player == null)
return
val uri =
adPlaybackState?.adGroups?.getOrNull(adGroupIndex)?.uris?.getOrNull(adIndexInAdGroup)
try {
handleAdPrepareError(adGroupIndex, adIndexInAdGroup, exception)
} catch (e: Exception) {
maybeNotifyInternalError(uri, "handlePrepareError", e)
}
}
private fun maybeNotifyInternalError(uri: Uri?, name: String, cause: Exception) {
val message = "Internal error in $name"
Timber.e(cause, message)
adPlaybackState?.let { aps ->
// We can't recover from an unexpected error in general, so skip all remaining ads.
for (i in 0 until aps.adGroupCount) {
adPlaybackState = aps.withSkippedAdGroup(i)
}
updateAdPlaybackState()
uri?.let {
eventListener?.onAdLoadError(
AdsMediaSource.AdLoadException.createForUnexpected(
RuntimeException(
message,
cause
)
),
DataSpec(uri)
)
}
}
}
/** TODO how we have to handle this **/
private fun handleAdPrepareError(
adGroupIndex: Int,
adIndexInAdGroup: Int,
exception: IOException?
) {
}
private fun updateAdPlaybackState() {
eventListener?.onAdPlaybackState(adPlaybackState)
}
override fun setSupportedContentTypes(vararg contentTypes: Int) {
val supportedMimeTypes = mutableListOf<String>()
for (contentType in contentTypes) {
when (contentType) {
C.TYPE_DASH -> supportedMimeTypes.add(MimeTypes.APPLICATION_MPD)
C.TYPE_HLS -> supportedMimeTypes.add(MimeTypes.APPLICATION_M3U8)
C.TYPE_OTHER -> supportedMimeTypes.addAll(
listOf(
MimeTypes.VIDEO_MP4,
MimeTypes.VIDEO_WEBM,
MimeTypes.VIDEO_H263,
MimeTypes.AUDIO_MP4,
MimeTypes.AUDIO_MPEG
)
)
C.TYPE_SS -> {
// IMA does not support Smooth Streaming ad media.
}
}
}
this.supportedMimeTypes = supportedMimeTypes.toList()
}
override fun release() {
player?.removeListener(this)
player = null
eventListener = null
adPlaybackState = null
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment