将用户加入同一房间以显示两个对等方的流(本地和远程)

时间:2019-03-06 11:53:37

标签: javascript reactjs webrtc kurento

我正在使用kurento-client进行一对一的视频通话。我的应用程序的用例是,将有两个 用户。任何用户都可以是主叫方和被叫方。首先创建房间的是呼叫者,另一个加入的是 在那个房间是被呼叫者。呼叫者加入会议室时,他/她应该看到他/她的网络摄像头以及被呼叫者 加入该房间,则应显示两个用户的网络摄像头。一个用户最多只能有2位用户 房间。

为此,我尝试通过自己创建房间来执行以下操作,但是我无法显示 远程对等体。

这是我的工作方式

class Studio extends Component {
  constructor(props) {
    super(props);
    this.state = {
      startCall: false,
      room: ''
    };
    this.localStreamRef = React.createRef();
    this.remoteStreamRef = React.createRef();
    this.handleCallStart = this.handleCallStart.bind(this);
    this.socket = null;
    this.webRTC = null;
    this.loginName=null;
  }

  componentDidMount() {
    this.socket = new socketIOClient("https://localhost:8443/sockets");
    this.socket.on("ROOM_CREATED", room => this.grabWebcam(room))
    this.socket.on("ROOM_JOINED", async room => {
      await this.grabWebcam(room, true);
      await this.handleCreateOffer(room, true, true);
    })
    this.socket.on("OFFER_RESPONSE", async response => await this.offerResponse(response));
    this.socket.on("ICE_CANDIDATE", async candidate => {
      console.log('candidate in listener', candidate);
      await this.webRTC.addIceCandidate(candidate)
    }
    );
    this.socket.on("ERROR", error => this.onError(error));
  }

  componentWillUnmount() {
    this.socket = null;
  }

  handleCallStart() {
    const { room } = this.state;
    console.log('room', room)
    this.socket.emit("room:join", { interviewId: room, userEmail: 'abc' });
  }

  grabWebcam = async (room, joined = false) => {
    if(joined){
      this.loginName = "interviewee";
    }else {
      this.loginName = "interviewer"
    }
    const options = {
      localVideo: this.localStreamRef.current,
      remoteVideo: this.remoteStreamRef.current,
      onicecandidate: this.onIceCandidate,
      mediaConstraints: CONSTRAINTS
    };
    this.webRTC = kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv(options, err => {
        if (err) return this.onError(err);
        // this will be needed once another user joins the created room
      }
    );
  }

  handleCreateOffer = async (room, initial = false, joined = false) => {
     this.webRTC.generateOffer((error, offerSdp) => {
       if (error) {
         console.error(error);
       }
       const offer = {
         role: joined ? 'interviewee' : 'interviwer',
         room,
         sdpOffer : offerSdp
       }
       this.onOffer(offer);
     });
  }

  // sending offer to other peer using SDP which is a signaling mechanism
  onOffer = (offer) => {
    console.info(
      "STEP 2 -> Invoking SDP offer callback function " + window.location.host
    );
    // We've made this function up sendOfferToRemotePeer(sdpOffer,
    this.socket.emit("OFFER_CREATE", JSON.stringify(offer));
  };

  offerResponse = async answer => {
    await this.webRTC.processAnswer(answer.sdpAnswer);
  };

  onIceCandidate = candidate => {
    console.log("Local candidate" + JSON.stringify(candidate));
  };

  onError = error => console.error(error);

  handleRoomChange = event => {
    this.setState({ room: event.target.value })
  }

  render() {
    return (
      <div className="App">
        <input type="text" name="room" onChange={this.handleRoomChange} value={this.state.room} />
        <button type="button" onClick={this.handleCallStart}>
          {!this.state.startCall && "Start"} Call
        </button>
          <h3>Local stream</h3>
          <video
            id="videoInput"
            ref={this.localStreamRef}
            autoPlay
          />
          <h3>Remote stream</h3>
          <video
            id="videoOutput"
            ref={this.remoteStreamRef}
            autoPlay
          />
      </div>
    );
  }
}

export default Studio;

server.js


const sessionHandler = session({
    secret : 'none',
    rolling : true,
    resave : true,
    saveUninitialized : true
});

app.use(sessionHandler);

/*
 * Definition of global variables.
 */
const users = {};
const sessions = {};
const candidatesQueue = {};
let kurentoClient = null;


/*
 * Server startup
 */
const asUrl = url.parse(argv.as_uri);
const port = asUrl.port;
const server = https.createServer(options, app).listen(port, function() {
    console.log('Open ' + url.format(asUrl) + ' with a WebRTC capable browser');
});

const io = require("socket.io")(server);

io.of('/sockets').on('connection', socket => {
  const sessionId = socket.id;
  socket.on("room:join", ({ interviewId: room, userEmail }) => {
    console.log('room join socket listened')
    const clientsInRoom = io.of('sockets').adapter.rooms[room];
    const numberOfClientsInRoom = clientsInRoom
      ? Object.keys(clientsInRoom.sockets).length
      : 0;
    console.log(`room: ${room}, number: ${numberOfClientsInRoom}, user: ${userEmail}`);
    if (!users[userEmail]) {
      users[userEmail] = {
        email: userEmail,
        interviewId: room,
        socketId: sessionId
      };
    }
    if (numberOfClientsInRoom === 0) {
      // enters the room and waits for other user
      console.log(`joining ${room}, waiting for others to join`);
      socket.join(room);
      socket.room = room;
      socket.emit('ROOM_CREATED', room, socket.id);
    } else if (numberOfClientsInRoom === 1) {
      // user arrived, now start sharing
      console.log(`joining ${room}, establishing connection...`);
      socket.join(room);
      socket.room = room;
      socket.emit('ROOM_JOINED', room, socket.id);
    } else {
      console.log(`cant join room::room ${socket.room}`);
      // max two clients
      socket.emit('ROOM_FULL', room);
    }
  });
  // OFFER_CREATE
  socket.on('OFFER_CREATE', offer => {
    const { room } = offer;
    console.log(`creating offer to ${room}`);
    start(sessionId, socket, offer, function(error, sdpAnswer) {
      if (error) {
        return socket.emit('ERROR', error);
      }
      const answer = {
        room: room || socket.room,
        sdpAnswer
      }
      socket.broadcast.to(room).emit('OFFER_RESPONSE', answer);
    })
  })
  // leaving session
  socket.on('STOP', () => stop(sessionId))
  //
  socket.on('CANDIDATE_NEW', response => onIceCandidate(socket.id, response.candidate))
})


// Definition of functions

// Recover kurentoClient for the first time.
function getKurentoClient(callback) {
    if (kurentoClient !== null) {
        return callback(null, kurentoClient);
    }

    kurento(argv.ws_uri, function(error, _kurentoClient) {
        if (error) {
            console.log("Could not find media server at address " + argv.ws_uri);
            return callback("Could not find media server at address" + argv.ws_uri
                    + ". Exiting with error " + error);
        }

        kurentoClient = _kurentoClient;
        callback(null, kurentoClient);
    });
}

function start(socketId, socket, offer, callback) {
  console.log('start function', offer, callback);
    if (!socketId) {
        return callback('Cannot use undefined socketId');
    }

    getKurentoClient(function(error, kurentoClient) {
        if (error) {
            return callback(error);
        }

        kurentoClient.create('MediaPipeline', function(error, pipeline) {
          console.log('pipeline', pipeline);
            if (error) {
                return callback(error);
            }

            createMediaElements(pipeline, socket, function(error, webRtcEndpoint) {
                if (error) {
                    pipeline.release();
                    return callback(error);
                }

                if (candidatesQueue[socketId]) {
                    while(candidatesQueue[socketId].length) {
                        const candidate = candidatesQueue[socketId].shift();
                        webRtcEndpoint.addIceCandidate(candidate);
                    }
                }

                connectMediaElements(webRtcEndpoint, function(error) {
                    if (error) {
                        pipeline.release();
                        return callback(error);
                    }

                    webRtcEndpoint.on('OnIceCandidate', function(event) {
                        var candidate = kurento.getComplexType('IceCandidate')(event.candidate);
                        // console.log('candidate', candidate);
                        socket.emit('ICE_CANDIDATE', candidate);
                    });

                    webRtcEndpoint.processOffer(offer, function(error, sdpAnswer) {
                        if (error) {
                            pipeline.release();
                            return callback(error);
                        }

                        sessions[socketId] = {
                            'pipeline' : pipeline,
                            'webRtcEndpoint' : webRtcEndpoint
                        }
                        console.log('sessions', sessions);
                        return callback(null, sdpAnswer);
                    });

                    webRtcEndpoint.gatherCandidates(function(error) {
                        if (error) {
                            return callback(error);
                        }
                    });
                });
            });
        });
    });
}


function createMediaElements(pipeline, socket, callback) {
    pipeline.create('WebRtcEndpoint', function(error, webRtcEndpoint) {
        if (error) {
            return callback(error);
        }

        return callback(null, webRtcEndpoint);
    });
}

function connectMediaElements(webRtcEndpoint, callback) {
    webRtcEndpoint.connect(webRtcEndpoint, function(error) {
        if (error) {
            return callback(error);
        }
        return callback(null);
    });
}

function stop(sessionId) {
    if (sessions[sessionId]) {
        var pipeline = sessions[sessionId].pipeline;
        console.info('Releasing pipeline');
        pipeline.release();

        delete sessions[sessionId];
        delete candidatesQueue[sessionId];
    }
}

function onIceCandidate(sessionId, _candidate) {
    var candidate = kurento.getComplexType('IceCandidate')(_candidate);

    if (sessions[sessionId]) {
        console.info('Sending candidate');
        const webRtcEndpoint = sessions[sessionId].webRtcEndpoint;
        webRtcEndpoint.addIceCandidate(candidate);
    }
    else {
        console.info('Queueing candidate');
        if (!candidatesQueue[sessionId]) {
            candidatesQueue[sessionId] = [];
        }
        candidatesQueue[sessionId].push(candidate);
    }
}

0 个答案:

没有答案