Skip to content

Commit

Permalink
Interface for DRM Visibility
Browse files Browse the repository at this point in the history
- Adds DrmState to ArmadilloState, giving full visibility into DRM status to the client, including the expiration date for content.
- Splits SocketTimeout from HttpResponseCodeException, into ConnectivityException to better differentiate connectivity difficulties from
  developer error.
- Ensures that ArmadilloState is updated from the main thread consistently.
  • Loading branch information
kabliz committed Aug 23, 2024
1 parent 93eaed8 commit 4b0a2c4
Show file tree
Hide file tree
Showing 4 changed files with 11 additions and 16 deletions.
7 changes: 3 additions & 4 deletions Armadillo/src/main/java/com/scribd/armadillo/StateStore.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.scribd.armadillo

import android.content.Context
import android.os.Handler
import com.scribd.armadillo.actions.Action
import com.scribd.armadillo.actions.ClearErrorAction
Expand All @@ -27,8 +26,8 @@ internal interface StateStore {
}
}

internal class ArmadilloStateStore(private val reducer: Reducer, private val appContext: Context) :
StateStore.Modifier, StateStore.Provider, StateStore.Initializer {
internal class ArmadilloStateStore(private val reducer: Reducer, private val handler: Handler) :
StateStore.Modifier, StateStore.Provider, StateStore.Initializer {

private companion object {
const val TAG = "ArmadilloStateStore"
Expand All @@ -40,7 +39,7 @@ internal class ArmadilloStateStore(private val reducer: Reducer, private val app

override fun dispatch(action: Action) {
//run on consistent thread
Handler(appContext.mainLooper).post {
handler.post {
val newAppState = reducer.reduce(currentState, action)
armadilloStateObservable.onNext(newAppState)

Expand Down
3 changes: 2 additions & 1 deletion Armadillo/src/main/java/com/scribd/armadillo/di/AppModule.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.scribd.armadillo.di

import android.content.Context
import android.os.Handler
import com.scribd.armadillo.ArmadilloStateStore
import com.scribd.armadillo.Constants
import com.scribd.armadillo.Reducer
Expand Down Expand Up @@ -33,7 +34,7 @@ internal class AppModule(private val context: Context) {
@Singleton
@PrivateModule
@Provides
fun stateStore(reducer: Reducer): ArmadilloStateStore = ArmadilloStateStore(reducer, context)
fun stateStore(reducer: Reducer): ArmadilloStateStore = ArmadilloStateStore(reducer, Handler(context.mainLooper))

@Singleton
@Provides
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.scribd.armadillo.download.drm

import android.media.MediaDrm
import android.util.Log
import androidx.annotation.GuardedBy
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.MediaItem.DrmConfiguration
Expand All @@ -15,7 +14,6 @@ import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import com.google.android.exoplayer2.util.Assertions
import com.google.android.exoplayer2.util.Util
import com.google.common.collect.UnmodifiableIterator
import com.google.common.primitives.Ints
import com.scribd.armadillo.StateStore
import com.scribd.armadillo.actions.LicenseDrmErrorAction
Expand Down Expand Up @@ -73,11 +71,10 @@ internal class ArmadilloDrmSessionManagerProvider @Inject constructor(private va
private fun createManager(drmConfiguration: DrmConfiguration): DrmSessionManager {
val dataSourceFactory = this.drmHttpDataSourceFactory
?: DefaultHttpDataSource.Factory().setUserAgent(this.userAgent)
val httpDrmCallback = HttpMediaDrmCallback(if (drmConfiguration.licenseUri == null) null else drmConfiguration.licenseUri.toString(), drmConfiguration.forceDefaultLicenseUri, (dataSourceFactory)!!)
val var4: UnmodifiableIterator<*> = drmConfiguration.licenseRequestHeaders.entries.iterator()
val license = if (drmConfiguration.licenseUri == null) null else drmConfiguration.licenseUri.toString()
val httpDrmCallback = HttpMediaDrmCallback(license, drmConfiguration.forceDefaultLicenseUri, dataSourceFactory)

while (var4.hasNext()) {
val entry: Map.Entry<String, String> = var4.next() as Map.Entry<String, String>
drmConfiguration.licenseRequestHeaders.entries.forEach { entry ->
httpDrmCallback.setKeyRequestProperty(entry.key, entry.value)
}

Expand All @@ -92,17 +89,16 @@ internal class ArmadilloDrmSessionManagerProvider @Inject constructor(private va
return drmSessionManager
}

/** New original provider for this class */
/** New original provider for this class to supply DRM events to the StateStore */
class ArmadilloDrmProvider(private val stateStore: StateStore.Modifier) : ExoMediaDrm.Provider {
private var drmExpirationMillis: Long? = null
override fun acquireExoMediaDrm(uuid: UUID): ExoMediaDrm {
Log.i(TAG, "drm start")
//uses the main MediaDrm object that this class uses originally, then after we add new listeners to it.
val instance = FrameworkMediaDrm.newInstance(uuid)

//ExoMediaDrm.OnEventListener doesn't do anything at all, so its not used
if (Util.SDK_INT >= 23) {
instance.setOnKeyStatusChangeListener { exoMediaDrm, sessionId, keyStatuses, b ->
instance.setOnKeyStatusChangeListener { exoMediaDrm, sessionId, keyStatuses, hasNewUsableKey ->
keyStatuses.firstOrNull()?.let { keyStatus ->
//See MediaPlayer.onPlayerError() for playback-affecting errors. This block is more for transparency.
when(keyStatus.statusCode) {
Expand All @@ -125,7 +121,6 @@ internal class ArmadilloDrmSessionManagerProvider @Inject constructor(private va
}
//this listener often fires later than the above one
instance.setOnExpirationUpdateListener { exoMediaDrm, sessionId, expireMillis ->
Log.i(TAG, "drm event key expires ${expireMillis}")
drmExpirationMillis = expireMillis
stateStore.dispatch(LicenseExpirationDetermined(expireMillis.milliseconds))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ internal class DashMediaSourceGenerator @Inject constructor(
val dataSourceFactory = mediaSourceHelper.createDataSourceFactory(context, request)

val download = downloadTracker.getDownload(request.url.toUri())
val isDownloaded = download != null && download.state != Download.STATE_FAILED
val isDownloaded = download != null && download.state == Download.STATE_COMPLETED
val mediaItem = drmMediaSourceHelper.createMediaItem(context = context, request = request, isDownload = isDownloaded)

return if (isDownloaded) {
Expand Down

0 comments on commit 4b0a2c4

Please sign in to comment.