ConnectyCube / connectycube-reactnative-samples

Chat and Video Chat code samples for React Native, ConnectyCube
https://connectycube.com
Apache License 2.0
125 stars 111 forks source link

the person who receives the call does not view the webcam of the person who initiated the call #81

Closed uendar closed 4 years ago

uendar commented 4 years ago

Hi everyone,

I am facing an issue with connectycube. I have followed the example and fit on my project based on what i want to do. So what i am doing is that i have a multiple screen react native app and i want to receive calls from everywhere on my app. Also i have a screenof video where i redirect when i get the call from different screen. The issue is that when i do call from chat screen as the example it works fine but when i get a call from different screen and accept the call i navigate to cat screen and there i cant see the caller video. I pass data as below.

This is the Screen Home

constructor(props) {
        this._session = null;
        this.state = {
            isIncomingCall: false
        };
        this._setUpListeners();
        requestCameraAndAudioPermission();
    }

_setUpListeners() {
        ConnectyCube.videochat.onCallListener = this._onCallListener;
        ConnectyCube.videochat.onStopCallListener = this._onStopCallListener;
        ConnectyCube.videochat.onRejectCallListener = this._onRejectCallListener;
    };

 // _onCallListener
    _onCallListener = (session, extension) => {
        CallService.processOnCallListener(session)
          .then(() => this.showInomingCallModal(session))
          .catch(this.hideInomingCallModal);
    };

    showInomingCallModal = session => {
        this._session = session;
        this.setState({isIncomingCall: true});
    };

    hideInomingCallModal = () => {
      this._session = null;
      this.setState({isIncomingCall: false});
    };

    _onStopCallListener = (session, userId, extension) => {
        this._session=null;
        this.hideInomingCallModal();
    };

  _onPressAccept = () => {
    const user = CallService.getUserById(this._session.initiatorID);
    let session = this._session;
    let fromUser = {
     id: user.id,
     full_name:user.full_name,
     login: user.login,
    };
    let users = readChatList().map(ele=>ele.id);
    this.hideInomingCallModal();
    setTimeout(() => {
        this.props.navigation.navigate("ChatScreen",{selectedUsersIds:[fromUser], opponents:users,session:session, list:true})
    }, 1000);
   };

    _onPressReject = () => {
      CallService.rejectCall(this._session);
      this.hideInomingCallModal();
      this._session =null;
      CallService.stopCall();
    };

    _onRejectCallListener = (session, userId, extension) => {
        CallService.rejectCall(this._session);
        this.hideInomingCallModal();
        this._session =null;
        CallService.stopCall();
      };

While ChatScreen

class Chat extends Component {

    constructor(props) {
        super(props);
        this._session = props.navigation.state.params.list ? props.navigation.state.params.session : null;
        this.opponentsIds = props.navigation.state.params.opponents;
        props.navigation.setParams({ language: props.language });
        this.state = {
          selectedUsersIds:[props.navigation.state.params.selectedUsersIds[0].id] ,
          localStream: null,
          remoteStreams:[],
          isActiveSelect: props.navigation.state.params.list? false :true,
          isActiveCall: props.navigation.state.params.list?true:false,
          isIncomingCall:false
        };
        this._setUpListeners();
      };

  componentWillUnmount() {
     // CallService.stopCall();
      // AuthService.logout();
  }

  componentDidMount(){
    if(this.props.navigation.state.params.list){
      CallService.acceptCall(this._session).then(stream => {
        const {opponentsIDs, initiatorID, currentUserID} = this._session;
        const opponentsIds = [initiatorID, ...opponentsIDs].filter(
          userId => currentUserID !== userId,
        );
        this.initRemoteStreams(opponentsIds);
        this.setLocalStream(stream);
        this.closeSelect();
      });
    }
  }

  componentDidUpdate(prevProps, prevState) {
    console.log("componentDidUpdate----", prevState)
    const currState = this.state;

    if (
      prevState.remoteStreams.length === 1 &&
      currState.remoteStreams.length === 0
    ) {
     // CallService.stopCall();
      this.resetState();
    }
  }

  _setUpListeners() {

    ConnectyCube.videochat.onRejectCallListener = this._onRejectCallListener;
    ConnectyCube.videochat.onUserNotAnswerListener = this._onUserNotAnswerListener;
    ConnectyCube.videochat.onRemoteStreamListener = this._onRemoteStreamListener;
    ConnectyCube.videochat.onCallListener = this._onCallListener;
    ConnectyCube.videochat.onStopCallListener = this._onStopCallListener;
  }

  //call listener
  _onCallListener = (session, extension) => {
    console.log("Call Listener 1111111111111")
    CallService.processOnCallListener(session)
      .then(() => this.showInomingCallModal(session))
      .catch(this.hideInomingCallModal);
  };

  _onAcceptCallListener = (session, userId, extension) => {
    console.log("_onAcceptCallListener xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
    CallService.processOnAcceptCallListener(session, userId, extension)
      .then(this.setOnCall)
      .catch(this.hideInomingCallModal);
  };

  showInomingCallModal = session => {
    console.log("showInomingCallModal 22222222222222")
    this._session = session;
    this.setState({isIncomingCall: true});
  };

  hideInomingCallModal = () => {
    console.log("hideInomingCallModal33333333333333")
    this._session = null;
    this.setState({isIncomingCall: false});
  };

  _onPressAccept = () => {
    console.log("_onPressAccept =>>>>> 444444444444444")
    CallService.acceptCall(this._session).then(stream => {
      const {opponentsIDs, initiatorID, currentUserID} = this._session;
      const opponentsIds = [initiatorID, ...opponentsIDs].filter(
        userId => currentUserID !== userId,
      );
      this.initRemoteStreams(opponentsIds);
      this.setLocalStream(stream);
      this.closeSelect();
      this.hideInomingCallModal();
    });
  };

  initRemoteStreams = opponentsIds => {
    console.log("initRemoteStreams =>>>>>",opponentsIds)
    const emptyStreams = opponentsIds.map(userId => ({
      userId,
      stream: null,
    }));
    console.log("initRemoteStreams =>>>>>",emptyStreams)
    this.setState({remoteStreams: emptyStreams});
  };

  setLocalStream = stream => {
    console.log("setLocalStream =>>>>>",stream)
    this.setState({localStream: stream});
  };

  closeSelect = () => {
    this.setState({isActiveSelect: false});
  };

  //on ignore press by you
  _onPressReject = () => {
    console.log("_onPressReject 5555555555555555555555")
    CallService.rejectCall(this._session);
    this.hideInomingCallModal();
    this.resetState();
  };

//when user calling you stops
  _onStopCallListener = (session, userId, extension) => {
    console.log("_onStopCallListener 666666666666666666666")
    const isStoppedByInitiator = session.initiatorID === userId;

    CallService.processOnStopCallListener(userId, isStoppedByInitiator)
      .then(() => {
        console.log("_onStopCallListener 666666666666666666666",userId)
        console.log("_onStopCallListener 666666666666666666666", isStoppedByInitiator)
        if (isStoppedByInitiator) {
          this._session =null;
          this.resetState();
        } else {
          this.removeRemoteStream(userId);
        }
      })
      .catch(this.hideInomingCallModal);

  };

  removeRemoteStream = userId => {
    console.log("remoteStreams remoteStreams",userId)
    console.log("remoteStreams remoteStreams",remoteStreams )
    this.setState(({remoteStreams}) => ({
      remoteStreams: remoteStreams.filter(item => item.userId !== userId),
    }));
  };

  _onRemoteStreamListener = (session, userId, stream) => {
    console.log("_onRemoteStreamListener 888888888888888888888888888")
    CallService.processOnRemoteStreamListener(userId)
      .then(() => {
        console.log("_onRemoteStreamListener 8888111111")
        this.setOnCall();
        this.updateRemoteStream(userId, stream);

      })
      .catch(this.hideInomingCallModal);
  };

  updateRemoteStream = (userId, stream) => {
    console.log("updateRemoteStream tttttttttttttttttttttttttttttttttttttttt")
    this.setState(({remoteStreams}) => {
      const updatedRemoteStreams = remoteStreams.map(item => {
        if (item.userId === userId) {
          return {userId, stream};
        }

        return {userId: item.userId, stream: item.stream};
      });

      return {remoteStreams: updatedRemoteStreams};
    });
  };

  setOnCall = () => {
    console.log("setOnCall 999999999999999999999999999999")
    this.setState({isActiveCall: true});
  };

  _onUserNotAnswerListener = (session, userId) => {
    console.log("_onUserNotAnswerListener 100000000000000000000000")
    CallService.processOnUserNotAnswerListener(userId)
      .then(() => this.removeRemoteStream(userId))
      .catch(this.hideInomingCallModal);
  };

  _onRejectCallListener = (session, userId, extension) => {
    console.log("CHATTTTTTTTTTTTT REJECT")

    CallService.processOnRejectCallListener(session, userId, extension)
      .then(() => this.removeRemoteStream(userId))
      .catch(this.hideInomingCallModal);
  };

  resetState = () => {
    this.setState({
      localStream: null,
      remoteStreams: [],
      // selectedUsersIds: [],
      isActiveSelect: true,
      isActiveCall: false,
    });
  };

      render() {
        const {
          localStream,
          remoteStreams,
          selectedUsersIds,
          isActiveSelect,
          isActiveCall,
          isIncomingCall,
        } = this.state;

        const initiatorName = isIncomingCall
          ? CallService.getUserById(this._session.initiatorID, 'name')
          : '';
        const localStreamItem = localStream
          ? [{userId: 'localStream', stream: localStream}]
          : [];
        const streams = [...remoteStreams, ...localStreamItem];

        CallService.setSpeakerphoneOn(remoteStreams.length > 0);

        // console.log("Render initiatorName", initiatorName)
        // console.log("Render SELECTEEEEEEEEEEED", this.state.selectedUsersIds)
        // console.log("Render isIncomingCall", this.state.isIncomingCall)
        // console.log("Render localStream", this.state.localStream)
        // console.log("Render streams", streams)
        // console.log("Render remoteStreams", [...this.state.remoteStreams, ...localStreamItem])

        // console.log("Render isActiveSelect", isActiveSelect)
        // console.log("Render this.opponentsIds", this.opponentsIds)
        // console.log("Render selectedUsersIds", selectedUsersIds)
        // console.log("Render localStream", localStream)
         console.log("Render isActiveCall", isActiveCall)

        return (
          <SafeAreaView style={{flex: 1, backgroundColor: 'black'}}>
            <StatusBar backgroundColor="black" barStyle="light-content" />
            <RTCViewGrid streams={streams} />

            <UsersSelect
              isActiveSelect={isActiveSelect}
              opponentsIds={this.opponentsIds}
              selectedUsersIds={selectedUsersIds}
              selectUser={this.selectUser}
              unselectUser={this.unselectUser}
            />
            <ToolBar
              selectedUsersIds={selectedUsersIds}
              localStream={localStream}
              isActiveSelect={isActiveSelect}
              isActiveCall={isActiveCall}
              closeSelect={this.closeSelect}
              initRemoteStreams={this.initRemoteStreams}
              setLocalStream={this.setLocalStream}
              resetState={this.resetState}
            />
            <AwesomeAlert
              show={isIncomingCall}
              showProgress={false}
              title={`Incoming call from ${initiatorName}`}
              closeOnTouchOutside={false}
              closeOnHardwareBackPress={true}
              showCancelButton={true}
              showConfirmButton={true}
              cancelText="Reject"
              confirmText="Accept"
              cancelButtonColor="red"
              confirmButtonColor="green"
              onCancelPressed={this._onPressReject}
              onConfirmPressed={this._onPressAccept}
              onDismiss={this.hideInomingCallModal}
              alertContainerStyle={{zIndex: 1}}
              titleStyle={{fontSize: 21}}
              cancelButtonTextStyle={{fontSize: 18}}
              confirmButtonTextStyle={{fontSize: 18}}
            />
          </SafeAreaView>
        )
      }
    }

    const styles = StyleSheet.create({
      menu: {
        width: 50,
        height: 40,
        justifyContent: 'center',
        alignItems: 'center'
    },
  });

    const mapStateToProps = state => {

        return {
            isConnected: state.system.isConnected,
            language: state.user.owner.language,
            token:state.user.owner.token,
            idOwner:state.user.owner._id,
            idName:state.user.owner.name +" " + state.user.owner.lastname,
            password:state.user.owner.password,
            username:state.user.owner.username
        };
    };

    const mapDispatchToProps = dispatch => (bindActionCreators({
    }, dispatch));

 /**
  *  connect  is a function connects the two above functions within the class
  */
export default connect(mapStateToProps, mapDispatchToProps)(Chat);
banshiAnton commented 4 years ago

Hello @uendar i don't see your onRemoteStreamListener on Home screen. Your can store streams and other call data in redux

banshiAnton commented 4 years ago

I think you should setup call listeners in top app level (e. g. Screen than will never unmount or service)

uendar commented 4 years ago

Why should i use onRemoteStreamListener on Home when i pass session and users id from home to chat ?

banshiAnton commented 4 years ago

Because onRemoteStreamListener is only way to get remote stream, in our project we setup call listeners in service and put call data (streams, call participants peer states in redux)

NeenaMishra12 commented 4 years ago

Hi @banshiAnton , I am also facing the same issue after integrating video sample in my application that call gets initiated by the user and another user gets the popup for Accept and Reject the call. When another user accepts the call his webcam shows but, not the webcam of call initiator same happens with initiator that he only sees his camera and for other person loader continues.

In logs I can see this warning. Can you please help me with this?

Sending peerConnectionIceConnectionChanged with no listeners registered.

Sending peerConnectionStateChanged with no listeners registered.

Sending peerConnectionSignalingStateChanged with no listeners registered.

ccvlad commented 4 years ago

Hi @NeenaMishra12 Did you setup the ConnectyCube.videochat.onRemoteStreamListener? Check the incoming remote stream there. You should obtain remote stream and paste it into the RTCView component.

NeenaMishra12 commented 4 years ago

@ccvlad ,

I am not getting how to check that. Two things you have marked as yellow in above solution that is already there in my code. Can we connect via mail so that I can share the logs with you.

ccvlad commented 4 years ago

@ccvlad ,

I am not getting how to check that. Two things you have marked as yellow in above solution that is already there in my code. Can we connect via mail so that I can share the logs with you.

You can share your logs here, cause we are interested to solve the problem on public.

I was trying to point you on the guide how to accept a call

import {RTCView} from 'react-native-connectycube';

//init listeners:
state = {
    remoteStream: null,
    userId: null
}

componentDidMount() {
    // ... here must be other listeners too
    ConnectyCube.videochat.onCallListener = this.onIncomingCall
    ConnectyCube.videochat.onRemoteStreamListener = this.onRemoteStream
}

// you get the incoming call here and accept it
onIncomingCall = (session, extension) => {
    // here show some UI with 2 buttons - accept & reject, and by accept -> run the following code:
    const extension = {};
    session.accept(extension);
};

// then you will get a remote stream here
onRemoteStream = (session, userID, stream) => {
    // attach the remote stream to the RTCView
    this.setState({remoteStream: stream, userId: userID});
};

render() {
    const {userId, remoteStream} = this.state;

    return (
        ...
        <RTCView  objectFit="cover" style={...} key={userId} streamURL={remoteStream.toURL()} />
        ...
    )
}
ccvlad commented 4 years ago

@NeenaMishra12 sorry I didn't want to close the issue, just click a wrong button =(

NeenaMishra12 commented 4 years ago

@ccvlad , I am not getting how to check that. Two things you have marked as yellow in above solution that is already there in my code. Can we connect via mail so that I can share the logs with you.

You can share your logs here, cause we are interested to solve the problem on public.

I was trying to point you on the guide how to accept a call

import {RTCView} from 'react-native-connectycube';

//init listeners:
state = {
    remoteStream: null,
    userId: null
}

componentDidMount() {
    // ... here must be other listeners too
    ConnectyCube.videochat.onCallListener = this.onIncomingCall
    ConnectyCube.videochat.onRemoteStreamListener = this.onRemoteStream
}

// you get the incoming call here and accept it
onIncomingCall = (session, extension) => {
    // here show some UI with 2 buttons - accept & reject, and by accept -> run the following code:
    const extension = {};
    session.accept(extension);
};

// then you will get a remote stream here
onRemoteStream = (session, userID, stream) => {
    // attach the remote stream to the RTCView
    this.setState({remoteStream: stream, userId: userID});
};

render() {
    const {userId, remoteStream} = this.state;

    return (
        ...
        <RTCView  objectFit="cover" style={...} key={userId} streamURL={remoteStream.toURL()} />
        ...
    )
}

@ccvlad ,

All these code is already there in my code as I have followed the sample only. But still what I found is when we make a call in sample we get a call on onRemoteStreamListener but, in my case I am not getting call on it.

Screenshot 2020-07-30 at 4 52 09 PM Screenshot 2020-07-30 at 4 52 19 PM Screenshot 2020-07-30 at 4 52 30 PM Screenshot 2020-07-30 at 4 51 53 PM Screenshot 2020-07-30 at 4 52 01 PM

ccvlad commented 4 years ago

@NeenaMishra12 1) could you check console.log(remoteStream) in the ConnectyCube.videochat.onRemoteStreamListener? 2) also you have to return some state or null from the static getDerivedStateFromProps(props, state)

NeenaMishra12 commented 4 years ago

@NeenaMishra12

  1. could you check console.log(remoteStream) in the ConnectyCube.videochat.onRemoteStreamListener?
  2. also you have to return some state or null from the static getDerivedStateFromProps(props, state)

Hi @ccvlad , Please see below code snippet for the same together with its logs when I tried with it:

_setUpListeners() { console.log('Listeners getting called') ConnectyCube.videochat.onCallListener = this._onCallListener; ConnectyCube.videochat.onAcceptCallListener = this._onAcceptCallListener; ConnectyCube.videochat.onRejectCallListener = this._onRejectCallListener; ConnectyCube.videochat.onStopCallListener = this._onStopCallListener; ConnectyCube.videochat.onUserNotAnswerListener = this._onUserNotAnswerListener; ConnectyCube.videochat.onRemoteStreamListener = this._onRemoteStreamListener; console.log('this.remotestreams----->',this.state.remoteStreams) }

Screenshot 2020-08-01 at 5 10 30 PM Screenshot 2020-08-01 at 5 10 42 PM

And my _onRemoteStreamListener is not getting called as that of getting called in Connectycube sample code. Also I am not getting these peerConnection warnings in the sample code which you can see in my app logs.

NeenaMishra12 commented 4 years ago

@ccvlad , Also just a confusion we can use Connectycube free plan for audio and video calling. Right? It is not the issue with rendering of stream.

ccvlad commented 4 years ago

@ccvlad , Also just a confusion we can use Connectycube free plan for audio and video calling. Right? It is not the issue with rendering of stream.

Not related. It is something with code. You can check the Videochat Sample with your creds (appId, authKey , authSecret). It should be OK.

Check like this:

_setUpListeners() {
  ConnectyCube.videochat.onCallListener = this._onCallListener;
  ConnectyCube.videochat.onAcceptCallListener = this._onAcceptCallListener;
  ConnectyCube.videochat.onRejectCallListener = this._onRejectCallListener;
  ConnectyCube.videochat.onStopCallListener = this._onStopCallListener;
  ConnectyCube.videochat.onUserNotAnswerListener = this._onUserNotAnswerListener;
  ConnectyCube.videochat.onRemoteStreamListener = this._onRemoteStreamListener;
}

...

_onRemoteStreamListener = (session, userID, stream) => {
  console.log("onRemoteStreamListener", {session, userID, stream});
}

...
pankajinfowind commented 3 years ago

@ccvlad

   _setUpListeners() {
       ConnectyCube.videochat.onCallListener = this._onCallListener;
       ConnectyCube.videochat.onAcceptCallListener = this._onAcceptCallListener;
       ConnectyCube.videochat.onRejectCallListener = this._onRejectCallListener;
       ConnectyCube.videochat.onStopCallListener = this._onStopCallListener;
       ConnectyCube.videochat.onUserNotAnswerListener = this._onUserNotAnswerListener;
       ConnectyCube.videochat.onRemoteStreamListener = this._onRemoteStreamListener;
   }

In my code every listener does call except "ConnectyCube.videochat.onRemoteStreamListener" whereas i added it also.