-
Notifications
You must be signed in to change notification settings - Fork 5
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
Add MPEG-DASH support to playback #27
Changes from all commits
f5b1bcd
85800ef
90507f8
e5b9ce6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package com.scribd.armadillo.playback.mediasource | ||
|
||
import android.content.Context | ||
import com.google.android.exoplayer2.MediaItem | ||
import com.google.android.exoplayer2.offline.Download | ||
import com.google.android.exoplayer2.offline.DownloadHelper | ||
import com.google.android.exoplayer2.source.MediaSource | ||
import com.google.android.exoplayer2.source.dash.DashMediaSource | ||
import com.scribd.armadillo.download.DownloadTracker | ||
import com.scribd.armadillo.extensions.toUri | ||
import com.scribd.armadillo.models.AudioPlayable | ||
import javax.inject.Inject | ||
|
||
internal class DashMediaSourceGenerator @Inject constructor( | ||
private val mediaSourceHelper: HeadersMediaSourceHelper, | ||
private val downloadTracker: DownloadTracker) : MediaSourceGenerator { | ||
|
||
override fun generateMediaSource(context: Context, request: AudioPlayable.MediaRequest): MediaSource { | ||
val dataSourceFactory = mediaSourceHelper.createDataSourceFactory(context, request) | ||
|
||
downloadTracker.getDownload(request.url.toUri())?.let { | ||
if (it.state != Download.STATE_FAILED) { | ||
return DownloadHelper.createMediaSource(it.request, dataSourceFactory) | ||
} | ||
} | ||
|
||
val mediaItem = MediaItem.Builder() | ||
.setUri(request.url) | ||
.build() | ||
|
||
return DashMediaSource.Factory(dataSourceFactory) | ||
.createMediaSource(mediaItem) | ||
} | ||
|
||
override fun updateMediaSourceHeaders(request: AudioPlayable.MediaRequest) = mediaSourceHelper.updateMediaSourceHeaders(request) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.scribd.armadillo.playback.mediasource | ||
|
||
import android.content.Context | ||
import com.google.android.exoplayer2.upstream.DataSource | ||
import com.scribd.armadillo.models.AudioPlayable | ||
|
||
internal interface HeadersMediaSourceHelper { | ||
fun createDataSourceFactory(context: Context, request: AudioPlayable.MediaRequest): DataSource.Factory | ||
fun updateMediaSourceHeaders(request: AudioPlayable.MediaRequest) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.scribd.armadillo.playback.mediasource | ||
|
||
import android.content.Context | ||
import com.google.android.exoplayer2.upstream.DataSource | ||
import com.google.android.exoplayer2.upstream.DefaultDataSource | ||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource | ||
import com.scribd.armadillo.Constants | ||
import com.scribd.armadillo.HeadersStore | ||
import com.scribd.armadillo.download.CacheManager | ||
import com.scribd.armadillo.models.AudioPlayable | ||
import javax.inject.Inject | ||
import javax.inject.Singleton | ||
|
||
@Singleton | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just curious what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're probably right, but I think it's helpful to see it here to see that it's a singleton, otherwise it's hidden. |
||
internal class HeadersMediaSourceHelperImpl @Inject constructor( | ||
private val cacheManager: CacheManager, | ||
private val headersStore: HeadersStore | ||
): HeadersMediaSourceHelper { | ||
private val previousRequests = mutableMapOf<String, DefaultHttpDataSource.Factory>() | ||
|
||
override fun createDataSourceFactory(context: Context, request: AudioPlayable.MediaRequest): DataSource.Factory { | ||
val httpDataSourceFactory = DefaultHttpDataSource.Factory() | ||
.setUserAgent(Constants.getUserAgent(context)) | ||
.setConnectTimeoutMs(DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS) | ||
.setReadTimeoutMs(DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS) | ||
.setAllowCrossProtocolRedirects(true) | ||
|
||
previousRequests[request.url] = httpDataSourceFactory | ||
if (request.headers.isNotEmpty()) { | ||
headersStore.keyForUrl(request.url)?.let { | ||
headersStore.setHeaders(it, request.headers) | ||
} | ||
httpDataSourceFactory.setDefaultRequestProperties(request.headers) | ||
} | ||
|
||
val upstreamFactory = DefaultDataSource.Factory(context, httpDataSourceFactory) | ||
return cacheManager.playbackDataSourceFactory(context, upstreamFactory) | ||
|
||
} | ||
|
||
override fun updateMediaSourceHeaders(request: AudioPlayable.MediaRequest) { | ||
previousRequests[request.url]?.let { factory -> | ||
if (request.headers.isNotEmpty()) { | ||
headersStore.keyForUrl(request.url)?.let { | ||
headersStore.setHeaders(it, request.headers) | ||
} | ||
// Updating the factory instance updates future requests generated from this factory by ExoPlayer | ||
factory.setDefaultRequestProperties(request.headers) | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is DASH likely to diverge from HLS? If not, you should combine these cases.