새소식

개발/Web

[WebRTC] PeerJS 사용법

  • -

NodeJS를 이용해 WebRTC를 구현하기 위해,

peers/peerjs: Simple peer-to-peer with WebRTC (github.com)

 

peers/peerjs

Simple peer-to-peer with WebRTC. Contribute to peers/peerjs development by creating an account on GitHub.

github.com

처음 peerjs 깃허브에 들어가면, 예제가 있긴하지만 예제만으로 동작시키기엔 어려움이 있다.
또한, 유투브에서도 은근 동작하는 예제를 찾기가 힘든데.. 이런 고생을 하는 다른 사람들을 위해 공부했던 내용을 공유한다.

공부를 위해 사용한 예제는 (5) How To Create A Video Chat App With WebRTC - YouTube 프로젝트이며, 해당 유투브 링크에서 공유하는 깃허브 자료만으론, 동작하지 않아 동작 시키는데 필요한 이벤트 시퀀스 정보를 덧붙인다.

peer js는 위 도표와 같이 동작한다고 생각하면 된다.
순서대로 살펴보면, 아래와 같다.

  1. peer-login : peer 생성시 호출되는 이벤트다.

  2. 서버에서 peer-login 수신시 ‘peer-connected’ 소켓 이벤트를 broadcast한다.

  3. ‘peer-connected’를 수신 받은 peer는 새로 접속한 peer의 uid를 인자로 받으며, 이 인자에 자신의 stream 영상정보를 담아 call한다.
    (myPeer.call(uid, stream))

  4. 새로 접속한 peer는 call을 수신받으며, 이는 myPeer.on(‘call’, call) 형식으로 이뤄진다.

  5. 이 call 수신 단계에서, 송신자의 stream 정보를 송출하는 video를 생성한다.

  6. 이후 answer로 stream 정보를 수신받았음을 송신자에게 알린다.
    call.answer(stream){여기서 stream에 새로 들어온 peer의 stream 정보를 담는다.}

  7. stream 이벤트를 수신 받은 peer는 이벤트 파라미터에 담긴, 새로 접속한 peer의 stream 정보를 영상에 띄운다.

이런 일련의 이벤트를 수신받고, 송신하는 클라이언트 객체를, MyPeer로 묶었으며 이 객체를 생성하면 손쉽게 RTC 연결을 할 수 있다.
코드는 아래와 같다.

 

const MyPeer = (socket, posAudio, scene) => {
	//	WebRTC는 영상통화를 하는 API이기에
    //	추가되는 비디오들이 나열되는 video-grid 요소를 추가해야한다.
    const videoGrid = document.getElementById('video-grid')
    //	peer.js에 선언되어있는 Peer 객체를 생성한다.
    //	이때, 현재 테스트환경이 로컬 단위이기에 3001포트를 사용하도록 한다.
    const myPeer = new Peer(undefined, {
        host: 'localhost',
        port: '3001',
        path: '/peer'
    })
	//	video-grid에 추가할 video를 생성한다. 
    //	이 비디오엔 내 카메라가 찍는 나의 모습이 보인다.
    const myVideo = document.createElement('video');
    //	내가 내는 소리는 듣고 싶지 않기에, 뮤트한다.
    myVideo.muted = true;
    const peers = {};

    myPeer.on('open', (id) => {
    	//	피어가 생성되면 자동으로 호출된다.
        socket.emit('peer-login', id);
    });
	//	새로운 피어가 연결되면 호출된다.
    socket.on('peer-connected', data => {
        connectToNewUser(data.uid, data.pid);
    });
	//	새로운 피어와의 연결이 성공적으로 이뤄질때 호출한다.
    myPeer.on('connection', (conn)=>{
       console.log("incoming peer connection!");
       conn.on('data',(data)=>{
          console.log("MY Received Data : " + data);
       });
       conn.on('open', ()=>{
           conn.send('My Send Hello!');
       })
    });

    //	기존에 room에 존재하던 피어로부터 call 신호를 수신받으면 호출된다.
    //	내 카메라의 Videostream 정보를 넘겨줘야 한다.
    myPeer.on('call', (call)=>{
    	//	videostream 정보를 담는다.
        navigator.mediaDevices.getUserMedia({
            video: true,
            audio: true
        }).then(stream=>{
        	//	비동기처리기를 통해 stream 정보를 answer에 실어 응답한다.
            call.answer(stream);

            let video = document.createElement('video');
            videoGrid.append(video);

            call.on('stream', (remoteStream)=>{
                addVideoStream(video, remoteStream)
            });

        }).catch((err)=>{
            console.log("Failed to get local stream", err);
        });
    });


    socket.on('peer-disconnected', uid => {
        if (peers[uid]) peers[uid].close()
    })

    function connectToNewUser(uid, pid) {
        let conn = myPeer.connect(pid);
        conn.on('data', (data)=>{
            console.log("Receive Data : " + data);
        })
        conn.on('open', ()=>{
            conn.send('hi!');
        })
        navigator.mediaDevices.getUserMedia({video:false, audio:true})
            .then((stream)=>{
                let call = myPeer.call(pid, stream);
                let video = document.createElement('video');
                videoGrid.append(video);
                call.on('stream', (userVideoStream)=>{
                    console.log("스트림에 연결됨")
                    addVideoStream(video, userVideoStream)
                })
                peers[uid] = call;
            })
            .catch((err)=>{
               console.log('Failed to get local stream', err);
            });
      }

      function addVideoStream(video, stream) {
          console.log("video added");
        video.srcObject = stream
        video.addEventListener('loadedmetadata', () => {
          video.play()
        })
        videoGrid.append(video)
      }
}

export default MyPeer

서버사이드 코드는 유투브 링크와 크게 차이없게 작성되었음으로, 그대로 사용하면 된다.

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.