WebRTC - other parts
Remote streams
RTCPeerConnection이 다른 동료와 연결될 때, 비디오나 오디오를 송출하는 것이 가능해 진다. 바로 이 때가 getUserMedia()로 받은 송출 흐름(stream)을 RTCPeerConnection에 연결할 때이다. 다른 동료에게 media를 전송할 때, 최소 한 개 이상의 media track으로 구성된 media stream을 개별적으로 RTCPeerConnection에 추가한다.
const localStream = await getUserMedia({vide: true, audio: true});
const peerConnection = new RTCPeerConnection(iceConfig);
localStream.getTracks().forEach(track => {
peerConnection.addTrack(track, localStream);
});
트랙이 다른 동료와 연결되기 전에도 RTCPeerConnection에 추가할 수 있기 때문에, 이 연결 작업을 최대한 빨리 하는 게 좋다.
Adding remote tracks
RTCPeerConnection에 track 이벤트 리스너를 설정함으로써 다른 동료가 추가한 트랙들에 대한 정보를 받을 수 있다.
재생은 MediaStream 오브젝트에서 실행된다. 따라서, empty instance를 먼저 생성하고 트랙을 다른 동료로부터 받는 대로 empty instance에 채워 넣으면 된다.
const remoteStream = MediaStream();
const remoteVideo = document.querySelector('#remoteVideo');
remoteVideo.srcObject = remoteStream;
peerConenction.addEventListener('track', async (event) => {
remoteStream.addTrack(event.track, remoteStream);
});
Data channels
WebRTC표준은 RTCPeerConnection을 이용해 arbitrary data를 보내는 API도 포함한다. RTCPeerConnection 오브젝트의 createDataChannel()함수를 호출하면 되고, 이 함수는 RTCDataChannel 오브젝트를 반환한다.
const peerConnection = new RTCPeerConnection(configuration);
const dataChannel = peerConnection.createDataChannel();
다른 동료는 RTCPeerConnection 오브젝트의 datachannel 이벤트를 이용해 data channels를 수신할 수 있다. 수신된 이벤트는 RTCDataChannelEvent 타입이고 동료들간 연결된 RTCDataChannel을 나타내는 channel 프로퍼티를 포함한다.
const peerConnection = new RTCPeerConnection(configuration);
peerConnection.addEventListener('datachannel', event => {
const dataChannel = event.channel;
});
Open and close events
data channel을 이용해 데이터를 보내기 전에 data channel이 열렸는지부터 확인을 해야 한다.
open 이벤트를 이용해 data channel이 열렸는지 확인할 수 있고, 마찬가지로 close 이벤트를 이용해 data channel이 닫혔는지 확인할 수 있다.
const messageBox = document.querySelector('#messageBox');
const sendButton = document.querySelector('#sendButton');
const peerConnection = new RTCPeerConnection(configuration);
const dataChannel = peerConnection.createDataChannel();
// Enable textarea and button when opened
dataChannel.addEventListener('open', event => {
messageBox.disabled = false;
messageBox.focus();
sendButton.disabled = false;
})
// Disabled input when closed
dataChannel.addEventListener('close', event => {
messageBox.disabled = false;
sendButton.disabled = false;
});
Messages
메세지를 보내려면 RTCDataChannel의 send()함수를 호출하면 된다. data 파라미터로는 string, Blob, ArrayBuffer, ArrayBufferView가 있다.
const messageBox = document.querySelector('#messageBox');
const sendButton = document.querySelector('#sendButton');
// Send a simply text message when we click the button
sendButton.addEventListener('click', event => {
const message = messageBox.textContent;
dataChannel.send(message);
})
반대편의 동료는 message 이벤트를 이용해 RTCDataChannel로 전송된 메세지를 받아볼 수 있다.
const incomingMessages = document.querySelector('#incomingMessages');
const peerConnection = new RTCPeerConnection(configuration);
const dataChannel = peerConnection.createDataChannel();
// Append new messages to the box of incoming messages
dataChannel.addEventListener('message', event => {
const message = event.data;
incomingMessages.textContent += message + '\n';
});
Turn server
동료들이 같은 local network에 있지 않는 이상 direct socket을 사용하는 것은 불가능할 수도 있다. 따라서 서버 기능을 위한 WebRTC 애플리케이션을 만들기 위해선 연결된 동료들간의 traffic을 중계(relaying)할 필요가 있다. 이 때 가장 많이 사용하는 방법은 TURN(Traversal Using Relay NAT) 서버를 이용하는 것이다. TURN은 network traffic을 중계하기 위한 규약이다.
온라인엔 TURN서버를 사용하기 위한 몇 가지 선택지들이 있다. COTURN project(open-soruce) 같은 self-hosted 애플리케이션도 있고 cloud provided services도 있다.
TURN 서버가 준비됐으면 이제 올바른 RTCConfiguration만 있으면 된다.
아래 코드 스니펫은 TURN 서버에 연결할 때 필요한 RTCPeerConnection을 위한 구성의 예시이다.
TURN 서버의 hostname은 my-turn-server.mycompany.com이고, 19403포트를 이용한다.
서버에 안전히 접근하기 위해 username과 credentials 프로퍼티를 사용할 수 있다.
const iceConfiguration = {
iceServers: [
{
urls: 'turn:my-turn-server.mycompany.com:19403',
username: 'optional-username',
credentials: 'auth-token'
}
]
}
const peerConnection = new RTCPeerConnection(iceConfiguration);
COUTRN project: https://github.com/coturn/coturn
Testing
자동으로 WebRTC를 테스트하기 위한 코드를 작성할 때 유용한 구성들이 있다.
Chrome
- --allow-file-access-from-files - Allows API access for file:// URLs
- --disable-translate - Disables the translation popup
- --use-fake-ui-for-media-stream - Provide fake media streams. Useful when running on CI servers.
- --use-file-for-fake-audio-capture=<filename> - Provide a file to use when capturing audio.
- --use-file-for-fake-video-capture=<filename> - Provide a file to use when capturing video.
- --headless - Run in headless mode. Useful when running on CI servers.
- --mute-audio - Mute audio output.
Unified Plan transition guide
구글은 Chrome의 WebRTC 구현을 바꾸려고 계획 중이다.
현재 "Plan B"라고 불리는 SDP format을 사용하고 있지만 앞으로는 "Unified Plan"이라고 불리는 conformant format을 사용할 것이다. 이 계획에는 4개의 phases와 1개의 일시적인(transient) API를 포함한다.
Who will be affected
하나의 PeerConnection을 이용해 다수의 비디오나 오디오 트랙을 이용할 사람들은 Unified Plan을 이용해 제품을 테스트 해야 할 것이다.
크롬이 아닌 브라우저에서 크롬을 호출하는 경우에 offer의 형태가 달라질 수 있다.
구체적인 SDP parsing을 이용하고 msid attributes를 신경쓰는 사람들은 parsing 코드가 새로운 format을 잘 반영하는지 점검해야 한다.
이번 변화에 의해 영향을 받을 앱에 대한 기준은 없다. 하지만, 하나의 RTCPeerCoonection에 하나의 비디오나 오디오만 쓰는 애플리케이션은 영향을 받지 않을 가능성이 높다.
더 자세한 내용은 https://webrtc.org/getting-started/unified-plan-transition-guide에서 확인하자.
본 게시글은 www.webRTC.org 의 guide 부분을 번역한 글입니다.