Skip to content

Commit

Permalink
[APT-9577] Add DRM for downloads for offline usage : enable DRM downl…
Browse files Browse the repository at this point in the history
…oad/removal to execute in parallel to audio download/removal
  • Loading branch information
rubeus90 committed Feb 13, 2024
1 parent 88ff7bd commit 6f182fc
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ import com.scribd.armadillo.extensions.toUri
import com.scribd.armadillo.hasSnowCone
import com.scribd.armadillo.models.AudioPlayable
import com.scribd.armadillo.playback.createRenderersFactory
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.io.IOException
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton

internal interface DownloadEngine {
Expand All @@ -48,42 +51,53 @@ internal class ExoplayerDownloadEngine @Inject constructor(
private val downloadTracker: DownloadTracker,
private val stateModifier: StateStore.Modifier,
private val offlineDrmManager: OfflineDrmManager,
@Named(Constants.DI.GLOBAL_SCOPE) private val globalScope: CoroutineScope,
) : DownloadEngine {
override fun init() = downloadTracker.init()

override fun download(audiobook: AudioPlayable) {
// Download DRM license for offline use
offlineDrmManager.downloadDrmLicenseForOffline(audiobook)
globalScope.launch {
launch {
// Download DRM license for offline use
offlineDrmManager.downloadDrmLicenseForOffline(audiobook)
}

val downloadHelper = downloadHelper(context, audiobook.request)
launch {
val downloadHelper = downloadHelper(context, audiobook.request)

downloadHelper.prepare(object : DownloadHelper.Callback {
override fun onPrepared(helper: DownloadHelper) {
val request = helper.getDownloadRequest(audiobook.id.encodeInByteArray())
try {
startDownload(context, request)
} catch (e: Exception) {
if (hasSnowCone() && e is ForegroundServiceStartNotAllowedException) {
stateModifier.dispatch(ErrorAction(DownloadServiceLaunchedInBackground(audiobook.id)))
} else {
stateModifier.dispatch(ErrorAction(com.scribd.armadillo.error.ArmadilloIOException(e)))
downloadHelper.prepare(object : DownloadHelper.Callback {
override fun onPrepared(helper: DownloadHelper) {
val request = helper.getDownloadRequest(audiobook.id.encodeInByteArray())
try {
startDownload(context, request)
} catch (e: Exception) {
if (hasSnowCone() && e is ForegroundServiceStartNotAllowedException) {
stateModifier.dispatch(ErrorAction(DownloadServiceLaunchedInBackground(audiobook.id)))
} else {
stateModifier.dispatch(ErrorAction(com.scribd.armadillo.error.ArmadilloIOException(e)))
}
}
}
}
}

override fun onPrepareError(helper: DownloadHelper, e: IOException) =
stateModifier.dispatch(ErrorAction(com.scribd.armadillo.error.ArmadilloIOException(e)))
})
override fun onPrepareError(helper: DownloadHelper, e: IOException) =
stateModifier.dispatch(ErrorAction(com.scribd.armadillo.error.ArmadilloIOException(e)))
})
}
}
}

override fun removeDownload(audiobook: AudioPlayable) {
downloadManager.removeDownload(audiobook.request.url)
offlineDrmManager.removeDownloadedDrmLicense(audiobook)
globalScope.launch {
launch { downloadManager.removeDownload(audiobook.request.url) }
launch { offlineDrmManager.removeDownloadedDrmLicense(audiobook) }
}
}

override fun removeAllDownloads() {
downloadManager.removeAllDownloads()
offlineDrmManager.removeAllDownloadedDrmLicenses()
globalScope.launch {
launch { downloadManager.removeAllDownloads() }
launch { offlineDrmManager.removeAllDownloadedDrmLicenses() }
}
}

override fun updateProgress() = downloadTracker.updateProgress()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@ import android.content.Context
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.util.Log
import com.google.android.exoplayer2.util.Util
import com.scribd.armadillo.Constants
import com.scribd.armadillo.encryption.SecureStorage
import com.scribd.armadillo.error.DrmContentTypeUnsupportedException
import com.scribd.armadillo.extensions.toUri
import com.scribd.armadillo.models.AudioPlayable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.supervisorScope
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton

/**
Expand All @@ -23,16 +21,15 @@ import javax.inject.Singleton
@Singleton
internal class OfflineDrmManager @Inject constructor(
private val context: Context,
@Named(Constants.DI.GLOBAL_SCOPE) private val globalScope: CoroutineScope,
private val secureStorage: SecureStorage,
private val dashDrmLicenseDownloader: DashDrmLicenseDownloader,
) {
companion object {
private const val TAG = "OfflineDrmManager"
}

fun downloadDrmLicenseForOffline(audiobook: AudioPlayable) {
globalScope.launch(Dispatchers.IO) {
suspend fun downloadDrmLicenseForOffline(audiobook: AudioPlayable) {
withContext(Dispatchers.IO) {
audiobook.request.drmInfo?.let { drmInfo ->
val drmResult = when (@C.ContentType val type = Util.inferContentType(audiobook.request.url.toUri(), null)) {
C.TYPE_DASH -> dashDrmLicenseDownloader
Expand All @@ -50,8 +47,8 @@ internal class OfflineDrmManager @Inject constructor(
}
}

fun removeDownloadedDrmLicense(audiobook: AudioPlayable) {
globalScope.launch(Dispatchers.IO) {
suspend fun removeDownloadedDrmLicense(audiobook: AudioPlayable) {
withContext(Dispatchers.IO) {
audiobook.request.drmInfo?.let { drmInfo ->
secureStorage.getDrmDownload(context, audiobook.request.url, drmInfo.drmType)?.let { drmDownload ->
// Remove the persisted download info immediately so audio playback would stop using the offline license
Expand All @@ -67,8 +64,8 @@ internal class OfflineDrmManager @Inject constructor(
}
}

fun removeAllDownloadedDrmLicenses() {
globalScope.launch(Dispatchers.IO) {
suspend fun removeAllDownloadedDrmLicenses() {
withContext(Dispatchers.IO) {
// Make sure that a removal fails, it won't affect the removal of other licenses
supervisorScope {
secureStorage.getAllDrmDownloads(context).forEach { drmDownloadPair ->
Expand Down

0 comments on commit 6f182fc

Please sign in to comment.