Skip to content
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

Fatal Exception: java.lang.NullPointerException #2023

Open
dpatel-jac opened this issue Sep 18, 2024 · 3 comments
Open

Fatal Exception: java.lang.NullPointerException #2023

dpatel-jac opened this issue Sep 18, 2024 · 3 comments
Labels
bug Something isn't working keep track

Comments

@dpatel-jac
Copy link

Bug:- Android App Getting Crashed after accepting Incoming call on system apps

We integrate agora as video calling feature in our app. It working fine in most of the cases, but in situation application will terminate due to NullPointerException. Please follow exception logs and suggest me possible outputs.

Exception details
Fatal Exception: java.lang.NullPointerException
Attempt to invoke interface method 'void io.agora.rtc2.internal.AudioRoutingController$ControllerState.setState(int)' on a null object reference

StackTrace
io.agora.rtc2.internal.AudioRoutingController$2.run (Unknown Source:7)
android.os.Handler.handleCallback (Handler.java:883)
android.os.Handler.dispatchMessage (Handler.java:100)
android.os.Looper.loop (Looper.java:214)
android.os.HandlerThread.run (HandlerThread.java:67)

Here is sample code for connection to agora channel.

class MeetHelperNotifier with ChangeNotifier {

  final AppSettings setting;
  final CallArguments args;
  late RtcEngine _engine;
  RtcEngine get engine => _engine;

  MeetHelperNotifier(this.setting, this.args) {
    _engine = createAgoraRtcEngine();
  }

  bool isSessionEnded = false;
  bool isRecordingRelatedError = false;
  ValueNotifier<bool> isInSession = ValueNotifier<bool>(false);
  ValueNotifier<bool> isCallConnected = ValueNotifier<bool>(false);

  int? currentUserId;
  Map<int, VideoStatus> userVideoStatus = <int, VideoStatus>{};
  Map<int, bool> userAudioStatus = <int, bool>{};
  ValueNotifier<List<int>> users = ValueNotifier<List<int>>([]);
  List<int> get otherUsers => users.value.where((e) => e != currentUserId).toList();
  

  reloadUserList() {
    users.value = List<int>.from(users.value);
  }

  void _connect(String token) async {
    try {

      await _engine.initialize(RtcEngineContext(
        appId: configs['Agora_APPID'],
        channelProfile: ChannelProfileType.channelProfileLiveBroadcasting,
        logConfig: const LogConfig(level: LogLevel.logLevelNone),
      ));

      await _engine.setAudioProfile(
        profile: AudioProfileType.audioProfileDefault,
        scenario: AudioScenarioType.audioScenarioMeeting,
      );

      /// setup noise cancellation mode
      _engine.setAINSMode(enabled: true, mode: AudioAinsMode.ainsModeAggressive);

      await _engine.setVideoEncoderConfiguration(
        const VideoEncoderConfiguration(
          frameRate: 15,
          bitrate: 400,
          dimensions: VideoDimensions(width: 640, height: 360),
          orientationMode: OrientationMode.orientationModeAdaptive,
          degradationPreference: DegradationPreference.maintainBalanced,
        ),
      );

      _engine.registerEventHandler(
          RtcEngineEventHandler(
            onError: (ErrorCodeType err, String msg) {
              /// Check only when session not connected
              if (!isInSession.value) {
                /// Permission related error no need to terminate call
                if ([ErrorCodeType.errAdmInitRecording, ErrorCodeType.errAdmStartRecording, ErrorCodeType.errAdmStartPlayout].contains(err)) {
                  isRecordingRelatedError = true;
                  return;
                }
                isInSession.value = false;
                users.value = <int>[];
                isSessionEnded = true;
                Fluttertoast.showToast(
                  msg: 'Unable to join this call at this time.\n Detail: ${err.name}',
                  toastLength: Toast.LENGTH_LONG,
                );
                isInSession.notifyListeners();
              }
            },
            onJoinChannelSuccess: (RtcConnection connection, int elapsed) async {
              debugPrint('local user ${connection.localUid} joined');
              currentUserId = 0;
              isInSession.value = true;
              users.value = List.from([currentUserId!]);

              /// Update callkit mute and speaker status
              if (Platform.isIOS) {
                //_updateCallKitMuteStatus();
                await _engine.adjustAudioMixingPublishVolume(100);
                await _engine.enableAudioVolumeIndication(interval: 10000, smooth: 3, reportVad: false);
                await _engine.adjustRecordingSignalVolume(100);
                await _engine.adjustPlaybackSignalVolume(100);
                await _engine.adjustAudioMixingVolume(100);
                await _engine.setDefaultAudioRouteToSpeakerphone(true);
              }
            },
            onLeaveChannel: (RtcConnection connection, RtcStats stats) {
              isInSession.value = false;
              users.value = <int>[];
              isSessionEnded = true;
            },
            onUserJoined: (RtcConnection connection, int remoteUid, int elapsed) {
              final userList = List<int>.from(users.value);
              userList.add(remoteUid);
              users.value = List<int>.from(userList.toSet());
              if (userList.length > 1) {
                isCallConnected.value = true;
              }
              userVideoStatus.putIfAbsent(remoteUid, () => VideoStatus.on);
            },
            onUserOffline: (RtcConnection connection, int remoteUid, UserOfflineReasonType reason) {
              final userList = List<int>.from(users.value);
              userList.removeWhere((e) => e == remoteUid);
              users.value = List<int>.from(userList.toSet());
            },
            onRemoteVideoStateChanged: (RtcConnection connection, int remoteUid, RemoteVideoState state, RemoteVideoStateReason reason, int elapsed) {
              logger.v('remoteUid :: $remoteUid reason :: $reason');
              if (reason == RemoteVideoStateReason.remoteVideoStateReasonSdkInBackground) {
                userVideoStatus[remoteUid] = VideoStatus.pause;
                reloadUserList();
                return;
              }
              bool isVideoOn = ![RemoteVideoStateReason.remoteVideoStateReasonRemoteMuted, RemoteVideoStateReason.remoteVideoStateReasonRemoteOffline].any((e) => e == reason);
              final statusInDict = userVideoStatus[remoteUid] == VideoStatus.on;
              if (statusInDict != isVideoOn) {
                userVideoStatus[remoteUid] = isVideoOn ? VideoStatus.on : VideoStatus.off;
                reloadUserList();
              }
              logger.v('remoteVUid :: $remoteUid reason :: $reason elapsed :: $elapsed time: ${DateTime.now()}');
            },
            onRemoteAudioStateChanged: (RtcConnection connection, int remoteUid, RemoteAudioState state, RemoteAudioStateReason reason, int elapsed) {
              logger.v('remoteAUid :: $remoteUid reason :: $reason elapsed :: $elapsed time: ${DateTime.now()}');
            }
          )
      );

      await _engine.setClientRole(role: ClientRoleType.clientRoleBroadcaster);
      await _engine.enableVideo();
      
      await _engine.enableAudio();

      await _engine.startPreview();

      await _engine.joinChannel(
        token: token,
        channelId: args.sessionName,
        uid: setting.deviceId?.convertUserUIdToInt() ?? 0,
        options: const ChannelMediaOptions(),
      );

    } catch (error) {
      logger.e('Error : ${error.runtimeType}');
      Fluttertoast.showToast(
        msg: 'Error :: ${e.toString()}',
        toastLength: Toast.LENGTH_LONG,
      );
    }
  }

  Future<void> disconnect() async {
    _engine.leaveChannel().then((value) {

      _engine.release();
    });
  }
}
@littleGnAl
Copy link
Contributor

Thanks for reporting, I found this is a known issue internally, it will be fixed in the next release.

@littleGnAl littleGnAl added bug Something isn't working keep track labels Sep 20, 2024
@dpatel-jac
Copy link
Author

@littleGnAl , Is there any ETA for new version for this issues? or let me know if you provide intermediate solution to mitigate this crash issues.

@littleGnAl
Copy link
Contributor

It's, unfortunately, there's no workaround in the agora_rtc_engine since it crashed in the Agora Native SDK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working keep track
Projects
None yet
Development

No branches or pull requests

2 participants