지금까지 진행해오던 프로젝트 중 몇가지는 끝나고, 몇가지는 중단된 상태에서 다음 들어갈 프로젝트에 대해 미리 공부해보고있다!
그 중 webRTC 에 대해 공부한 내용을 정리해보려고 한당
WebRTC
- 웹을 위한 실시간 커뮤니케이션, 통신기능을 애플리케이션에 추가할 수 있음. Real-Time Communication
- 동영상, 음성, 일반 데이터를 동종 앱 간에 전송할 수 있음
- socket.io 와 다르게 사용자 간 통신이 가능. (소켓은 사용자와 서버간 통신)
- 웹 애플리케이션과 사이트가 중간자 없이 브라우저 간에 오디오나 영상 미디어를 포착하고 마음대로 스트림 할 뿐만 아니라, 임의의 데이터도 교환할 수 있도록 하는 기술.
- 드라이버나 플러그인 설치 없이 웹 브라우저 간 P2P 연결을 통해 데이터 교환을 가능하게 하는 기술
- P2P : peer-to-peer. 중앙 서버를 통하지 않고 클라이언트 컴퓨터끼리 연결되는 것을 의미
- web 3.0 : 컴퓨터가 시맨틱 웹 기술을 이용하여 웹페이지에 담긴 내용을 이해하고 개인 맞춤형 정보를 제공할 수 있는 지능형 웹 기술. 지능화, 개인화된 맞춤형 웹.
- 시맨틱 웹 : 의미론적인 웹이라는 뜻으로 현재의 인터넷과 같은 분산환경에서 리소스에 대한 정보와 자원 사이의 관계-의미 정보를 컴퓨터가 처리할 수 있는 형태로 표현하고, 처리하도록 하는 프레임워크이자 기술
- signaling server : 각 peer 간 SDP (offer, answer) 나 ICE candidate 를 주고받을 수 있는 서버. 두 클라이언트는 SDP 기반의 offer - answer 를 교환
- SDP : Session Description Protocol. 스트리밍 미디어의 초기화 인수를 기술하고 협상하기 위한 것Signaling : 서로 다른 두 클라이언트가 데이터를 교환할 때 미디어 포맷 등을 상호 연동하기 위한 협의(nagotiation) 과정
- 상세 과정
- Alice 가 SDP 형태의 Offer 를 생성 (peerConnection.createOffer())
- 생성한 Offer 를 본인의 localDescription 으로 등록 (peerConnection.setLocalDescription())
- Offer 를 시그널링 서버에 전달
- Bob 은 시그널링 서버로부터 Offer 전달받음
- 전달받은 Offer 를 본인의 remoteDescription 에 등록(peerConnection.setRemoteDescription())
- SDP 형태의 Answer 생성(peerConnection.createAnswer())
- 생성한 Answer 를 본인의 localDescription 으로 등록(oeerConnection.setLocalDescription())
- Answer 를 시그널링 서버에 전달
- Alice 는 시그널링 서버로부터 Answer 전달받음
- 전달받은 Answer 를 본인의 remoteDescription 에 등록(peerConnection.setRemoteDescription
- 드라이버나 플러그인 설치 없이 웹 브라우저 간 P2P 연결을 통해 데이터 교환을 가능하게 하는 기술
- ICE 협상 : SDP를 서로 교환한 후 각 Peer 는 서로의 주소 값을 알기 위해 ICE candidate 를 교환. 이때 사용되는 기술이 NAT Traversal.
- ICE : Interactive Connectivity Establishment. P2P 네트워킹에서 두 컴퓨터가 가능한 한 직접 서로 통신하는 방법을 찾기위해 컴퓨터 네트워킹에 사용되는 기술.
⇒ SDP 는 서로의 정보, ICE candidate 는 서로의 주소값 (서로에 대한 정보도 알고 주소도 알아야 만날 수 / 연결될 수 있다)
개념은 이렇게 간단히 정리해보고, 직접 코드를 보며 실습해보쟈. 가장 먼저 시도했던건 역시나 공식문서!
이러나 저러나 해도 공식문서가 가장 빠르고 정확한 정보를 다루고 있기 때문에 공식 페이지에서 예시를 보고 따라해보기로 했다
WebRTC
An open framework for the web that enables Real-Time Communications (RTC) capabilities in the browser.
webrtc.org
firebase 와 webRTC 를 함께 사용하는 예시였는데, 이 전에 파이어베이스도 써본 기억이 있기 때문에 어렵지 않게 해볼 수 있다고 생각..했는데...?
일단 github 에 있는 기본 코드를 받아서 핵심 기능만 직접 코드를 쓰며 따라할 수 있는 방식인 것 같았는데,
뭐가 문젠지 (업데이트가 안된건지) 깃헙에 올라온 코드와 공식문서에서 설명하는 문서가 묘하게 달라서 아무리 읽어도 따라할 수가 없는 거시어따...^^
샘플 코드를 세팅하고, 채팅방을 만드는 것 부터 시작이라고 생각하고 공식문서에 나온대로 코드를 적었고..
그 다음 스텝으로 넘어가려고 하는데,,,왜 어디에 코드 넣어야 하는지 안알려주시죠...ㅜㅜ
이 부분에서 한참 막혀있다가, 다른 강의를 봐야겠다 싶어서 일단 미뤄두고 유튜브에서 다른 강의를 찾아보아따
https://www.youtube.com/watch?v=5M3Jzs2NFSA&list=LL&index=2&t=2136s
그러다 찾게된 강의!
한시간 정도 되는 강의였기때무네 금방 끝낼 수 있을 것 같기도 했고 react hook 을 사용한다고 해서 시도해봐따
자막도 없는 영어강의라 살짝 긴장했지만,,"진짜" 개발자는 영어를 두려워하지 않기에,,
생각보다 설명도 간단히 해주시고 말하는 속도도 빠르지 않아서 쉽게 이해할 수 있었다ㅋㅋㅋㅋㅋ
요 강의를 간단히 정리해보면,
이렇게 1:1 영상통화를 구현하는게 강의의 목표고, 두 화면 아래에 input 창에서 offer 나 answer, candidate 를 입력할 수 있다
콘솔까지 켜놓고 위에 정리한 순서처럼 offer 생성 -> remote description 등록 -> answer 생성 -> remote description 등록 -> candidate 등록 하면 이렇게 두 화면에 각각의 영상이 뜨고 1:1 채팅을 할 수 있게 된다
(호다닥 웹캠 가리느라 지문 등장 ㅎㅎ;;)
코드로 살펴보면 이렇다!
// Step 1.
// ref 생성
const localRef = useRef(); // local peer
const remoteRef = useRef(); // remote peer
const pc = useRef(new RTCPeerConnection(null)); // peer connection
const textRef = useRef(); // description, candidate 입력용 textarea ref
const getUserMedia = async () => {
const constraints = {
audio: false,
video: true,
};
// local media 자동 실행
const userMedia = await navigator.mediaDevices.getUserMedia(constraints);
localRef.current.srcObject = userMedia;
// 함수 내부 peer connection 생성
const _pc = new RTCPeerConnection(null);
// peer connection 에 local media 추가
userMedia.getTracks().forEach((track) => {
_pc.addTrack(track, userMedia);
});
// setLocalDescription 이 작동하면 트리거됨
_pc.onicecandidate = (e) => {
if (e.candidate) console.log(e.candidate, "e onicecandidate");
};
_pc.oniceconnectionstatechange = (e) => {
console.log(e, "ice connection state changes"); // connected, disconnected, failed, closed
};
_pc.ontrack = (e) => {
console.log(e, "on track");
//we got remote stream...
remoteRef.current.srcObject = e.streams[0];
};
// 외부 peer connection 덮어쓰기
pc.current = _pc;
};
useEffect(() => {
getUserMedia()
})
// Step 2.
// Offer 생성
const createOffer = async () => {
try {
const sdp = await pc.current.createOffer({
offerToReceiveAudio: 1,
offerToReceiveVideo: 1,
});
console.log(sdp, "===> sdp of offer description");
pc.current.setLocalDescription(sdp);
} catch (error) {
console.error(error);
}
};
// Answer 생성
const createAnswer = async () => {
try {
const sdp = await pc.current.createAnswer({
offerToReceiveAudio: 1,
offerToReceiveVideo: 1,
});
console.log(sdp, "===> sdp of answer description");
pc.current.setLocalDescription(sdp); // TODO: 영상과 달라진 부분!!
} catch (error) {
console.error(error);
}
};
// Offer, Answer 의 description 지정
const setRemoteDescription = () => {
const sdp = JSON.parse(textRef.current.value);
pc.current.setRemoteDescription(sdp);
};
// Candidate 추가하여 peer connection 연결 완료
const addCandidate = async () => {
const candidate = JSON.parse(textRef.current.value);
await pc.current.addIceCandidate(candidate); // TODO: 영상과 다른 점...candidate 첫번째꺼 쓰기...
console.log("Adding Candidate ...", candidate);
};
공식문서로 봤을 땐 순서가 어떻고 candidate 가 어떻고 이해가 안됐는데, 이 강의 보고 순서나 description 을 이해하는 데에도 쉬웠다!
이거 보고 나서 공식문서 코드도 내가 고쳐볼까 생각했는데 일단 webRTC 는 2차 개발에 들어간대서...(아니 공부하랬잔아요ㅜ;)
다음에 시간나면 더 공부해보는걸로 하고! webRTC 찍먹은 이렇게 마무리!