HLS Streaming / Recording
HLS Streaming allows for scaling to millions of viewers in near real time. You can give a link of your web-app which will be converted to a HLS feed by our server and can be played across devices for consumption.
Behind the scenes, this will be achieved by having a bot join your room and stream what it sees and hears. Once the feed is ready, the server will give a URL which can be played using any HLS Player.
Note that the media server serving the content in this case is owned by 100ms. If you're looking for a way to stream on YouTube, Twitch etc., please have a look at our RTMP streaming docs here.
Starting
HLS can be started in two ways depending on the level of customization you need.
- Default View: The simplest view to just begin a stream with default UI and parameters.
- Custom Views: To use your own UI for HLS streaming, you need to provide your own web-app URL for our bot to join and stream.
Default View
Begins a stream with default parameters.
hmsSdkHost.startHLSStreaming(hmsActionResultListener = object : HMSActionResultListener { override fun onSuccess() { // hls was started successfully } override fun onError(error: HMSException) { // hls failed to start with error $error } })
Custom View
To use our own browser UI for HLS, you'll need to pass in a meeting URL. The 100ms bot will open this URL to join your room, so it must allow access without any user level interaction. In the future it'll be possible to start HLS for multiple such URLs for the same room.
For this purpose the API supports taking in an array, although currently only the first element of the array will be used. To distinguish between multiple URLs an additional field metadata
can be optionally passed. The meetingURL
and metadata
are clubbed together to form what we'll call a variant
.
You can call hmsSDK.startHLSStreaming
with a HMSHLSConfig
having an array of such variants. HMSHlsRecordingConfig
is optional.
fun hlsStreaming(meetingUrl : String, hmssdk: HMSSDK) { val meetingUrlVariant1 = HMSHLSMeetingURLVariant( meetingUrl = meetingUrl, metadata = "tag for reference" ) val hlsConfig = HMSHLSConfig(listOf(meetingUrlVariant1)) hmssdk.startHLSStreaming(hlsConfig, object : HMSActionResultListener { override fun onSuccess() { } override fun onError(error: HMSException) { } }) }
Optional HLS Recording
Optionally to record the HLS stream you may specify an HMSHlsRecordingConfig
within the HMSHLSConfig
.
Here's what the HMSHlsRecordingConfig
looks like
data class HMSHlsRecordingConfig( val singleFilePerLayer : Boolean, val videoOnDemand : Boolean )
singleFilePerLayer
if the desired end result is a mp4 file per HLS layer, false by default.videoOnDemand
if the desired end result is a zip of m3u8 and all the chunks, false by default.
Here's what it looks like to call for recording configs.
// Optional recording config val hlsRecordingConfig = HMSHlsRecordingConfig(false, false) val hlsConfig = HMSHLSConfig(listOf(meetingUrlVariant), hlsRecordingConfig)
Stopping HLS
You can call hmsSDK.stopHLSStreaming
to stop HLS Streaming which will stop all the variants.
hmssdk.stopHLSStreaming(null, object : HMSActionResultListener { override fun onSuccess() { } override fun onError(error: HMSException) { } })
Want to see how this works in a live project? Take a look at our advanced sample app.
Current Room Status
The current status for the room is always reflected in the HMSRoom
object.
Here are the relevant properties inside the HMSRoom
object which you can read to get the current hls streaming status of the room namely: hlsStreamingState
.
The object contains a boolean running
which lets you know if it's active on the room right now as well as list of active variants.
- hlsStreamingState an instance of
HMSHLSStreamingState
, which looks like:
data class HMSHLSStreamingState( val running : Boolean, val variants : ArrayList<HMSHLSVariant>?, val error: HMSException?, val state: HMSStreamingState )
This represents a livestream to one or more HLS URLs in the container of HMSHLSVariant
. Which looks like:
data class HMSHLSVariant( val hlsStreamUrl: String?, val meetingUrl: String?, val metadata: String?, val startedAt: Long?, val state: BeamStreamingStates? )
The room status should be checked in following two places -
- In the
onJoin(room: HMSRoom)
callback ofHMSUpdateListener
The properties mentioned above will be on theHMSRoom
object. - In the
onRoomUpdate(type: HMSRoomUpdate, hmsRoom: HMSRoom)
callback ofHMSUpdateListener
. TheHMSRoomUpdate
type will beHMSRoomUpdate.HLS_STREAMING_STATE_UPDATED
.
In most cases it's enough to take the URL from the first of the variants like so:
val hlsUrl = room.hlsStreamingState?.variants?.get(0)?.hlsStreamUrl
Tips
- If you're using the dashboard web-app from 100ms, please make sure to use a role which doesn't have publish permissions for beam tile to not show up.
- If using your own web-app, do put in place retries for API calls like tokens etc. just in case any call fails. As human users we're used to reloading the page in these scenarios which is difficult to achieve in the automated case.
- Make sure to not disable the logs for the passed in meeting URL. This will allow for us to have more visibility into the room, refreshing the page if join doesn't happen within a time interval.