Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

HTML5 WebRTC 시그널링 채널 만들기: createSignalingChannel() 예제 완벽 정리

WebRTC와 시그널링의 기본 개념

WebRTC(Web Real-Time Communication)는 브라우저 간에 서버를 거치지 않고 직접 연결되는 P2P(peer-to-peer) 통신을 가능하게 하는 HTML5 핵심 기술입니다. 이러한 통신이 실제로 성립하려면 크게 네 가지 요소가 필요합니다.

  • 시그널링(Signaling): 연결 설정을 위한 제어 메시지 교환
  • 네트워크 정보: IP 주소, 포트 등 상대방을 찾기 위한 ICE 후보 정보
  • 세션 제어: 통화 시작·종료, 오디오/비디오 협상 등 세션 관리
  • 미디어 정보: 코덱, 해상도 등 실제 미디어 스트림에 대한 메타데이터

웹 개발자는 이러한 시그널링 메시지를 주고받기 위해 SIP, XMPP 같은 표준 프로토콜을 사용할 수도 있고, WebSocket처럼 양방향 통신이 가능한 어떤 수단이든 자유롭게 선택할 수 있습니다. WebRTC 표준은 시그널링 방식을 강제하지 않기 때문에 개발 환경에 맞는 방법을 고르면 됩니다.

createSignalingChannel() 예제 코드

아래는 createSignalingChannel()을 활용해 발신자(caller)와 수신자(callee) 간에 연결을 맺는 대표적인 예제입니다.

var signalingChannel = createSignalingChannel();
var pc;
var configuration = ...;

// start(true)를 호출하면 발신자로 통화를 시작
function start(isCaller) {
    pc = new RTCPeerConnection(configuration);
    // ICE 후보(candidate)를 상대 피어에게 전송
    pc.onicecandidate = function (evt) {
        signalingChannel.send(JSON.stringify({ "candidate": evt.candidate }));
    };
    
    // 원격 스트림이 도착하면 remote video 요소에 표시
    pc.onaddstream = function (evt) {
        remoteView.src = URL.createObjectURL(evt.stream);
    };

    // 로컬 스트림을 가져와 local video 요소에 표시하고 전송
    navigator.getUserMedia({ "audio": true, "video": true }, function (stream) {
        selfView.src = URL.createObjectURL(stream);
        pc.addStream(stream);
        if (isCaller)
            pc.createOffer(gotDescription);
        else
            pc.createAnswer(pc.remoteDescription, gotDescription);
        function gotDescription(desc) {
            pc.setLocalDescription(desc);
            signalingChannel.send(JSON.stringify({ "sdp": desc }));
        }
    });
}
signalingChannel.onmessage = function (evt) {
    if (!pc)
        start(false);
        var signal = JSON.parse(evt.data);
        if (signal.sdp)
        pc.setRemoteDescription(new RTCSessionDescription(signal.sdp));
    else
        pc.addIceCandidate(new RTCIceCandidate(signal.candidate));
};

코드 동작 흐름 살펴보기

1. 피어 커넥션 생성 및 ICE 후보 전송

start() 함수가 호출되면 먼저 RTCPeerConnection 객체가 생성됩니다. 이후 onicecandidate 이벤트가 발생할 때마다 해당 네트워크 정보(ICE 후보)를 JSON으로 직렬화해 시그널링 채널을 통해 상대에게 전달합니다.

2. 로컬 미디어 스트림 확보

navigator.getUserMedia()를 통해 마이크와 카메라 권한을 요청하고, 받아온 스트림은 로컬 비디오 요소에 출력하는 동시에 pc.addStream()으로 피어 커넥션에 추가됩니다.

3. Offer/Answer 교환(SDP 협상)

발신자(isCaller가 true)는 createOffer()로 SDP 제안을 만들고, 수신자는 createAnswer()로 응답을 생성합니다. 생성된 SDP 정보는 setLocalDescription()으로 로컬에 저장된 뒤 시그널링 채널을 통해 상대방에게 전송됩니다.

4. 수신 메시지 처리

signalingChannel.onmessage 핸들러는 상대방이 보낸 메시지를 파싱합니다. SDP 정보가 포함되어 있으면 setRemoteDescription()으로 원격 세션을 설정하고, 그렇지 않으면 ICE 후보로 판단해 addIceCandidate()로 추가합니다.

참고: 최신 브라우저에서의 API 변경 사항

위 예제는 WebRTC 초기 명세 기반의 코드로, 일부 API는 현재 지원 중단(deprecated) 상태입니다. 최신 브라우저에서 작업할 때는 다음과 같이 변경된 API를 사용하는 것이 좋습니다.

  • navigator.getUserMedia() → navigator.mediaDevices.getUserMedia()
  • pc.onaddstream → pc.ontrack
  • URL.createObjectURL(stream) → video.srcObject = stream

동작 원리 자체는 동일하므로, 이 예제를 통해 WebRTC 시그널링의 전체적인 흐름을 이해한 뒤 최신 API로 옮겨 적는 것을 추천합니다.