WebRTC 시작하기

WebRTC는 개방적이고 제약 없는 웹을 위한 오랜 전쟁의 새로운 전선입니다.

브렌던 아이크, JavaScript 개발자

플러그인 없이 실시간 통신

휴대전화, TV, 컴퓨터가 공통 플랫폼에서 통신할 수 있는 세상을 상상해 보세요. 웹 앱에 화상 채팅과 P2P 데이터 공유를 쉽게 추가할 수 있다고 가정해 보세요. 이것이 바로 WebRTC의 비전입니다.

이용해 보시겠습니까? WebRTC는 Chrome, Safari, Firefox, Opera의 데스크톱 및 모바일에서 사용할 수 있습니다. appr.tc의 간단한 영상 채팅 앱을 사용해 보세요.

  1. 브라우저에서 appr.tc를 엽니다.
  2. 참여를 클릭하여 채팅방에 참여하고 앱에서 웹캠을 사용하도록 허용합니다.
  3. 페이지 끝에 표시된 URL을 새 탭에서 열거나 다른 컴퓨터에서 엽니다.

빠른 시작

이 도움말을 읽을 시간이 없거나 코드만 확인하고 싶으신가요?

또는 간단한 신호 서버를 포함하여 완벽한 영상 채팅 앱을 빌드하는 방법을 설명하는 단계별 가이드인 WebRTC Codelab로 바로 이동하세요.

WebRTC의 간단한 역사

웹의 마지막 주요 과제 중 하나는 음성 및 동영상을 통한 인간의 커뮤니케이션을 지원하는 것입니다. 즉, 실시간 통신(RTC)입니다. RTC는 텍스트 입력에 텍스트를 입력하는 것처럼 웹 앱에서 자연스러워야 합니다. 데이터가 없으면 사용자가 상호작용할 수 있는 새로운 방법을 혁신하고 개발하는 데 제약이 따릅니다.

RTC는 그동안 기업용으로 복잡하여 값비싼 오디오 및 동영상 기술을 라이선스 구매하거나 자체 개발해야 했습니다. RTC 기술을 기존 콘텐츠, 데이터, 서비스와 통합하는 것은 특히 웹에서 어렵고 시간이 많이 걸렸습니다.

Gmail 영상 채팅은 2008년에 인기를 얻었고 2011년에는 Gmail과 마찬가지로 Talk를 사용하는 행아웃이 도입되었습니다. Google은 코덱 및 에코 제거 기술과 같이 RTC에 필요한 여러 구성요소를 개발한 GIPS를 인수했습니다. Google은 GIPS에서 개발한 기술을 오픈소스로 제공하고 업계 합의를 도출하기 위해 인터넷 엔지니어링 태스크 포스 (IETF) 및 월드 와이드 웹 컨소시엄 (W3C)의 관련 표준 기관과 협력했습니다. 2011년 5월, Ericsson은 WebRTC의 첫 번째 구현을 빌드했습니다.

WebRTC는 플러그인 없이 실시간으로 동영상, 오디오, 데이터를 주고받는 개방형 표준을 구현했습니다. 실제적인 필요성이 있었습니다.

  • 많은 웹 서비스에서 RTC를 사용했지만 다운로드, 네이티브 앱 또는 플러그인이 필요했습니다. 여기에는 Skype, Facebook, 행아웃이 포함됩니다.
  • 플러그인을 다운로드, 설치, 업데이트하는 작업은 복잡하고 오류가 발생하기 쉬우며 불편합니다.
  • 플러그인은 배포, 디버그, 문제 해결, 테스트, 유지관리하기가 어렵고 복잡하고 비용이 많이 드는 기술을 라이선스 구매 및 통합해야 할 수도 있습니다. 사용자가 플러그인을 설치하도록 설득하는 것조차 어려운 경우가 많습니다.

WebRTC 프로젝트의 기본 원칙은 API가 오픈소스여야 하고, 무료여야 하며, 표준화되어야 하며, 웹브라우저에 내장되어야 하며, 기존 기술보다 효율적이어야 한다는 것입니다.

지금 어디쯤 와 있나요?

WebRTC는 Google Meet과 같은 다양한 앱에서 사용됩니다. WebRTC는 WebKitGTK+ 및 Qt 네이티브 앱과도 통합되었습니다.

WebRTC는 다음 세 가지 API를 구현합니다. - MediaStream (getUserMedia라고도 함) - RTCPeerConnection - RTCDataChannel

API는 다음 두 사양에 정의되어 있습니다.

세 가지 API는 모두 Chrome, Safari, Firefox, Edge, Opera에서 모바일과 데스크톱에서 지원됩니다.

getUserMedia: 데모 및 코드는 WebRTC 샘플을 참고하거나 getUserMedia를 웹 오디오의 입력으로 사용하는 크리스 윌슨의 놀라운 예시를 사용해 보세요.

RTCPeerConnection: 간단한 데모와 완전한 기능을 갖춘 영상 채팅 앱은 각각 WebRTC 샘플 Peer connectionappr.tc를 참고하세요. 이 앱은 WebRTC 커뮤니티의 도움을 받아 Google에서 유지 관리하는 JavaScript shim인 adapter.js를 사용하여 브라우저 차이와 사양 변경사항을 추상화합니다.

RTCDataChannel: 이 기능을 실제로 확인하려면 WebRTC 샘플에서 데이터 채널 데모 중 하나를 확인하세요.

WebRTC Codelab에서는 세 가지 API를 모두 사용하여 영상 채팅 및 파일 공유를 위한 간단한 앱을 빌드하는 방법을 보여줍니다.

첫 번째 WebRTC

WebRTC 앱은 다음과 같은 몇 가지 작업을 실행해야 합니다.

  • 스트리밍 오디오, 동영상 또는 기타 데이터를 가져옵니다.
  • IP 주소 및 포트와 같은 네트워크 정보를 가져와 다른 WebRTC 클라이언트 (피어라고 함)와 교환하여 NAT 및 방화벽을 통한 연결도 지원합니다.
  • 오류를 보고하고 세션을 시작하거나 종료하기 위한 신호 통신을 조정합니다.
  • 해상도 및 코덱과 같은 미디어 및 클라이언트 기능에 관한 정보를 교환합니다.
  • 스트리밍 오디오, 동영상 또는 데이터를 전송합니다.

스트리밍 데이터를 획득하고 통신하기 위해 WebRTC는 다음 API를 구현합니다.

  • MediaStream는 사용자의 카메라 및 마이크와 같은 데이터 스트림에 액세스합니다.
  • RTCPeerConnection: 암호화 및 대역폭 관리 기능을 사용하여 오디오 또는 영상 통화를 사용 설정합니다.
  • RTCDataChannel: 일반 데이터의 P2P 통신을 사용 설정합니다.

WebRTC의 네트워크 및 신호 측면에 관한 자세한 내용은 뒷부분에서 설명합니다.

MediaStream API (getUserMedia API라고도 함)

MediaStream API는 동기화된 미디어 스트림을 나타냅니다. 예를 들어 카메라 및 마이크 입력에서 가져온 스트림에는 동기화된 동영상 및 오디오 트랙이 있습니다. MediaStreamTrack완전히 다른 <track> 요소와 혼동하지 마세요.

MediaStream API를 이해하는 가장 쉬운 방법은 실제 사용 사례를 살펴보는 것입니다.

  1. 브라우저에서 WebRTC 샘플 getUserMedia로 이동합니다.
  2. Console을 엽니다.
  3. 전역 범위의 stream 변수를 검사합니다.

MediaStream에는 입력(getUserMedia()에서 생성된 MediaStream일 수 있음)과 출력(동영상 요소 또는 RTCPeerConnection에 전달될 수 있음)이 있습니다.

getUserMedia() 메서드는 MediaStreamConstraints 객체 매개변수를 사용하고 MediaStream 객체로 확인되는 Promise를 반환합니다.

MediaStream에는 label(예: 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ')가 있습니다. MediaStreamTrack 배열은 getAudioTracks()getVideoTracks() 메서드에 의해 반환됩니다.

getUserMedia 예시에서 stream.getAudioTracks()는 오디오가 없으므로 빈 배열을 반환하고, 작동하는 웹캠이 연결되어 있다고 가정하면 stream.getVideoTracks()는 웹캠의 스트림을 나타내는 MediaStreamTrack 배열 1개를 반환합니다. 각 MediaStreamTrack에는 종류 ('video' 또는 'audio'), label ('FaceTime HD Camera (Built-in)'과 유사)가 있으며 오디오 또는 동영상의 하나 이상의 채널을 나타냅니다. 이 경우 동영상 트랙은 하나이고 오디오는 없지만 전면 카메라, 후면 카메라, 마이크에서 스트림을 가져오는 채팅 앱, 화면을 공유하는 앱 등 트랙이 더 많은 사용 사례를 쉽게 상상할 수 있습니다.

srcObject 속성을 설정하여 MediaStream를 동영상 요소에 연결할 수 있습니다. 이전에는 src 속성을 URL.createObjectURL()로 만든 객체 URL로 설정하여 이 작업을 실행했지만 이러한 방법은 지원 중단되었습니다.

getUserMediaWeb Audio API의 입력 노드로도 사용할 수 있습니다.

// Cope with browser differences.
let audioContext;
if (typeof AudioContext === 'function') {
  audioContext = new AudioContext();
} else if (typeof webkitAudioContext === 'function') {
  audioContext = new webkitAudioContext(); // eslint-disable-line new-cap
} else {
  console.log('Sorry! Web Audio not supported.');
}

// Create a filter node.
var filterNode = audioContext.createBiquadFilter();
// See https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#BiquadFilterNode-section
filterNode.type = 'highpass';
// Cutoff frequency. For highpass, audio is attenuated below this frequency.
filterNode.frequency.value = 10000;

// Create a gain node to change audio volume.
var gainNode = audioContext.createGain();
// Default is 1 (no change). Less than 1 means audio is attenuated
// and vice versa.
gainNode.gain.value = 0.5;

navigator.mediaDevices.getUserMedia({audio: true}, (stream) => {
  // Create an AudioNode from the stream.
  const mediaStreamSource =
    audioContext.createMediaStreamSource(stream);
  mediaStreamSource.connect(filterNode);
  filterNode.connect(gainNode);
  // Connect the gain node to the destination. For example, play the sound.
  gainNode.connect(audioContext.destination);
});

Chromium 기반 앱과 확장 프로그램도 getUserMedia를 통합할 수 있습니다. 매니페스트에 audioCapture 또는 videoCapture 권한을 추가하면 설치 시 한 번만 권한을 요청하고 부여할 수 있습니다. 이후에는 사용자에게 카메라 또는 마이크 액세스 권한을 요청하지 않습니다.

getUserMedia()에는 권한을 한 번만 부여하면 됩니다. 처음에는 브라우저의 infobar에 허용 버튼이 표시됩니다. getUserMedia()의 HTTP 액세스는 강력한 기능으로 분류되어 2015년 말에 Chrome에서 지원 중단되었습니다.

이는 카메라나 마이크뿐만 아니라 모든 스트리밍 데이터 소스에 MediaStream를 사용 설정하기 위함입니다. 이렇게 하면 저장된 데이터 또는 센서나 기타 입력과 같은 임의의 데이터 소스에서 스트리밍할 수 있습니다.

getUserMedia()는 다른 JavaScript API 및 라이브러리와 함께 사용하면 더욱 효과적입니다.

  • Webcam Toy는 WebGL을 사용하여 로컬에서 공유하거나 저장할 수 있는 사진에 기이하고 멋진 효과를 추가하는 사진 부스 앱입니다.
  • FaceKatheadtrackr.js로 빌드된 얼굴 추적 게임입니다.
  • ASCII 카메라는 Canvas API를 사용하여 ASCII 이미지를 생성합니다.
idevelop.ro/ascii-camera에서 생성된 ASCII 이미지
gUM ASCII 아트!

제약조건

제약 조건을 사용하여 getUserMedia()의 동영상 해상도 값을 설정할 수 있습니다. 이렇게 하면 가로세로 비율, 방향 모드 (전면 또는 후면 카메라), 프레임 속도, 높이 및 너비, applyConstraints() 메서드와 같은 기타 제약 조건을 지원할 수도 있습니다.

예를 보려면 WebRTC 샘플 getUserMedia: 해상도 선택을 참고하세요.

허용되지 않는 제약 조건 값을 설정하면 예를 들어 요청된 해상도를 사용할 수 없는 경우 DOMException 또는 OverconstrainedError이 표시됩니다. 실제 동작을 보려면 데모로 WebRTC 샘플 getUserMedia: 해상도 선택을 참고하세요.

화면 및 탭 캡처

Chrome 앱을 사용하면 chrome.tabCapturechrome.desktopCapture API를 통해 단일 브라우저 탭 또는 전체 데스크톱의 라이브 동영상을 공유할 수도 있습니다. 데모 및 자세한 내용은 WebRTC로 화면 공유하기를 참고하세요. 이 도움말은 몇 년 전에 작성되었지만 여전히 흥미롭습니다.)

실험용 chromeMediaSource 제약 조건을 사용하여 Chrome에서 화면 캡처를 MediaStream 소스로 사용할 수도 있습니다. 화면 캡처에는 HTTPS가 필요하며 이 게시물에 설명된 대로 명령줄 플래그를 통해 사용 설정되므로 개발에만 사용해야 합니다.

신호: 세션 제어, 네트워크, 미디어 정보

WebRTC는 RTCPeerConnection를 사용하여 브라우저(피어라고도 함) 간에 스트리밍 데이터를 통신하지만 통신을 조정하고 제어 메시지를 전송하는 메커니즘(신호라고 하는 프로세스)도 필요합니다. 신호 메서드와 프로토콜은 WebRTC에서 지정하지 않습니다. 신호는 RTCPeerConnection API의 일부가 아닙니다.

대신 WebRTC 앱 개발자는 SIP 또는 XMPP와 같은 원하는 메시지 프로토콜과 적절한 듀플렉스 (양방향) 통신 채널을 선택할 수 있습니다. appr.tc 예에서는 XHR 및 Channel API를 신호 메커니즘으로 사용합니다. 이 Codelab에서는 Node 서버에서 실행되는 Socket.io를 사용합니다.

신호는 다음 세 가지 유형의 정보를 교환하는 데 사용됩니다.

  • 세션 제어 메시지: 통신을 초기화하거나 종료하고 오류를 보고합니다.
  • 네트워크 구성: 외부에서 컴퓨터의 IP 주소와 포트는 무엇인가요?
  • 미디어 기능: 브라우저와 통신하려는 브라우저에서 처리할 수 있는 코덱과 해상도는 무엇인가요?

피어 투 피어 스트리밍을 시작하려면 신호를 통한 정보 교환이 완료되어야 합니다.

예를 들어 앨리스가 밥과 통신하려고 한다고 가정해 보겠습니다. 다음은 신호 프로세스가 작동하는 모습을 보여주는 W3C WebRTC 사양의 코드 샘플입니다. 이 코드는 createSignalingChannel() 메서드에서 생성된 일부 신호 메커니즘이 있다고 가정합니다. 또한 Chrome 및 Opera에서는 현재 RTCPeerConnection가 접두사로 사용됩니다.

// handles JSON.stringify/parse
const signaling = new SignalingChannel();
const constraints = {audio: true, video: true};
const configuration = {iceServers: [{urls: 'stun:stun.example.org'}]};
const pc = new RTCPeerConnection(configuration);

// Send any ice candidates to the other peer.
pc.onicecandidate = ({candidate}) => signaling.send({candidate});

// Let the "negotiationneeded" event trigger offer generation.
pc.onnegotiationneeded = async () => {
  try {
    await pc.setLocalDescription(await pc.createOffer());
    // Send the offer to the other peer.
    signaling.send({desc: pc.localDescription});
  } catch (err) {
    console.error(err);
  }
};

// Once remote track media arrives, show it in remote video element.
pc.ontrack = (event) => {
  // Don't set srcObject again if it is already set.
  if (remoteView.srcObject) return;
  remoteView.srcObject = event.streams[0];
};

// Call start() to initiate.
async function start() {
  try {
    // Get local stream, show it in self-view, and add it to be sent.
    const stream =
      await navigator.mediaDevices.getUserMedia(constraints);
    stream.getTracks().forEach((track) =>
      pc.addTrack(track, stream));
    selfView.srcObject = stream;
  } catch (err) {
    console.error(err);
  }
}

signaling.onmessage = async ({desc, candidate}) => {
  try {
    if (desc) {
      // If you get an offer, you need to reply with an answer.
      if (desc.type === 'offer') {
        await pc.setRemoteDescription(desc);
        const stream =
          await navigator.mediaDevices.getUserMedia(constraints);
        stream.getTracks().forEach((track) =>
          pc.addTrack(track, stream));
        await pc.setLocalDescription(await pc.createAnswer());
        signaling.send({desc: pc.localDescription});
      } else if (desc.type === 'answer') {
        await pc.setRemoteDescription(desc);
      } else {
        console.log('Unsupported SDP type.');
      }
    } else if (candidate) {
      await pc.addIceCandidate(candidate);
    }
  } catch (err) {
    console.error(err);
  }
};

먼저 앨리스와 밥이 네트워크 정보를 교환합니다. 후보 찾기라는 표현은 ICE 프레임워크를 사용하여 네트워크 인터페이스와 포트를 찾는 프로세스를 나타냅니다.

  1. 앨리스는 네트워크 후보를 사용할 수 있게 되면 실행되는 onicecandidate 핸들러가 있는 RTCPeerConnection 객체를 만듭니다.
  2. 앨리스는 WebSocket 또는 기타 메커니즘과 같은 사용 중인 신호 채널을 통해 직렬화된 후보 데이터를 밥에게 전송합니다.
  3. 밥은 앨리스로부터 후보 메시지를 수신하면 addIceCandidate를 호출하여 원격 피어 설명에 후보를 추가합니다.

WebRTC 클라이언트 (피어라고도 함, 이 예에서는 앨리스와 밥)도 해상도 및 코덱 기능과 같은 로컬 및 원격 오디오 및 동영상 미디어 정보를 확인하고 교환해야 합니다. 미디어 구성 정보를 교환하기 위한 신호는 세션 설명 프로토콜 (SDP)을 사용하여 오퍼답변을 교환하는 방식으로 진행됩니다.

  1. 앨리스가 RTCPeerConnection createOffer() 메서드를 실행합니다. 여기서 반환된 값은 RTCSessionDescription - 앨리스의 로컬 세션 설명을 전달합니다.
  2. 콜백에서 Alice는 setLocalDescription()를 사용하여 로컬 설명을 설정한 다음 신호 채널을 통해 이 세션 설명을 Bob에게 전송합니다. setLocalDescription()이 호출될 때까지 RTCPeerConnection는 후보 수집을 시작하지 않습니다. 이는 JSEP IETF 초안에 명시되어 있습니다.
  3. 밥은 setRemoteDescription()를 사용하여 앨리스가 보낸 설명을 원격 설명으로 설정합니다.
  4. 밥은 RTCPeerConnection createAnswer() 메서드를 실행하여 앨리스로부터 받은 원격 설명을 전달하여 앨리스의 세션과 호환되는 로컬 세션을 생성할 수 있습니다. createAnswer() 콜백에는 RTCSessionDescription가 전달됩니다. 밥은 이를 로컬 설명으로 설정하고 앨리스에게 전송합니다.
  5. 앨리스는 밥의 세션 설명을 가져와 setRemoteDescription를 사용하여 원격 설명으로 설정합니다.
  6. 핑!

RTCSessionDescription 객체는 세션 설명 프로토콜(SDP)을 준수하는 블롭입니다. 직렬화된 SDP 객체는 다음과 같습니다.

v=0
o=- 3883943731 1 IN IP4 127.0.0.1
s=
t=0 0
a=group:BUNDLE audio video
m=audio 1 RTP/SAVPF 103 104 0 8 106 105 13 126

// ...

a=ssrc:2223794119 label:H4fjnMzxy3dPIgQ7HxuCTLb4wLLLeRHnFxh810

네트워크 및 미디어 정보의 획득 및 교환은 동시에 실행할 수 있지만, 피어 간에 오디오 및 동영상 스트리밍을 시작하려면 두 프로세스가 모두 완료되어야 합니다.

앞서 설명한 오퍼/답변 아키텍처를 JavaScript 세션 설정 프로토콜(JSEP)이라고 합니다. 첫 번째 WebRTC 구현을 위한 Ericsson의 데모 동영상에서 신호 전송 및 스트리밍 프로세스를 설명하는 멋진 애니메이션을 확인할 수 있습니다.

JSEP 아키텍처 다이어그램
JSEP 아키텍처

신호 프로세스가 완료되면 호출자와 호출 대상 간에 직접 피어 투 피어로 데이터를 스트리밍할 수 있습니다. 또는 실패하면 중간 릴레이 서버를 통해 스트리밍할 수 있습니다 (자세한 내용은 나중에 설명). 스트리밍은 RTCPeerConnection의 작업입니다.

RTCPeerConnection

RTCPeerConnection는 피어 간에 스트리밍 데이터를 안정적이고 효율적으로 통신하는 WebRTC 구성요소입니다.

다음은 RTCPeerConnection의 역할을 보여주는 WebRTC 아키텍처 다이어그램입니다. 녹색 부분이 복잡한 것을 확인할 수 있습니다.

WebRTC 아키텍처 다이어그램
WebRTC 아키텍처 (webrtc.org)

JavaScript 관점에서 이 다이어그램에서 이해해야 할 핵심 사항은 RTCPeerConnection가 웹 개발자를 숨겨진 수많은 복잡성으로부터 보호한다는 것입니다. WebRTC에서 사용하는 코덱과 프로토콜은 안정적이지 않은 네트워크에서도 실시간 통신을 가능하게 하기 위해 엄청난 작업을 실행합니다.

  • 패킷 손실 은폐
  • 에코 제거
  • 대역폭 적응성
  • 동적 지터 버퍼링
  • 입력 신호량 자동 조절
  • 노이즈 감소 및 제거
  • Image-cleaning

이전 W3C 코드는 신호 전달 관점에서 WebRTC의 단순화된 예시를 보여줍니다. 다음은 작동하는 두 가지 WebRTC 앱의 워크스루입니다. 첫 번째는 RTCPeerConnection를 보여주는 간단한 예시이고 두 번째는 완전히 작동하는 영상 채팅 클라이언트입니다.

서버가 없는 RTCPeerConnection

다음 코드는 한 웹페이지에 로컬 원격 RTCPeerConnection (및 로컬 및 원격 동영상)가 있는 WebRTC 샘플 피어 연결에서 가져온 것입니다. 이는 매우 유용한 것은 아닙니다. 호출자와 호출 대상이 동일한 페이지에 있기 때문입니다. 하지만 페이지의 RTCPeerConnection 객체가 중간 신호 메커니즘을 사용하지 않고도 데이터와 메시지를 직접 교환할 수 있으므로 RTCPeerConnection API의 작동 방식을 조금 더 명확하게 이해할 수 있습니다.

이 예에서 pc1는 로컬 피어 (호출자)를 나타내고 pc2는 원격 피어 (호출 대상)를 나타냅니다.

발신자

  1. RTCPeerConnection를 만들고 getUserMedia()에서 스트림을 추가합니다. ```js // Servers는 선택적 구성 파일입니다. (나중에 TURN 및 STUN에 관한 설명 참고) pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) => { pc1.addTrack(track, localStream); });
  1. 제품을 만들고 pc1의 로컬 설명 및 pc2의 원격 설명으로 설정합니다. 호출자와 호출 대상이 모두 동일한 페이지에 있으므로 신호를 사용하지 않고 코드에서 직접 할 수 있습니다. js pc1.setLocalDescription(desc).then(() => { onSetLocalSuccess(pc1); }, onSetSessionDescriptionError ); trace('pc2 setRemoteDescription start'); pc2.setRemoteDescription(desc).then(() => { onSetRemoteSuccess(pc2); }, onSetSessionDescriptionError );

호출 대상

  1. pc2를 만들고 pc1의 스트림이 추가되면 동영상 요소에 표시합니다. js pc2 = new RTCPeerConnection(servers); pc2.ontrack = gotRemoteStream; //... function gotRemoteStream(e){ vid2.srcObject = e.stream; }

RTCPeerConnection API 및 서버

실제로는 WebRTC에 서버가 필요하므로 간단하더라도 다음과 같은 상황이 발생할 수 있습니다.

  • 사용자가 서로를 발견하고 이름과 같은 실제 세부정보를 교환합니다.
  • WebRTC 클라이언트 앱 (피어)이 네트워크 정보를 교환합니다.
  • 피어는 동영상 형식 및 해상도와 같은 미디어에 관한 데이터를 교환합니다.
  • WebRTC 클라이언트 앱은 NAT 게이트웨이 및 방화벽을 통과합니다.

즉, WebRTC에는 다음과 같은 네 가지 유형의 서버 측 기능이 필요합니다.

  • 사용자 검색 및 통신
  • 신호
  • NAT/방화벽 순회
  • P2P 통신이 실패할 경우 릴레이 서버

NAT 트래버설, 피어 투 피어 네트워킹, 사용자 검색 및 신호 전송을 위한 서버 앱 빌드 요구사항은 이 도움말의 범위를 벗어납니다. ICE 프레임워크에서 RTCPeerConnection가 NAT 순회 및 기타 네트워크 변동사항을 처리할 수 있도록 STUN 프로토콜과 확장 프로그램인 TURN이 사용된다고만 하면 됩니다.

ICE는 두 개의 영상 채팅 클라이언트와 같은 피어를 연결하기 위한 프레임워크입니다. 처음에 ICE는 UDP를 통해 가능한 한 낮은 지연 시간으로 피어를 직접 연결하려고 시도합니다. 이 프로세스에서 STUN 서버는 NAT 뒤의 피어가 공개 주소와 포트를 찾을 수 있도록 하는 단일 작업을 실행합니다. STUN 및 TURN에 관한 자세한 내용은 WebRTC 앱에 필요한 백엔드 서비스 빌드를 참고하세요.

연결 후보 찾기
연결 후보 찾기

UDP가 실패하면 ICE가 TCP를 시도합니다. 특히 기업 NAT 순회 및 방화벽으로 인해 직접 연결이 실패하면 ICE는 중간 (릴레이) TURN 서버를 사용합니다. 즉, ICE는 먼저 UDP와 함께 STUN을 사용하여 피어를 직접 연결하고, 연결에 실패하면 TURN 릴레이 서버로 대체합니다. 후보 찾기라는 표현은 네트워크 인터페이스와 포트를 찾는 프로세스를 나타냅니다.

WebRTC 데이터 경로
WebRTC 데이터 경로

WebRTC 엔지니어 저스틴 우베르티가 2013 Google I/O WebRTC 프레젠테이션에서 ICE, STUN, TURN에 대해 자세히 설명합니다. 프레젠테이션 슬라이드에서는 TURN 및 STUN 서버 구현의 예를 보여줍니다.

간단한 영상 채팅 클라이언트

STUN 서버를 사용한 신호 전달 및 NAT/방화벽 순회가 완료된 WebRTC를 사용해 보려면 appr.tc의 영상 채팅 데모를 참고하세요. 이 앱은 사양 변경과 접두사 차이로부터 앱을 보호하는 심인 adapter.js를 사용합니다.

코드는 의도적으로 로깅에서 상세합니다. 콘솔을 확인하여 이벤트 순서를 파악합니다. 다음은 코드에 관한 자세한 안내입니다.

네트워크 토폴로지

현재 구현된 WebRTC는 일대일 통신만 지원하지만, 여러 피어가 서로 직접 통신하거나 다수의 참여자를 처리하고 선택적 스트림 전달을 실행할 수 있는 서버인 다중점 제어 장치 (MCU)를 통해 통신하는 등 더 복잡한 네트워크 시나리오에서 사용할 수 있습니다. 또한 오디오 및 동영상의 믹싱 또는 녹화도 가능합니다.

멀티포인트 컨트롤 유닛 토폴로지 다이어그램
멀티포인트 제어 장치 토폴로지 예시

기존의 많은 WebRTC 앱은 웹브라우저 간의 통신만 보여줍니다. 하지만 게이트웨이 서버를 사용하면 브라우저에서 실행되는 WebRTC 앱이 전화 (PSTN이라고도 함)와 같은 기기 및 VOIP 시스템과 상호작용할 수 있습니다. 2012년 5월, Doubango Telecom은 WebRTC 및 WebSocket으로 빌드된 sipml5 SIP 클라이언트를 오픈소스로 공개했습니다. 이 클라이언트는 iOS 및 Android에서 실행되는 브라우저와 앱 간에 영상 통화를 지원하는 등 다양한 용도로 사용할 수 있습니다. Google I/O에서 Tethr과 Tropo는 OpenBTS 셀을 사용하여 WebRTC를 통해 피처폰과 컴퓨터 간의 통신을 지원하는 브리프케이스재해 커뮤니케이션을 위한 프레임워크를 시연했습니다. 이동통신사 없이 전화 통신

Google I/O 2012의 Tethr/Tropo 데모
Tethr/Tropo: 비상 통신 도구 키트

RTCDataChannel API<

WebRTC는 오디오 및 동영상 외에도 다른 유형의 데이터에 대한 실시간 통신을 지원합니다.

RTCDataChannel API를 사용하면 짧은 지연 시간과 높은 처리량으로 임의 데이터를 피어 투 피어 교환할 수 있습니다. 단일 페이지 데모와 간단한 파일 전송 앱을 빌드하는 방법을 알아보려면 각각 WebRTC 샘플WebRTC Codelab을 참고하세요.

이 API의 사용 사례는 다음을 비롯하여 다양합니다.

  • 게임
  • 원격 데스크톱 앱
  • 실시간 텍스트 채팅
  • 파일 전송
  • 분산형 네트워크

이 API에는 RTCPeerConnection를 최대한 활용하고 강력하고 유연한 P2P 통신을 지원하는 여러 기능이 있습니다.

  • RTCPeerConnection 세션 설정 활용
  • 우선순위가 지정된 여러 채널 동시 운영
  • 안정적인 전송 시맨틱과 비안정적인 전송 시맨틱
  • 기본 제공 보안 (DTLS) 및 혼잡 제어
  • 오디오 또는 동영상 유무와 관계없이 사용할 수 있는 기능

문법은 send() 메서드와 message 이벤트가 있는 WebSocket과 의도적으로 유사합니다.

const localConnection = new RTCPeerConnection(servers);
const remoteConnection = new RTCPeerConnection(servers);
const sendChannel =
  localConnection.createDataChannel('sendDataChannel');

// ...

remoteConnection.ondatachannel = (event) => {
  receiveChannel = event.channel;
  receiveChannel.onmessage = onReceiveMessage;
  receiveChannel.onopen = onReceiveChannelStateChange;
  receiveChannel.onclose = onReceiveChannelStateChange;
};

function onReceiveMessage(event) {
  document.querySelector("textarea#send").value = event.data;
}

document.querySelector("button#send").onclick = () => {
  var data = document.querySelector("textarea#send").value;
  sendChannel.send(data);
};

통신은 브라우저 간에 직접 이루어지므로 방화벽 및 NAT를 처리하기 위한 홀 펀칭에 실패할 때 릴레이 (TURN) 서버가 필요하더라도 RTCDataChannel는 WebSocket보다 훨씬 빠를 수 있습니다.

RTCDataChannel는 Chrome, Safari, Firefox, Opera, Samsung Internet에서 사용할 수 있습니다. Cube Slam 게임은 API를 사용하여 게임 상태를 전달합니다. 친구나 곰 역할을 맡아 보세요. 혁신적인 플랫폼인 SharefestRTCDataChannel를 통해 파일 공유를 지원했으며 peerCDN은 WebRTC가 피어 투 피어 콘텐츠 배포를 지원하는 방법을 살짝 보여주었습니다.

RTCDataChannel에 관한 자세한 내용은 IETF의 프로토콜 사양 초안을 참고하세요.

보안

실시간 커뮤니케이션 앱이나 플러그인이 보안을 손상시킬 수 있는 방법에는 여러 가지가 있습니다. 예를 들면 다음과 같습니다.

  • 암호화되지 않은 미디어 또는 데이터는 브라우저 간 또는 브라우저와 서버 간에 가로채일 수 있습니다.
  • 앱이 사용자 모르게 동영상이나 오디오를 녹음하고 배포할 수 있습니다.
  • 멀웨어 또는 바이러스가 무해해 보이는 플러그인이나 앱과 함께 설치되었을 수 있습니다.

WebRTC에는 이러한 문제를 방지하기 위한 몇 가지 기능이 있습니다.

  • WebRTC 구현은 DTLSSRTP와 같은 보안 프로토콜을 사용합니다.
  • 신호 메커니즘을 비롯한 모든 WebRTC 구성요소에는 암호화가 필수입니다.
  • WebRTC는 플러그인이 아닙니다. 구성요소는 별도의 프로세스가 아닌 브라우저 샌드박스에서 실행됩니다. 구성요소는 별도로 설치할 필요가 없으며 브라우저가 업데이트될 때마다 업데이트됩니다.
  • 카메라 및 마이크 액세스는 명시적으로 부여되어야 하며, 카메라나 마이크가 실행 중일 때는 사용자 인터페이스에 명확하게 표시됩니다.

스트리밍 미디어의 보안에 대한 자세한 내용은 이 도움말의 범위를 벗어납니다. 자세한 내용은 IETF에서 제안한 제안된 WebRTC 보안 아키텍처를 참고하세요.

결론

WebRTC의 API 및 표준을 사용하면 전화, 게임, 동영상 제작, 음악 제작, 뉴스 수집 등 콘텐츠 제작 및 커뮤니케이션 도구를 민주화하고 분산할 수 있습니다.

기술이 이보다 더 혁신적일 수는 없습니다.

블로거 필 에드홀름이 말했듯이, 'WebRTC와 HTML5는 원래 브라우저가 정보에 대해 수행한 것과 동일한 변환을 실시간 통신에 적용할 수 있습니다.'

개발자 도구

자세히 알아보기

표준 및 프로토콜

WebRTC 지원 요약

MediaStreamgetUserMedia API

  • Chrome 데스크톱 18.0.1008 이상, Android용 Chrome 29 이상
  • Opera 18 이상, Android용 Opera 20 이상
  • Opera 12, Opera Mobile 12 (Presto 엔진 기반)
  • Firefox 17 이상
  • Microsoft Edge 16 이상
  • iOS의 Safari 11.2 이상, macOS의 Safari 11.1 이상
  • Android의 UC 11.8 이상
  • Samsung Internet 4 이상

RTCPeerConnection API

  • Chrome 데스크톱 20 이상, Android용 Chrome 29 이상 (플래그 없음)
  • Opera 18 이상 (기본적으로 사용 설정됨), Android용 Opera 20 이상 (기본적으로 사용 설정됨)
  • Firefox 22 이상 (기본적으로 사용 설정됨)
  • Microsoft Edge 16 이상
  • iOS의 Safari 11.2 이상, macOS의 Safari 11.1 이상
  • Samsung Internet 4 이상

RTCDataChannel API

  • Chrome 25에서는 실험 버전이지만 Chrome 26 이상에서는 더 안정적이며 Firefox 상호 운용성을 지원합니다. Android용 Chrome 29 이상
  • Opera 18 이상 (Firefox 상호 운용성 포함)의 안정화 버전, Android용 Opera 20 이상
  • Firefox 22 이상 (기본적으로 사용 설정됨)

getUserMediaRTCPeerConnection와 같은 API의 크로스 플랫폼 지원에 관한 자세한 내용은 caniuse.comChrome 플랫폼 상태를 참고하세요.

RTCPeerConnection용 네이티브 API는 webrtc.org의 문서에서도 확인할 수 있습니다.