Agora in Flutter- navigating to the video chat screen more than one time keeps local video loading forever
I think the problem is that when pressing back
button you are just being taken to the previous screen and the call session
is not being end. You can try by leaving
the channel when pressing back button like :
_engine.leaveChannel();
End Call
button sample
ElevatedButton(
onPressed: () {
_rtcEngine.leaveChannel();
Navigator.pop(context);
},
style: ButtonStyle(
shape: MaterialStateProperty.all(CircleBorder()),
backgroundColor: MaterialStateProperty.all(Colors.red),
padding: MaterialStateProperty.all(
EdgeInsets.fromLTRB(15, 15, 15, 12)),
),
child: Icon(
Icons.phone,
size: 30,
),
)
Back Button
override using WillPopScope
return WillPopScope(
onWillPop: () async {
_rtcEngine.leaveChannel();
return true;
},
child: Scaffold(
body: Container(),
),
);
![Istiaque Ahmed](https://i.stack.imgur.com/t1FT1.jpg?s=256&g=1)
Comments
-
Istiaque Ahmed over 1 year
I am using Agora for a one-to-one video chat purpose in Flutter. User1 has an app to go online and user2 has another app to go online. After both of them go online, they can do video chat with one another. Both apps have almost similar codebase.
I have a screen or activity (say screen1) where an alert dialog is shown on tapping a button (say button1). On tapping the
Continue
button in the alert dialog, the dialog disappears and the user is taken to the screen (say screen2) where the video chat takes place. But after going to the video chat screen successfully, if the user taps on the back button on the mobile set then s/he is taken to screen1 and after tapping on button1, if the user taps on theContinue
button in the popped up alert dialog, the user is again taken to screen2 but this time the local video (i.e. video of the user using the app) keeps loading for ever. Obviously I want the local video to load as it did for the first time.I am gonna put my code here in such a way that you can easily run that.
Following code is for user1. For user2, no alert box is there in the app. Same code from user1 is used for user2 app, except the value of
remoteUid
is set to be 2 for user2 while this value is set to be 1 for user1. These are just two values identifying 2 users.For user1:
main.dart:
import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'livesession1to1.dart'; void main() { runApp(MessagingExampleApp()); } class NavigationService { static GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>(); } /// Entry point for the example application. class MessagingExampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Messaging Example App', navigatorKey: NavigationService.navigatorKey, // set property theme: ThemeData.dark(), routes: { '/': (context) => Application(), '/liveSession1to1': (context) =>LiveSession1to1(), }, ); } } int _messageCount = 0; /// The API endpoint here accepts a raw FCM payload for demonstration purposes. String constructFCMPayload(String? token, String server_key) { _messageCount++; return jsonEncode({ 'token': token, 'to':token, 'data': { 'via': 'FlutterFire Cloud Messaging!!!', 'count': _messageCount.toString(), }, 'notification': { 'title': 'Hello FlutterFire!', 'body': 'This notification (#$_messageCount) was created via FCM! =============', }, "delay_while_idle" : false, "priority" : "high", "content_available" : true }); } /// Renders the example application. class Application extends StatefulWidget { @override State<StatefulWidget> createState() => _Application(); } class _Application extends State<Application> { String? _token; @override void initState() { super.initState(); } showAlertDialog() { BuildContext context=NavigationService.navigatorKey.currentContext!; // set up the buttons Widget cancelButton = TextButton( child: Text("Cancel"), onPressed: () {}, ); Widget continueButton = TextButton( child: Text("Continue"), onPressed: () { Navigator.of(context, rootNavigator: true).pop(); Navigator.of(context).pushNamed('/liveSession1to1'); }, ); Timer? timer = Timer(Duration(milliseconds: 5000), (){ Navigator.of(context, rootNavigator: true).pop(); }); showDialog( context: context, builder: (BuildContext builderContext) { return AlertDialog( backgroundColor: Colors.black26, title: Text('One to one live session'), content: SingleChildScrollView( child: Text('Do you want to connect for a live session ?'), ), actions: [ cancelButton, continueButton, ], ); } ).then((value){ // dispose the timer in case something else has triggered the dismiss. timer?.cancel(); timer = null; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('My App'), ), floatingActionButton: Builder( builder: (context) => FloatingActionButton( onPressed: showAlertDialog, backgroundColor: Colors.white, child: const Icon(Icons.send), ), ), body: SingleChildScrollView( child: Text( 'Trigger Alert' ), ), ); } }
livesession1to1.dart:
import 'dart:async'; import 'package:agora_rtc_engine/rtc_engine.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:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; // const appId = "<-- Insert App Id -->"; // const token = "<-- Insert Token -->"; const appId = "......";// Put Agora App ID from Agora site here const token = "....";// Put token ( temporary token avilable from Agora site) void main() => runApp(MaterialApp(home: LiveSession1to1())); class LiveSession1to1 extends StatefulWidget { @override _LiveSession1to1State createState() => _LiveSession1to1State(); } class _LiveSession1to1State extends State<LiveSession1to1> { int _remoteUid=1; bool _localUserJoined = false; late RtcEngine _engine; @override void initState() { super.initState(); setState(() {}); initAgora(); } Future<void> initAgora() async { // retrieve permissions await [Permission.microphone, Permission.camera].request(); // Create RTC client instance RtcEngineContext context = RtcEngineContext(appId); _engine = await RtcEngine.createWithContext(context); await _engine.enableVideo(); _engine.setEventHandler( RtcEngineEventHandler( joinChannelSuccess: (String channel, int uid, int elapsed) { print("local user $uid joined"); setState(() { _localUserJoined = true; }); }, userJoined: (int uid, int elapsed) { print("remote user $uid joined"); setState(() { _remoteUid = uid; }); }, userOffline: (int uid, UserOfflineReason reason) { print("remote user $uid left channel"); setState(() { // _remoteUid = null; _remoteUid = 0; }); }, ), ); try { await _engine.joinChannel(token, "InstaClass", null, 0); } catch (e) { print("error with agora = "); print("$e"); print("error printeddddd"); } } // Create UI with local view and remote view @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Agora Video Call'), ), body: Stack( children: [ Center( child: _remoteVideo(), ), Align( alignment: Alignment.topLeft, child: Container( width: 100, height: 150, child: Center( child: _localUserJoined ? RtcLocalView.SurfaceView() : CircularProgressIndicator(), ), ), ), ], ), ); } // Display remote user's video Widget _remoteVideo() { if (_remoteUid != 0) { return RtcRemoteView.SurfaceView( uid: _remoteUid, channelId: "InstaClass", ); }else { print("'Please wait for remote user to join',"); return Text( 'Please wait for remote user to join', textAlign: TextAlign.center, ); } } }
For user2:
main.dart:
import 'dart:async'; import 'package:agora_rtc_engine/rtc_engine.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:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; const appId = "....."; // Same as user1 app const token = "....."; // same as user1 app void main() => runApp(MaterialApp(home: MyApp())); class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { // int? _remoteUid=1; int _remoteUid=2; bool _localUserJoined = false; late RtcEngine _engine; @override void initState() { super.initState(); initAgora(); } Future<void> initAgora() async { // retrieve permissions await [Permission.microphone, Permission.camera].request(); //create the engine _engine = await RtcEngine.create(appId); await _engine.enableVideo(); _engine.setEventHandler( RtcEngineEventHandler( joinChannelSuccess: (String channel, int uid, int elapsed) { print("local user $uid joined"); setState(() { _localUserJoined = true; }); }, userJoined: (int uid, int elapsed) { print("remote user $uid joined"); setState(() { _remoteUid = uid; }); }, userOffline: (int uid, UserOfflineReason reason) { print("remote user $uid left channel"); setState(() { // _remoteUid = null; _remoteUid = 0; }); }, ), ); // await _engine.joinChannel(token, "test", null, 0); await _engine.joinChannel(token, "InstaClass", null, 0); } // Create UI with local view and remote view @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Agora Video Call'), ), body: Stack( children: [ Center( child: _remoteVideo(), ), Align( alignment: Alignment.topLeft, child: Container( width: 100, height: 150, child: Center( child: _localUserJoined ? RtcLocalView.SurfaceView() : CircularProgressIndicator(), ), ), ), ], ), ); } // Display remote user's video Widget _remoteVideo() { /*if (_remoteUid != null) { return RtcRemoteView.SurfaceView(uid: _remoteUid!); }*/ if (_remoteUid != 0) { return RtcRemoteView.SurfaceView( uid: _remoteUid, channelId: "InstaClass", ); }else { return Text( 'Please wait for remote user to join', textAlign: TextAlign.center, ); } } }
In order to get the app ID and token, login to Agora site. After logging in, go to the 'Project Management' section to see the projects already created there. Under the
Functions
column, click on the key symbol and you will be taken to a page where you can generate a temporary token. On that page, give the channel name input the value 'InstaClass' as I have used this name in my code.How to make the video chat work smoothly after the first time it works well ?
-
Istiaque Ahmed over 2 yearsHow to detect the back button pressing event in Flutter ?
-
Diwyansh over 2 yearsFor that you can use custom end call button or use WillPopScope widget .
-
Istiaque Ahmed over 2 yearsI was looking for an way to use the custom end call button. Any suggestion ?
-
Diwyansh over 2 yearsAs you know the that we can customize full UI of call page so just put a button to end the call I'm adding that to my answer.
-
Istiaque Ahmed over 2 yearsI'm gonna test and let you know the result.
-
Diwyansh over 2 yearsSure let me know when you tried.
-
Istiaque Ahmed over 2 yearsLet us continue this discussion in chat.
-
Istiaque Ahmed over 2 yearsYour answer works in the case of an end button in video screen. Can you please add the default back button pressing event handling as you said to do it with
WillPopScope
? Then I can accept your answer. -
Istiaque Ahmed over 2 yearsI can find the
leaveChannel
method here (docs.agora.io/en/Video/leave_android?platform=Android) for Android platform. But for flutter, where is it documented ? I cannot event find it even in theagora_rtc_engine
API doc (pub.dev/packages/agora_rtc_engine/example) . -
Diwyansh over 2 yearsPlease go through this docs.agora.io/en/Voice/API%20Reference/flutter/index.html and I will add a WillPopScope functions as well.
-
Istiaque Ahmed over 2 yearsThe link you gave is for voice call. 1) Still where is it said in the doc that we have to call the
leaveChannel
method when coming out of the chat screen ? Besides I am usingagora_rtc_engine
plugin. Found no mention of it in the plugin doc. 2) Shouldn't the plugin doc have mentioned it ? -
Diwyansh over 2 yearsSorry I mistaken check this docs.agora.io/en/Video/API%20Reference/flutter/index.html but not much difference because for voice we also use same plugin
-
Istiaque Ahmed over 2 yearsI have invited you to a chat room auto generated from here
-
Diwyansh over 2 yearsNo chat room found
-
Istiaque Ahmed over 2 yearsjoin here: chat.stackoverflow.com/rooms/240597/…