Skip to main content
Version: 4.x.x

PubSub - Flutter

PubSub is a short acronym for Publish-Subscribe mechanism. This mechanism is used to send and recieve messages from a particular topic. As the name suggests, for someone to send a message, they have to specify the topic and the message which should be published and for someone to receive a message, they should be subscribed to that topic.

Here is a visual to better understand publish-subscribe mechanism.

pubsub

PubSub

In order to use PubSub in a meeting, VideoSDK provides the pubSub property on the Room object, which allows you to subscribe to any topic and publish to any topic, allowing you to pass on messages and instructions during the meeting easily.

note

From v4.x, publish(), subscribe() and unsubscribe() throw a PubSubException when the call does not take effect. Every call site needs a catch or a .catchError — see Handling failures below and section 1 of the Migration Guide.

publish()

  • This method is used for publishing message of specific topic.
  • This method can be accessed from the pubSub from the Room.
  • This method will accept following parameters as input:
    • topic: This will be the topic where the message will be published.
    • message: This will be the actual message to be published. It has to be in String format.
    • options: This is an object of PubSubPublishOptions which specifies the options for publish. PubSubPublishOptions has 2 properties.
      • persist : persist offered the option of keeping the message around for the duration of the session. When persist is set to true, that message will be retained for upcoming participants and will be available in VideoSDK Session Dashboard with .CSV format after completion of session.
      • sendOnly: If you want to send a message to specific participants, you can pass their respective participantId in form of List<String>. If you don't provide any IDs, the message will be sent to all participants by default. This is optional parameter.
    • payload: If you need to include additional information along with a message, you can pass here as Map<String, dynamic>. This is optional parameter.
  • From v4.x the returned Future completes once the server has acknowledged the message, and throws a PubSubException if the publish is rejected or is not acknowledged within 30 seconds.
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';

class MeetingScreen extends StatefulWidget {
...
}

class _MeetingScreenState extends State<MeetingScreen> {
late Room _room;

@override
void initState() {
...
}

@override
Widget build(BuildContext context) {
return Column(
children:[
//These will publish "Hello World!" on the "CHAT" topic
ElevatedButton(
onPressed:() async {
try {
await _room.pubSub.publish("CHAT", "Hello World!");
} on PubSubException catch (e) {
// Not sent — mark the message unsent or offer a retry here.
debugPrint("Publish failed: ${e.message}");
}
},
child: const Text("Send Message"),
),
]
);
}
}

Receiving the messages

  • All the previous messages for the particular topic can be recieved by subscribing to the topic.

  • To subscribe to a specific topic, use can use the subscribe() method which will return the Future<PubSubMessages> and accepts the topic to be subscribed and a callback function which will be called when ever any new message is received.

  • PubSubMessages contains the messages as a list of PubSubMessage which will contain following properties:

    • senderId: This represents the participantId of the participant who send the message.
    • senderName: This represents the displayName of the participant who send the message.
    • message: This will be the acatual message that was send.
    • timestamp: This wil the timestamp for when the message was published.
    • topic: This will be the name of the topic message was published to.
    • payload: This will be the data that you have send with message.
    • sendOnly: This will be the list of participantIds the message was addressed to, when it was published with PubSubPublishOptions.sendOnly. It is empty for a message that was broadcast to everyone on the topic.
  • A subscription survives a reconnect — subscribe once and it keeps working after the connection recovers, without subscribing again.

Subscription options and callbacks

From v4.x, subscribe() also accepts options and three optional callbacks that control how much history is replayed and how live messages are delivered on a busy topic.

room.pubSub.subscribe(
"CHAT",
messageHandler,
options: const PubSubSubscribeOptions(
oldMessageLimit: 100,
realtimeOverflow: PubSubRealtimeOverflow.queue,
maxQueue: 70,
),
onOldMessagesReceived: (messages, isLast) {
// Past messages, oldest first, so a long conversation starts rendering
// before all of it has arrived. isLast is true on the final batch.
},
onBatchReceived: (messages) {
// On a busy topic live messages arrive in groups.
},
onMessageDrop: (count) {
// This many live messages could not be delivered.
},
);
  • oldMessageLimit: How many stored messages are replayed when you subscribe. null replays all of them, 0 replays none, and N > 0 replays the last N. Only messages published with persist enabled are stored at all.
  • realtimeOverflow: What happens to live messages arriving faster than they can be delivered. PubSubRealtimeOverflow.queue briefly holds them so a subscriber that falls behind can catch up; PubSubRealtimeOverflow.drop discards them. Use drop only where stale data has no value, such as typing indicators.
  • maxQueue: How far a subscriber may fall behind, counted in delivery batches, before the server gives up on it. Only allowed with PubSubRealtimeOverflow.queue.
  • newMessageLimit: Caps how many live messages this subscriber accepts at a time.

An out-of-range value makes subscribe() throw an ArgumentError before anything is sent — the same rules iOS and Android enforce:

RuleExample that throws
oldMessageLimit must be >= 0, or null for all historyoldMessageLimit: -1
maxQueue must be >= 1maxQueue: 0
newMessageLimit must be >= 0, or null for unlimitednewMessageLimit: -5
maxQueue is not allowed with PubSubRealtimeOverflow.droprealtimeOverflow: PubSubRealtimeOverflow.drop, maxQueue: 70
note

An ArgumentError is not a PubSubException, so on PubSubException catch will not catch it and it never reaches Events.error. These are programming errors — fix the call rather than handle it at runtime.

Handling failures

From v4.x, publish(), subscribe() and unsubscribe() throw a PubSubException when the call does not take effect. In v3.x.x they failed silently, and Dart cannot flag an unhandled one at compile time — an unawaited onPressed: () => room.pubSub.publish(...) turns a failure into a runtime async error. Give every call site a catch or a .catchError.

SituationExceptionCode
publish() was rejectedPubSubPublishFailed4087
subscribe() was rejectedPubSubSubscribeFailed4088
unsubscribe() was rejectedPubSubUnsubscribeFailed4089
Called before joining, or after leavingPubSubMeetingNotJoined3022
Called while reconnectingPubSubMeetingReconnecting3027

PubSubException is sealed, so a switch over these is exhaustive and the analyzer tells you when a case is missing. It carries code, name and message.

try {
await room.pubSub.publish("CHAT", text);
} on PubSubException catch (e) {
switch (e) {
case PubSubMeetingNotJoined():
showToast("Join the meeting before publishing");
case PubSubMeetingReconnecting():
showToast("Reconnecting — try again shortly");
case PubSubPublishFailed():
markUnsent(id, e.message);
default:
debugPrint(e.toString());
}
}

The same failure is also delivered to Events.error with the same code, name and message. Catch to handle one call; listen on the event for centralized logging.

A few things behave differently from what you might expect:

  • A failed subscribe() leaves nothing behind. Your handler is not registered, so no messages arrive for that topic.
  • unsubscribe() detaches your handler before anything that can throw, so a dispose() teardown always completes. From v4.x it also waits for the server to answer, bounded by the same 30 second timeout as publish().
  • Not every failure can throw. A subscription the server drops later, or one that cannot be restored after a reconnect, has no call left to throw from and reaches you on Events.error only. Keep that listener if your UI shows subscription state.
  • Using .catchError() on subscribe()? It returns Future<PubSubMessages>, so the callback has to return a value — PubSubMessages(messages: const []) will do.

Example

import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';

class ChatView extends StatefulWidget {
final Room room;
...
}

class _ChatViewState extends State<ChatView> {

// PubSubMessages
PubSubMessages? messages;

@override
void initState() {
...

// Subscribing 'CHAT' Topic
widget.meeting.pubSub
.subscribe("CHAT", messageHandler)
.then((value) => setState((() => messages = value)))
// initState() cannot await, so failures are caught here.
.catchError((Object e) => debugPrint("Subscribe failed: $e"));
}

//Handler which will be called when new mesasge is received
void messageHandler(PubSubMessage message) {
setState(() => messages!.messages.add(message));
}

@override
Widget build(BuildContext context) {
return Column(
children:[
Expanded(
child: messages == null
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
reverse: true,
child: Column(
children: messages!.messages
.map(
(message) => Text(
message.message
),
)
.toList(),
),
),
),
]
);
}

@override
void dispose() {
// Unsubscribe. dispose() cannot await, so the failure is logged instead.
widget.room.pubSub
.unsubscribe("CHAT", messageHandler)
.catchError((Object e) => debugPrint("Unsubscribe failed: $e"));
super.dispose();
}
}

Applications of PubSub

PubSub is a very powerful mechanism which can be used to do alot of things which can make your meeting experience much more interactive. Some of the most common usecase that we have come across for the PubSub during a meeting are listed below:

  1. Chat: You can utilise this to develop various Chat features, such as Private Chat and Group Chat. You can follow our chat integration guide here.
  2. Raise Hand: You can allow attendees to raise their hands at any time during the meeting, informing everyone else that someone has done so.
  3. Layout Switching: You can change the meeting's layout for every participant at once during the meeting, such as from Grid layout to Spotlight or Grid Layout to Sidebar Layout, etc.
  4. Poll: You may make polls, let users respond to them, and display the results at the end of a poll.
  5. Question Answer Session: You can also design interactive functionality that is question-and-answer based.

Downloading PubSub Messages

All the messages from the PubSub which were published with persist : true and can be downloaded as an .csv file. This file will be available in the VideoSDK dashboard as well as throught the Sessions API.

API Reference

The API references for all the methods and events utilised in this guide are provided below.

Got a Question? Ask us on discord