You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am implementing a live streaming feature using the Agora SDK in a Flutter application. There are three types of roles in my app: VIEWER, PARTICIPANT, and HOST. When users join the channel with their initial roles, everything works perfectly—audio and video streams function as expected for all roles. However, when a user changes their role from VIEWER to PARTICIPANT during the session, the following issue occurs:
Initialize the Agora engine and join the channel with the VIEWER role.
Change the user's role from VIEWER to PARTICIPANT during the session by calling setClientRole.
Enable audio and video after the role change.
Observe other users in the channel (both HOST and PARTICIPANT) after the role change.
Expected results
After a role change from VIEWER to PARTICIPANT:
The user's audio and video streams should be visible and audible to other users in the channel.
Actual results
After a role change from VIEWER to PARTICIPANT:
Other users in the channel cannot see the new PARTICIPANT's video stream or hear their audio.
The onUserJoined callback is triggered, and the local video preview works for the new PARTICIPANT.
New PARTICIPANT can hear and see Host video and audio
Code sample
Code sample
RxList<ProfileModel> remoteRenderers =<ProfileModel>[].obs;
lateRtcEngine engine;
//initialize it in initFuture<void> initAgora() async {
print("Initializing Agora");
// Get microphone and camera permissionsawait [Permission.microphone, Permission.camera].request();
// Create RtcEngine instance
engine =createAgoraRtcEngine();
// Initialize RtcEngineawait engine.initialize(constRtcEngineContext(
appId:Constants.appId,
));
// Set channel profile to live broadcastingawait engine
.setChannelProfile(ChannelProfileType.channelProfileLiveBroadcasting);
// Register event handlers
engine.registerEventHandler(
RtcEngineEventHandler(
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
localUserJoined.value =true;
update();
},
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
print("Remote user $remoteUid joined the channel");
SocketIOHelper.socket?.emitWithAck(Constants.socketUserInfo, {
"userId": remoteUid,
"roomId": roomId,
}, ack: (data) async {
if (data['data']['roomRole'] !="VIEWER") {
await engine.muteRemoteAudioStream(uid: remoteUid, mute:false);
await engine.muteRemoteVideoStream(uid: remoteUid, mute:false);
}
if (data['data']['roomRole'] =="HOST") {
remoteHost.value =ProfileModel.fromJson(data['data']);
update();
} else {
CustomSnackBar.showCustomErrorToast(
message:"onUserJoined user $remoteUid joined the channel",
duration:Duration(seconds:5),
);
remoteRenderers.add(ProfileModel.fromJson(data['data']));
update();
}
});
updateViewerCount();
},
onUserOffline: (RtcConnection connection, int remoteUid,
UserOfflineReasonType reason) {
print("Remote user $remoteUid left the channel");
remoteRenderers.removeWhere((user) => user.id == remoteUid);
updateViewerCount();
update();
},
onConnectionStateChanged: (connection, state, reason) {
print("Connection state changed: $state, reason: $reason");
},
onLeaveChannel: (connection, stats) {
remoteRenderers.removeWhere((user) => user.id == connection.localUid);
updateViewerCount();
},
onClientRoleChanged: (connection, oldRole, newRole, newRoleOptions) {
localUserJoined.value =true;
update();
CustomSnackBar.showCustomErrorToast(
message:"Role Changed $oldRole to $newRole",
duration:constDuration(seconds:5),
);
},
onError: (code, message) {
print("Error occurred: $code\n $message");
CustomSnackBar.showCustomErrorToast(
message: code.toString(),
);
update();
},
onClientRoleChangeFailed: (connection, code, message) {
print("Role change failed: $code\n $message");
CustomSnackBar.showCustomErrorToast(
message:" onClientRoleChangeFailed $code.toString()",
);
update();
},
onUserStateChanged:
(RtcConnection connection, int remoteUid, int state) {},
onLocalAudioStateChanged: (RtcConnection rtcConnection,
LocalAudioStreamState audioStream,
LocalAudioStreamReason audioStreamReason) {
print("Local audio state changed: $audioStream.");
update();
},
),
);
// Enable videoawait engine.enableVideo();
// Start local video previewawait engine.startPreview();
// Get user UIDint uid =MySharedPref.getUserId()!;
// Join the channelawait engine.joinChannel(
token: token!,
channelId: roomId,
options:ChannelMediaOptions(
autoSubscribeVideo:true,
autoSubscribeAudio:true,
token: token,
publishCameraTrack:true, //joinType.value != "VIEWER",
publishMicrophoneTrack:true// joinType.value != "VIEWER",
),
uid: uid, // Let Agora assign a random UID
);
// Set the client role based on the join type after joining the channelawait engine.setClientRole(
role: joinType.value =="VIEWER"?ClientRoleType.clientRoleAudience
:ClientRoleType.clientRoleBroadcaster,
options:constClientRoleOptions(
audienceLatencyLevel:AudienceLatencyLevelType.audienceLatencyLevelUltraLowLatency,
),
);
// Set beauty effect optionstry {
engine.setBeautyEffectOptions(
enabled:true,
options:constBeautyOptions(smoothnessLevel:1.0, lighteningLevel:0.7),
);
} catch (e) {
print("Error setting beauty options: $e");
}
//set log file on asset folder
engine.setLogFile("assets/agora-rtc.log");
}
//for role changevoidlistenPermitParticipantRequest() {
SocketIOHelper.socket?.on(Constants.socketListenPermitParticipant,
(data) async {
// Check if the current user is the one who has been granted permissionif (data['data']['user']['id'] ==MySharedPref.getUserId()) {
joinType.value ='PARTICIPANT'; // Update the join type to participantupdate();
// Set client role to broadcaster after receiving permissionawait engine.setClientRole(
role:ClientRoleType.clientRoleBroadcaster,
);
// Enable audio and video for the broadcasterawait engine.enableAudio();
await engine.enableVideo();
await engine.muteLocalAudioStream(false);
await engine.muteLocalVideoStream(false);
await engine.startPreview();
for (var user in remoteRenderers) {
await engine.muteRemoteAudioStream(uid: user.id!, mute:false);
await engine.muteRemoteVideoStream(uid: user.id!, mute:false);
}
}
});
}
Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
[Paste your logs here]
Flutter Doctor output
Doctor output
ABIR ~ %flutter doctor -v[✓] Flutter (Channel stable, 3.27.0, on macOS 15.1.1 24B91 darwin-x64, locale en-BD) • Flutter version 3.27.0 on channel stable at /Users/abir/Developer/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 8495dee1fd (34 hours ago), 2024-12-10 14:23:39 -0800 • Engine revision 83bacfc525 • Dart version 3.6.0 • DevTools version 2.40.2[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1) • Android SDK at /Users/abir/Library/Android/sdk • Platform android-35, build-tools 33.0.1 • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231) • All Android licenses accepted.[✓] Xcode - develop for iOS and macOS (Xcode 16.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Build 16B40 • CocoaPods version 1.13.0[✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome[✓] Android Studio (version 2022.3) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)[✓] VS Code (version 1.96.0) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.102.0[✓] Connected device (3 available) • Nokia C32 (mobile) • 192.168.2.77:5555 • android-arm64 • Android 13 (API 33) • macOS (desktop) • macos • darwin-x64 • macOS 15.1.1 24B91 darwin-x64 • Chrome (web) • chrome • web-javascript • Google Chrome 131.0.6778.109[✓] Network resources • All expected network resources are available.• No issues found!
The text was updated successfully, but these errors were encountered:
Version of the agora_rtc_engine
agora_rtc_engine: ^6.5.0
Platforms affected
Steps to reproduce
I am implementing a live streaming feature using the Agora SDK in a Flutter application. There are three types of roles in my app: VIEWER, PARTICIPANT, and HOST. When users join the channel with their initial roles, everything works perfectly—audio and video streams function as expected for all roles. However, when a user changes their role from VIEWER to PARTICIPANT during the session, the following issue occurs:
Expected results
After a role change from VIEWER to PARTICIPANT:
The user's audio and video streams should be visible and audible to other users in the channel.
Actual results
After a role change from VIEWER to PARTICIPANT:
Code sample
Code sample
Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
[Paste your logs here]
Flutter Doctor output
Doctor output
The text was updated successfully, but these errors were encountered: