Skip to content

Instantly share code, notes, and snippets.

@clackbib
Last active June 14, 2018 06:49
Show Gist options
  • Save clackbib/1cb6a617e9d051ad7315dd6ad75750cd to your computer and use it in GitHub Desktop.
Save clackbib/1cb6a617e9d051ad7315dd6ad75750cd to your computer and use it in GitHub Desktop.
Ideas for MediaPlayer/Exoplayer Kotlin extensions
import android.util.Log
import com.google.android.exoplayer2.ExoPlaybackException
import com.google.android.exoplayer2.PlaybackParameters
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.Timeline
import com.google.android.exoplayer2.source.TrackGroupArray
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
private fun sample(player: Player) {
player.setup {
onLoadingChange {
Log.d("SAMPLE", "Loading = $it")
}
onError { exception ->
exception?.let {
Log.e("SAMPLE", it.message, it)
}
}
onTracksChanged { tracks, selections ->
Log.d("SAMPLE", "TrackGroupArray size=${tracks?.length}")
Log.d("SAMPLE", "TrackSelectionArray size=${selections?.length}")
}
}
}
private fun sampleDesugared(player: Player) {
player.addListener(object : Player.EventListener {
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {
Log.d("SAMPLE", "TrackGroupArray size=${trackGroups?.length}")
Log.d("SAMPLE", "TrackSelectionArray size=${trackSelections?.length}")
}
override fun onPlayerError(error: ExoPlaybackException?) {
error?.let {
Log.e("SAMPLE", it.message, it)
}
}
override fun onLoadingChanged(isLoading: Boolean) {
Log.d("SAMPLE", "Loading = $isLoading")
}
override fun onPositionDiscontinuity(reason: Int) {
// noop
}
override fun onRepeatModeChanged(repeatMode: Int) {
// noop
}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
// noop
}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?) {
// noop
}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
// noop
}
override fun onSeekProcessed() {
// noop
}
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {
// noop
}
})
}
class PlayerListenerBuilder {
private var onPlaybackParameters: ((PlaybackParameters?) -> Unit)? = null
private var onSeek: (() -> Unit)? = null
private var onTracksChanged: ((TrackGroupArray?, TrackSelectionArray?) -> Unit)? = null
private var onError: ((ExoPlaybackException?) -> Unit)? = null
private var onLoadingChange: ((Boolean?) -> Unit)? = null
private var onShuffleChange: ((Boolean?) -> Unit)? = null
private var onPositionDiscontinuity: ((Int?) -> Unit)? = null
private var onRepeatModeChange: ((Int?) -> Unit)? = null
private var onTimelineChange: ((Timeline?, Any?) -> Unit)? = null
private var onPlayerState: ((Boolean, Int) -> Unit)? = null
fun onPlaybackParameters(callback: ((PlaybackParameters?) -> Unit)) {
onPlaybackParameters = callback
}
fun onSeek(callback: (() -> Unit)) {
onSeek = callback
}
fun onTracksChanged(callback: (TrackGroupArray?, TrackSelectionArray?) -> Unit) {
onTracksChanged = callback
}
fun onError(callback: (ExoPlaybackException?) -> Unit) {
onError = callback
}
fun onLoadingChange(callback: (Boolean?) -> Unit) {
onLoadingChange = callback
}
fun onShuffleChange(callback: (Boolean?) -> Unit) {
onShuffleChange = callback
}
fun onPositionDiscontinuity(callback: (Int?) -> Unit) {
this.onPositionDiscontinuity = callback
}
fun onRepeatModeChange(callback: (Int?) -> Unit) {
onRepeatModeChange = callback
}
fun onTimelineChange(callback: (Timeline?, Any?) -> Unit) {
onTimelineChange = callback
}
fun onPlayerState(callback: (Boolean, Int) -> Unit) {
onPlayerState = callback
}
fun build(): Player.EventListener {
return object : Player.EventListener {
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {
onPlaybackParameters?.invoke(playbackParameters)
}
override fun onSeekProcessed() {
onSeek?.invoke()
}
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {
onTracksChanged?.invoke(trackGroups, trackSelections)
}
override fun onPlayerError(error: ExoPlaybackException?) {
onError?.invoke(error)
}
override fun onLoadingChanged(isLoading: Boolean) {
onLoadingChange?.invoke(isLoading)
}
override fun onPositionDiscontinuity(reason: Int) {
onPositionDiscontinuity?.invoke(reason)
}
override fun onRepeatModeChanged(repeatMode: Int) {
onRepeatModeChange?.invoke(repeatMode)
}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
onShuffleChange?.invoke(shuffleModeEnabled)
}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?) {
onTimelineChange?.invoke(timeline, manifest)
}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
onPlayerState?.invoke(playWhenReady, playbackState)
}
}
}
}
fun Player.setup(configure: PlayerListenerBuilder.() -> Unit) {
val builder = PlayerListenerBuilder()
builder.configure()
this.addListener(builder.build())
}
import android.net.Uri
import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.PlaybackParameters
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.source.DynamicConcatenatingMediaSource
import com.google.android.exoplayer2.source.ExtractorMediaSource
import com.google.android.exoplayer2.source.MediaSource
private fun sampleUsage(mediaSourceFactory: ExtractorMediaSource.Factory,
player: ExoPlayer,
uris: List<Uri>) {
val playlist = listOf(Uri.parse("http://sampleaudio.com/random.mp3"),
Uri.parse("file://downloads/random2.mp3"),
Uri.parse("file://downloads/random3.mp3"))
.toMediaSource(mediaSourceFactory)
val playlist2 = uris.toMediaSource(mediaSourceFactory)
player.prepare(playlist - 1 + playlist2) {
playWhenReady = true
shuffleModeEnabled = false
repeatMode = Player.REPEAT_MODE_ALL
playbackParameters = PlaybackParameters(1.2f, 0.8f)
}
}
private fun sampleUsageDesugared(mediaSourceFactory: ExtractorMediaSource.Factory,
player: ExoPlayer,
uris: List<Uri>) {
val trackOne = mediaSourceFactory.createMediaSource(Uri.parse("http://sampleaudio.com/random.mp3"))
val trackTwo = mediaSourceFactory.createMediaSource(Uri.parse("file://downloads/random2.mp3"))
val trackThree = mediaSourceFactory.createMediaSource(Uri.parse("file://downloads/random3.mp3"))
val playlist = DynamicConcatenatingMediaSource()
playlist.addMediaSource(trackOne)
playlist.addMediaSource(trackTwo)
playlist.addMediaSource(trackThree)
val playlist2 = DynamicConcatenatingMediaSource()
for (uri: Uri in uris) {
playlist2.addMediaSource(mediaSourceFactory.createMediaSource(uri))
}
val playlist3 = DynamicConcatenatingMediaSource()
playlist3.addMediaSource(playlist)
playlist.removeMediaSource(1)
playlist3.addMediaSource(playlist2)
player.playWhenReady = true
player.shuffleModeEnabled = false
player.repeatMode = Player.REPEAT_MODE_ALL
player.playbackParameters = PlaybackParameters(1.2f, 0.8f)
player.prepare(playlist3)
}
operator fun MediaSource.plus(other: MediaSource): DynamicConcatenatingMediaSource {
val source = DynamicConcatenatingMediaSource()
source.addMediaSource(this)
source.addMediaSource(other)
return source
}
operator fun DynamicConcatenatingMediaSource.minus(atIndex: Int): DynamicConcatenatingMediaSource {
this.removeMediaSource(atIndex)
return this
}
operator fun DynamicConcatenatingMediaSource.plus(other: MediaSource): DynamicConcatenatingMediaSource {
this.addMediaSource(other)
return this
}
operator fun DynamicConcatenatingMediaSource.plusAssign(other: MediaSource) {
this + other
}
operator fun DynamicConcatenatingMediaSource.minusAssign(atIndex: Int) {
this - atIndex
}
operator fun DynamicConcatenatingMediaSource.get(index: Int): MediaSource? {
return this.getMediaSource(index)
}
inline fun ExoPlayer.prepare(mediaSource: MediaSource, config: ExoPlayer.() -> Unit) {
config()
this.prepare(mediaSource)
}
operator fun Uri.plus(otherUri: Uri): MutableList<Uri> {
return mutableListOf(this, otherUri)
}
operator fun MutableList<Uri>.plus(otherUri: Uri): MutableList<Uri> {
this.add(otherUri)
return this
}
fun List<Uri>.toMediaSource(factory: ExtractorMediaSource.Factory): DynamicConcatenatingMediaSource {
val source = DynamicConcatenatingMediaSource()
this.forEach {
source += it.toMediaSource(factory)
}
return source
}
fun Uri.toMediaSource(factory: ExtractorMediaSource.Factory): MediaSource {
return factory.createMediaSource(this)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment