Offline Playback
This tutorial will walk you through the facilities that the Bitmovin Player Android SDK offers for working with offline content and offline playback.
Overview
The Bitmovin Android SDK minimizes offline content management and playback to a few API calls, and allows fast integration of offline capabilities.
Setup
In order to use offline functionality, the following dependency must be added manually to your app's build.gradle
file:
implementation("androidx.localbroadcastmanager:localbroadcastmanager:1.1.0")
Additionally, the permission for checking the network state is required in the Android Manifest:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Depending on the location the offline data is saved, it may also be required to add the STORAGE permission to the Android Manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Assets are downloaded using a foreground service. In order to be able to start it, the FOREGROUND_SERVICE
permission is required. When targeting Android 14 (API level 34) and above, the FOREGROUND_SERVICE_DATA_SYNC
permission also has to be added. See the Android Developers guide for more details.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
When targeting Android 13 (API level 33) and above, the following permission has to be declared in the manifest and requested at runtime before starting downloads, otherwise the notifications posted by the download service will not be displayed. See the Android Developers guide for more details.
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
API Usage
The core component responsible for handling offline content is the OfflineContentManager
. It allows fetching the current offline state, requesting state changes and generating SourceConfig
for offline playback.
Initialization
One OfflineContentManager
is linked with one SourceConfig
. When instantiating an OfflineContentManager
, it is required to provide a storage location, a unique ID for the content and a listener of type OfflineContentManagerListener
.
val listener = object : OfflineContentManagerListener {
override fun onCompleted(sourceConfig: SourceConfig, offlineContentOptions: OfflineContentOptions) {}
override fun onError(sourceConfig: SourceConfig, errorEvent: ErrorEvent) {}
override fun onProgress(sourceConfig: SourceConfig, progress: Float) {}
override fun onOptionsAvailable(sourceConfig: SourceConfig, offlineContentOptions: OfflineContentOptions) {}
override fun onDrmLicenseUpdated(sourceConfig: SourceConfig) {}
override fun onSuspended(sourceConfig: SourceConfig) {}
override fun onResumed(sourceConfig: SourceConfig) {}
}
val offlineContentManager = OfflineContentManager.getOfflineContentManager(
sourceConfig = SourceConfig.fromUrl("//url.to/online/resource.mpd"),
location = getDir("offline", ContextWrapper.MODE_PRIVATE).path,
id = "uniqueID",
listener = listener,
context = androidContext
)
OfflineContentManager
Interaction with the OfflineContentManager
is mostly done asynchronously. The results when calling getOptions
, process
and renewDrmLicense
are received by the OfflineContentManagerListener
, which is passed at creation of the OfflineContentManager
. Only calls to getRemainingOfflineLicenseDuration
, offlineSourceConfig
and release
are synchronous and return their values immediately.
OfflineContentManagerListener
The OfflineContentManagerListener
provides seven callbacks:
- onOptionsAvailable is called after a
getOptions
call, or when the state of an OfflineOptionEntry has changed. The states can beNOT_DOWNLOADED
,DOWNLOADED
,DOWNLOADING
orDELETING
. - onProgress is called when the progress for an ongoing operation has changed e.g. the download progress.
- onCompleted is called when an operation has completed. This could be the downloading or deleting of content.
- onDrmLicenseUpdated is called when the stored DRM license was updated.
- onError is called when an error occurs.
- onSuspended is called when all actions have been suspended.
- onResumed is called when all actions have been resumed.
OfflineContentOptions
OfflineContentOptions
can be received by calling getOptions
on the OfflineContentManager
for a specific SourceConfig
. OfflineContentOptions
represent the "offline state" of a stream and each available track (video, audio, captions/subtitles). It contains four lists, containing the different types: video, audio, text (captions/subtitles) and thumbnails.
Downloading Content
Once an OfflineContentManger
is created, downloading of content can be started. To gain knowledge of the available tracks and their state, getOptions
should be called:
offlineContentManager.getOptions()
As this is an asynchronous call, the response must be handled in the OfflineContentManagerListener
callback:
override fun onOptionsAvailable(sourceConfig: SourceConfig, offlineContentOptions: OfflineContentOptions) {
// Handle offline content options
}
From the received OfflineContentOptions
the separate OfflineOptionEntry
can be received and selected for download or deletion. As an example, the VideoOfflineOptionEntry
with the highest bitrate will be selected here for download:
val bestVideoOption = offlineContentOptions.videoOptions.maxByOrNull { it.bitrate } ?: return
bestVideoOption.action = OfflineOptionEntryAction.Download
Note: Depending on the current state of the OfflineOptionEntry
it might be not possible to set all actions. For example, already downloaded content cannot be downloaded again.
After successfully preparing the download, by setting the desired actions, the OfflineContentOptions
object is pushed back to the (correct) OfflineContentManager
using the process(...)
call:
offlineContentManager.process(offlineContentOptions);
This triggers an onOptionsAvailable(...)
listener callback. The OfflineOptionEntry
entries which were selected to be downloaded will have the state DOWNLOADING
now. Until the onCompleted(...)
listener is invoked, the onProgress(...)
listener is called frequently with updated information about the ongoing operation.
Playback of Offline Content
When the onCompleted(...)
listener callback has been invoked, meaning at least one OfflineOptionEntry
is in the DOWNLOADED
state, an OfflineSourceConfig
can be requested from the OfflineContentManager
for playback. With this OfflineSourceConfig
a SourceConfig
can be created and loaded into the Player
as usual:
...
bitmovinPlayer.load(offlineContentManager.offlineSourceConfig);
The Player is now ready to play the offline stored content.
Updated 8 months ago