Telegram supports E2E-encrypted group calls.
This page describes the API methods used to work with group calls.
groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall;
groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall;
All group calls are represented by the groupCall constructor, or by a groupCallDiscarded constructor after it ends.
Group calls can be classified in the following categories:
groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall;
inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall;
messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction;
messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction;
updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update;
updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector<GroupCallParticipant> version:int = Update;
chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector<BotInfo> pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector<long> available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull;
channelFull#e4e0b29d flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector<string> groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector<long> default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long main_tab:flags2.22?ProfileTab = ChatFull;
---functions---
phone.createGroupCall#48cdc6d8 flags:# rtmp_stream:flags.2?true peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates;
phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates;
phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates;
A video chat/livestream is a group call associated to a specific basic group, supergroup or channel, created using phone.createGroupCall by admins with the manage_call admin right ».
A group call is called a video chat when it's associated to a basic group or supergroup.
A group call is called a livestream when it's associated to a channel.
A basic group/supergroup/channel can have only one associated video chat/livestream: starting a new one will terminate the previous one.
To interact with a video chat/livestream, use the inputGroupCall constructor which will always be present in the basic group/supergroup/channel's chatFull/channelFull, if a video chat/livestream is currently active or scheduled.
The same inputGroupCall will also be present in messageActionGroupCallScheduled, messageActionGroupCall service messages sent to the group/channel when a video chat/livestream is scheduled, started or ended.
Updates to info about a video chat/livestream are delivered using updateGroupCall/updateGroupCallParticipants to all members/subscribers of the basic group/supergroup/channel, and should be handled as specified here ».
When invoking phone.createGroupCall, the following flags can be optionally set:
title - Specifies a custom group call title, if not set defaults to the group/channel's name
schedule_date - Creates a scheduled call for the specified date (at least 10 seconds and at most 8 days into the future).
This will not automatically start the call at the specified date: a scheduled call must be manually started by invoking phone.startScheduledGroupCall.
A scheduled call can also be started before or after its scheduled date.
To get a notification when a scheduled livestream is started, invoke phone.toggleGroupCallStartSubscription.
phone.toggleGroupCallStartSubscription can only be invoked for scheduled video chats/livestreams, before they are started.
The notification will be received in an updateNewMessage coming from the service notifications user (ID 777000).
groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall;
inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall;
messageMediaVideoStream#ca5cab89 flags:# rtmp_stream:flags.0?true call:InputGroupCall = MessageMedia;
messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector<Document> video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia;
storyItem#16a4b93c flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector<MessageEntity> media:MessageMedia media_areas:flags.14?Vector<MediaArea> privacy:flags.2?Vector<PrivacyRule> views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector<int> music:flags.20?Document = StoryItem;
updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update;
updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector<GroupCallParticipant> version:int = Update;
---functions---
stories.startLive#d069ccde flags:# pinned:flags.2?true noforwards:flags.4?true rtmp_stream:flags.5?true peer:InputPeer caption:flags.0?string entities:flags.1?Vector<MessageEntity> privacy_rules:Vector<InputPrivacyRule> random_id:long messages_enabled:flags.6?Bool send_paid_messages_stars:flags.7?long = Updates;
A live story is a group call associated to a specific story of a user, supergroup or channel.
A peer can only have one associated active live story, which can be created by the user or by supergroup/channel admins by invoking stories.startLive.
Clients should prevent users and channel admins from creating a new live story if a live story is already currently active: if someone attempts to create a new live story on a peer that already has one, a STORY_LIVE_ALREADY_%d RPC error will be emitted, containing the ID of the currently active live story.
A supergroup/channel can have both an active live story and an active video chat/livestream: the main difference is that live stories also support comments with donations, and are visible in the top bar of the dialog list of subscribers.
Since basic groups cannot post stories, they also cannot have an associated live story.
To interact with a live story, use the inputGroupCall constructor which will always be present in the messageMediaVideoStream contained in the story's storyItem.media, if a live story is currently active.
Updates to info about a live story are delivered using updateGroupCall/updateGroupCallParticipants to all subscribers of the group/channel and all contacts for user live stories, and should be handled as specified here ».
Once a live story ends, the messageMediaVideoStream in the story's storyItem.media will be replaced with a messageMediaDocument, containing a video recording of the story.
groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall;
inputGroupCallSlug#fe06823f slug:string = InputGroupCall;
inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall;
updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update;
updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector<GroupCallParticipant> version:int = Update;
messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector<Peer> = MessageAction;
---functions---
phone.createConferenceCall#7d0444bb flags:# muted:flags.0?true video_stopped:flags.2?true join:flags.3?true random_id:int public_key:flags.3?int256 block:flags.3?bytes params:flags.3?DataJSON = Updates;
phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates;
phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates;
phone.deleteConferenceCallParticipants#8ca60525 flags:# only_left:flags.0?true kick:flags.1?true call:InputGroupCall ids:Vector<long> block:bytes = Updates;
phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates;
phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates;
phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates;
phone.sendGroupCallMessage#b1d11410 flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long send_as:flags.1?InputPeer = Updates;
phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool;
phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector<int> = Updates;
phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates;
phone.getGroupCallStars#6f636302 call:InputGroupCall = phone.GroupCallStars;
phone.saveDefaultSendAs#4167add1 call:InputGroupCall send_as:InputPeer = Bool;
A conference call is a group call not associated to any group or channel, and is uniquely identified by a link.
Additionally, conference calls are E2E-encrypted, see here » for a full description of the end-to-end encryption protocol used for group calls (including group call messages).
To create a conference, invoke phone.createConferenceCall: this will return an updateGroupCall containing a groupCall constructor, which will also contain the conference deep link » (invite_link) that other users can use to interact with the call.
You can invite users to join the conference using the link, or by invoking phone.inviteConferenceCallParticipant, passing an inputGroupCall generated from the previously returned groupCall and the ID of the user to invite.
If phone.inviteConferenceCallParticipant is used, the destination user will receive a messageActionConferenceCall constructor: if the call_requests_disabled client configuration key » is not set or false, an incoming messageActionConferenceCall with the missed and active flags not set should trigger ringing and an incoming call screen, just like for one-on-one calls.
To interact with a conference call, use one of the following constructors of type InputGroupCall:
id and access_hashmsg_id should point to the ID of the messageActionConferenceCall service message (no need to specify the peer, because messageActionConferenceCall can only be received in private chats, which share a single ID sequence)The newly created conference can be joined by invoking phone.joinGroupCall, as for all other group call types, with the following distinctions:
join_as can only be equal to inputPeerSelf for conference calls (i.e. you cannot join a conference call on behalf of an owned channel).public_key must be populated with your public key.block must be populated with the appropriate block containing an appropriate e2e.chain.changeSetGroupState event.Conference creators can also use phone.createConferenceCall's join flag to create and immediately join the conference in a single query, sending the initial public_key, block and local params together with the usual mute/video flags.
Updates to info about a conference are delivered using updateGroupCall/updateGroupCallParticipants to all participants, and should be handled as specified here ».
To join an existing conference, first synchronize the latest blockchain state with phone.getGroupCallChainBlocks. After computing the local "add self" block and public key, join the conference with phone.joinGroupCall, this time setting public_key and block in addition to the normal group-call fields. In other words, existing conferences are joined with the same RPC as ordinary group calls, but with extra E2E payloads.
After joining, keep the conference blockchain synchronized: official clients broadcast locally-produced blocks with phone.sendConferenceCallBroadcast, and request more blocks or subchains with phone.getGroupCallChainBlocks whenever they detect gaps.
Manage membership with phone.inviteConferenceCallParticipant, phone.deleteConferenceCallParticipants and phone.declineConferenceCallInvite. Telegram Android also uses phoneCallDiscardReasonMigrateConferenceCall when escalating a one-to-one call into a conference call.
Conference message overlays use phone.sendGroupCallEncryptedMessage instead of plain phone.sendGroupCallMessage: official clients serialize the local in-call message object, encrypt it with the conference state, and then send the ciphertext through this RPC.
groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall;
phone.groupCall#9e727aad call:GroupCall participants:Vector<GroupCallParticipant> participants_next_offset:string chats:Vector<Chat> users:Vector<User> = phone.GroupCall;
phone.groupParticipants#f47751b6 count:int participants:Vector<GroupCallParticipant> next_offset:string chats:Vector<Chat> users:Vector<User> version:int = phone.GroupParticipants;
---functions---
phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall;
phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector<InputPeer> sources:Vector<int> offset:string limit:int = phone.GroupParticipants;
To fetch the currently active groupCall of any type, invoke phone.getGroupCall passing the appropriate subtype of InputGroupCall according to the call type »; this method can also be used to fetch some of the group's participants (the max number of returned participants can be controlled by the limit parameter, 0 to return a server-defined number of results).
If the number of returned participants is less than groupCall.participants_count, you can later paginate through the remaining participants using phone.getGroupParticipants, passing to offset the phone.groupCall.participants_next_offset returned by phone.getGroupCall, and then the phone.groupParticipants.next_offset returned by phone.getGroupParticipants.
Note that the limit parameter of phone.getGroupCall behaves in a different way compared to the limit of phone.getGroupParticipants: regardless of the value passed to phone.getGroupCall.limit, the number of returned results will always be at least equal to 3 or the number of participants, whichever is smaller; however, the returned participants_next_offset will still correctly point to the limitth participant (or to the last one, if no more are available), and using the returned offset will fetch members starting from the limitth participant.
For example, with 5 members (A..E), invoking phone.getGroupCall with limit=1 will return members A, B, C, but passing the returned participants_next_offset to phone.getGroupParticipants with limit=10 will return members B, C, D, E.
On the other hand, limit parameter of phone.getGroupParticipants behaves as usual, properly restricting the number of returned participants.
Alternatively, the sources or ids flags of phone.getGroupParticipants may be populated to fetch information only about specific users, based on their WebRTC source IDs or Telegram user IDs.
Note: if no more results are available, phone.getGroupParticipants will return an empty next_offset; thus, avoid providing the next_offset returned in phone.groupParticipants if it is empty, to avoid an infinite loop.
groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall;
groupCallParticipant#2a3dc7ac flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo paid_stars_total:flags.16?long = GroupCallParticipant;
updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update;
updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector<GroupCallParticipant> version:int = Update;
All updates related to group calls have a non-zero version integer field, which should be used to apply the update, comparing it with the non-zero version field of the cached groupCall (from now on, referred to as cached_version).
The version field of groupCall is the revision number of group call information (which includes the group call participant list).
The logic used to apply updateGroupCall and updateGroupCallParticipants varies slightly.
To apply an incoming updateGroupCall, extract the version from updateGroupCall.call.version, and follow this algorithm:
If version is smaller than cached_version+1, skip the update
If version is equal to cached_version+1, apply the update by updating the cached groupCall with the groupCall provided in the update.
Note that if the groupCall.min flag is set, a specific set of groupCall fields specified in the constructor page » cannot be applied over the locally cached version.
If version is bigger than cached_version+1, wait up to 1 second for another updateGroupCall to arrive for the same group call, filling the gap in the version sequence; if no such update arrives in time, skip the update, and invalidate and refetch locally cached group call information and the participant list by using phone.getGroupCall.
If there is no locally cached groupCall for this chat, apply the update, caching the groupCall.
In this case, do not apply the update if the groupCall.min flag is set.
To apply an incoming updateGroupCallParticipants, extract the version from updateGroupCallParticipants.version, and follow this algorithm:
versioned flag set, follow these steps:
version is smaller than cached_version, skip the updateversion is equal to cached_version, apply the update only if this is the first updateGroupCallParticipants received for this group call, see below on how to apply it.version is equal to cached_version+1, apply the update by updating the version of the local groupCall and updating/populating groupCallParticipant info.min flag is set, a specific set of groupCallParticipant fields specified in the constructor page » cannot be applied over the locally cached version.left flag is set, this participant left the call, and the local groupCallParticipant should be deleted.version is bigger than cached_version+1, wait up to 1 second for another updateGroupCallParticipants to arrive for the same group call, filling the gap in the version sequence; if no such update arrives in time, skip the update, and invalidate and refetch locally cached group call information and the participant list by using phone.getGroupCall.version.phone.joinAsPeers#afe5623f peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = phone.JoinAsPeers;
---functions---
phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers;
phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool;
Before joining a group call, you can fetch the list of identities that can be used to create/join the group call by invoking phone.getGroupCallJoinAs, choose one, and persist the preferred choice with phone.saveDefaultGroupCallJoinAs.
Join with phone.joinGroupCall, passing the chosen join_as, the current local mute/camera state in muted and video_stopped, and an opaque local join payload in params. If the user entered through an invite link, pass the invite_hash.
Process the returned updates: official clients look for updateGroupCallParticipants to learn their own media source, and updateGroupCallConnection to feed the server join response back into the running group-call engine. The same phone.joinGroupCall flow is reused for reconnects.
Use phone.getGroupCall, phone.getGroupParticipants and phone.checkGroupCall to keep local state in sync. In particular, Android uses phone.checkGroupCall as a short poll to verify that the current source is still active and recreates the local group instance if the server stops reporting it.
Screen sharing is a separate join flow: after starting capture, official clients call phone.joinGroupCallPresentation with another opaque params payload, then later phone.leaveGroupCallPresentation to stop the presentation connection. This is separate from simply toggling the camera inside the main group call.
Use phone.inviteToGroupCall, phone.exportGroupCallInvite, phone.editGroupCallParticipant, phone.editGroupCallTitle, phone.toggleGroupCallSettings, and phone.toggleGroupCallRecord to manage the room. Use phone.leaveGroupCall to leave your current media source without ending the room; use phone.discardGroupCall to end the room for everyone.
phone.joinAsPeers#afe5623f peers:Vector<Peer> chats:Vector<Chat> users:Vector<User> = phone.JoinAsPeers;
---functions---
phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates;
phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates;
phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates;
phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates;
///
phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector<InputUser> = Updates;
phone.discardGroupCall#7a777135 call:InputGroupCall = Updates;
phone.toggleGroupCallSettings#974392f2 flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool messages_enabled:flags.2?Bool send_paid_messages_stars:flags.3?long = Updates;
phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector<int> = Vector<int>;
phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates;
phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates;
phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates;
phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite;
phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates;
phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates;
---functions---
phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels;
phone.getGroupCallStreamRtmpUrl#5af4c73a flags:# live_story:flags.0?true peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl;
Livestreams are a special rtmp_stream mode of phone.createGroupCall. Official clients still create and join them as group calls, but publishing and playback diverge from normal RTC rooms.
rtmp_stream flag. As with ordinary group calls, schedule_date may be used to schedule the start for later.revoke=true to rotate the key. On Android, live_story is set when requesting RTMP credentials for a live story instead of a chat or channel livestream.params, but the local engine is initialized in RTMP/broadcast mode instead of ordinary RTC mode.stream_dc_id download DC via upload.getFile with inputGroupCallStream.allow_paid_stars and send_as fields for paid messages/reactions and for choosing the commenting identity; persist the preferred identity with phone.saveDefaultSendAs.messages_enabled to enable or disable livestream comments.