Hosting Streams
Hosting live streams means interacting with the io.video.videokit.live.host.StreamHost
interface.
This interface provides functions to:
- start, pause and stop the streaming
- control the camera through
StreamHost.camera
- listen to relevant events through
addListener(StreamHostListener)
, useful for building responsive UIs
Implementations
We provide three StreamHost
implementations that you can choose from depending on your case.
The usage varies a bit but they all share the same functionality from StreamHost
.
### StreamHostController
A StreamHostController
is the low level implementation that, unlike the others, is detached from
the UI. You will typically hold the controller instance in a ViewModel. Optionally,
for perfect state restoration during configuration changes, we also recommend that you use Android's
SavedStateHandle
and pass it to the controller constructor.
class StreamingViewModel(state: SavedStateHandle) : ViewModel() {
val streamHost = StreamHostController("low-latency", state)
override fun onCleared() {
super.onCleared()
streamHost.release()
}
}
As you can see, the StreamHostController
must be released when you're done with it.
In order to show the UI and start using the host, you must also call one of the bind
methods
as soon as you have a view container. For example, with a fragment:
class StreamingFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.streamHost.bind(this, view.findViewById(R.id.streaming_container))
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
viewModel.streamHost.onRequestPermissionResult(requestCode)
}
}
By passing in the fragment instance, the controller will know how to ask for permissions. We also use the fragment lifecycle to avoid memory leaks, so there's no need to unbind.
StreamHostFragment
The StreamHostFragment
is a fragment implemented exactly as described above. It is
the recommended implementation as it is very easy to use - no need to release or bind UI,
because the fragment owns the views.
You can customize the fragment after it is attached or when creating it, thanks to
the StreamHostOptions
class:
val options = StreamHostOptions.build {
facing(CameraFacing.FRONT)
flash(CameraFlash.OFF)
zoom(0F)
profile("low-latency")
streamingMode(StreamingMode.CAMERA_AND_AUDIO)
}
val fragment = StreamHostFragment.newInstance(options)
StreamHostView
The StreamHostView
is a view that holds a controller, to be used for codebases that
do not use fragments at all. Just like the controller:
- The view must be released with
release()
- You must pass a fragment / activity / lifecycle with
bind()
Usage
Once you have chosen the stream host implementation, using it is pretty simple.
Host state
At any moment, you can retrieve the host state using StreamHost.state
:
State | Description |
---|---|
StreamHostState.BUSY | The host is asking the user for permissions, or asking the backend for a Stream object. |
StreamHostState.IDLE | The host is not streaming, but it is ready to. Stream might have started and then paused, or never started. |
StreamHostState.STREAMING | The host is currently streaming. |
You also have handy functions to navigate through the different states easily:
// start streaming, or resume previously paused stream
streamHost.start()
// pause streaming or toggle
streamHost.pause()
streamHost.toggle()
// stop streaming. The current stream will be marked as finished. Any call to
// start() after this will actually create a new stream object.
streamHost.confirm()
// abort everything. This signals cancellation to the error callback in StreamHostListener.
streamHost.abort()
You can also, at any moment, access the underlying Stream object through StreamHost.stream
.
This object, especially the playback urls, can be shared to viewers to access the stream.
Configuration
You can use StreamHost.camera
to configure everything related to camera, as explained here.
We also offer different StreamHost.streamingMode
options to choose between different audio/video sources:
StreamingMode.CAMERA_AND_AUDIO
: default stream, with camera + microphoneStreamingMode.CAMERA_ONLY
: no audio streamStreamingMode.AUDIO_ONLY
: no video stream
Events
Events are subscribed to through the StreamHost.addListener
and StreamHost.removeListener
functions.
val streamHost: StreamHost = ...
streamHost.addListener(object : StreamHostListener {
override fun onStreamChanged(stream: Stream) {
// New stream was created! Share with viewers.
}
override fun onError(error: VideoError) {
// Handle error!
}
override fun onResult(stream: Stream) {
// Called after confirm(). Stream is now marked as finished.
}
override fun onStateChanged(@StreamHostState.Value state: Int) {
// State has changed.
}
override fun onDurationChanged(duration: Long) {
// Stream duration has changed. This is called repeatedly as
// streaming progresses.
}
override fun onStreamingModeChanged(@StreamingMode.Value streamingMode: Int) {
// Streaming mode was changed via StreamHost.streamingMode setter.
}
})