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

Redux is not updating, hence can't video call or receive call #115

Open
hatreact opened this issue Nov 13, 2023 · 12 comments
Open

Redux is not updating, hence can't video call or receive call #115

hatreact opened this issue Nov 13, 2023 · 12 comments

Comments

@hatreact
Copy link

Versions:

"react-native-connectycube": "^3.22.3",
"react-native-incall-manager": "^4.0.1",
"react-native-invoke-app": "^1.0.6",
"react-native-callkeep": "^4.3.3",
"react-native-notifications": "^4.3.1",

Issue:

  • Caller starts the AudioCall.
  • Actions are being dispatched and states are updating while starting the call.
  • Video Screen appears.
  • Redux is not updating and not showing the updated states in VideoScreen.
  • Receiver can hear the incoming ringtone.
  • IncomingCallScreen doesn't appear on receiver's side.
  • Incase of VideoCall, same steps happen but camera doesn't show

Caller's logs:

Screenshot 2023-11-13 at 11 44 35 PM Screenshot 2023-11-13 at 11 45 01 PM

Receiver's logs:

Screenshot 2023-11-13 at 11 50 16 PM

As you can see in receiver's logs, right above [VIDEO-SCREEN] log at the end of the line, you'll see true value. This is isIncoming value. In receiver's logs, [SET_CALL_SESSION] log run when _onCallListener function run on receiver's side. And in [VIDEO-SCREEN] log the session is null, which shouldn't be.

Why ActiveCall reducer behaving strangely despite actions being dispatched correctly?

@ccvlad
Copy link
Contributor

ccvlad commented Nov 14, 2023

@hatreact
I can't see how you pass a remoteStream after getting it in the onRemoteStreamListener or how you pass a localStream to a screen where you want to display it.
I am not sure about the issue with the redux. On the last screen, you have the warning "Non-serializable values were found in the navigation state". Referring to this warning, I can assume that you are trying to transmit the media stream (local/remote) through the navigation state, could this be true?

@hatreact
Copy link
Author

 const startCall = async (callType = "video") => {
    CallService.getStore(store);
    if (user.UserSetting.ccuid == null) {
      showToast("User does not have a valid connectycube id");
      return;
    }

    const selectedOpponentsIds = [user.UserSetting.ccuid];

    const callSession = await CallService.startCall(
      selectedOpponentsIds,
      callType == "video"
        ? ConnectyCube.videochat.CallType.VIDEO
        : ConnectyCube.videochat.CallType.AUDIO,
      { token, callType, userId: user.id }
    );

    const pushParams = {
      message: `Incoming call from ${user.firstName}`,
      ios_voip: 1,
      handle: user.firstName,
      initiatorId: callSession.initiatorID,
      opponentsIds: selectedOpponentsIds.join(","),
      uuid: callSession.ID,
      callType,
    };

    PushNotificationsService.sendPushNotification(
      selectedOpponentsIds,
      pushParams
    );

    navigation.navigate("VideoScreen", {
      initiatorName: user,
    });
  };

CallService.startCall ran and streams is passed to action ADD_OR_UPDATE_STREAMS. You can see in Caller's log, 2nd image right above ADD_OR_UPDATE_STREAMS[0]. This stream is being accessed in VideoScreen by using this selector

const streams = useSelector(store => store.ActiveCall.streams);

Even though startCall is running successfully without any error, when user navigates to VideoScreen right after startCall.

const callSession = useSelector(store => store.ActiveCall.session);
callSession is still null. So I passed callSession in VideoScreen to confirm if session coming through. That's why it was showing warning for Non-serializable values.

_onCallListener ran and session is dispatched.
_onRemoteStreamListener is not triggering at all.

@ccvlad
Copy link
Contributor

ccvlad commented Nov 15, 2023

Can you display the localStream (a media stream from a device's camera)? Check this.

_onCallListener ran and session is dispatched.
_onRemoteStreamListener is not triggering at all.

Both users should get a remote stream in onRemoteStreamListener after the receiver does session. accept(extension) inside the onCallListener = (session, extension) => {...}. Also, check this guide.

======================================

Your steps to set a call between users should look like this:

Make sure you have remote streams, then you can dispatch them to Redux to be able to use them from Redux state on any screen. You can test Redux with a local stream first because it is created locally.

@hatreact
Copy link
Author

hatreact commented Nov 15, 2023

No I'm not able to see media stream from device's camera.

With my code

static MEDIA_OPTIONS_AUDIO = { audio: true };

 async startCall(usersIds, callType, options = {}) {
    const session = ConnectyCube.videochat.createNewSession(
      usersIds,
      callType,
      options
    );
    store.dispatch(setCallSession(session));

    await this.setMediaDevices();

    // create local stream
    // I write local stream logic like this for readability
    
    const stream = await this.callSession.getUserMedia(
      callType == 2
        ? CallService.MEDIA_OPTIONS_AUDIO
        : CallService.MEDIA_OPTIONS
    );
    console.log("[START-STREAM][0]", stream);

    // store streams
    const streams = [{ userId: LOCAL_STREAM_USER_ID, stream: stream }];
    for (let uId of usersIds) {
      streams.push({ userId: parseInt(uId), stream: null });
    }
    console.log("streams", streams);
    store.dispatch(addOrUpdateStreams(streams));

    this.callSession.call({ options });

    const userName = `${this.currentUser.firstName} ${this.currentUser.lastName}`;
    const receivedNames = await getCallRecipientString(usersIds);

    // report to CallKit (iOS only)
    this.reportStartCall(
      this.callSession.ID,
      userName,
      receivedNames,
      "generic",
      callType === "video"
    );

    this.playSound("outgoing");

    return session;
  }
Screenshot 2023-11-15 at 6 23 57 PM

With connectycube sample code

async startCall(usersIds, callType, options = {}) {
    const session = ConnectyCube.videochat.createNewSession(
      usersIds,
      callType,
      options
    );
    store.dispatch(setCallSession(session));

    await this.setMediaDevices();

     // create local stream
     const mediaOptions = {...CallService.MEDIA_OPTIONS};
     if (callType === ConnectyCube.videochat.CallType.AUDIO) {
       mediaOptions.video = false;
     }
     const stream = await this.callSession.getUserMedia(mediaOptions);
    console.log("[START-STREAM]", stream);

    // store streams
    const streams = [{ userId: LOCAL_STREAM_USER_ID, stream: stream }];
    for (let uId of usersIds) {
      streams.push({ userId: parseInt(uId), stream: null });
    }
    console.log("streams", streams);
    store.dispatch(addOrUpdateStreams(streams));

    this.callSession.call({ options });

    const userName = `${this.currentUser.firstName} ${this.currentUser.lastName}`;
    const receivedNames = await getCallRecipientString(usersIds);

    // report to CallKit (iOS only)
    this.reportStartCall(
      this.callSession.ID,
      userName,
      receivedNames,
      "generic",
      callType === "video"
    );

    this.playSound("outgoing");

    return session;
  }
Screenshot 2023-11-15 at 6 18 54 PM

And localStream is shown in <VideoGrid streams={streams} /> in VideoScreen.

I tried to follow documentation and compare code with connectycube-reactnative-sdk multiple times. And there is no step I have missed.

  • ConnectyCube inialized.
  • Session starts
  • CallService.init(); pushNotificationService.init(); Both these initialize after session starts successfully.
  • I do get UDID for channels APNS, APNS VOIP and FCM and device are subscribe to PushNotification. I can see them in Push Notifications Queue on dashboard and status is sent.
  • _onCallListener runs and nothing happens afterwards.

My guess is it could be due to non-serialized values which could be session or streams being passed in redux. Maybe non-serialized values could be causing this unexpected behaviour. Do you think that it could cause serious problems?

@ccvlad
Copy link
Contributor

ccvlad commented Nov 17, 2023

Ensure you use a real device instead of an iOS simulator or Android emulator.
Add the prop "video: true" like this. There isn't a video track in your stream. Only the audio track is present.

@hatreact
Copy link
Author

hatreact commented Nov 20, 2023

Sorry, previous logs were from audio call. I have tested on emulators/simulators and real devices.

Tested on following Devices. I got same behaviour.
iPhone XS MAX ios 15
OnePluse 6t android 11
Galaxy A52 android 13

Screenshot 2023-11-20 at 3 27 16 PM

I added log in _createAndStoreSession inside cubeWebRTCClient.js

Screenshot 2023-11-20 at 4 38 12 PM

@ccvlad
Copy link
Contributor

ccvlad commented Nov 24, 2023

I added log in _createAndStoreSession inside cubeWebRTCClient.js

You've gotten the log of the new session, it’s obvious that it’s empty.

From previous logs I see that you have a correct localStream and sent it.
Check this call on a receiver side and accept the call session. You should get this stream as remote for the receiver (into the onRemoteStreamListener)

@hatreact
Copy link
Author

hatreact commented Dec 4, 2023

Screenshot 2023-12-04 at 1 03 42 PM

In _onCallListener, value for isIcoming is passed as true. But still it's not invoking IncomingCallScreen. When I log isIcoming value it is false which is very strange behaviour.

  async _onCallListener(session, extension) {
    this.token = extension.options.token;
    this.otherUserId = extension.options.userId;

    // if already on a call
    if (this.callSession && !this.isDummySession) {
      console.log("[CallService][_onCallListener] reject, already_on_call");
      this.rejectCall(session, { already_on_call: true });
      return;
    }

    this.playSound("incoming");

    console.log("[CallService][_onCallListener]", {
      isEarlyAccepted: this.isEarlyAccepted,
      isAccepted: this.isAccepted,
    });

    if (this.isEarlyAccepted && !this.isAccepted) {
      setTimeout(() => {
        // wait until redux updated the data
        this.acceptCall();
      });
    }

    console.log("[_onCallListener][Session]", session);

    store.dispatch(setCallSession(session, true));
  }

@ccvlad
Copy link
Contributor

ccvlad commented Dec 4, 2023

Somewhere you also call the store.dispatch(setCallSession(session)) without the second argument or it is "false". In our RNVideoChat sample the store.dispatch(setCallSession(session, true)) calls in _onCallListener to mark a call as incoming (isIncoming = true). When the store.dispatch(setCallSession(session)) (with isIncoming = false) can be called only from the sender side due to the process of starting a new call (select callee/callees and press the call button).

It means that isIncoming === true is possible on the receiver side and isIncoming === false on the side. Check your code to block the unnecessary store.dispatch(setCallSession(...)).

===========

Are you using our sample as is or did you change something in the code instead of configs?

@hatreact
Copy link
Author

Yeah I tried to integrate sample code as well but facing the same issue.

I created a repo with produceable behavior. It has the sample sdk code.
https://github.com/hatreact/RAApp.git

@DaveLomber
Copy link
Contributor

@ccvlad could you follow up?

@ccvlad
Copy link
Contributor

ccvlad commented Feb 2, 2024

Hey, @hatreact !

I've used your project (RAApp) to find the issue and prepared diff file with fixes - fix_redux_configurations.diff.zip
I think you can apply this file by the command git apply < path/to/fix_redux_configurations.diff from the root of your project.

You made a lot of mistakes in setting up the redux lib, so I advise you to understand the redux documentation.

I haven't fixed other issues you might encounter later because you should figure it out for yourself.

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

3 participants