Change Mode - Flutter
In a live stream, audience members usually join in RECV_ONLY mode, meaning they can only view and listen to the hosts. However, if a host invites an audience member to actively participate (e.g., to speak or present), the audience member can switch their mode to SEND_AND_RECV using the changeMode() method.
This guide explains how to use the changeMode() method and walks through a sample implementation where a host invites an audience member to become a host using PubSub.
changeMode()
- The changeMode()method from theRoomclass allows a participant to switch between modes during a live stream—for example, from audience to host.
import 'package:flutter/material.dart';
import 'package:videosdk/videosdk.dart';
class LivestreamScreen extends StatefulWidget {
  const LivestreamScreen({Key? key}) : super(key: key);
  @override
  _LiveStreamScreenState createState() => _LiveStreamScreenState();
}
class _LiveStreamScreenState extends State<LiveStreamScreen> {
  late Room _room;
  @override
  void initState() {
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Column(children: [
      ElevatedButton(
        child: const Text('Change Mode'),
        onPressed: () async {
          if (_room.localParticipant.mode == Mode.SEND_AND_RECV) {
            _room.changeMode(Mode.RECV_ONLY);// change mode to RECV_ONLY
          } else if (_room.localParticipant.mode == Mode.RECV_ONLY) {
            _room.changeMode(Mode.SEND_AND_RECV); // change Mode to SEND_AND_RECV
          }
          Navigator.pop(context);
        },
      ),
    ]);
  }
}
Implementation Guide
Step 1 : Create a Pubsub Topic
- Set up a PubSub topic to send a mode change request from the host to a specific audience member.
void sendInvite(Room livestream, String participantId) {
  livestream.pubSub.publish(
    "REQUEST_TO_JOIN_AS_HOST_$participantId", // PubSub topic specific to participant
    "SEND_AND_RECV", // message
  );
}
Step 2 : Create an Invite Button
- Add an "Invite" button for each audience member. When clicked, it publishes a PubSub message with the mode "SEND_AND_RECV" to that participant.
Widget buildInviteButton(Room livestream, Participant participant) {
  return  Expanded(
              child: ListView.builder(
                itemCount: _participants.values.length,
                itemBuilder: (context, index) => ParticipantListItem(
                  participant: _participants.values.elementAt(index),
                  isRaisedHand: raisedHandParticipant
                      .contains(_participants.values.elementAt(index).id),
                  onMoreOptionsSelected: (value) {
                    if (value == "Remove from Co-host" ||
                        value == "Add as a Co-host") {
                      sendInvite(widget.livestream.id,_participants.values.elementAt(index).id)
                  
                    } 
                  },
                ),
              ),
            ),
}
class ParticipantListItem extends StatefulWidget {
...
}
class _ParticipantListItemState extends State<ParticipantListItem> {
...
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Container(
          // padding: const EdgeInsets.all(12),
          padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 8),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              if (!widget.participant.isLocal)
                PopupMenuButton(
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(12)),
                    color: black700,
                    icon: const Icon(
                      Icons.more_vert,
                      color: Colors.white,
                    ),
                    onSelected: (value) {
                      widget.onMoreOptionsSelected(value);
                    },
                    itemBuilder: (context) {
                      return {
                        (widget.participant.mode == Mode.RECV_ONLY
                            ? "Add as a Co-host"
                            : "Remove from Co-host"),
                        'Remove Participant'
                      }.map((String choice) {
                        return PopupMenuItem<String>(
                          value: choice,
                          child: Text(choice),
                        );
                      }).toList();
                    }),
            ],
          ),
        ),
      ],
    );
  }
  void addParticipantListener(Participant participant) {
    participant.on(Events.streamEnabled, (Stream _stream) {
      if (mounted) {
        setState(() {
          if (_stream.kind == "video") {
            videoStream = _stream;
          } else if (_stream.kind == 'audio') {
            audioStream = _stream;
          }
        });
      }
    });
    participant.on(Events.streamDisabled, (Stream _stream) {
      if (mounted) {
        setState(() {
          if (_stream.kind == "video") {
            videoStream = null;
          } else if (_stream.kind == 'audio') {
            audioStream = null;
          }
        });
      }
    });
  }
}
Step 3 : Create a Listener to Change the Mode
- On the audience side, subscribe to the specific PubSub topic. When a mode request is received, update the participant’s mode using changeMode().
void registerModeListener(Room livestream, BuildContext context) async {
  await livestream.pubSub.subscribe(
    "CHANGE_MODE_${livestream.localParticipant.id}",
    (PubSubMessage pubSubMessage) {
      final message = pubSubMessage.message;
      if (message == "SEND_AND_RECV") {
        showDialog(
          context: context,
          builder: (context) => AlertDialog(
            content: Text(
              "${pubSubMessage.senderName} requested you to join as a speaker",
            ),
            actions: [
              TextButton(
                onPressed: () => Navigator.pop(context),
                child: const Text("Decline"),
              ),
              TextButton(
                onPressed: () {
                  livestream.changeMode(Mode.SEND_AND_RECV);
                  Navigator.pop(context);
                },
                child: const Text("Accept"),
              ),
            ],
          ),
        );
      }
    },
  );
}
API Reference
The API references for all the methods and events utilized in this guide are provided below.
Got a Question? Ask us on discord

