Watching a Livestream

This guide demonstrates how to build advanced UIs for watching livestreams in your Flutter applications using Stream’s Video SDK.

This cookbook assumes you already know how to join a livestream call.

If you haven’t completed the Livestream Tutorial yet, we recommend doing so before proceeding.

Overview

Stream’s Video SDK supports two methods for watching livestreams:

  1. HLS (HTTP Live Streaming) - enables reliable large-scale broadcasting with broad device compatibility and adaptive quality. While it has higher latency (5-30 seconds), it excels at reaching large audiences with stable playback
  2. WebRTC - provides ultra-low latency streaming (sub-second) - perfect for interactive experiences like live auctions or Q&As where real-time engagement is critical

HLS Streaming

We can then obtain the HLS URL by querying the hlsPlaylistURL from call.state:

final url = call.state.value.egress.hlsPlaylistUrl;

To view HLS streaming with quality selection and playback controls, we recommend using the lecle_yoyo_player package.

WebRTC Streaming

For WebRTC livestreams, you can either:

  • Use our pre-built LivestreamPlayer component
  • Create your own custom implementation

Using the LivestreamPlayer

Our LivestreamPlayer widget provides a complete livestreaming experience with these built-in features:

  • Live indicator showing when the stream is active
  • Real-time livestream duration display
  • Viewer/participant counter
  • Full-screen mode toggle
  • Handling various livestream states like backstage or call ended

Livestream viewer

Basic Implementation

To use the LivestreamPlayer, simply provide a Call instance:

LivestreamPlayer(call: call);

Customization Options

The LivestreamPlayer supports extensive customization:

PropertyDescriptionDefault
showParticipantCountControls visibility of participant counttrue
backButtonBuilderCustom builder for the back buttonNone
livestreamEndedBuilderCustom builder for when livestream has endedDefault ended view
livestreamBackstageBuilderCustom builder for backstage mode viewDefault backstage view
livestreamControlsBuilderCustom builder for livestream controlsDefault controls
onCallDisconnectedCallback when call disconnectsNone
onRecordingTappedCallback when recording is tappedNone
onFullscreenTappedCallback when fullscreen button is tappedChanges the VideoFit between cover and contain
startInFullscreenModeWhether livestream should start in fullscreen modefalse

Minimal Player Example

To create a minimal player without the default controls panel:

LivestreamPlayer(
  call: _call,
  startInFullscreenMode: true, // Optional fullscreen mode
  livestreamControlsBuilder: (context, call, callState) => const SizedBox.shrink(),
)

This configuration preserves the built-in handling of backstage mode and ended states, while hiding the default controls panel. This gives you complete flexibility to build custom controls and overlays on top of the video player.

Building a Custom Livestream Player

You can create your own livestream player component for complete control:

@override
Widget build(BuildContext context) {
  return SafeArea(
    child: StreamBuilder(
      stream: _call.state.valueStream,
      initialData: _call.state.value,
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return const Center(child: CircularProgressIndicator());
        }

        final callState = snapshot.data!;

        if (callState.endedAt != null) {
          return const Center(child: Text('Livestream has ended'));
        }

        if (callState.isBackstage) {
          return const Center(child: Text('Host is backstage. Stream will begin soon.'));
        }

        // Render the actual livestream content
        return _buildLivestreamContent(context, callState);
      },
    ),
  );
}

Accessing Livestream Tracks

To render the actual livestream video, you need to have access to the livestream track (or tracks).

If there is only one video track (you only have one person livestreaming), you can get it with the following code:

final streamingParticipant =
          callState.callParticipants.firstWhere((e) => e.isVideoEnabled);

If you have multiple hosts that are livestreaming, and you want to show them all, you can fetch the hosts by role:

final streamingParticipants = callState.callParticipants
    .where((p) => p.roles.contains('host'))
    .toList();

To render the video track you can use our StreamCallParticipant widget:

StreamCallParticipant(
  key: ValueKey(participant.uniqueParticipantKey),
  call: call,
  participant: streamingParticipant,
  showConnectionQualityIndicator: false,
  showParticipantLabel: false,
  showSpeakerBorder: false,
)

Additional Resources

For more Video SDK examples, check out our Flutter Cookbook samples on GitHub.

© Getstream.io, Inc. All Rights Reserved.