admin管理员组

文章数量:1023519

I have written react-native application that using RTCPeerConnection (from react-native-webrtc) that I run on my both Android phones throug USB debugging. Also I have my own local signaling server (I use a native WebSocket as transport). Everything seems written correct, but now I cannot establisch a simple connection beetween 2 peers for some reason on my phones. I noticed that peerConnection.connectionState is always new (should be transmitted to connected state). I cannot figure out why.

This is code of my react-native application (minimized for convenience):

import {Button,SafeAreaView,ScrollView,StyleSheet,Text,View} from 'react-native';
import { mediaDevices,MediaStream,RTCIceCandidate, RTCPeerConnection} from 'react-native-webrtc'
import { reconnectWebSocket, webSocket } from './socket'; //webSocket is `new WebSocket`, logic for reconnecting if state is CLOSED

function App(): React.JSX.Element {
  const [localStream, setLocalStream] = useState<MediaStream | null>(null);
  const peerConnection = useRef<RTCPeerConnection | null>(null);
  const [iceServers, setIceServers] = useState<Object[]>([]); 

  const [callerId, setCallerId] = useState(Math.floor(Math.random() * 10000)); //ID for caller
  let calleeId = useRef<number | null>(null); //ID for callee

  useEffect(() => {
    console.info(`Caller ID: ${callerId}`)
    const getAndSetIceServers = async(): Promise<Object[]> => {      
      const _iceServers = [{ url: 'stun:freestun:3478' }]      
      try {
        //simplicated
        setIceServers(_iceServers);  
        return Promise.resolve(IceServers);     
        }
        catch (e: any) {
          console.log(`Error while fetching TURN`);
          //some fall-back
        }      
    }
    getAndSetIceServers().then(async() =>
      await createPeerConnection()
    );
    //fired when WebSocket open
    const onOpen = async () => {
      try {
        //send to my server 'connection' event
        webSocket.send(JSON.stringify({ type: "connection", data: { callerId: callerId } }));
        setCallStatus(CallStatuses.READY);
      }
      catch (e) {                  
        console.error(e);
      }
    }
    //fired when message from server
    const onMessage = async (event: WebSocketMessageEvent) => {
      let message = JSON.parse(event.data);
      switch (message.type) {
        case "candidate":
          {
            await handleCandidate(message);         
            break;
          }
        case "offer":
          {
            await handleOffer(message);
            break;
          }
        case "answer":
          {
            await handleAnswer(message);
            break;
          }
        case "icecandidate":
          {
            await hadleICECandidate(message);
            break;
          }
        case "offline":
          {
            console.log("offline handling");
            calleeId.current = null;
            break;
          }
      }
    }
    //when WebSocket error
    const onError = async (event: WebSocketErrorEvent) => {
      console.log("WebSocket error: ", event);
      setCallStatus(CallStatuses.NOT_READY);
    }
    //attach the listeners above to the WebSocket 
    webSocket.onopen = onOpen;
    webSocket.onmessage = onMessage;
    webSocket.onerror = onError;

    const handleOffer = async (offer: any) => {      
      
      calleeId.current = offer.data.callerId;
      console.log(`handleOffer calleeId: ${calleeId.current}`);
      const description = offer.data.description;
      await peerConnection.current.setRemoteDescription(description);

      const sessionDescription = await peerConnection.current.createAnswer();
      await peerConnection.current.setLocalDescription(sessionDescription);
      // send answer      
      webSocket.send(JSON.stringify({ type: "answer", data: { callerId: callerId, calleeId: calleeId.current, description: sessionDescription } }));

    }

    const handleAnswer = async (answer: any) => {

      calleeId.current = answer.data.callerId;
      console.log(`handleAnswer calleeId: ${calleeId.current}`);
      const description = answer.data.description;
      await peerConnection.current.setRemoteDescription(description);
    }

    const handleCandidate = async (candidate: any) => {
                
      calleeId.current = candidate.calleeId;
      const options = { iceRestart: false } //can be ommitted
      const offer = await peerConnection.current.createOffer(options);
      await peerConnection.current.setLocalDescription(offer);
      //send offer to the server
      webSocket.send(JSON.stringify({ type: "offer", data: { callerId: callerId, calleeId: calleeId.current, description: peerConnection.current.localDescription } }));
    }

    const hadleICECandidate = async (candidate: any) => {     
        const iceCandidate = candidate.data.candidate as RTCIceCandidate;
        console.log("icecandidate handling. Candidate:" + JSON.stringify(iceCandidate));
        await peerConnection.current.addIceCandidate(candidate);
    }
    //reconnect webSocket but here no issues..
    let reconnectTimerId = setInterval(() => { reconnectWebSocket(onOpen, onMessage, onError) }, 5000)

    return () => {
      webSocket.onopen = null;
      webSocket.onerror = null;
      webSocket.onmessage = null;
      webSocket.close(1000, callerId.toString());
      clearInterval(reconnectTimerId);
    }
  }, [])
  
  const createPeerConnection = async () => {
    
    console.debug(`Creating new RTCPeerConnection`);
    peerConnection.current = new RTCPeerConnection({iceServers: iceServers})     
    peerConnection.current.addEventListener("icecandidate", iceCandidateListener); 
    console.debug(`RTCPeerConnection ${peerConnection.current._pcId} created`);
    
    const _localStream = await mediaDevices.getUserMedia({ audio: true });   
    _localStream.getTracks().map((track) => peerConnection?.current?.addTrack(track))
    setLocalStream(_localStream); //keep localStream in state just for case
  }

  const iceCandidateListener = (e: any) => {
    if (e.candidate) {
      console.log(`icecandidate event: ${JSON.stringify(e)}. to calleeId=${calleeId.current}`);
        //we need to send local ICE-candidate to peer (according to ICE-trickle approach)
        webSocket.send(JSON.stringify({
          type: "icecandidate", data: {
            calleeId: calleeId.current,
            candidate: e.candidate.toJSON()
          }
        }))
      console.log(`icecandidate sent from callerId ${callerId} to calleeId ${calleeId.current}`);
    }
  }
  //BUTTONS
  const goOnline = async () => {
    console.log("goOnline called");

    if (!peerConnection.current)          
      await createPeerConnection();

    webSocket.send(JSON.stringify({ type: "online", data: { callerId: callerId } }));
  }

  const goOffline = async () => {
    console.log("goOffline called");
    webSocket.send(JSON.stringify({ type: "offline", data: { callerId: callerId, calleeId: calleeId.current } }));
    calleeId.current = null;
    setCallStatus(CallStatuses.READY);
  }
  
  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.container}>
        <ScrollView
          contentContainerStyle={styles.container}
          contentInsetAdjustmentBehavior="automatic">
          <View style={styles.top}>
            <Text>Caller ID: {callerId}</Text>
            <Text>Callee ID: {calleeId.current}</Text>
          </View>
          <View style={styles.bottom}>
            <Button title='ONLINE' onPress={goOnline}></Button>
            <Button title='OFFLINE' onPress={goOffline}></Button>
          </View>
        </ScrollView>
      </View>
    </SafeAreaView>
  );
}

export default App;
<script src=".2.0/umd/react.production.min.js"></script>
<script src=".2.0/umd/react-dom.production.min.js"></script>

I have written react-native application that using RTCPeerConnection (from react-native-webrtc) that I run on my both Android phones throug USB debugging. Also I have my own local signaling server (I use a native WebSocket as transport). Everything seems written correct, but now I cannot establisch a simple connection beetween 2 peers for some reason on my phones. I noticed that peerConnection.connectionState is always new (should be transmitted to connected state). I cannot figure out why.

This is code of my react-native application (minimized for convenience):

import {Button,SafeAreaView,ScrollView,StyleSheet,Text,View} from 'react-native';
import { mediaDevices,MediaStream,RTCIceCandidate, RTCPeerConnection} from 'react-native-webrtc'
import { reconnectWebSocket, webSocket } from './socket'; //webSocket is `new WebSocket`, logic for reconnecting if state is CLOSED

function App(): React.JSX.Element {
  const [localStream, setLocalStream] = useState<MediaStream | null>(null);
  const peerConnection = useRef<RTCPeerConnection | null>(null);
  const [iceServers, setIceServers] = useState<Object[]>([]); 

  const [callerId, setCallerId] = useState(Math.floor(Math.random() * 10000)); //ID for caller
  let calleeId = useRef<number | null>(null); //ID for callee

  useEffect(() => {
    console.info(`Caller ID: ${callerId}`)
    const getAndSetIceServers = async(): Promise<Object[]> => {      
      const _iceServers = [{ url: 'stun:freestun:3478' }]      
      try {
        //simplicated
        setIceServers(_iceServers);  
        return Promise.resolve(IceServers);     
        }
        catch (e: any) {
          console.log(`Error while fetching TURN`);
          //some fall-back
        }      
    }
    getAndSetIceServers().then(async() =>
      await createPeerConnection()
    );
    //fired when WebSocket open
    const onOpen = async () => {
      try {
        //send to my server 'connection' event
        webSocket.send(JSON.stringify({ type: "connection", data: { callerId: callerId } }));
        setCallStatus(CallStatuses.READY);
      }
      catch (e) {                  
        console.error(e);
      }
    }
    //fired when message from server
    const onMessage = async (event: WebSocketMessageEvent) => {
      let message = JSON.parse(event.data);
      switch (message.type) {
        case "candidate":
          {
            await handleCandidate(message);         
            break;
          }
        case "offer":
          {
            await handleOffer(message);
            break;
          }
        case "answer":
          {
            await handleAnswer(message);
            break;
          }
        case "icecandidate":
          {
            await hadleICECandidate(message);
            break;
          }
        case "offline":
          {
            console.log("offline handling");
            calleeId.current = null;
            break;
          }
      }
    }
    //when WebSocket error
    const onError = async (event: WebSocketErrorEvent) => {
      console.log("WebSocket error: ", event);
      setCallStatus(CallStatuses.NOT_READY);
    }
    //attach the listeners above to the WebSocket 
    webSocket.onopen = onOpen;
    webSocket.onmessage = onMessage;
    webSocket.onerror = onError;

    const handleOffer = async (offer: any) => {      
      
      calleeId.current = offer.data.callerId;
      console.log(`handleOffer calleeId: ${calleeId.current}`);
      const description = offer.data.description;
      await peerConnection.current.setRemoteDescription(description);

      const sessionDescription = await peerConnection.current.createAnswer();
      await peerConnection.current.setLocalDescription(sessionDescription);
      // send answer      
      webSocket.send(JSON.stringify({ type: "answer", data: { callerId: callerId, calleeId: calleeId.current, description: sessionDescription } }));

    }

    const handleAnswer = async (answer: any) => {

      calleeId.current = answer.data.callerId;
      console.log(`handleAnswer calleeId: ${calleeId.current}`);
      const description = answer.data.description;
      await peerConnection.current.setRemoteDescription(description);
    }

    const handleCandidate = async (candidate: any) => {
                
      calleeId.current = candidate.calleeId;
      const options = { iceRestart: false } //can be ommitted
      const offer = await peerConnection.current.createOffer(options);
      await peerConnection.current.setLocalDescription(offer);
      //send offer to the server
      webSocket.send(JSON.stringify({ type: "offer", data: { callerId: callerId, calleeId: calleeId.current, description: peerConnection.current.localDescription } }));
    }

    const hadleICECandidate = async (candidate: any) => {     
        const iceCandidate = candidate.data.candidate as RTCIceCandidate;
        console.log("icecandidate handling. Candidate:" + JSON.stringify(iceCandidate));
        await peerConnection.current.addIceCandidate(candidate);
    }
    //reconnect webSocket but here no issues..
    let reconnectTimerId = setInterval(() => { reconnectWebSocket(onOpen, onMessage, onError) }, 5000)

    return () => {
      webSocket.onopen = null;
      webSocket.onerror = null;
      webSocket.onmessage = null;
      webSocket.close(1000, callerId.toString());
      clearInterval(reconnectTimerId);
    }
  }, [])
  
  const createPeerConnection = async () => {
    
    console.debug(`Creating new RTCPeerConnection`);
    peerConnection.current = new RTCPeerConnection({iceServers: iceServers})     
    peerConnection.current.addEventListener("icecandidate", iceCandidateListener); 
    console.debug(`RTCPeerConnection ${peerConnection.current._pcId} created`);
    
    const _localStream = await mediaDevices.getUserMedia({ audio: true });   
    _localStream.getTracks().map((track) => peerConnection?.current?.addTrack(track))
    setLocalStream(_localStream); //keep localStream in state just for case
  }

  const iceCandidateListener = (e: any) => {
    if (e.candidate) {
      console.log(`icecandidate event: ${JSON.stringify(e)}. to calleeId=${calleeId.current}`);
        //we need to send local ICE-candidate to peer (according to ICE-trickle approach)
        webSocket.send(JSON.stringify({
          type: "icecandidate", data: {
            calleeId: calleeId.current,
            candidate: e.candidate.toJSON()
          }
        }))
      console.log(`icecandidate sent from callerId ${callerId} to calleeId ${calleeId.current}`);
    }
  }
  //BUTTONS
  const goOnline = async () => {
    console.log("goOnline called");

    if (!peerConnection.current)          
      await createPeerConnection();

    webSocket.send(JSON.stringify({ type: "online", data: { callerId: callerId } }));
  }

  const goOffline = async () => {
    console.log("goOffline called");
    webSocket.send(JSON.stringify({ type: "offline", data: { callerId: callerId, calleeId: calleeId.current } }));
    calleeId.current = null;
    setCallStatus(CallStatuses.READY);
  }
  
  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.container}>
        <ScrollView
          contentContainerStyle={styles.container}
          contentInsetAdjustmentBehavior="automatic">
          <View style={styles.top}>
            <Text>Caller ID: {callerId}</Text>
            <Text>Callee ID: {calleeId.current}</Text>
          </View>
          <View style={styles.bottom}>
            <Button title='ONLINE' onPress={goOnline}></Button>
            <Button title='OFFLINE' onPress={goOffline}></Button>
          </View>
        </ScrollView>
      </View>
    </SafeAreaView>
  );
}

export default App;
<script src=".2.0/umd/react.production.min.js"></script>
<script src=".2.0/umd/react-dom.production.min.js"></script>

本文标签: react nativeRTCPeerConnectionconnectionState does not change to connected stateStack Overflow