Skip to main content
Markdown

Live streams

One person presents live to everyone watching: the picture, a chat beside it, reactions, and the count of who watches. In cloud.wordplus:realtime-calls, on the same media servers as the browser: an app watches a stream a browser presents, and goes live itself.

Who is who​

Your server declares streams by pattern, as it declares rooms and calls (live streams in depth):

realtime.streams( 'show:{id}', ( user ) => ( user === ANN ? 'host' : 'viewer' ), { reactions: true } );

The app asks the calls route of your server, as for calls: nothing more to add.

Watching​

import cloud.wordplus.realtime.calls.LiveStreamVideoView
import cloud.wordplus.realtime.calls.calls
import cloud.wordplus.realtime.calls.stream

// In a coroutine on the main thread, such as one of lifecycleScope.
val show = rt.calls(context).stream("show:mugs")

val player = LiveStreamVideoView(context)
player.show(show) // the main picture of the stream as it changes, its sound plays by itself

show.onChange { // the state, the count, the chat, the pictures
state.text = if (show.state == LiveStreamState.LIVE) "Live now" else "Not live"
count.text = "${show.viewers} watching"
}
show.onMessage { message -> add(message.name, message.text) }
show.send("Hello!")
show.react(LiveStreamReaction.HEART)
show.leave()
  • state is IDLE, LIVE or ENDED. media is where the app is in the room of the stream: OFF, CONNECTING, LIVE, RECONNECTING.
  • The main picture is the one the host chose: a shared screen, the picture from OBS, else the camera of the host. show.tiles has each picture, and player.show(show, tile = identity) draws one of them. Call player.release() once the view leaves the screen for good.
  • The chat: messages (the history, oldest first), pinned, canWrite, slow. Each message has the app user id of who wrote it, null for a visitor.
  • onEnded says why the app is out of the stream: left, banned, kicked.

In Compose, put the player in an AndroidView, and read the state of the stream from a counter that onChange raises, as the example app does.

Going live​

The app of the host shows its camera, then goes live:

show.preview()                          // the camera and microphone, in the same LiveStreamVideoView
show.setCamera(false) // or setMicrophone(on)
show.goLive()
show.end()
  • The camera and microphone need CAMERA and RECORD_AUDIO, asked for at runtime before preview(), as for calls.
  • goLive() with nothing on turns the camera and microphone on first.
  • What a role may not do throws a CallException with its code: not_host, read_only, slow, timeout.
  • From OBS: val (url, key) = show.ingest(). ingest(renew = true) makes a new key and cuts off the old one.

Keeping the chat​

The host, and anyone the rule made mod: deleteMessage(id), pin(id), unpin(), timeout(user, seconds) (from a minute to a day, they go on watching), setSlow(seconds), clearChat(), kick(user) (out now, they may come back) and ban(user).

The show card of the Example Shop watches the show of Ann from the app: the example app.