I am developing a voice call application using Flutter Agora SDK. So far, I have been able to comfortably perform voice calls without any errors. But today, while testing it on my real device, it gives an error even though I haven't made any changes to the initializing process. Even strangely, it works without any error on the emulator, but only on the real device gives error.
Future<void> initAgora() async {
await [Permission.microphone].request();
try {
engine = await RtcEngine.createWithContext(RtcEngineContext(APP_ID));
await engine.enableAudio();
await engine.setChannelProfile(ChannelProfile.Communication);
engine.setEventHandler(
RtcEngineEventHandler(
activeSpeaker: (i) {
log("Active Speaker: $i");
},
microphoneEnabled: (enable) {
log("Microphone: " + enable.toString());
callingController.microphoneState.value = enable;
},
warning: (warningCode) {
print(warningCode.toString());
},
rtcStats: (stats) {
log("User Count: ${stats.userCount}");
},
connectionStateChanged: (state, reason) {
log("Connection Changed : ${state.toString()}, ${reason.toString()}");
},
joinChannelSuccess: (String channel, int uid, int elapsed) {
log('joinChannelSuccess $channel $uid');
},
userJoined: (int uid, int elapsed) {
log('userJoined $uid');
},
userOffline: (int uid, UserOfflineReason reason) {
log('userOffline $uid');
callingController.finishCall(uid, "user_left");
},
error: (error) {
log("ERROR: $error", name: "AGORA");
},
),
);
if (callingController.isCallerMe) {
await joinChannel();
}
} catch (e) {
print(e);
failureSnackbar(e.toString());
}
}
The error that you shared occurs when you try calling a method before the SDK has been initialised properly. Can you please check your RtcEngine config. Also, if you have enabled tokens in your project please make sure that you pass it to the config.
Related
I implemented Firebase phone authentication (OTP Login) successfully and it was working fine. However, I had to change my keystore alias and generate a new keystore to update the app in Play Store.
Since then, I am facing this issue where it says the otp is wrong every time. Even when I copy-paste the otp from message, it throws the error every time. It is also behaving weird, for some phone numbers, the otp works successfully but for some others, it doesn't. Any little help will be appreciated a lot.
It is important to note that OTP Authentication is working fine in emulators but the error shows up when installed in a real device.
Here's my code snippet below -
String verficationIdRecieved = "";
int? _resendToken;
void verifyNumber() {
auth.verifyPhoneNumber(
phoneNumber: "+880" + phoneNoController.text,
verificationCompleted: (PhoneAuthCredential credential) async {
await auth.signInWithCredential(credential).then((value) async {
print("verficationCompleted : Logged in");
// Get.offAll(() => OtpVerifyCodeScreen);
});
},
verificationFailed: (FirebaseAuthException exception) {
LoadingDialog().dismiss();
print(exception.message);
getPrefix.Get.snackbar("Error verifyNumber",
"Please check if your phone number is right. ${exception.message}");
},
codeSent: (String verficationId, int? resendToken) async {
verficationIdRecieved = verficationId;
_resendToken = resendToken;
otpCodeVisible = true;
setState(() {
timedButtonActtive = true;
});
LoadingDialog().dismiss();
},
timeout: Duration(seconds: 60),
forceResendingToken: _resendToken,
codeAutoRetrievalTimeout: (String verificationId) {
// ADDED LATER https://stackoverflow.com/questions/61132218/resend-otp-code-firebase-phone-authentication-in-flutter
// REMOVE IF ERROR
verficationIdRecieved = verificationId;
},
);
}
var firebaseToken;
void verifyCode(BuildContext context) async {
LoadingDialog().show(context);
PhoneAuthCredential credential = PhoneAuthProvider.credential(
verificationId: verficationIdRecieved, smsCode: codeController.text);
try {
await auth.signInWithCredential(credential).then((value) {
// print("\n\n User UID should be ${value.user!.uid}");
print("verifyCode : Login successfull");
value.user!.getIdToken().then((value) => {
firebaseToken = value,
print("This is the firebase token == $firebaseToken"),
verifyOtp(
mobileNo: phoneNoController.text,
otp: codeController.text,
ftoken: firebaseToken)
});
final snackBar = SnackBar(content: Text("Login Successful"));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
// getPrefix.Get.offAll(() => SetUsernameScreen());
});
} catch (e) {
final snackBar = SnackBar(
content: Text(
"The sms code has expired or you entered a wrong code. Please re-send the code to try again."));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}
I think I know your problem.
Android automatically confirms the user as soon as it receives the code before the user clicks the confirmation button.
Saying that you do not have this problem in the emulator is why you receive the code on the real phone.
If you want to manually verify the user, you have two options:
One is to set the timeout to 5 seconds. (So that Android can not automatically verify the user).
The second solution is not to do anything in the verificationCompleted method because now Android is using this method to confirm the user. (My suggestion is to use this way.)
I hope this will solve your problem.
void verifyNumber() {
auth.verifyPhoneNumber(
phoneNumber: "+880" + phoneNoController.text,
verificationCompleted: (PhoneAuthCredential credential) async {
// await auth.signInWithCredential(credential).then((value) async {
// print("verficationCompleted : Logged in"); //Here
// // Get.offAll(() => OtpVerifyCodeScreen);
// });
},
verificationFailed: (FirebaseAuthException exception) {
LoadingDialog().dismiss();
print(exception.message);
getPrefix.Get.snackbar("Error verifyNumber",
"Please check if your phone number is right. ${exception.message}");
},
codeSent: (String verficationId, int? resendToken) async {
verficationIdRecieved = verficationId;
_resendToken = resendToken;
otpCodeVisible = true;
setState(() {
timedButtonActtive = true;
});
LoadingDialog().dismiss();
},
timeout: Duration(seconds: 60),
forceResendingToken: _resendToken,
codeAutoRetrievalTimeout: (String verificationId) {
// ADDED LATER https://stackoverflow.com/questions/61132218/resend-otp-code-firebase-phone-authentication-in-flutter
// REMOVE IF ERROR
verficationIdRecieved = verificationId;
},
);
}
I have a program that will check a password with bcrypt library, this is quite computing intensive, so as a result the UI will be stuck for like 2 seconds. It is very annoying and I cannot figure out what to do to stop it.
I want a loader to be shown when the password is being checked.
This is my code:
class _MyWidgetState<MyWidget> extends State{
build() {
return GetPassCode(PassCodeType.ENTER,
onDone: ({context, data}) async {
unlock(state, data?['password'] ?? '', Languages.of(context));
}, goBack: () {}, data: {});
}
unlock(userState, String? password, Languages strings) async {
final user = userState.currentUser;
if (!(await user.checkPassword(password))) {
return;
}
}
context.read<LockCubit>().unlock();
}
}
you can put the caculating into a isolate.
https://api.flutter-io.cn/flutter/dart-isolate/dart-isolate-library.html
here's some example code:
class IsoMessage {
final SendPort? sendPort;
final List<String> args;
IsoMessage(this.sendPort, this.args);
}
String myCaculate(IsoMessage message) {
String result = message.args[0][0] + message.args[1][1];
message.sendPort?.send(result);
return result;
}
here's how to calling the func
var port = ReceivePort();
port.listen((message) {
print("onData: $message");
}, onDone: () {
print('iso close');
}, onError: (error) {
print('iso error: $error');
});
IsoMessage message = IsoMessage(port.sendPort,["asd", "dsa"]);
Isolate.spawn<IsoMessage>(myCaculate, message);
// Get microphone permission
await PermissionHandler().requestPermissions(
[PermissionGroup.microphone],
);
var engine = await RtcEngine.create(APP_ID);
engine.enableAudio();
// Define event handler
engine.setEventHandler(RtcEngineEventHandler(
joinChannelSuccess: (String channel, int uid, int elapsed) {
print('joinChannelSuccess ${channel} ${uid}');
setState(() {
_joined = true;
});
}, userJoined: (int uid, int elapsed) {
print('userJoined ${uid}');
setState(() {
_remoteUid = uid;
});
}, userOffline: (int uid, UserOfflineReason reason) {
print('userOffline ${uid}');
setState(() {
_remoteUid = null;
});
}));
// Join channel 123
await engine.joinChannel(Token, '123', null, 0);
i am tring to build audio calling app using agora.io but i keep getting this error saying "Access denied finding property "net.dns1" "
I want to add in-app (video) calling like Messenger (Facebook) does. It works when one party creates channel and another one joins.
But is there a way to create calling screen where party B can accept or reject call? I am looking in Agora.io documentation but cannot find anything suitable for this.
This is my code though...
Future<void> initialize() async {
if (APP_ID.isEmpty) {
setState(() {
_infoStrings.add(
'APP_ID missing, please provide your APP_ID in settings.dart',
);
_infoStrings.add('Agora Engine is not starting');
});
return;
}
await _initAgoraRtcEngine();
_addAgoraEventHandlers();
await AgoraRtcEngine.enableWebSdkInteroperability(true);
await AgoraRtcEngine.setParameters('''
{\"che.video.lowBitRateStreamParameter\":{\"width\":320,\"height\":180,\"frameRate\":15,\"bitRate\":140}}''');
await AgoraRtcEngine.joinChannel(null, 'Test', null, 0);
}
Future<void> _initAgoraRtcEngine() async {
AgoraRtcEngine.create(APP_ID);
AgoraRtcEngine.enableVideo();
}
void _addAgoraEventHandlers() {
AgoraRtcEngine.onError = (dynamic code) {
setState(() {
final info = 'onError: $code';
_infoStrings.add(info);
});
};
AgoraRtcEngine.onJoinChannelSuccess = (
String channel,
int uid,
int elapsed,
) {
setState(() {
final info = 'onJoinChannel: $channel, uid: $uid';
_infoStrings.add(info);
});
};
AgoraRtcEngine.onLeaveChannel = () {
setState(() {
_infoStrings.add('onLeaveChannel');
_users.clear();
});
};
AgoraRtcEngine.onUserJoined = (int uid, int elapsed) {
setState(() {
final info = 'userJoined: $uid';
_infoStrings.add(info);
_users.add(uid);
});
};
AgoraRtcEngine.onUserOffline = (int uid, int reason) {
setState(() {
final info = 'userOffline: $uid';
_infoStrings.add(info);
_users.remove(uid);
});
};
AgoraRtcEngine.onFirstRemoteVideoFrame = (
int uid,
int width,
int height,
int elapsed,
) {
setState(() {
final info = 'firstRemoteVideo: $uid ${width}x $height';
_infoStrings.add(info);
});
};
}
You will need to push channelId to other user mobile in this case.
The CS Guy has created very useful video on you tube to implement this step as well as calling screen.
https://www.youtube.com/watch?v=v9ngriCV0J0
You need to use Native ConnectionService for Android and Callkit of iOS.
You can find the official Agora samples for the above feature here: https://github.com/AgoraIO/Advanced-Video/tree/master/Calling-Interface, but I don't think Agora has call-interface sample in Flutter, you have to write the wrapper on your own for now.
widget.chatRoomId is the id specified for both of the users when you create a chatroom for them.
Future<void> onJoin() async {
// update input validation
if (widget.chatRoomId.isNotEmpty) {
// await for camera and mic permissions before pushing video page
await _handleCameraAndMic();
// push video page with given channel name
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CallPage(
channelName: widget.chatRoomId,
// TODO: set to _role
role: ClientRole.Broadcaster,
),
),
);
}
}
I am having some trouble implementing WebSockets in my flutter application.
Here is code my code:
void connectToWebSocket() {
print("trying to connect to websocket");
final Future futureChannel = establishConnection();
futureChannel.then((future) {
print("Connection established, registering interest now...");
channel = future;
webSocketConnected = true;
channel.sink.add({
"action": "saveConnection",
"UserName": "rakshak#gmail.com",
"DeviceId": "1d0032000947363339343638"
});
}).catchError((error) {
channel = null;
webSocketConnected = false;
webSocketConnectionError = error.toString();
print("Connection failed \n $webSocketConnectionError");
});
}
Future<IOWebSocketChannel> establishConnection() async {
final IOWebSocketChannel channel = IOWebSocketChannel.connect(
'wss://1j839fy6t3.execute-api.us-east-1.amazonaws.com/Dev');
return channel;
}
Nothing seems to happen when this code runs. I can see the print messages saying "trying to connect to WebSocket" and "Connection established, registering interest now..." on the console.
The WebSocket is implemented using AWS API Gateway and I can see in the logs that the Flutter app has not connected to the WebSocket.
I have tested the WebSocket using wscat command-line tool and I know that it works.
I am not seeing any error in the console.
Let me know if you would like to see any more of my code.
Turns out you channel.sink.add accepts a string and not a Map.
Replace
channel.sink.add({
"action": "saveConnection",
"UserName": "rakshak#gmail.com",
"DeviceId": "1d0032000947363339343638"
});
With
channel.sink.add('{
"action": "saveConnection",
"UserName": "rakshak#gmail.com",
"DeviceId": "1d0032000947363339343638"
}');
and it should work.
I don't understand what you want. But If you want websocket, you can refer below one.
Add Dart Pub
adhara_socket_io
Add class
class SignalServer {
static SignalServer _instatnce;
factory SignalServer() => _instatnce ?? new SignalServer._();
SignalServer._();
SocketIO socketIO;
int State = 0;
void ConnectServer() async {
this.socketIO = await SocketIOManager().createInstance("http://192.168.50.65:8081");
socketIO.onConnect((data) {
print("Signal server connected");
State = 1;
});
socketIO.onDisconnect((_) {
print("Signal Disconnected");
State = 0;
});
socketIO.connect();
}
}
For Instance(main.dart)
static SignalServer signalServer;
....
signalServer = new SignalServer();
signalServer.ConnectServer();
For use
In any widget
void initState() {
super.initState();
setSocketEvent();
}
void setSocketEvent() async{
await MyApp.signalServer.socketIO.on("room-ready", (data) {
//enter your code
});
await MyApp.signalServer.socketIO.on("on-message", (data) {
//enter your code
});
...
}
I hope it will help you.