Skip to main content
VESDK/Android/Guides/Audio Overlays

Soundstripe integration

VideoEditor SDK for Android allows fetching Audio from Soundstripe.

The VideoEditor SDK has two options, making it easier to add Soundstripe to your editor instance.

Option 1. Using the built-in SoundstripeProxyPagingSource#

The simplest solution is to proxy Soundstripe's API (https://docs.soundstripe.com/docs/integrating-soundstripes-content-into-your-application#option-2-proxy-soundstripes-api).

You can configure the endpoint URI in the SoundstripeSettings by setting the proxySourceUri. Additionally, you can add headers that are sent with each request using addHeader(name: String, content: String), which is useful if you need user authentication.

Within your module's build.gradle file, insert the soundstripe module.

IMGLY.configure {
...
modules {
...
include 'ui:soundstripe'
}
}

After applying the module and syncing with Gradle, you can set your proxySourceUri in the SoundstripeSettings of your SettingsList.

settingsList.configure<SoundstripeSettings> {
it.proxySourceUri = "http://example.com/soundsripe"
}

Option 2. Using a custom SoundstripePagingSource#

SoundstripePagingSource is an abstract class that provides a basic implementation of the Paging Library's PagingSource class. It provides the core functionality for loading a page of audio tracks from a data source. The SoundstripePagingSource class can be extended to create a custom implementation for loading audio tracks from a specific data source.

Implementation#

To implement a custom SoundstripePagingSource:

  1. Create a new class that extends SoundstripePagingSource.
  2. Override the onCreate method. This method is called when the Paging Library is first set up and is used to initialize any resources required by the custom SoundstripePagingSource.
  3. Override the load method. This method is called when the Paging Library needs to load a new page of data. In this method, you should load the audio tracks from the data source and return the result as a LoadResult.
  4. Override the getRefreshKey method if required. This method is used to determine the key to be passed to the load method when the Paging Library needs to refresh the data.
  5. Add you class by setting SoundstripeSettings.pagingSourceClass=MyProxyPagingSource::class.java.

Here is an example implementation of a custom SoundstripePagingSource, showing our SoundstripeProxyPagingSource implementation:

open class SoundstripeProxyPagingSource @Keep constructor(
private val query: String = ""
) : SoundstripePagingSource<Int>() {
private val defaultCover = ImageSource.create(R.drawable.imgly_placeholder_album_cover)
private lateinit var endpoints: SoundstripeProxyEndpoints
override fun onCreate(context: Context) {
endpoints = stateHandler[SoundstripeSettings::class].proxyApi
}
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, AudioTrackAsset> {
val position = params.key ?: 0
return try {
val result = endpoints.listSongs(
query = query,
pageNumber = position,
pageCount = params.loadSize
).also {
it.resolveData()
}
val data = result.data
val nextKey = if (data.isNotEmpty() && result.links.next != null) {
position + (params.loadSize / params.loadSize)
} else {
null
}
val nativeAssets = data.mapNotNull { song ->
val audioFile = (song.relationships?.audioFiles?.data?.firstOrNull() as? AudioFileDAO)
val songUri = audioFile?.attributes?.versions?.mp3 ?: return@mapNotNull null
AudioTrackAsset.createTemporaryAsset(
id = "imgly_soundstripe_${song.id}",
resolver = SoundstripeProxyAssetResolver(song.id),
audioSource = AudioSource.create(Uri.parse(songUri)),
title = song.attributes?.title,
artist = (song.relationships?.artists?.data?.firstOrNull() as? ArtistDAO)?.attributes?.name,
durationInSeconds = audioFile.attributes?.duration?.roundToInt() ?: -1,
cover = (song.relationships?.artists?.data?.firstOrNull() as? ArtistDAO)?.attributes?.image?.let { ImageSource.create(Uri.parse(it)) } ?: defaultCover
)
}
LoadResult.Page(
data = nativeAssets,
prevKey = null, // Only paging forward.
// assume that if a full page is not loaded, that means the end of the data
nextKey = nextKey
)
} catch (e: Exception) {
e.printStackTrace()
LoadResult.Error(e)
}
}
override fun getRefreshKey(state: PagingState<Int, AudioTrackAsset>) = state.anchorPosition!!
}