Concepts
The VideoKit
object
Using the core SDK means interacting with the io.video.videokit.VideoKit
object. This is the
entry point for the whole SDK and gives you access to:
- the session manager, with
VideoKit.sessions()
, to retrieve a session token - the upload manager, with
VideoKit.uploads()
, to upload videos - the video store, with
VideoKit.videos()
, to query, update or delete videos - the stream store, with
VideoKit.streams()
, to manage live streams - the token registry, with
VideoKit.tokens()
, to manage signed playback
These methods return a concrete implementation of base interfaces (respectively,
SessionManager
, UploadManager
, VideoStore
, StreamStore
, TokenRegistry
) that will let you
communicate with our infrastructure and perform all core operations.
This design makes it very easy to mock the behavior of these components in your unit tests.
val sessions: SessionManager = VideoKit.sessions()
val uploads: UploadManager = VideoKit.uploads()
val videos: VideoStore = VideoKit.videos()
val streams: StreamStore = VideoKit.streams()
val tokens: TokenRegistry = VideoKit.tokens()
Keep reading to know about the capabilities of each component.
The Call
interface
All of our API calls are asynchronous. By default, they are encapsulated in an object called Call
,
which will give you full control over the action and handling its results.
Coroutine-based projects
For kotlinx.coroutines
users, a Call
acts similar to a Deferred
object. We recommend to use
the get()
function which will suspend until the result is available, or throw in case of errors.
It will also handle cancellation automatically.
suspend fun updateVideo(request: UpdateRequest): Video {
return VideoKit.videos().update(request).get()
}
In addition, most APIs that would return a Call
have a *suspending()
version which calls get
under the hood while keeping the code readable.
Regular projects
If you are not using coroutines, the Call
object offers a lot of flexibility.
First of all, calls can be canceled:
val call: Call<Video> = VideoKit.videos().update(request)
call.cancel() // user changed its mind
If needed, calls can block the current thread to wait for their result. In this case, the result instance will determine whether the call was successful or not:
val call: Call<Video> = VideoKit.videos().update(request)
val result: Result<Video> = call.getBlocking()
when (result) {
is Result.Success -> {
val video: Video = result.result
// Do something with video
}
is Result.Error -> {
val error: VideoError = result.error
// Handle error
}
}
However, you will typically observe the call so that no thread is blocked. Results are received in the UI thread by default, but different threads can be specified through the handler parameter:
val call: Call<Video> = VideoKit.videos().update(request)
// Observe with plain observer
call.onResult { result: Result<Video> -> ...}
// Observe with flat observer, for JS-style callback.
call.onResult(object: FlatReceiver() {
override fun receiveResult(result: Video?, error: VideoKitException?) { ... }
})
// Observe only if successful or failed.
call.onResult(object: SuccessReceiver() {
override fun receiveSuccess(result: Video) { ... }
})
call.onResult(object: ErrorReceiver() {
override fun receiveError(error: VideoError) { ... }
})
// Kotlin friendly extensions
call.onSuccess { ... }
call.onError { ... }
The Observable
interface
All objects that produce events implement the io.video.videokit.common.Observable<T>
interface,
where T
is a certain type of observable. This interface provides a few base functions:
addObserver(T)
to start observing eventsremoveObserver(T)
to stop observing
In addition, observation can be scoped to some 'lifecycle' so that the observer is removed automatically and you don't risk leaking it. See:
observeIn(LifecycleOwner, T)
: ties observation to the lifecycle of the given owner, e.g. a FragmentobserveIn(Job, T)
: ties observation to the lifecycle of the given coroutineJob
. You can usecurrentCoroutineContext().job
to retreive the current job.