Skip to main content

Cross-Room Co-Streaming

In cross-room co-streaming, it's essential to distinguish between the primary room and secondary room. These concepts are relative and defined as follows:

  • Primary Room: The room initially joined by the local user.
  • Secondary Room: After a co-streaming invitation is accepted, both parties must join each other's rooms.

Before initiating cross-room co-streaming, both users must have joined their respective primary rooms. Co-streaming cannot proceed if either user hasn't joined their primary room.

Handling Co-Streaming Invitations

To establish co-streaming, one host sends an invitation, and the other responds by accepting or rejecting it.

Sending an Invitation

To send a cross-room co-streaming request, call the RCRTCEngine object's requestJoinSubRoom method. Upon successful delivery, the invitee will receive a notification via the onJoinSubRoomRequestReceived callback.

Future<int> requestJoinSubRoom(String roomId, String userId, [bool autoLayout = true, String? extra]);
ParameterTypeDescription
roomIdStringTarget room ID
userIdStringTarget user ID
autoLayoutboolWhether to use floating layout. If true, the server merges the invitee's streams into the inviter's view after successful room joining (default: floating layout only). If the invitee hasn't published streams, merging occurs upon publication. Regardless of autoLayout, both parties can manually set layouts using setLiveMixCustomLayouts. Once manually configured, subsequent auto-layout parameters become invalid. Default: true.
extraStringAdditional information
// Callback for inviting others to co-stream
engine.onJoinSubRoomRequested = (roomId, userId, code, message) {
if (code == 0) {
// Invitation sent successfully, awaiting response
} else {
// Failed to send invitation
}
};
// Invite another user to co-stream
engine.requestJoinSubRoom(roomId, userId);

Responding to an Invitation

When an invitation is received, the SDK triggers the RCRTCEngine object's onJoinSubRoomRequestReceived callback. The invitee must respond by either accepting or rejecting.

  • To accept, call responseJoinSubRoomRequest with agree set to true, then join the secondary room via joinSubRoom.
  • To reject, call responseJoinSubRoomRequest with agree set to false.
Future<int> responseJoinSubRoomRequest(String roomId, String userId, bool agree, [bool autoLayout = true, String? extra]);
ParameterTypeDescription
roomIdStringTarget room ID
userIdStringTarget user ID
autoLayoutBoolSame as above
extraStringAdditional information

After responding, the local user receives confirmation via onJoinSubRoomRequestResponded, while the inviter gets notified via onJoinSubRoomRequestResponseReceived.

  • If accepted, all non-audience users (except the invitee) in both rooms receive onJoinSubRoomRequestResponseReceived.
  • If rejected, only the inviter receives the rejection callback.
// Callback for received co-stream invitations
engine.onJoinSubRoomRequestReceived = (String roomId, String userId, String? extra) {
// Callback after accepting
engine.onJoinSubRoomRequestResponded = (String roomId, String userId, bool agree, int code, String? errMsg) {
if (code == 0) {
// Acceptance confirmed
} else {
// Failed to accept
}
};

// Accept the invitation
engine.responseJoinSubRoomRequest(roomId, userId, true);
};

Canceling an Invitation

If an inviter wishes to retract an invitation, call RCRTCEngine's cancelJoinSubRoomRequest method. The invitee will receive onCancelJoinSubRoomRequestReceived.

Future<int> cancelJoinSubRoomRequest(String roomId, String userId, [String? extra]);
ParameterTypeDescription
roomIdStringTarget room ID
userIdStringTarget user ID
// Callback for canceled invitations
engine.onJoinSubRoomRequestCanceled = (String roomId, String userId, int code, String? errMsg) {
if (code == 0) {
// Successfully canceled
} else {
// Failed to cancel
}
};

// Cancel the invitation
engine.cancelJoinSubRoomRequest(roomId, userId);

Joining Secondary Rooms

After accepting an invitation, both parties must join each other's rooms. Relative to the local user's primary room, the other room becomes a secondary room. Join via:

Future<int> joinSubRoom(String roomId);

Timing differs for inviters and invitees:

  • Invitee: After accepting (responseJoinSubRoomRequest with agree=true), call joinSubRoom.
  • Inviter: Upon receiving acceptance (onJoinSubRoomRequestResponseReceived), call joinSubRoom. This triggers onSubRoomJoined, onSubRoomBanded, and onUserJoined.
// Callback for joining secondary rooms
engine.onSubRoomJoined = (String roomId, int code, String? errMsg) {
if (code == 0) {
// Successfully joined
} else {
// Failed to join
}
}

// Join the secondary room
engine.joinSubRoom(roomId);

For multi-host scenarios:

  • Scenario A: If secondary rooms exist before joining the primary room, receive onSubRoomBanded after joinRoom, then optionally join those rooms.

    // Callback for pre-existing secondary rooms
    Function(String roomId)? onSubRoomBanded;
  • Scenario B: If another host initiates co-streaming after local joining, receive onSubRoomBanded to optionally join new secondary rooms.

Subscribing to Streams

After joining a secondary room, subscribe to its hosts' streams via:

  1. Direct subscription using subscribe (see Subscribing to Streams).

    engine.onSubscribed = (String id, RCRTCMediaType type, int code, String? message) {
    if (code == 0) {
    // Subscription successful
    } else {
    // Subscription failed
    }
    };

    engine.subscribe(userId, RCRTCMediaType.video);
  2. Automatic subscription via onRemotePublished when streams become available.

    engine.onRemotePublished = (String roomId, String userId, RCRTCMediaType type) {
    engine.subscribe(userId, type);
    }

To unsubscribe, use unsubscribe (see Unsubscribing).

Temporarily Pausing Co-Streaming

To pause co-streaming without ending it, leave the secondary room via leaveSubRoom with disband=false. This triggers onSubRoomLeft locally and onUserLeft for others, who may then unsubscribe.

// Callback for leaving
engine.onSubRoomLeft = (roomId, code, message) {
if (code == 0) {
// Successfully left
} else {
// Failed to leave
}
}

// Pause co-streaming
engine.leaveSubRoom(roomId, false);

The server automatically removes paused streams from the mix. To resume, rejoin the secondary room without re-invitation.

Ending Co-Streaming

To fully end co-streaming, call leaveSubRoom with disband=true. This unsubscribes from all streams and triggers onSubRoomLeft locally and onSubRoomDisband for others.

// Callbacks
Function(String roomId, int code, String? errMsg)? onSubRoomLeft;
Function(String roomId, String userId)? onSubRoomDisband;

Server-Initiated Room Removal

tip

Use server APIs to remove users from specific rooms.

  • Before removal, notify the client via IM to properly end co-streaming.

  • If removed from the primary room, receive onKicked. The SDK automatically leaves all rooms and cleans up resources.

  • If removed from a secondary room, receive onKicked and automatically leave that room while unsubscribing.

    // Callback for server-initiated removal
    Function(String? roomId, String? errMsg)? onKicked;