Here, I am going to share the code of Agora voice call and Flutter integration. Here we need to make sure you have agora sdk installed using the plugin.
In this flutter application I have used Getx for state management. It’s a complete about audio and video voice call.
Make sure you installed the plugin.
agora_rtc_engine: ^6.1.0Here’s the complete code
class VoiceCallController extends GetxController {
  VoiceCallController();
  final state = VoiceCallState();
  final player = AudioPlayer();
  String appId = APPID;
  final db = FirebaseFirestore.instance;
  final profile_token = UserStore.to.profile.token;
  late final RtcEngine engine;
  ChannelProfileType channelProfileType = ChannelProfileType.channelProfileCommunication;
  @override
  void onInit(){
    super.onInit();
    var data  = Get.parameters;
    state.to_name.value = data["to_name"]??"";
    state.to_avatar.value = data["to_avatar"]??"";
    state.call_role.value = data["call_role"]??"";
    state.doc_id.value = data["doc_id"]??"";
    state.to_token.value = data['to_token']??"";
    print("...your name id ${state.to_name.value}");
    initEngine();
  }
  Future<void> initEngine()async {
    await player.setAsset("assets/Sound_Horizon.mp3");
    engine = createAgoraRtcEngine();
    await engine.initialize(RtcEngineContext(
      appId: appId,
    ));
    engine.registerEventHandler(RtcEngineEventHandler(
      onError: (ErrorCodeType err, String msg){
        print('[....onError] err: $err, ,msg:$msg');
      },
      onJoinChannelSuccess: (RtcConnection connection, int elapsed){
        print('....onConnection ${connection.toJson()}');
        state.isJoined.value = true;
      },
      onUserJoined: (RtcConnection connection, int remoteUid, int elasped) async {
        await player.pause();
      },
      onLeaveChannel: (RtcConnection connection, RtcStats stats){
        print('...user left the room...');
        state.isJoined.value= false;
      },
      onRtcStats: (RtcConnection connection, RtcStats stats){
        print("time....");
        print(stats.duration);
      }
    ));
    await engine.enableAudio();
    await engine.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
    await engine.setAudioProfile(
        profile: AudioProfileType.audioProfileDefault,
        scenario: AudioScenarioType.audioScenarioGameStreaming
    );
    await joinChannel();
    if(state.call_role=="anchor"){
      // send notifcation to the other user
      await sendNotification("voice");
      await player.play();
    }
  }
  Future<void> sendNotification(String call_type)async {
    CallRequestEntity callRequestEntity= CallRequestEntity();
    callRequestEntity.call_type = call_type;
    callRequestEntity.to_token = state.to_token.value;
    callRequestEntity.to_avatar = state.to_avatar.value;
    callRequestEntity.doc_id = state.doc_id.value;
    callRequestEntity.to_name = state.to_name.value;
    print("...the other user's token is ${state.to_token.value}");
    var res = await ChatAPI.call_notifications(params: callRequestEntity);
    if(res.code==0){
      print("notification success");
    }else
      print("could not send notification");
  }
  
  Future<String> getToken() async {
    if(state.call_role=="anchor"){
     state.channelId.value =      //12              //13
         md5.convert(utf8.encode("${profile_token}_${state.to_token}")).toString();
    }else{
      state.channelId.value =           //12               //13
          md5.convert(utf8.encode("${state.to_token}_${profile_token}")).toString();
    }
   CallTokenRequestEntity callTokenRequestEntity= CallTokenRequestEntity();
    callTokenRequestEntity.channel_name = state.channelId.value;
    print("...channel id is ${state.channelId.value}");
    print("...my access token is ${UserStore.to.token}");
    var res = await ChatAPI.call_token(params: callTokenRequestEntity);
    if(res.code==0){
      return res.data!;
    }else{
      print("my data is ${res.data}");
      return res.data!;
    }
    return "";
  }
  Future<void> joinChannel() async {
    await Permission.microphone.request();
    EasyLoading.show(
      indicator: CircularProgressIndicator(),
      maskType: EasyLoadingMaskType.clear,
      dismissOnTap: true
    );
     
    String token = await getToken();
    if(token.isEmpty){
      EasyLoading.dismiss();
      Get.back();
      return;
    }
    await engine.joinChannel(
        token: token,
        channelId: state.channelId.value,
        uid: 0,
        options: ChannelMediaOptions(
          channelProfile: channelProfileType,
          clientRoleType: ClientRoleType.clientRoleBroadcaster
        )
    );
    EasyLoading.dismiss();
  }
  Future<void> leaveChannel() async {
    EasyLoading.show(
      indicator: CircularProgressIndicator(),
      maskType: EasyLoadingMaskType.clear,
      dismissOnTap: true
    );
    await player.pause();
    await sendNotification("cancel");
    state.isJoined.value = false;
    EasyLoading.dismiss();
    Get.back();
  }
  Future<void> _dispose() async {
    await player.pause();
    await engine.leaveChannel();
    await engine.release();
    await player.stop();
  }
  @override
  void onClose(){
    _dispose();
    super.onClose();
  }
}It includes notification as well. The code shows notification, playing audio, connecting with other on the agora server.
Other features include
- join channel
- get device token
- leave channel
