Broadcasting
The Stream Video Flutter SDK has support for HLS broadcasting. This allows you to broadcast a call over HLS, which can then be watched using any HLS-compatible player. You can also use RTMP to ingest streams from external tools like OBS.
Call type for broadcasting
Among the pre-built call types, the livestream type is best suited for broadcasting events. When a livestream call is created, it is set to backstage mode by default. Backstage mode lets hosts set up cameras and equipment before going live.
final call = StreamVideo.instance.makeCall(
callType: StreamCallType.liveStream(),
id: 'your_call_id',
);
await call.getOrCreate(
members: [
MemberRequest(
userId: StreamVideo.instance.currentUser.id,
role: 'host',
),
],
);
await call.join();Start and stop HLS broadcasting
You can start HLS broadcasting by calling startHLS() on the Call object. The user must have the start-broadcast-call capability to perform this action.
final result = await call.startHLS();
if (result.isSuccess) {
final hlsUrl = result.getDataOrNull();
// hlsUrl contains the HLS playlist URL
}To stop broadcasting:
await call.stopHLS();After a few seconds of setup, broadcasting will start and the call state will be updated — the isBroadcasting flag will become true.
Starting HLS when going live
You can start HLS broadcasting automatically when the call transitions out of backstage mode by passing startHls: true to goLive():
await call.goLive(startHls: true);This is a convenient way to ensure HLS broadcasting starts alongside the WebRTC stream.
Observing the broadcasting state
You can observe the isBroadcasting property from the call state to update your UI:
PartialCallStateBuilder(
call: call,
selector: (state) => state.isBroadcasting,
builder: (context, isBroadcasting) {
return Text(isBroadcasting ? 'Broadcasting' : 'Not broadcasting');
},
);Here is an example of a toggle button that starts and stops HLS broadcasting:
PartialCallStateBuilder(
call: call,
selector: (state) => state.isBroadcasting,
builder: (context, isBroadcasting) {
return ElevatedButton(
onPressed: () async {
if (isBroadcasting) {
await call.stopHLS();
} else {
await call.startHLS();
}
},
child: Text(isBroadcasting ? 'Stop Broadcasting' : 'Start Broadcasting'),
);
},
);Listening to broadcasting events
You can listen to broadcasting-related events via the callEvents stream on the Call object:
call.callEvents.on<StreamCallBroadcastingStartedEvent>((event) {
final hlsPlaylistUrl = event.hlsPlaylistUrl;
// Broadcasting has started, use hlsPlaylistUrl to watch the stream
});
call.callEvents.on<StreamCallBroadcastingStoppedEvent>((event) {
// Broadcasting has stopped
});
call.callEvents.on<StreamCallBroadcastingFailedEvent>((event) {
// Broadcasting failed
});See more about subscribing to events on the events page.
Retrieving the broadcast URL
The HLS playlist URL can be retrieved from the call state after broadcasting has started:
final hlsUrl = call.state.value.egress.hlsPlaylistUrl;This URL can be shared with viewers to watch the broadcast in any HLS-compatible player.
Displaying an HLS stream
To play an HLS stream in your Flutter app, use a video player package that supports HLS playback, such as video_player or media_kit.
Using video_player
import 'package:video_player/video_player.dart';
final controller = VideoPlayerController.networkUrl(
Uri.parse(hlsUrl),
);
await controller.initialize();
controller.play();Then use the VideoPlayer widget to display the video:
AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: VideoPlayer(controller),
);Using media_kit
import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';
final player = Player();
final videoController = VideoController(player);
player.open(Media(hlsUrl));Then use the Video widget to display the video:
Video(controller: videoController);Remember to dispose the player when you no longer need it to free system resources.
RTMP-In
You can use RTMP streams as input for a call. This is useful for integrating professional broadcasting tools like OBS.
The RTMP address is available from the call state:
final rtmpAddress = call.state.value.rtmpIngress;The streaming key for OBS and other tools uses the format: apiKey/userToken.
Configuring OBS
- Open OBS and go to Settings > Stream
- Select Custom as the service
- Set the Server to the
rtmpAddressfrom the call state - Set the Stream Key to
your_api_key/user_token - Click Start Streaming in OBS
The RTMP stream will now show up in the call just like a regular video participant.
A user corresponding to the token provided to OBS will appear as a participant in the call. Consider creating a dedicated user for OBS streaming.
Error handling
Broadcasting depends on many factors, including network conditions. Wrap your broadcasting actions with proper error handling:
final result = await call.startHLS();
if (result.isFailure) {
// Show error to the user
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Failed to start broadcasting')),
);
}Permissions
Before a user can start or stop broadcasting, they must have the corresponding capabilities:
start-broadcast-callto start broadcastingstop-broadcast-callto stop broadcasting
Permissions for each role can be configured in the Stream Dashboard under Roles & Permissions for your call type.
final hasPermission = call.state.value.ownCapabilities.contains(
CallPermission.startBroadcastCall,
);