Skip to content

After upgrading from version 5.0.0 to 6.5.1, it was discovered that when a new SDK participant joins the channel, the onUserJoined callback is not triggered. #2310

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

Open
2 of 5 tasks
dingjianjaja opened this issue May 10, 2025 · 7 comments
Labels
waiting for customer response waiting for customer response, or closed by no-reponse bot

Comments

@dingjianjaja
Copy link

Version of the agora_rtc_engine

After upgrading from version 5.0.0 to 6.5.1, it was discovered that when a new SDK participant joins the channel, the onUserJoined callback is not triggered.

Platforms affected

  • Android
  • iOS
  • macOS
  • Windows
  • Web

Steps to reproduce

1、version 5.0.0 is ok
2、upgrading from version 5.0.0 to 6.5.1
3、it was discovered that when a new SDK participant joins the channel, the onUserJoined callback is not triggered.

Expected results

the onUserJoined callback can be triggered.

Actual results

it was discovered that when a new SDK participant joins the channel, the onUserJoined callback is not triggered.

Code sample

Code sample
[Paste your code here]

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs
[Paste your logs here]

Flutter Doctor output

Doctor output
[Paste your output here]
@peilinok
Copy link
Contributor

@dingjianjaja Could you please provide a detailed step-by-step guide for SDK integration to address the issue?

@peilinok peilinok added the waiting for customer response waiting for customer response, or closed by no-reponse bot label May 16, 2025
@arslan9380
Copy link

The same issue is with me, and no audio started because of this.

@arslan9380
Copy link

Any update on this issue?

@peilinok
Copy link
Contributor

@arslan9380 Could you please provide a detailed step-by-step guide for SDK integration to address the issue?

@peilinok
Copy link
Contributor

@dingjianjaja @arslan9380 I believe this issue stems from the recent SDK integration changes. Specifically, there have been modifications to several key APIs including joinChannel, setClientRole, changeAudience, and other related methods.

@arslan9380
Copy link

arslan9380 commented May 19, 2025

`class CallingView extends StatefulWidget {
CallModel callModel;
final bool video;

CallingView(this.callModel, this.video);

@OverRide
_CallPageState createState() => _CallPageState();
}

class _CallPageState extends State {
final GlobalKey _scaffoldKey = GlobalKey();
final _users = [];
int? _remoteUid;
RtcEngine? _engine;
StreamSubscription? stream;
bool muted = false;
bool showUserSheet = false;
bool speaker = false;
AudioPlayer audioPlayer = AudioPlayer();
List callingUsers = [];

@OverRide
void dispose() {
_users.clear();
_engine?.leaveChannel();
_engine?.release(); // Use release() instead of destroy()
stream?.cancel();
audioPlayer.dispose();
WakelockPlus.disable();
super.dispose();
}

@OverRide
void initState() {
_handleCameraAndMic();
initialize();
playDialTone();
WakelockPlus.enable();
callingUsers = widget.callModel.requestedUsers ?? [];
super.initState();
}

Future _handleCameraAndMic() async {
await [Permission.camera, Permission.microphone, Permission.storage]
.request();
}

Future initialize() async {
await _initAgoraRtcEngine();
_addAgoraEventHandlers();
String token = Utils()
.generateAgoraToken(Utils().decryptString(widget.callModel.callingId!));
String channelId = Utils().decryptString(widget.callModel.callingId!);
print("Calling Token: ${token}");
print("Channel Id: ${channelId}");
await _engine?.joinChannel(
token: token,
channelId: channelId,
uid: 0,
options: const ChannelMediaOptions(),
);
}

Future _initAgoraRtcEngine() async {
_engine = createAgoraRtcEngine();
await _engine!.initialize(RtcEngineContext(appId: APP_ID));

await _engine?.enableVideo();
await _engine?.enableAudio();
await _engine?.enableLocalAudio(true);
await _engine?.enableLocalVideo(false);

}

void _addAgoraEventHandlers() {
_engine!.registerEventHandler(RtcEngineEventHandler(
onJoinChannelSuccess: (RtcConnection connection, int elapsed) {
print("channel join success call start");
addCall(connection.localUid ?? 0);
},
onError: (codeType, error) {
print(error.toString());
},
onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
print("------calling person joined");
setState(() {
_remoteUid = remoteUid;
stopDialTone();
});
},
onUserOffline: (RtcConnection connection, int remoteUid,
UserOfflineReasonType reason) {
setState(() {
_remoteUid = null;
});
},
));

}

void showInSnackBar(String value) {
CommonUiService().showSnackBar(value);
}

@OverRide
Widget build(BuildContext context) {
return ViewModelBuilder.reactive(
builder: (context, model, child) {
return WillPopScope(
onWillPop: () async {
if (showUserSheet) {
showUserSheet = false;
setState(() {});
return true;
}
model.endCall(widget.callModel);
return true;
},
child: Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.black,
body: SafeArea(
child: Center(
child: Stack(
alignment: Alignment.bottomCenter,
children: [
_renderRemoteVideo(),
Container(
alignment: Alignment.bottomCenter,
padding: const EdgeInsets.symmetric(vertical: 48),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RawMaterialButton(
onPressed: () {
_onSpeaker();
},
child: Icon(
speaker
? Icons.speaker_phone
: Icons.speaker_outlined,
color: speaker ? Colors.white : Colors.red,
size: 20.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: speaker ? Colors.red : Colors.white,
padding: const EdgeInsets.all(12.0),
),
RawMaterialButton(
onPressed: _onToggleMute,
child: Icon(
muted ? Icons.mic_off : Icons.mic,
color: muted ? Colors.white : Colors.red,
size: 20.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: muted ? Colors.red : Colors.white,
padding: const EdgeInsets.all(12.0),
),
RawMaterialButton(
onPressed: () => model.endCall(widget.callModel),
child: Icon(
Icons.call_end,
color: Colors.white,
size: 35.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: Colors.redAccent,
padding: const EdgeInsets.all(15.0),
),
],
),
),
if (showUserSheet == true)
Container(
alignment: Alignment.bottomCenter,
height: Get.height * 0.6,
child: UsersList(widget.callModel, model))
],
),
),
),
),
);
},
viewModelBuilder: () => CallingViewModel());
}

void _onSpeaker() {
setState(() {
speaker = !speaker;
});
print("speaker $speaker");
showInSnackBar(speaker ? 'On Speaker' : 'On ear-piece');
_engine?.setEnableSpeakerphone(speaker);
}

void _onToggleMute() {
setState(() {
muted = !muted;
});
showInSnackBar(muted ? 'Mic Muted' : 'Mic Un-muted');
_engine?.muteLocalAudioStream(muted);
}

Widget _renderRemoteVideo() {
if (_remoteUid != null) {
return Center(
child: Column(
children: [
Container(
width: Get.width,
alignment: Alignment.centerRight,
child: RawMaterialButton(
onPressed: () {
setState(() {
showUserSheet = !showUserSheet;
});
},
child: Icon(
Icons.person,
color: Colors.white,
size: 35.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: Theme.of(context).primaryColor,
padding: const EdgeInsets.all(15.0),
),
),
SizedBox(
height: Get.height * 0.1,
),
RoundImage(
imageUrl: widget.callModel.callerImage,
radius: Get.height * 0.2,
),
SizedBox(
height: 12,
),
if (widget.callModel.subjectName != "")
Text(
widget.callModel.callType == "group"
? "Group: " + widget.callModel.subjectName!
: "Subject: " + widget.callModel.subjectName!,
style: TextStyle(color: Colors.white),
textAlign: TextAlign.center,
),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Call Started',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold,
fontSize: 26),
),
],
),
],
));
} else {
return Center(
child: Column(children: [
Container(
width: Get.width,
alignment: Alignment.centerRight,
child: RawMaterialButton(
onPressed: () {
setState(() {
showUserSheet = !showUserSheet;
});
},
child: Icon(
Icons.person,
color: Colors.white,
size: 35.0,
),
shape: CircleBorder(),
elevation: 2.0,
fillColor: Theme.of(context).primaryColor,
padding: const EdgeInsets.all(15.0),
),
),
Spacer(),
RoundImage(
imageUrl: widget.callModel.callerImage,
radius: Get.width * 0.4,
),
SizedBox(
height: 20,
),
if (widget.callModel.subjectName != "")
Text(
"Subject: " + widget.callModel.subjectName!,
style: TextStyle(color: Colors.white),
textAlign: TextAlign.center,
),
SizedBox(
height: 16,
),
Container(
margin: EdgeInsets.only(left: Get.width * 0.4, bottom: 10),
child: ImageStack(
imageList: callingUsers
.map((e) => e.image ?? personPlaceholder)
.toList(),
imageRadius: 35,
imageCount: 3,
imageBorderWidth: 1.5,
totalCount: callingUsers.length,
backgroundColor: Colors.transparent,
imageBorderColor: Colors.white,
extraCountBorderColor: Colors.transparent,
extraCountTextStyle: TextStyle(
color: Colors.white,
fontSize: 18,
height: 1,
fontWeight: FontWeight.w500,
),
),
),
SizedBox(
height: 40,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
callingUsers.length > 0 ? 'Connecting...' : "Call Started..",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold,
fontSize: 26),
),
],
),
]),
);
}
}

void stopDialTone() {
audioPlayer.dispose();
}

Future addCall(int uid) async {
await locator().makeCall(widget.callModel);
startStream();
}

startStream() {
stream = FirebaseFirestore.instance
.collection("onGoingCalls")
.doc(widget.callModel.id)
.snapshots()
.listen((event) {
widget.callModel = CallModel.fromMap(event.data()!);
print("Requested Users==>${widget.callModel.requestedUsers}");
callingUsers = widget.callModel.requestedUsers ?? [];

  if ((widget.callModel.callType == "personal" ||
          widget.callModel.callType == "group") &&
      widget.callModel.requestedUserIds!.isEmpty &&
      widget.callModel.joinedUserIds!.isEmpty) {
    CallingViewModel().endCall(widget.callModel);
  }

  print(event.data());
  print("Requested Users==>${callingUsers.length}");

  setState(() {});
});

}

playDialTone() async {
try {
audioPlayer.play(AssetSource("dial_tone.mp3"));
// _engine?.setEnableSpeakerphone(false);
} on Exception catch (e) {
print("Error in playing dial tone: $e");
}
}
}`

@peilinok
Copy link
Contributor

@arslan9380 You should set clientRole to broadcaster by 'setClientRole' after initialize and before joinChannel or set 'ChannelMediaOptions.clientRoleType' with 'ClientRoleType.clientRoleBroadcaster' when joinChannel

visit
https://api-ref.agora.io/en/voice-sdk/flutter/6.x/API/class_irtcengine.html#ariaid-title154
or
https://github.com/AgoraIO-Extensions/Agora-Flutter-SDK/blob/main/example/lib/examples/basic/join_channel_video/join_channel_video.dart#L115
to find more details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting for customer response waiting for customer response, or closed by no-reponse bot
Projects
None yet
Development

No branches or pull requests

3 participants