Skip to main content
VESDK/Android/Guides/Audio Overlays/Add Overlays
Language:

From Remote URL

VideoEditor SDK supports loading audio files from a remote URL, this can be a resource hosted by a hosting provider or your servers.

Download audio#

For each remote resource, we create a File in the cache directory and download the remote resource. Since file handling and downloading are IO operations, we do this inside a coroutine using the IO dispatcher.

Add audio assets to AssetConfig#

To use the audio clips, they must first be available in the SDK's backend. This is done by adding the audio assets to the AssetConfig. The AudioTrackAsset takes in a unique identifier, an AudioSource, and optionally the title, artist, and duration in seconds.

Create categories#

We then add the audio clips to an AudioTrackCategoryItem object that holds the metadata of the category such as a unique identifier, title, and optionally a preview image.

The AudioTrackItem uses the same identifier as the one specified when creating the corresponding AudioTrackAsset. It also optionally takes an ImageSource that is used to display its thumbnail.

Configure UiConfigAudio#

Here, we configure UiConfigAudio and set the audio track lists.

File:
class AddAudioOverlaysFromRemoteURL(private val activity: AppCompatActivity) : Example(activity) {
// Filenames of remote assets
private val assetNames = arrayOf("elsewhere", "trapped_in_the_upside_down")
override fun invoke() {
activity.lifecycleScope.launch {
showLoader(true)
val files = runCatching {
coroutineScope {
// Download each of the remote resources
assetNames.map {
async(Dispatchers.IO) {
// Create file in cache directory
val file = File(activity.cacheDir, it)
if (file.exists()) file.delete()
file.createNewFile()
// Save remote resource to file
URL("https://img.ly/static/example-assets/$it.mp3").openStream().use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
file
}
}.awaitAll() // Wait for all downloads to finish
}
}.getOrNull()
showLoader(false)
files?.let {
startEditor(it)
} ?: showMessage("Error downloading the file")
}
}
private fun startEditor(files: List<File>) {
// In this example, we do not need access to the Uri(s) after the editor is closed
// so we pass false in the constructor
val settingsList = VideoEditorSettingsList(false)
// Set the source as the Uri of the image to be loaded
.configure<LoadSettings> {
it.source = activity.resourceUri(R.raw.skater)
}
// Add asset to AssetConfig
assetNames.forEachIndexed { idx, name ->
settingsList.config.addAsset(AudioTrackAsset("id_$name", AudioSource.create(files[idx])))
}
val audioTrackCategories = listOf(
AudioTrackCategoryItem(
"audio_cat_elsewhere", "Elsewhere", assetNames.map { AudioTrackItem("id_$it") }
)
)
settingsList.configure<UiConfigAudio> {
it.setAudioTrackLists(audioTrackCategories)
}
// Start the video editor using VideoEditorBuilder
// The result will be obtained in onActivityResult() corresponding to EDITOR_REQUEST_CODE
VideoEditorBuilder(activity)
.setSettingsList(settingsList)
.startActivityForResult(activity, EDITOR_REQUEST_CODE)
// Release the SettingsList once done
settingsList.release()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
intent ?: return
if (requestCode == EDITOR_REQUEST_CODE) {
// Wrap the intent into an EditorSDKResult
val result = EditorSDKResult(intent)
when (result.resultStatus) {
EditorSDKResult.Status.CANCELED -> showMessage("Editor cancelled")
EditorSDKResult.Status.EXPORT_DONE -> showMessage("Result saved at ${result.resultUri}")
else -> {
}
}
}
}
}