Audience Connection
Description of the Feature
The 'audience mic link' feature is a real-time interactive communication method. By using the audience mic link feature, hosts can interact in real time with up to 9 audience members, whether it's answering questions, sharing experiences, or engaging in entertainment interactions, all of which significantly enhance the audience's engagement and satisfaction. This direct interaction and communication provide a more convenient and efficient channel for commercial operations and also offer the audience a more personalized and customized shopping experience. The audience mic link feature is suitable for multiple scenarios, including e-commerce live streaming, entertainment live streaming, and online teaching.
Dual-person Mic Connection | Group Mic Connection |
| |
Use Instructions
Note:
This note introduces the audience mic connection feature in TUILiveKit. If you are not using TUILiveKit and are directly using LiveCoreView or RTCRoomEngine, you can skip this step and go directly to the Access Process or the corresponding API documentation.
Audience initiates join microphone application.
Click the co-mic request button | Choose the way to connect the microphone | Send a connection request and wait for the host to agree | After the host agrees, the connection is successful |
| | | |
The host handles the audience's mic connection requests.
Received the audience's connection request | Click on the connected mic user to open the connection dashboard | After clicking agree, the connection is successful |
| | |
Access Process
Audience mic connection process
The TUILiveKit audience mic connection feature is mainly implemented through LiveCoreView. You can call the following API functions to implement the audience mic connection feature. As an example, Audience B requests to connect with Anchor A as follows.
Note:
The following are active call methods provided by LiveCoreView.
All callback methods refer to the callback methods in the ConnectionObserver object set by LiveCoreView.
In Flutter TUILiveKit, the audience mic connection feature is directly implemented through RTCRoomEngine. All Flutter-related content below is in TUILiveKit, calling methods provided by RTCRoomEngine to achieve the corresponding feature for your reference.
Audience sends a mic connection request
Audience B sends a mic connection request to Anchor A. Anchor A will receive the mic connection request from Audience B in the onUserConnectionRequest callback.
val userId = "anchorUserId"; // Change to the UserId of the anchor. If an empty string is passed in, it defaults to the UserId of the anchor.val timeout = 60;liveCoreView.requestIntraRoomConnection(userId, timeout, null)
String userId = "anchorUserId"; // Change to the UserId of the anchor. If an empty string is passed in, it defaults to the UserId of the anchor.int timeout = 60;liveCoreView.requestIntraRoomConnection(userId, timeout, true, null);
let timeout = 60let userId = "anchorUserId" // Change to the UserId of the anchor. If an empty string is passed in, it defaults to the UserId of the anchor.liveCoreView.requestIntraRoomConnection(userId: "", timeOut: timeOut, openCamera: true) {} onError: { code, message in}
NSInteger timeout = 60;NSString userId = "anchorUserId" // Change to the UserId of the anchor. If an empty string is passed in, it defaults to the UserId of the anchor.[liveCoreView requestIntraRoomConnection:""timeOut:timeoutonSuccess:^(void) {} onError:^(NSInteger code, NSString * _Nonnull message) {}];
// File Location: Flutter/lib/service/impl/room_engine_service.dart@overrideTUIRequest takeSeat(int seatIndex, int timeout, TUIRequestCallback? requestCallback) {return roomEngine.takeSeat(seatIndex, timeout, requestCallback);}
The anchor receives the mic connection request
Anchor A will receive Audience B's mic connection request in the onUserConnectionRequest callback method.
override fun onUserConnectionRequest(inviterUser: UserInfo) {Log.i(TAG, "Received audience connection request: ${inviterUser.userId}")}
@Overridepublic void onUserConnectionRequest(LiveStreamDefine.LiveUser inviterUser) {Log.i(TAG, "Received audience connection request: " + inviterUser.userId);}
func onUserConnectionRequest(inviterUser: TUIUserInfo) {print("Received audience connection request: \(inviterUser.userId)")}
- (void)onUserConnectionRequest:(TUIUserInfo *)inviterUser {NSLog(@"Received audience connection request: %@", hostUser.userId);}
In Flutter, Anchor A will receive Audience B's mic connection request in the
RTCRoomEngine
's onRequestReceived callback.// File Location: Flutter/lib/manager/observer/live_observer.dartsuper.onRequestReceived = (request) {LiveKitLogger.info("$tag onRequestReceived:[request:$request");liveController.seatController.onRequestReceived(request);};
Anchor responds to the mic connection request
After Anchor A receives Audience B's mic connection request, they can call respondIntraRoomConnection to respond to Audience B on whether the mic connection is accepted.
// Anchor agrees to mic connectionliveCoreView.respondIntraRoomConnection(audienceBUserId, true, null)
// Anchor agrees to mic connectionliveCoreView.respondIntraRoomConnection(userId, true, null);// Anchor rejects the mic connectionliveCoreView.respondIntraRoomConnection(userId, false, null);
// Anchor agrees to mic connectionliveCoreView.respondIntraRoomConnection(userId: audienceBUserId, isAccepted: true) {} onError: { code, message in}
// Anchor agrees to mic connection[liveCoreView respondIntraRoomConnection:audienceBUserIdisAccepted:YESonSuccess:^(void) {} onError:^(NSInteger code, NSString * _Nonnull message) {}];
// File Location: Flutter/lib/service/impl/room_engine_service.dartmTUIRoomEngine.responseRemoteRequest(requestId, true, new TUIRoomDefine.ActionCallback() {@Overridepublic void onSuccess() {}@Overridepublic void onError(TUICommonDefine.Error error, String message) {}});
The audience receives the anchor's response callback
After Anchor A agrees to the co-broadcast request from Audience B, Audience B will receive Anchor A's agreement to co-broadcast through the onUserConnectionAccepted callback.
override fun onUserConnectionAccepted(inviterUser: UserInfo) {Log.i(TAG, "Audience agrees to connect:${inviterUser.userId}")}
@Overridepublic void onUserConnectionAccepted(LiveStreamDefine.LiveUser liveUser) {Log.i(TAG, "Audience agrees to connect:" + liveUser.userId);}@Overridepublic void onUserConnectionRejected(LiveStreamDefine.LiveUser liveUser) {Log.i(TAG, "Audience rejects to connect:" + liveUser.userId);}
func onUserConnectionAccepted(userId: String) {print("Audience agrees to connect: \(userId)")}
- (void)onUserConnectionAccepted:(NSString *)userId {NSLog(@"Audience agrees to connect: %@", userId);}
In Flutter, the callback for the audience receiving the host's response to the mic connection request is provided by the
takeSeat
API's requestCallback
. For specific examples, refer to the following code:// File Location: Flutter/lib/manager/controller/seat_controller.dartTUIRequest request = liveService.takeSeat(index,timeout,TUIRequestCallback(onAccepted: (String requestId, String userId) { // connection request},onRejected: (String requestId, String userId, String message) { // connection request rejected},},onCancelled: (String requestId, String userId) { // connection request cancell},onTimeout: (String requestId, String userId) { // Mic connection request timed ou},onError: (String requestId, String userId, TUIError error, String message) { // Error callback},));
Callback for changes in the list of co-broadcasting users
After Host A agrees to the co-broadcast request from Audience B, LiveCoreView will send notifications to both Host A and Audience B about the changes in co-broadcasting users.
override fun onConnectedUsersUpdated(inviterUser: UserInfo) {Log.i(TAG, "Callback for changes in the list of co-broadcasting user")}
@Overridepublic void onConnectedUsersUpdated(List<UserInfo> userList, List<UserInfo> joinList, List<UserInfo> leaveList) {Log.i(TAG, "Callback for changes in the list of co-broadcasting user");}
func onConnectedUsersUpdated(userList: [TUIUserInfo], joinList: [TUIUserInfo], leaveList: [TUIUserInfo]) {print("Callback for changes in the list of co-broadcasting user")}
- (void)onConnectedUsersUpdated:(NSArray<TUIUserInfo *> *)userListjoinList:(NSArray<TUIUserInfo *> *)joinListleaveList:(NSArray<TUIUserInfo *> *)leaveList {NSLog(@"Callback for changes in the list of co-broadcasting user");}
// File Location: Flutter/lib/manager/observer/live_observer.dartsuper.onSeatListChanged = (seatList, seatedList, leftList) {LiveKitLogger.info("$tag($hashCode) onSeatListChanged:[seatList:$seatList ,seatedList:$seatedList,leftList:$leftList]");liveController.target?.seatController.onSeatListChanged(seatList, seatedList, leftList);};
Process of disconnecting audio connection
After the audience successfully connects, the host hangs up the mic connection
After Audience B and Host A successfully connect, Host A disconnects the mic connection with Audience.
val userId = "audienceBUserId"liveCoreView.disconnectUser(userId, null)
String userId = "audienceUserId";liveCoreView.disconnectUser(userId, null);
let userId = "audienceBUserId"liveCoreView.disconnectUser(userId: userId) {} onError: { code, message in}
NSString *userId = @"audienceBUserId";[liveCoreView disconnectUser:userIdonSuccess:^{} onError:^(NSInteger code, NSString * _Nonnull message) {}];
// File Location: Flutter/lib/service/impl/room_engine_service.dartmLiveService.kickUserOffSeatByAdmin(0, userId, new TUIRoomDefine.ActionCallback() {@Overridepublic void onSuccess() {}@Overridepublic void onError(TUICommonDefine.Error error, String message) {}});
The audience receives a callback when the host disconnects the interactive connection.
After Host A disconnects the mic connection with Audience B, Audience B will receive the onUserConnectionTerminated callback.
override fun onUserConnectionTerminated(inviterUser: UserInfo) {Log.i(TAG, "Host closes the connection")}
@Overridepublic void onUserConnectionTerminated() {Log.i(TAG, "Host closes the connection");}
func onUserConnectionTerminated() {print("Host closes the connection")}
- (void)onUserConnectionTerminated {NSLog(@"Host closes the connection");}
In Flutter, after Anchor A disconnects the mic connection request with Audience B, Audience B will receive a notification in the
RTCRoomEngine
's onKickedOffSeat callback.// File Location: Flutter/lib/manager/observer/live_observer.dartsuper.onKickedOffSeat = (seatIndex, userInfo) {LiveKitLogger.info("$tag($hashCode) onKickedOffSeat:[seatIndex:$seatIndex,userInfo:$userInfo");liveController.target?.seatController.onKickedOffSeat(seatIndex, userInfo);};
After the audience successfully connects, the audience ends the mic connection
After Audience B successfully connects with Anchor A, Audience B can actively disconnect by calling
terminateIntraRoomConnection
.liveCoreView.terminateIntraRoomConnection()
liveCoreView.terminateIntraRoomConnection();
liveCoreView.terminateIntraRoomConnection()
[liveCoreView terminateIntraRoomConnection]
// File Location: Flutter/lib/service/impl/room_engine_service.dartmLiveService.leaveSeat(new TUIRoomDefine.ActionCallback() {@Overridepublic void onSuccess() {}@Overridepublic void onError(TUICommonDefine.Error error, String message) {}});
The anchor receives a callback when an audience member disconnects.
When Audience B actively disconnects the mic, the anchor will receive the
onUserConnectionExited
callback.override fun onUserConnectionExited(inviterUser: LiveStreamDefine.LiveUser) {Log.i(TAG, "Audience exits the connection")}
@Overridepublic void onUserConnectionExited(UserInfo liveUser) {Log.i(TAG, "Audience exits the connection:${liveUser.userId}");}
func onUserConnectionExited(userInfo: TUIUserInfo) {print("Audience exits the connection")}
- (void)onUserConnectionExited:(TUIUserInfo *)userInfo {NSLog(@"Audience exits the connection");}
In Flutter, you can check the audience who disconnected from the mic in the leftList provided by the onSeatListChanged callback.
// File Location: Flutter/lib/manager/observer/live_observer.dartsuper.onSeatListChanged = (seatList, seatedList, leftList) {LiveKitLogger.info("$tag($hashCode) onSeatListChanged:[seatList:$seatList ,seatedList:$seatedList,leftList:$leftList]");liveController.target?.seatController.onSeatListChanged(seatList, seatedList, leftList);};
Note:
The connection feature is implemented based on LiveCoreView. If you need to extend the connection feature, please refer to the LiveCoreView documentation.
Mic Connection Sequence Diagram