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 기술을 기존 콘텐츠, 데이터 및 서비스와 통합하는 것은 어렵고 시간이 많이 소요되었으며 특히 웹에서 어려웠습니다.

2008년에 Gmail 영상 채팅이 널리 사용되기 시작했으며 2011년 Google에서는 Gmail과 마찬가지로 토크를 사용하는 행아웃도 출시했습니다. Google은 코덱 및 에코 제거 기술 등 RTC에 필요한 여러 구성요소를 개발한 회사인 GIPS를 인수했습니다. Google은 GIPS에서 개발한 기술을 오픈소스로 제공하고 인터넷 엔지니어링 태스크포스 (IETF) 및 W3C (World Wide Web Consortium)의 관련 표준 기구와 협력하여 업계의 합의를 이끌어냈습니다. 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 샘플 피어 연결appr.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에는 'Xk7EuLhsuHKbnjLWkW4yYGNJJ8ONsgwHBvLQ'와 같은 label가 있습니다. getAudioTracks()getVideoTracks() 메서드에서 MediaStreamTrack의 배열을 반환합니다.

getUserMedia의 경우 stream.getAudioTracks()는 빈 배열을 반환하며 (오디오가 없으므로) 정상적으로 작동하는 웹캠이 연결되어 있다고 가정하면 stream.getVideoTracks()는 웹캠의 스트림을 나타내는 하나의 MediaStreamTrack 배열을 반환합니다. 각 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()에 대한 권한은 한 번만 부여하면 됩니다. 처음에는 브라우저의 정보 표시줄에 허용 버튼이 표시됩니다. getUserMedia()에 대한 HTTP 액세스는 강력한 기능으로 분류되어 2015년 말 Chrome에서 지원 중단되었습니다.

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

getUserMedia()는 다른 JavaScript API 및 라이브러리와 함께 사용하면 매우 유용합니다.

  • Webcam Toy는 WebGL을 사용하여 사진에 이상하고 놀라운 효과를 더해 로컬에 공유하거나 저장할 수 있는 포토 부스 앱입니다.
  • FaceKatheadtrackr.js로 빌드된 얼굴 추적 게임입니다.
  • ASCII 카메라는 캔버스 API를 사용하여 ASCII 이미지를 생성합니다.
를 통해 개인정보처리방침을 정의할 수 있습니다. <ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">idevelop.ro/ascii-camera에서 생성된 ASCII 이미지</ph>
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노드 서버에서 실행되는 Socket.io를 사용합니다.

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

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

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

예를 들어 앨리스가 밥과 연락하려고 한다고 가정해 보겠습니다. 다음은 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. 콜백에서 앨리스는 setLocalDescription()를 사용하여 로컬 설명을 설정한 다음 신호 채널을 통해 이 세션 설명을 밥에게 전송합니다. RTCPeerConnectionsetLocalDescription()가 호출될 때까지 후보 수집을 시작하지 않습니다. 이는 JSEP IETF 초안에 성문화되어 있습니다.
  3. 밥은 setRemoteDescription()을 사용하여 윤아가 보낸 설명을 원격 설명으로 설정합니다.
  4. 밥은 RTCPeerConnection createAnswer() 메서드를 실행하여 앨리스로부터 얻은 원격 설명을 앨리스와 호환되는 로컬 세션을 생성할 수 있도록 전달합니다. createAnswer() 콜백에는 RTCSessionDescription이 전달됩니다. 영수씨는 이를 지역 설명으로 설정하여 윤아에게 전송합니다.
  5. 윤아는 밥의 세션 설명을 받으면 이를 setRemoteDescription를 사용하여 원격 설명으로 설정합니다.
  6. 핑!
를 통해 개인정보처리방침을 정의할 수 있습니다.

RTCSessionDescription 객체는 세션 설명 프로토콜(SDP)을 준수하는 blob입니다. 직렬화된 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)이라고 합니다. (Ericsson의 데모 동영상에는 첫 WebRTC 구현의 신호 및 스트리밍 프로세스를 설명하는 멋진 애니메이션이 있습니다.)

<ph type="x-smartling-placeholder">
</ph> JSEP 아키텍처 다이어그램
JSEP 아키텍처

신호 프로세스가 성공적으로 완료되면 호출자와 수신자 간에 P2P로 직접 스트리밍하거나, 스트리밍에 실패하면 중개 릴레이 서버를 통해 데이터를 스트리밍할 수 있습니다 (자세한 내용은 뒷부분 참고). 스트리밍은 RTCPeerConnection의 기능입니다.

RTCPeerConnection

RTCPeerConnection는 피어 간 스트리밍 데이터의 안정적이고 효율적인 통신을 처리하는 WebRTC 구성요소입니다.

다음은 RTCPeerConnection의 역할을 보여주는 WebRTC 아키텍처 다이어그램입니다. 보시다시피 녹색 부분은 복잡합니다.

<ph type="x-smartling-placeholder">
</ph> WebRTC 아키텍처 다이어그램
WebRTC 아키텍처 (webrtc.org에서 가져옴)

JavaScript 관점에서 이 다이어그램에서 이해해야 할 주요 사항은 RTCPeerConnection가 아래에 숨어 있는 수많은 복잡성으로부터 웹 개발자를 보호한다는 것입니다. WebRTC에서 사용하는 코덱과 프로토콜은 불안정한 네트워크에서도 실시간 통신을 가능하게 하기 위해 방대한 작업을 수행합니다.

  • 패킷 손실 은닉
  • 에코 취소
  • 대역폭 적응성
  • 동적 잡음 버퍼링
  • 입력 신호량 자동 조절
  • 노이즈 감소 및 제거
  • 이미지 정리

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

서버가 없는 RTCPeerConnection

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

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

발신자

  1. RTCPeerConnection를 만들고 getUserMedia()의 스트림을 추가합니다. ```js // 서버는 선택적 구성 파일입니다. (이후 TURN 및 STUN 토론을 참조하세요.) pc1 = new RTCPeerConnection(servers); // ... localStream.getTracks().forEach((track) =&gt; { 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의 스트림이 추가되면 동영상 요소에 표시합니다. <ph type="x-smartling-placeholder">js pc2 = new RTCPeerConnection(servers); pc2.ontrack = gotRemoteStream; //... function gotRemoteStream(e){ vid2.srcObject = e.stream; }</ph>

API 및 서버 RTCPeerConnection

실제로는 WebRTC가 아무리 간단하더라도 서버가 필요하므로 다음과 같은 일이 일어날 수 있습니다.

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

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

  • 사용자 검색 및 커뮤니케이션
  • 신호
  • NAT/방화벽 순회
  • P2P 통신 실패 시 릴레이 서버

NAT 순회, P2P 네트워킹, 사용자 검색 및 신호를 위한 서버 앱 빌드 요구사항은 이 문서에서 다루지 않습니다. 즉, STUN 프로토콜과 확장 프로그램인 TURNRTCPeerConnection가 NAT 순회 및 기타 네트워크 변화에 대처할 수 있도록 ICE 프레임워크에서 사용됩니다.

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

<ph type="x-smartling-placeholder">
</ph> 연결 후보 찾기
연결 후보 찾기

UDP가 실패하면 ICE에서 TCP를 시도합니다. 특히 엔터프라이즈 NAT 통과와 방화벽으로 인해 직접 연결에 실패할 경우 ICE는 중개 (릴레이) TURN 서버를 사용합니다. 즉, ICE는 먼저 UDP와 함께 STUN을 사용하여 피어를 직접 연결하고, 연결이 실패하면 TURN 릴레이 서버로 대체합니다. 검색 후보라는 표현식은 네트워크 인터페이스 및 포트를 찾는 프로세스를 가리킵니다.

<ph type="x-smartling-placeholder">
</ph> WebRTC 데이터 경로
WebRTC 데이터 경로

WebRTC 엔지니어 Justin Uberti가 2013 Google I/O WebRTC 프레젠테이션에서 ICE, STUN, TURN에 관한 자세한 정보를 제공합니다. (프레젠테이션 슬라이드에서 TURN 및 STUN 서버 구현의 예를 볼 수 있습니다.)

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

STUN 서버를 사용한 신호 및 NAT/방화벽 순회 기능을 갖춘 WebRTC를 사용해 보려면 appr.tc의 영상 채팅 데모를 확인해 보세요. 이 앱은 사양 변경 및 접두사 차이로부터 앱을 격리하는 shim인 adapter.js를 사용합니다.

코드는 로깅에 의도적으로 자세한 정보를 표시합니다. 콘솔에서 이벤트 순서를 확인하세요. 다음은 코드에 대한 자세한 설명입니다.

네트워크 토폴로지

현재 구현된 WebRTC는 일대일 통신만 지원하지만 더 복잡한 네트워크 시나리오에서도 사용할 수 있습니다. 예를 들어 여러 피어가 서로 직접 통신하는 경우 또는 다수의 참가자를 처리하고 선택적 스트림 전달, 오디오와 동영상의 믹싱 또는 녹음을 수행할 수 있는 서버인 MCU (Multipoint Control Unit)를 통해 통신할 수 있습니다.

<ph type="x-smartling-placeholder">
</ph> 멀티포인트 제어 장치 토폴로지 다이어그램
멀티포인트 제어 장치 토폴로지 예시

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

<ph type="x-smartling-placeholder">
</ph> Google I/O 2012의 Tethr/Tropo 데모
Tethr/Tropo: 서류 가방 속 재난 커뮤니케이션

RTCDataChannel API<

WebRTC는 오디오와 비디오뿐만 아니라 다른 유형의 데이터에 대한 실시간 통신을 지원합니다.

RTCDataChannel API를 사용하면 짧은 지연 시간과 높은 처리량으로 임의의 데이터를 P2P 방식으로 교환할 수 있습니다. 단일 페이지 데모와 간단한 파일 전송 앱을 빌드하는 방법을 알아보려면 각각 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, 삼성 인터넷에서 사용할 수 있습니다. Cube Slam 게임은 API를 사용하여 게임 상태를 전달합니다. 친구와 게임하거나 곰이 되어 보세요. 혁신적인 플랫폼인 SharefestRTCDataChannelpeerCDN을 통한 파일 공유를 가능하게 하여 WebRTC가 P2P 콘텐츠 배포를 가능하게 하는 방법을 간략하게 보여주었습니다.

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

보안

실시간 통신 앱이나 플러그인이 보안을 손상시킬 수 있는 몇 가지 방법이 있습니다. 예를 들면 다음과 같습니다.

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

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

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

스트리밍 미디어의 보안에 대한 전체 논의는 이 문서에서 다루지 않습니다. 자세한 내용은 IETF에서 제안하는 제안된 WebRTC 보안 아키텍처를 참조하세요.

결론

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

기술은 이보다 더 파괴적이지 않습니다.

블로거 Phil Edholm은 말했듯이 "잠재적으로 WebRTC와 HTML5는 정보를 위해 원래의 브라우저에서 했던 것과 동일한 혁신을 통해 실시간 커뮤니케이션을 가능하게 할 수 있습니다."라고 말했습니다.

개발자 도구

  • 진행 중인 세션의 WebRTC 통계는 다음에서 확인할 수 있습니다. <ph type="x-smartling-placeholder">
      </ph>
    • Chrome의 about://webrtc-internals
    • Opera의 opera://webrtc-internals
    • Firefox의 about:webrtc <ph type="x-smartling-placeholder">
      </ph> chrome://webrtc-internals 페이지
      chrome://webrtc-internals 스크린샷
  • 교차 브라우저 상호 운용성 메모
  • adapter.js는 공급업체 접두사, 브라우저 차이점 및 사양 변경사항을 추상화하는 WebRTC 커뮤니티의 도움을 받아 Google에서 유지 관리하는 WebRTC용 JavaScript 심입니다.
  • WebRTC 신호 프로세스에 대해 자세히 알아보려면 콘솔의 appr.tc 로그 출력을 확인하세요.
  • 너무 많다면 WebRTC 프레임워크 또는 완전한 WebRTC 서비스를 사용하는 것이 좋을 수도 있습니다.
  • 버그 신고 및 기능 요청은 언제든지 환영합니다. <ph type="x-smartling-placeholder">

자세히 알아보기

표준 및 프로토콜

WebRTC 지원 요약

MediaStreamgetUserMedia API

  • Chrome 데스크톱 18.0.1008 이상 Android 29 이상용 Chrome
  • Opera 18 이상 Android 20 이상용 Opera
  • Opera 12, Opera Mobile 12 (Presto 엔진 기반)
  • Firefox 17 이상
  • Microsoft Edge 16 이상
  • Safari 11.2 이상(iOS), 11.1 이상(MacOS)
  • Android: UC 11.8 이상
  • 삼성 인터넷 4 이상

RTCPeerConnection API

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

RTCDataChannel API

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

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

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