Skip to main content

Offline downloads using the react-native SDK

Overview

The VdoCipher react-native sdk also offers capability to download videos to local storage for offline playback on android devices running Lollipop and above (api level 20+).

It includes apis to :

  • fetch available download options for a video in your dashboard
  • download media assets to local storage
  • track download progress
  • manage downloads (query, delete, stop or resume downloads)

We'll explore a typical download workflow in this document. The example app on github provides code examples for a typical use case.

Note: Ensure android.permission.FOREGROUND_SERVICE_DATA_SYNC is declared in the manifest for download to work when target SDK version is set as 34 and higher.

Add the below permission in the android/app/src/main/AndroidManifest.xml -

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

Get the available options for a media

A video in your VdoCipher dashboard may be encoded in multiple bitrates (for adaptive streaming) or has multiple audio tracks for different languages. Hence, there are some options regarding what exactly needs to be downloaded. For offline playback, adaptive doesn't make sense, and also the user typically has a preferred language. So, you must specify exactly one video track and exactly one audio track for download.

The first step is to get the available options for the video. We'll use the getDownloadOptions function for this purpose. We'll need a playbackInfo and otp or signature corresponding to the video to fetch the options. We can also pass the customPlayerId along with the otp and playbackInfo which should be applied to the downloaded video.

import {VdoDownload} from 'vdocipher-rn-bridge';

// assuming we have otp and playbackInfo
VdoDownload.getDownloadOptions({otp, playbackInfo}).then(
({downloadOptions, enqueue}) => {
console.log('Got download options', downloadOptions);
},
);

The two parameters in the response to note are downloadOptions and enqueue.

downloadOptions is an object that contains a mediaInfo object (with general details of the media, such as title, description as set in your VdoCipher dashboard, etc.) and an array of track objects corresponding to the available audio and video track options. Each track object in the array corresponds to a audio or video track (specified by its type property) and contains relevant information such as bitrate, resolution, language, etc.

downloadOption:

PropertyTypeDescription
mediaIdstringstring identifying the video in your dashboard
mediaInfoobjectobject containing description of the video
availableTracksobject[]array of track objects available to download

where mediaInfo is:

PropertyTypeDescription
mediaIdstringstring identifying the video in your dashboard
titlestringvideo title as set in your dashboard
descriptionstringvideo description as set in your dashboard
durationnumbervideo duration in milliseconds

and track is:

PropertyTypeDescription
idnumberan integer identifying the track
typestringone of 'audio', 'video', 'captions', 'combined' or 'unknown'
languagestringoptional: language of track if relevant
bitratenumberoptional: bitrate in bps if relevant
widthnumberoptional: width resolution if relevant
heightnumberoptional: height resolution if relevant otherwise

enqueue is a function that you call after you have decided the track selections to start the download. It takes an object as argument which has a selections property equal to an array containing the indices of selected tracks from the downloadOptions.availableTracks array.

Once we've obtained the available options, the next step is to make a selection of which tracks to download.

Select the tracks to download, and enqueue request

As mentioned earlier in this document, we need to select exactly one audio track and one video track.

Once we have the download options, we can make selections automatically based on user preferences etc. (e.g. select the highest quality/bitrate) or present the options to the user to choose.

Once a selection has been made (automatically or by the user), call the enqueue function with the selections.

// selections must include exactly one audio track (`type` === 'audio') and one video track (`type` === 'video')
// In case of iOS only video track is required. No audio track option in iOS.
// track indices are the index of the track in the `availableTracks` array in received `downloadOptions`

const selections = getSelection(downloadOptions.availableTracks);
enqueue({selections}).then(() => console.log('enqueue success'));

This will add the request to the download queue and start download when all requests enqueued before have completed.

Monitoring download progress

We can monitor the progress of the download queue by registering a event listener.

// register listeners for download events; recommended to do this in componentDidMount()

this.state.unregister.push(
VdoDownload.addEventListener('onQueued', (mediaId, status) =>
console.log('queued', mediaId),
),
);
this.state.unregister.push(
VdoDownload.addEventListener('onChanged', (mediaId, status) =>
console.log('changed', mediaId, downloadStatus.downloadPercent + '%'),
),
);
this.state.unregister.push(
VdoDownload.addEventListener('onCompleted', (mediaId, status) =>
console.log('completed', mediaId),
),
);
this.state.unregister.push(
VdoDownload.addEventListener('onFailed', (mediaId, status) =>
console.warn('failed', mediaId, downloadStatus.reason),
),
);
this.state.unregister.push(
VdoDownload.addEventListener('onDeleted', (mediaId) =>
console.log('deleted', mediaId),
),
);

// unregister listeners in componentWillUnmount()
this.state.unregister.forEach((fn) => fn());

Query for downloads

The sdk allows querying for all downloads managed by it or only specific downloads specified by filters.

Queries provide status of all downloads that are queued or downloading or completed.

// query for all downloads
VdoDownload.query().then((statusArray) => {
console.log('query results', statusArray);
});

// filtered query
var queryFilters = {
mediaId: ['abc', 'xyz'],
status: ['pending', 'failed'],
};

VdoDownload.query(queryFilters).then((statusArray) => {
console.log('filtered query results', statusArray);
});

A query result is provided as an array of downloadStatus objects which provides information such as the mediaInfo, status, any errors if they occured while downloading, etc.

downloadStatus:

PropertyTypeDescription
mediaInfoobjectobject containing description of the video
statusstringone of 'pending', 'downloading', 'paused', 'completed, or 'failed'
reasonintif status is 'failed', this identifies an error reason
reasonDescriptionstringerror reason description
totalSizeBytesinttotal download size estimate in bytes. Not supported for iOS
bytesDownloadedintestimated downloaded bytes. Not supported for iOS
downloadPercentintdownload progress in percent
lastModifiedTimestampnumberlast status change timestamp. Not supported for iOS

Stop a download

To stop an offline download, use the stop() method. You will also receive a onChanged event if you have an event listener registered for the event.

// Specify an array of mediaId's to stop
VdoDownload.stop([mediaId]);

Resume a download

To resume an offline download, use the resume() method. You will also receive a onChanged event if you have an event listener registered for the event.

// Specify an array of mediaId's to resume
VdoDownload.resume([mediaId]);

Delete a download

To delete an offline download, use the remove() method. This will cancel the download if it is still downloading or pending and remove any downloaded media files. You will also receive a onDeleted event if you have an event listener registered for the event.

// Specify an array of mediaId's to delete
VdoDownload.remove([mediaId]);

Check if video is expired

Not supported in iOS

To check if a video is expired, use the isExpired() method. This will return true or false based on whether the provided media id is expired or not.

// Specify a mediaId for which you want to check the expiry
await VdoDownload.isExpired(mediaId);
  • If the video is not yet downloaded, this will throw an error.
  • If the video is expired, adjust the UI accordingly. Avoid playing the expired video to prevent displaying error code 6187 along with a message; the error message will provide viewers with context about the video expiration.
  • For expired video, you can choose to either re-download the video or remove the video.

Offline Playback

For playing downloaded videos, the initial step involves creating an offline embed info for offline playback. This offline embed info is then utilized in conjunction with the VdoPlayerView.

import {VdoPlayerView} from 'vdocipher-rn-bridge';

const embedInfo = {offline: true, mediaId: 'mediaId-of-the-downloaded-video'};

// in JSX

<VdoPlayerView style={{height: 200, width: '100%'}} embedInfo={embedInfo} />;
note

Downloads does not work for iOS in debug mode when flipper is enabled. To test iOS downloads in debug mode, disable flipper.