Step-by-Step
[6] 스트림 데이터 전송 P2P 본문
우선 같은 Room 내 접속한 Peer간 비디오 및 오디오 전송을 구현해야 한다. (나중에 채팅도 작성할 것임)
https://webrtc.org/getting-started/peer-connections?hl=ko
※ P2P 통신 구성은 다음과 같다.
1. ICE Candidate
- 정보 교환을 통해 상대 Peer의 네트워크 정보인 ICE(Interactive Connectivity Establishment) Candidate를 가져온다
- Candidate : STUN, TURN 등으로 찾아낸 연결 가능한 네트워크 주소들
STUN, TRUN 정보는 다음 확인 : https://developer.mozilla.org/ko/docs/Web/API/WebRTC_API/Protocols
단순히 타 네트워크에 있는 사용자 간 IP 접근 루트를 설정해주는 거라고 생각하면 된다 (local 사용해서 생략했음)
2. SDP
- SDP (Session Description Protocol) : 해상도나 형식, 코덱, 암호화등의 멀티미디어 컨텐츠의 연결을 설명하기 위한 표준
- 어떤 종류의 데이터를 주고 받을지 보내는 형식으로, createOffer()로 RTCSessionDescription 객체 생성 후 교환한다.
초기 설정
async function initCall(){
welcome.hidden = true;
call.style.display='inline-flex';
chat.style.display='block';
await getMedia();
makeConnection();
}
저번에 룸 입장시 처음 실행했던 초기 함수이다. 마지막 makeConnection()은 ICE 과정을 담고 있다
ICE Candidate
let myPeerConnection;
function makeConnection(){
// Server.js 에서 callback으로 실행하면 너무 빠르게 일어나서 offer의 setRemoteDescription때 에러가 발생
myPeerConnection = new RTCPeerConnection(
/* STUN Server
{
// GOOGLE STUN Server Ref : https://gist.github.com/zziuni/3741933
iceServers: [
{
urls: [
"stun:stun.l.google.com:19302",
"stun:stun1.l.google.com:19302",
"stun:stun2.l.google.com:19302",
"stun:stun3.l.google.com:19302",
"stun:stun4.l.google.com:19302"
]
}
]
}
*/
);
myPeerConnection.addEventListener("icecandidate", handleIce);
myPeerConnection.addEventListener("track", handleTrack);
/* myStream 데이터 저장하기 - P2P 로 데이터 보내기 위함 */
myStream.getTracks().forEach(track => myPeerConnection.addTrack(track, myStream));
}
인터넷에 나와있는 많은 STUN, TURN 서버 참조해서 구성해주면 된다.
function handleTrack(data) {
console.log("got an event from my peer");
//console.log("Peer's Stream", data.streams[0]);
const peerFace = document.getElementById("peerFace");
peerFace.srcObject = data.streams[0];
//console.log("My Stream", myStream);
}
function handleIce(data) {
console.log("Sent Candidate");
socket.emit("ice", data.candidate, roomName);
}
handleTrack을 통해 상대 오디오와 비디오 정보를 등록하고,
handleIce를 통해 동일 roomName 상대에게 candidate 정보를 전달해준다.
wsServer.on("connection", socket => {
/* ICE 받음 - (App.js) ice 넣어줌 */
socket.on("ice", (ice, roomName) => {
socket.to(roomName).emit("ice", ice);
});
})
서버에서 ICE 받아서 다른 Peer에게 전달
socket.on("ice", (ice) => {
console.log("Received Candidate");
myPeerConnection.addIceCandidate(ice);
});
다른 Peer에서 ice 받으면 myPeerConnection에 등록해줌
룸 입장시 Offer 통한 객체 생성 및 전달
/* 입장 후 동일 roomName 가진 사람에게 객체 전달 */
socket.on("welcome", async () => {
/* 객체 생성 후 */
const offer = await myPeerConnection.createOffer();
myPeerConnection.setLocalDescription(offer);
/* 입장한 사람에게 보내기 */
console.log("sent the offer")
socket.emit("offer", offer, roomName);
});
참조 : https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer
룸에 입장한 사용자는 Offer 생성 후 Local에 등록 후 동일 룸의 타 Peer에게 전달해준다.
wsServer.on("connection", socket => {
/* offer 받음 - (App.js) offer remote 등록 후 answer 제공해줌 */
socket.on("offer", (offer, roomName) => {
socket.to(roomName).emit("offer", offer);
});
}
사용자로부터 Offer과 roomName을 받아서 동일 룸 내의 다른 Peer에게 전송해준다.
socket.on("offer", async (offer) => {
console.log("received the offer");
myPeerConnection.setRemoteDescription(offer);
const answer = await myPeerConnection.createAnswer();
myPeerConnection.setLocalDescription(answer);
console.log("sent the answer");
socket.emit("answer", answer, roomName);
});
Offer를 받은 타 Peer들은 remote에 등록하고 자신의 Answer을 생성해서 Local에 저장 후 돌려준다.
wsServer.on("connection", socket => {
/* answer 받음 - (App.js) answer remote 등록 */
socket.on("answer", (answer, roomName) => {
socket.to(roomName).emit("answer", answer);
});
}
서버에서 Answer을 받은 후 Answer 생성자 제외 타 Peer에 전달한다.
(현재는 P2P 구현이니까 Offer 준 Peer에게만 가는 것임)
socket.on("answer", (answer)=>{
console.log("Received the Answer");
myPeerConnection.setRemoteDescription(answer);
});
Answer 받아서 Remote에 등록해준다.
엄청난 핑퐁이다...
비디오 바꿀 경우
async function handleCameraChange(){
await getMedia(camerasSelect.value);
/* 다른 Peer에 있는 my track 바꾸기 */
if(myPeerConnection){
const videoTrack = myStream.getVideoTracks()[0];
const videoSender = myPeerConnection.getSenders().find((sender) => sender.track.kind === "video");
videoSender.replaceTrack(videoTrack);
}
}
myPeerConnection에 등록된 Sender의 비디오를 바꿔준다. Peer 사전 등록하니까 편리한 기능이 많네요ㅋㅋㅋ
문서 : https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpSender/replaceTrack
'프로젝트 > Zoom (WebRTC)' 카테고리의 다른 글
[8] 결과 - WebRTC + Socket.IO를 이용한 스트리밍 서비스 (0) | 2023.04.11 |
---|---|
[7] 채팅 구현하기 + 인원 수 조절 (0) | 2023.04.10 |
[5] Video 및 Audio 출력하기 (0) | 2023.04.10 |
[4] Socket.IO 사용 - Room 생성 및 닉네임, 메세지 출력 (0) | 2023.03.08 |
[3] Chat 기능 구현 및 소켓에 Nickname 부여 (0) | 2023.03.04 |