Candidate State

Candidate State


프로젝트를 실제로 구현하다 보면 Candidate의 상태 중 NewCompleted만 보게 되는데 찾아보니 더 다양한 상태가 있었다.

state desc
New (새로운 상태)
  • • 새로운 ICE Candidate가 생성되었을 때의 초기 상태.
  • • 아직 연결 시도가 이루어지지 않은 상태.

Checking

(확인 중 상태)

  • • Candidate를 사용하여 연결을 시도하고 있는 상태.
  • • STUN/TURN 서버를 통해 연결 가능성을 확인하는 과정이 포함 된다.

Succeeded

(성공 상태)

  • • 해당 Candidate를 통한 연결이 성공적으로 이루어진 상태.
  • • 이 상태의 Candidate가 선택되어 실제 통신에 사용된다.

Failed

(실패 상태)

  • • Candidate를 통한 연결 시도가 실패한 상태.
  • • 네트워크 문제, 방화벽 설정 등 다양한 이유로 실패할 수 있다.

Frozen

(동결 상태)

• 다른 Candidate의 확인이 진행 중일 때, 대기 상태에 있는 Candidate의 상태.

• 네트워크 리소스를 효율적으로 사용하기 위해 일시적으로 확인을 미루는 상태.

Waiting

(대기 상태)

• Frozen 상태에서 전환된 후, 곧 확인될 예정인 Candidate의 상태.

• 우선순위에 따라 Checking 상태로 전환되기를 기다린다.

In Progress

(진행 중 상태)

• 로컬에서 생성된 Candidate가 원격 피어로 전송 중인 상태.

Completed

(완료 상태)

• 모든 Candidate의 확인이 완료된 상태.

• 이 상태에서는 더 이상 새로운 Candidate를 확인하지 않는다.

정보 수집 과정


PeerConnection을 구현하기 위해서는 순서가 중요하다. 먼저, RTCPeerConnection 객체를 생성한 직후 addTrack을 호출하여 해당 미디어에 대한 정보를 수집한다. 이 과정에서 RTCPeerConnection은 사용 가능한 네트워크 경로와 프로토콜을 파악하게 된다.

그 다음, createOffer 또는 createAnswer 메서드를 호출하여 SDP(Session Description Protocol)를 생성한다. SDP는 미디어 스트림의 속성과 형식을 설명하는 프로토콜이다.

🌟  
useRef를 사용하여 RTCPeerConnection을 저장하는 이유

• 컴포넌트가 리렌더링되더라도 useRef의 값은 보존된다.

• useRef의 값이 변경되어도 컴포넌트가 리렌더링되지 않는다.

• 비동기 콜백 내에서도 항상 최신의 RTCPeerConnection 인스턴스에 접근할 수 있다.

• 컴포넌트가 언마운트될 때 peer.current를 통해 RTCPeerConnection을 쉽게 정리할 수 있다.

const peer = useRef(null);
const { getMedia } = useGetMedia(); // get peer stream hook

const stream = await getMedia();
peer.current = new RTCPeerConnection(configuration);

stream.getTracks().forEach((track) => {
  if (peer.current) peer.current.addTrack(track, stream);
});

트랙이 추가된 이후 ICE후보 생성이 시작된다. 이 과정에서 onicecandidate 이벤트가 발생하며, 각 ICE 후보가 생성될 때마다 이 이벤트가 트리거된다.
addTrack을 호출하지 않을경우, peer.current는 null값을 가지게 된다.

peer.current.onicecandidate = (e) => {
  if (e.candidate) {
    console.log("setupPeerListeners - onicecandidate : ", e.candidate);
    socketClient.onEmit("candidate", { candidate: e.candidate });
  }
};

다음은 생성된 ICE Candidate에 대해 분석해 본다.

"sdpMid": "3"
• 이 후보와 관련된 미디어 스트림의 식별자.
• “3”은 SDP(Session Description Protocol)에서 이 후보가 네 번째 미디어 섹션에 해당함을 나타낸다.
"sdpMLineIndex":
• SDP의 미디어 라인 인덱. 여기서도 3은 네 번째 미디어 섹션을 가리킨다.
"usernameFragment":
• “h8Lg”은 ICE 프로세스에서 사용되는 사용자 이름 조각.
• 이는 “ufrag” 값과 일치하며, 연결의 특정 세션을 식별하는 데 사용된다

다음으로, 원격 피어의 미디어 스트림(비디오/오디오)을 받아 처리하는 ontrack 핸들러를 설정하여 원격 피어로부터 미디어 스트림을 받을 준비를 한다.
setRemote 함수를 통해 받은 스트림을 애플리케이션의 상태에 저장하여, UI에서 표시할 수 있다.

peer.current.ontrack = (ev) => {
  setRemote((prev) => ({ ...prev, stream: ev.streams[0] }));
};

WebRTC React ICE Candidate