Q1) how I can add more then one person to make conference with them ?
I success to make one person call to other but if person NO.3 want login in conference person NO.3 can't login even person NO.2 get out from conference.
and I have same channel ,ever user have name and uid ,have AppiToken from agora and I send them by FCM notification with them to get token and other
1-this is code (Screen Main) of Host user who make Conference :-
// ignore_for_file: deprecated_member_use
import 'dart:async';
import 'package:agora_rtc_engine/rtc_engine.dart';
import 'package:agora_rtm/agora_rtm.dart';
import 'package:broadcasting/modules/buttom.dart';
import 'package:broadcasting/shared/components/component.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
// import 'package:livestream/HomePage/homepage.dart';
import '../../cubit_main/cubit.dart';
import '../../cubit_main/states.dart';
import '../../model/FcmModel.dart';
import '../../network/end_points.dart';
// import '../constant/constant.dart';
import 'package:agora_rtc_engine/rtc_local_view.dart' as RtcLocalView;
import 'package:agora_rtc_engine/rtc_remote_view.dart' as RtcRemoteView;
import 'package:agora_rtc_engine/rtc_remote_view.dart' as RtcRemoteView2;
import 'dart:math' as math;
import '../../shared/styles/colores.dart';
// import '../constant/heartanim.dart';
class Host_5 extends StatefulWidget {
final String? channelName;
final String? userId;
const Host_5({Key? key, required this.channelName, required this.userId})
: super(key: key);
@override
State<Host_5> createState() => _Host_5State();
}
class _Host_5State extends State<Host_5> {
late RtcEngine _engine;
late int streamId;
bool muted = false;
List messages = [''];
List names = [userh]; //get user name
List images = [image]; //get image
bool heart = false;
double height = 0.5;
bool visable = false;
bool msgFCM = false;
int _remoteUid = 0;
int _remoteUid2 = 0;
@override
void initState() {
super.initState();
initializeAgora();
}
@override
void dispose() {
_engine.leaveChannel();
_engine.destroy();
super.dispose();
}
Future<void> initializeAgora() async {
_engine = await RtcEngine.createWithContext(RtcEngineContext(appId));
await _engine.enableVideo();
await _engine.setChannelProfile(ChannelProfile.LiveBroadcasting);
await _engine.setClientRole(ClientRole.Broadcaster);
streamId = (await _engine.createDataStream(false, false))!;
_engine.setEventHandler(RtcEngineEventHandler(
rejoinChannelSuccess: (channel, uid, elapsed) {
if (kDebugMode) {
print("onREJoinChannel: $channel, uid: $uid");
}
},
joinChannelSuccess: (channel, uid, elapsed) {
if (kDebugMode) {
print("onJoinChannel: $channel, uid: $uid");
}
},
leaveChannel: (stats) {
if (kDebugMode) {
print("channel left");
}
},
userJoined: (uid, elapsed) {
print("UserJoined: $uid");
setState(() {
_remoteUid2 = uid;
_remoteUid = uid;
});
},
userOffline: (uid, elapsed) {
if (kDebugMode) {
print("Useroffline: $uid");
setState(() {
_remoteUid = 0;
_remoteUid2 = 0;
});
}
},
));
await _engine.joinChannel(null, widget.channelName!, null, 0);
}
Widget build(BuildContext context) {
double w = MediaQuery.of(context).size.width;
double h = MediaQuery.of(context).size.height;
double hp = WidgetsBinding.instance.window.physicalSize.height;
double wp = WidgetsBinding.instance.window.physicalSize.width;
return BlocConsumer<Main_Cubit, Main_states>(
listener: (context, state) {},
builder: (context, state) {
return Scaffold(
body: Stack(
children: [
Container(
height: h,
width: w,
color: Colors.green,
child: _broadcastView(), //====> MY LIVE Person NO.1 Master
),
Align(
alignment: Alignment.topLeft,
child: Container(
color: Colors.amber,
width: 100,
height: 250,
margin: const EdgeInsets.only(left: 30, top: 40),
child: _renderRemoteView_out(),//====> come from out Person NO.2 can login
),
),
Align(
alignment: Alignment.topRight,
child: Container(
color: Colors.purple,
width: 100,
height: 250,
margin: const EdgeInsets.only(left: 30, top: 40),
child: _renderRemoteView_out2() ,//====> come from out Person NO.3 and can't login
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(height: 20),
RowHead(),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Visibility(
visible: msgFCM,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
height: 100,
width: 350,
color: Colors.black.withOpacity(0.5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
txt(size: 15, txt: 'Note Message'),
const SizedBox(height: 15),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(onPressed: (){
setState(() {
visable=true;
msgFCM=false;
// Navigator.of(context).pop();
});
}, child: txt(size: 12, txt: 'Ok',colors: Colors.white)),
const SizedBox(width: 15),
ElevatedButton(onPressed: (){
setState(() {
// Navigator.of(context).pop();
msgFCM=false;
});
}, child: txt(size: 12, txt: 'Cancel',colors: Colors.white)),
],
),
],
),),
),
),
_toolbar(),
// SizedBox(height: 55),
],
)
],
),
);
});
// }
}
//BroadCast host=======================================================
Widget _broadcastView() {
not_fcm();
return const RtcLocalView.SurfaceView();
}
//to get user name and Email from Person no.2 or no.3
void not_fcm() {
FirebaseMessaging.onMessage.listen((event) {
FcmModel? userModel;
userModel = FcmModel.fromJson(event.data);
// print('*************//////**************************');
// print(userModel.email);
// print(userModel.tokenFCM);
// print('*************//////**************************');
setState(() {
msgFCM=true;
});
}).onError((error) {
print(error);
});
}
//remot host=======================================================
//to get person no.1
Widget _renderRemoteView_out() {
if (_remoteUid != 0 && visable==true) {
// muted=true;
showTost(txt: 'Guses is ${userh}', state: ToastStates.SUCCESS);
return RtcRemoteView.SurfaceView(
uid: _remoteUid,
channelId: widget.channelName!,
);
} else {
// muted=false;
return txt(size: 12,txt: 'Waiting for other user to join',colors: Colors.white);
}
}
//to get person no.2
Widget _renderRemoteView_out2() {
if (_remoteUid2 != 0) {
return RtcRemoteView2.SurfaceView(
uid: _remoteUid2,
channelId: widget.channelName!,
);
} else {
return const Text("Waiting for other user to join");
}
}
void _onToggleMute() {
setState(() {
muted = !muted;
});
_engine.muteLocalAudioStream(muted);
}
void _onCallEnd() {
_engine.leaveChannel().then((value) {
// checkExist();
Navigator.push(
context, MaterialPageRoute(builder: (context) => bottom()));
});
}
void _onSwitchCamera() {
_engine.switchCamera();
}
Widget RowHead() => Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
RawMaterialButton(
onPressed: () {
_onCallEnd();
// _onScrollDown();
},
shape: const CircleBorder(),
padding: const EdgeInsets.all(5),
elevation: 2.0,
fillColor: Colors.black.withOpacity(0.50),
child: const Icon(
Icons.close_rounded,
color: Colors.white,
size: 30,
),
),
Spacer(),
Container(
margin: EdgeInsets.only(left: 20, top: 30, right: 20),
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent),
borderRadius: BorderRadius.circular(20),
color: Colors.black.withOpacity(0.2)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
CircleAvatar(
backgroundColor: circle_avtar_color,
radius: 20,
child: CircleAvatar(
// backgroundImage: AssetImage('assets/image/doctor.png'),
backgroundImage: NetworkImage(imageProfile!),
radius: 20,
backgroundColor: circle_avtar_color,
),
),
SizedBox(width: 10),
Column(children: [
txt(size: 12, txt: userProfile!, colors: Colors.white),
txt(size: 12, txt: 'Livel 20', colors: Colors.pink)
]),
],
),
)
],
);
Widget _toolbar() {
return Container(
alignment: Alignment.bottomCenter,
margin: const EdgeInsets.only(bottom: 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RawMaterialButton(
onPressed: () {
_onToggleMute();
},
shape: const CircleBorder(),
padding: const EdgeInsets.all(5),
elevation: 2.0,
fillColor: (muted) ? Colors.blue : Colors.white,
child: Icon(
(muted) ? Icons.mic_off : Icons.mic,
color: muted ? Colors.white : Colors.blue,
size: 40,
),
),
RawMaterialButton(
onPressed: () {
_onSwitchCamera();
},
shape: const CircleBorder(),
padding: const EdgeInsets.all(5),
elevation: 2.0,
fillColor: Colors.white,
child: const Icon(
Icons.switch_camera,
color: Colors.blue,
size: 40,
),
)
],
),
);
}
}
2-this is code person NO.2 OR NO.3 to login in Conference (sub Screen )
// ignore_for_file: deprecated_member_use
import 'dart:async';
import 'package:agora_rtc_engine/rtc_engine.dart';
import 'package:agora_rtm/agora_rtm.dart';
import 'package:broadcasting/modules/buttom.dart';
import 'package:broadcasting/shared/components/component.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
// import 'package:livestream/HomePage/homepage.dart';
import '../../cubit_main/cubit.dart';
import '../../cubit_main/states.dart';
import '../../network/end_points.dart';
// import '../constant/constant.dart';
import 'package:agora_rtc_engine/rtc_local_view.dart' as RtcLocalView;
import 'package:agora_rtc_engine/rtc_remote_view.dart' as RtcRemoteView;
import 'package:agora_rtc_engine/rtc_remote_view.dart' as RtcRemoteView2;
import '../../shared/styles/colores.dart';
class Audience_5 extends StatefulWidget {
final String? channelName;
final String? userId;
const Audience_5({Key? key, required this.channelName, required this.userId})
: super(key: key);
@override
State<Audience_5> createState() => _Audience_5State();
}
class _Audience_5State extends State<Audience_5> {
late RtcEngine _engine;
late int streamId;
bool muted = false;
late AgoraRtmClient _client;
late AgoraRtmChannel _channel;
List messages = [''];
List names = [userProfile]; //get user name
List images = [imageProfile]; //get image
final ScrollController _scrollController = ScrollController();
double height = 0.5;
int _remoteUid = 0;
int _remoteUid2 = 0;
@override
void initState() {
super.initState();
initializeAgora();
}
@override
void dispose() {
_engine.leaveChannel();
_engine.destroy();
super.dispose();
}
Future<void> initializeAgora() async {
_engine = await RtcEngine.createWithContext(
RtcEngineContext(appId)); //goto constant.dart file
await _engine.enableVideo();
await _engine.setChannelProfile(ChannelProfile.LiveBroadcasting);
await _engine.setClientRole(ClientRole.Broadcaster);
streamId = (await _engine.createDataStream(false, false))!;
_engine.setEventHandler(RtcEngineEventHandler(
joinChannelSuccess: (channel, uid, elapsed) {
if (kDebugMode) {
print("onJoinChannel: $channel, uid: $uid");
}
},
leaveChannel: (stats) {
if (kDebugMode) {
print("channel left");
}
},
userJoined: (uid, elapsed) {
print("UserJoined: $uid");
setState(() {
_remoteUid = uid;
_remoteUid2 = uid;
});
},
userOffline: (uid, elapsed) {
if (kDebugMode) {
print("Useroffline: $uid");
setState(() {
_remoteUid = 0;
_remoteUid2 = 0;
});
}
},
));
await _engine.joinChannel(null, widget.channelName!, null, 0);
}
Widget build(BuildContext context) {
double w = MediaQuery.of(context).size.width;
double h = MediaQuery.of(context).size.height;
double hp = WidgetsBinding.instance.window.physicalSize.height;
double wp = WidgetsBinding.instance.window.physicalSize.width;
return BlocConsumer<Main_Cubit, Main_states>(
listener: (context, state) {},
builder: (context, state) {
var cubit = Main_Cubit.get(context);
return Scaffold(
body: Stack(
children: [
Container(
height: h,
width: w,
color: Colors.green,
child: _renderRemoteView_out(),//=====>out from No1
),
Align(
alignment: Alignment.topLeft,
child: Container(
color: Colors.amber,
width: 100,
height: 250,
margin: const EdgeInsets.only(left: 30, top: 40),
child: _broadcastView(),//=============which make stream
),
),
Align(
alignment: Alignment.topRight,
child: Container(
color: Colors.purple,
width: 100,
height: 250,
margin: const EdgeInsets.only(left: 30, top: 40),
child: _renderRemoteView_out2(), //==================Out from NO2
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(height: 20),
RowHead(),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
alignment: Alignment.center,
height: h / 4,
// width: w,
width: 200,
child: Padding(
padding: const EdgeInsets.all(0.0),
child: ListView.builder(
itemCount: names.length,
// scrollDirection: Axis.vertical,
physics: const BouncingScrollPhysics(),
controller: _scrollController,
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black12),
borderRadius: BorderRadius.circular(20),
color: Colors.black.withOpacity(0.10),
),
// color: Colors.black.withOpacity(0.20),
// width: 150,
child: index == 0
? null
: ListTile(
leading: CircleAvatar(
backgroundImage:
NetworkImage(images[index]),
),
subtitle: txt(
size: 15,
txt: messages[index],
colors: Colors.white),
title: txt(
size: 18,
txt: names[index],
colors: Colors.black),
//
),
);
}),
),
),
_toolbar(),
// SizedBox(height: 55),
],
)
],
),
);
});
// }
}
//BroadCast host=======================================================
Widget _broadcastView() {
return const RtcLocalView.SurfaceView();
}
//remot host=======================================================
//person NO.1 who make Coneferance
Widget _renderRemoteView_out() {
if (_remoteUid != 0) {
return RtcRemoteView.SurfaceView(
uid: _remoteUid,
channelId: widget.channelName!,
);
} else {
return const Text("Waiting for other user to join");
}
}
//person NO.3
Widget _renderRemoteView_out2() {
if (_remoteUid2 != 0) {
return RtcRemoteView2.SurfaceView(
uid: _remoteUid2,
channelId: widget.channelName!,
);
} else {
return const Text("Waiting for other user to join");
}
}
void _onToggleMute() {
setState(() {
muted = !muted;
});
_engine.muteLocalAudioStream(muted);
}
void _onCallEnd() {
_engine.leaveChannel().then((value) {
// checkExist();
Navigator.push(
context, MaterialPageRoute(builder: (context) => bottom()));
});
}
void _call_host() {
Main_Cubit.get(context).PostFCM_to_otherM(
tokenFCM_host: tokenFCMCall!,
uId_host: uidCall!,
email_host: emailCall!,
name_host: nameCall!,
);
}
void _onSwitchCamera() {
_engine.switchCamera();
}
Widget RowHead() => Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
RawMaterialButton(
onPressed: () {
_onCallEnd();
// _onScrollDown();
},
shape: const CircleBorder(),
padding: const EdgeInsets.all(5),
elevation: 2.0,
fillColor: Colors.black.withOpacity(0.50),
child: const Icon(
Icons.close_rounded,
color: Colors.white,
size: 30,
),
),
Spacer(),
Container(
margin: EdgeInsets.only(left: 20, top: 30, right: 20),
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent),
borderRadius: BorderRadius.circular(20),
color: Colors.black.withOpacity(0.2)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
CircleAvatar(
backgroundColor: circle_avtar_color,
radius: 20,
child: CircleAvatar(
// backgroundImage: AssetImage('assets/image/doctor.png'),
backgroundImage: NetworkImage(image!),
radius: 20,
backgroundColor: circle_avtar_color,
),
),
SizedBox(width: 10),
Column(children: [
txt(size: 12, txt: userh!, colors: Colors.white),
txt(size: 12, txt: 'Livel 20', colors: Colors.pink)
]),
],
),
)
],
);
Widget _toolbar() {
return Container(
alignment: Alignment.bottomCenter,
margin: const EdgeInsets.only(bottom: 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RawMaterialButton(
onPressed: () {
_onToggleMute();
},
shape: const CircleBorder(),
padding: const EdgeInsets.all(5),
elevation: 2.0,
fillColor: (muted) ? Colors.blue : Colors.white,
child: Icon(
(muted) ? Icons.mic_off : Icons.mic,
color: muted ? Colors.white : Colors.blue,
size: 40,
),
),
RawMaterialButton(
onPressed: () {
_onSwitchCamera();
},
shape: const CircleBorder(),
padding: const EdgeInsets.all(5),
elevation: 2.0,
fillColor: Colors.white,
child: const Icon(
Icons.switch_camera,
color: Colors.blue,
size: 40,
),
),
RawMaterialButton(
onPressed: () {
_call_host();
},
shape: const CircleBorder(),
padding: const EdgeInsets.all(5),
elevation: 2.0,
fillColor: Colors.white,
child: const Icon(
Icons.wifi_calling_3_outlined,
color: Colors.blue,
size: 40,
),
)
],
),
);
}
}
and I search in agora Documentation can't find my issue https://api-ref.agora.io/en/video-sdk/flutter/6.x/API/rtc_api_overview_ng.html thank a lot