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

Null check operator on P2PClient.init #358

Open
coreyfreeman82 opened this issue Apr 26, 2024 · 5 comments
Open

Null check operator on P2PClient.init #358

coreyfreeman82 opened this issue Apr 26, 2024 · 5 comments

Comments

@coreyfreeman82
Copy link

coreyfreeman82 commented Apr 26, 2024

Specify the sample to which the issue belongs (use [x]):
[] Chat sample
[x] P2P Calls sample
[] Conference Calls sample

Platform (use [x])
[x] Android
[] iOS
[] macOS
[] Windows
[] Web
[] Linux

Describe the bug:
I'm trying to just get the callkit working to display incoming calls and do custom code on accept and decline etc. The incoming call needs to be shown at any time whether the app is in foreground, background or terminated. Now the problem I'm having is that I get an error while initializing the package: Null check operator used on a null value. Which is in
#0 RTCSignalingProcessor.addSignalingCallback rtc_signaling_processor.dart:172
#1 P2PClient.init.

My main.dart looks like this:

bool callOutdated(int epochSeconds) {
  DateTime now = DateTime.now();
  DateTime givenTime = DateTime.fromMillisecondsSinceEpoch(epochSeconds * 1000);

  Duration difference = now.difference(givenTime);

  return difference.inSeconds > 45;
}

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  print("on background message");

  if (message.data['name'] == null ||
      message.data['avatar'] == null ||
      message.data['intent-id'] == null ||
      message.data['uuid'] == null ||
      message.data['type'] == null) {
    return;
  }

  //still have to work on this
  showCallIncoming(P2PClient.instance);
}

showCallIncoming(P2PClient callClient) {
  int callType = CallType.VIDEO_CALL;
  // P2PClient callClient = P2PClient.instance;
  // callClient.init();
//dont really know what to do with this since i just want to see the incoming call and dont need a fully working example
  Set<int> opponentsIds = {123};
  P2PSession currentCall = callClient.createCallSession(callType, opponentsIds);
  CreateEventParams params = CreateEventParams();
  params.parameters = {
    'message':
        "Incoming ${currentCall.callType == CallType.VIDEO_CALL ? "Video" : "Audio"} call",
    'call_type': currentCall.callType,
    'session_id': currentCall.sessionId,
    'caller_id': currentCall.callerId,
    'caller_name': 'Caller name',
    'call_opponents': currentCall.opponentsIds.join(','),
    'photo_url': 'https://i.imgur.com/KwrDil8b.jpg',
    'signal_type': 'startCall',
    'ios_voip': 1,
  };

  params.notificationType = NotificationType.PUSH;
  params.environment = CubeEnvironment.DEVELOPMENT; // not important
  params.usersIds = currentCall.opponentsIds.toList();

  createEvent(params.getEventForRequest()).then((cubeEvent) {
    // event was created
  }).catchError((error) {
    // something went wrong during event creation
  });
}

void main() {
  runZonedGuarded(() async {
    WidgetsFlutterBinding.ensureInitialized();

    runApp(MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  final GlobalKey<NavigatorState> navigatorKey =
      new GlobalKey<NavigatorState>();
  bool calling = false;
  P2PClient? _callClient;

  @override
  void initState() {
    super.initState();
    initFirebase();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  initFirebase() async {
    await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform);

    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

    FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
      print("in on message");
      print(message.data);

      if (message.data['name'] == null ||
          message.data['avatar'] == null ||
          message.data['intent-id'] == null ||
          message.data['uuid'] == null ||
          message.data['type'] == null) {
        return;
      }

      print(_callClient);
      if (_callClient != null) {
        showCallIncoming(_callClient!);
      }
    });

    init(
      connctycube_app_id,
      connctycube_auth_key,
      connctycube_auth_secret,
      // onSessionRestore: () {
      //   return SharedPrefs.getUser().then((savedUser) {
      //     return createSession(savedUser);
      //   });
      // },
    );

    ConnectycubeFlutterCallKit.instance.init(
      onCallAccepted: _onCallAccepted,
      onCallRejected: _onCallRejected,
      onCallIncoming: _onCallIncoming,
    );

    if (Platform.isAndroid) {
      AndroidDeviceInfo androidDeviceInfo =
          await DeviceInfoPlugin().androidInfo;
      if (int.parse(androidDeviceInfo.version.release) >= 14) {
        var canUseFullScreenIntent =
            await ConnectycubeFlutterCallKit.canUseFullScreenIntent();

        if (!canUseFullScreenIntent) {
          ConnectycubeFlutterCallKit.provideFullScreenIntentAccess();
        }
      }
    } else if (Platform.isIOS) {
      await FirebaseMessaging.instance.requestPermission(
        alert: true,
        badge: true,
        sound: true,
        provisional: false,
      );
      await FirebaseMessaging.instance
          .setForegroundNotificationPresentationOptions(
        alert: true, // Required to display a heads up notification
        badge: true,
        sound: true,
      );
    }

    initCalls();
  }

  initCalls() {
    _callClient = P2PClient.instance;

    _callClient!.init();
  }

  _initChatConnectionStateListener() {
    CubeChatConnection.instance.connectionStateStream.listen((state) {
      print('state: $state');
      if (CubeChatConnectionState.Ready == state) {
        initCalls();
      }
    });
  }

  Future<void> _onCallAccepted(connctycube.CallEvent callEvent) async {
    // the call was accepted
    print('in call accepted');
  }

  Future<void> _onCallRejected(connctycube.CallEvent callEvent) async {
    // the call was rejected
    print('in call rejected');
  }

  Future<void> _onCallIncoming(connctycube.CallEvent callEvent) async {
    // the Incoming call screen/notification was shown for user
    print('in call incoming');
  }

  @override
  Widget build(BuildContext context) {}
}
@TatankaConCube
Copy link
Contributor

you should initialize P2PClient only after successful login to the chat. P2PClient uses the chat connection for signaling exchange and it won't work without the chat connection. it is not required for displaying CallKit or rejecting the call, but it is required for accepting the call and the next signaling packeges.

@coreyfreeman82
Copy link
Author

@TatankaConCube I did try to initialize this connecting but I couldn't get it to work either.

subscribe(String token) async {
  print('subscribe token: $token');
  CreateSubscriptionParameters parameters = CreateSubscriptionParameters();
  parameters.pushToken = token;
  parameters.environment =
      kReleaseMode ? CubeEnvironment.PRODUCTION : CubeEnvironment.DEVELOPMENT;

  if (Platform.isAndroid) {
    parameters.channel = NotificationsChannels.GCM;
    parameters.platform = CubePlatform.ANDROID;
  } else if (Platform.isIOS) {
    parameters.channel = NotificationsChannels.APNS_VOIP;
    parameters.platform = CubePlatform.IOS;
  }

  String? deviceId = GlobalData().device_uuid!;
  parameters.udid = deviceId;

  var packageInfo = await PackageInfo.fromPlatform();
  parameters.bundleIdentifier = packageInfo.packageName;

  createSubscription(parameters.getRequestParameters())
      .then((cubeSubscriptions) {
    log('[subscribe] subscription SUCCESS');
  }).catchError((error) {
    log('[subscribe] subscription ERROR: $error');
  });
}

//In my initFirebase function at the bottom instead of initCalls()

ConnectycubeFlutterCallKit.getToken().then((token) {
      if (token != null) {
        subscribe(token);
      }
});

But this gave me a 403 no token provided

@TatankaConCube
Copy link
Contributor

subscribe(String token) async {

no, it is just the creation of the subscription on the push notifications, and yes, you need to create the API session with a user first (to identify what the user is subscribing to)

in our sample, we do the chat login here https://github.com/ConnectyCube/connectycube-flutter-samples/blob/master/p2p_call_sample/lib/src/login_screen.dart#L141 but you can do it anywhere you need.

@coreyfreeman82
Copy link
Author

@TatankaConCube Do I have to use startCall from the sdk to get the callkit working in the background or in terminated state? I'm trying to do this using firebase but then i need to initialize all the stuff again: init to chat, events and subscription etc

@TatankaConCube
Copy link
Contributor

It depends on what do you need.
If you need just show the CallKit you need only data in the payload to show it. Also, you can reject the call using the data from the push notification payload. But if you need to accept the call, sure, you need to login to the chat, initialize the P2PClient and accept the call using the callSession.acceptCall(userInfo); method. The instance of the callSession you will receive in the onReceiveNewSession callback after initialization of the P2PClient.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants