react-native-webrtc / react-native-callkeep

iOS CallKit framework and Android ConnectionService for React Native
ISC License
923 stars 445 forks source link

Call not ending on remote device if call was declined too fast on iOS #754

Open wilmxre opened 11 months ago

wilmxre commented 11 months ago

Has anyone else experienced that if let's say someone calls an iOS phone (in my case an android phone was the emitter) and the iOS device declines the call too fast, like less then 2 seconds, sometimes the call ended event is not fired on the caller's device. So it will continuously ring. This isn't happening always, but when it happens it is annoying.

disco-panda commented 11 months ago

Are you starting CallKit from the native code? If so, check to ensure that your application is loaded and if not, handle the events that occurred before it opened using getInitialEvents or didLoadWithEvents.

wilmxre commented 11 months ago

yes i am using callkeep in self managed mode. in my scenario, my app on the ios device is killed, an incoming call comes from an android device, i decline the call really fast (on the CallKit UI), the call ends on the ios device's end like it should, but on the android the outgoing call is still not stopped.

so what you are saying is that when i decline the call really fast, my js app is not fully loaded so it can't send the call ended event to the android device? something like this i figured out too, but i don't know how to handle it. from what i read when you get a voip notification you have to report it instantly to pushkit, so i can't really wait for my app (js side) to fully load before i show the call notification to my user

can this didLoadWithEvents handle the call ending scenario in your opinion? after my app loads, should i call an endCall inside this event listener?

this is how this event listener is set up so far in my app:


let _initialEvents: any = null;
let _initialEventsLoaded = false;

RNCallKeep.addEventListener('didLoadWithEvents', (events) => {
      Logger.info('RNCallKeep didLoadWithEvents', events);
      if (_initialEventsLoaded) {
        _emitInitialEvents(events);
      } else {
        _initialEvents = events;
      }
    });

const _emitInitialEvents = (events: any) => {
  if (events?.length) {
    events.forEach(({ name, data }: any) =>
      emit(
        name,
        data ? { ...data, isInitialEvent: true } : { isInitialEvent: true }
      )
    );
  }
};
disco-panda commented 11 months ago

Take a look at what your logger outputs, you should see an event for when you decline the incoming call. Then you can clear the events (with clearInitialEvents) and get rid of the logic around _initialEventsLoaded as it will either have unprocessed events or a blank array.

If no events have loaded then you will receive an empty array.