Watching a Livestream

This sample walks you through building advanced UIs for watching a Livestream on Flutter.

In this cookbook tutorial, we will assume that you already know how to join a Livestream call. If you haven’t familiarized yourself with the Livestream Tutorial yet, we highly recommend doing so before proceeding with this cookbook.

To view an HLS stream and benefit from the full experience of selecting different streaming qualities and performing different player actions like muting and unmuting the stream, we recommend using lecle_yoyo_player.

When building for livestreaming, there are a few considerations you need to keep in mind for the UI:

  • UI for when the video isn’t loaded yet
  • A message to show when the Livestream hasn’t started yet
  • What to show when the Livestream stopped
  • How to indicate when there are connection problems
  • Number of participants
  • Duration of the call

Setting up the UI

To setup our UI for rendering a Livestream, we can use Flutter’s built-in StreamBuilder widget for listening to changes in our call state and rendering different UIs based on the stage of our live stream:

@override
  Widget build(BuildContext context) {
    return SafeArea(
      child: StreamBuilder(
        stream: widget.call.state.valueStream,
        initialData: widget.call.state.value,
        builder: (context, snapshot) {
          final callState = snapshot.data!;
          return Stack(
            children: [
              if (snapshot.hasData && !callState.isBackstage)
							 // TODO: Render Video

              if (snapshot.hasData && !callState.isBackstage)
							 // TODO: Render Participant Count

              if (!snapshot.hasData)
							 // TODO: Render loading indicator

              if (snapshot.hasData && callState.isBackstage)
							 // TODO: Display message call is not live

            ],
          );
        },
      ),
    );
  }
}

By looking at different properties on our CallState, we can render different UIs and messages based on whether the call is live, backstage, or loading. A Stack also allows us to add different secondary live stream elements such as a view count above the main UI.

Rendering the Livestream

Before running the code below to see the Livestream in action, we recommend going to our Dashboard and creating a Livestream first since it can be done visually without having to create another instance of the application on the simulator.

Once a stream is started on the dashboard, the Livestream ID can be passed to the id parameter for the Call object in code.

Stream Livestream Dashboard

@override
  Widget build(BuildContext context) {
    return SafeArea(
      child: StreamBuilder(
        stream: widget.call.state.valueStream,
        initialData: widget.call.state.value,
        builder: (context, snapshot) {
          final callState = snapshot.data!;
          return Stack(
            children: [
              if (snapshot.hasData && !callState.isBackstage)
                _buildRender(callState),
              if (snapshot.hasData && !callState.isBackstage)
                Positioned(
                  top: 12.0,
                  left: 12.0,
                  child: Material(
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(24),
                    ),
                    color: Colors.red,
                    child: Center(
                      child: Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Text(
                          'Viewers: ${callState.callParticipants.length - 1}',
                          style: const TextStyle(
                            fontSize: 14,
                            color: Colors.white,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              if (snapshot.hasData && (callState.isBackstage))
                const Material(
                  child: Center(
                    child: Text('Stream not live'),
                  ),
                ),
              if (!snapshot.hasData)
                const Center(
                  child: CircularProgressIndicator(),
                ),
            ],
          );
        },
      ),
    );
  }
}

To view our full list of Video examples, please check out our Flutter Cookbook on GitHub.

© Getstream.io, Inc. All Rights Reserved.