Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Users Cannot Hear or See new Participant After Role Change in Agora Flutter SDK #2153

Open
1 of 5 tasks
AbirAhsan opened this issue Dec 12, 2024 · 0 comments
Open
1 of 5 tasks

Comments

@AbirAhsan
Copy link

AbirAhsan commented Dec 12, 2024

Version of the agora_rtc_engine

agora_rtc_engine: ^6.5.0

Platforms affected

  • Android
  • iOS
  • macOS
  • Windows
  • Web

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:

  1. Initialize the Agora engine and join the channel with the VIEWER role.
  2. Change the user's role from VIEWER to PARTICIPANT during the session by calling setClientRole.
  3. Enable audio and video after the role change.
  4. 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;
 late RtcEngine engine; 
//initialize it in init
Future<void> initAgora() async {
    print("Initializing Agora");

    // Get microphone and camera permissions
    await [Permission.microphone, Permission.camera].request();

    // Create RtcEngine instance
    engine = createAgoraRtcEngine();

    // Initialize RtcEngine
    await engine.initialize(const RtcEngineContext(
      appId: Constants.appId,
    ));

    // Set channel profile to live broadcasting
    await 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: const Duration(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 video
    await engine.enableVideo();

    // Start local video preview
    await engine.startPreview();

    // Get user UID
    int uid = MySharedPref.getUserId()!;

    // Join the channel
    await 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 channel
    await engine.setClientRole(
      role: joinType.value == "VIEWER"
          ? ClientRoleType.clientRoleAudience
          : ClientRoleType.clientRoleBroadcaster,
      options: const ClientRoleOptions(
        audienceLatencyLevel:
            AudienceLatencyLevelType.audienceLatencyLevelUltraLowLatency,
      ),
    );

    // Set beauty effect options
    try {
      engine.setBeautyEffectOptions(
        enabled: true,
        options:
            const BeautyOptions(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 change
  
   void listenPermitParticipantRequest() {
    SocketIOHelper.socket?.on(Constants.socketListenPermitParticipant,
        (data) async {
      // Check if the current user is the one who has been granted permission
      if (data['data']['user']['id'] == MySharedPref.getUserId()) {
        joinType.value = 'PARTICIPANT'; // Update the join type to participant
        update();

        // Set client role to broadcaster after receiving permission
        await engine.setClientRole(
          role: ClientRoleType.clientRoleBroadcaster,
        );

        // Enable audio and video for the broadcaster
        await 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!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant