문제 배경
좀 더 원할한 디버깅을 위해서 기존의 모놀리식 WebRTCComponent를 여러 hook으로 분리하는 모듈화 작업을 진행했습니다. 모듈화 이전에는 정상 작동하던 화상연결이 모듈화 이후 여러 문제를 발생시켰습니다.
발생한 문제들 (시간순)
1차 문제: 화면 자체가 표시되지 않음
// 참가자 정보는 정상적으로 업데이트됨
[Participants] Updated list: (2) [{...}, {...}]
// 하지만 remoteStreams는 비어있음
VideoGrid render: {remoteStreamsArray: Array(0)}
원인 분석
handleTrack 함수에서 참가자의 senderId를 못 받아오는 현상 발견
- 모듈화 과정에서 WebRTC peer connection의 메타데이터(senderId) 전달 누락
시도한 해결방법
- event에 직접 senderId 할당 시도
peerConnection.current.ontrack = (event) => {
event.senderId = peerConnection.current.senderId; // ❌ 실패: event는 읽기 전용
onTrack(event);
};
- event 복제 후 데이터 추가 시도
peerConnection.current.ontrack = (event) => {
const enhancedEvent = { ...event }; // ❌ 실패: 얕은 복사로 인한 문제
enhancedEvent.senderId = peerConnection.current.senderId;
onTrack(enhancedEvent);
};
- 새로운 객체로 감싸서 전달 (최종 해결)
peerConnection.current.ontrack = (event) => {
const enhancedEvent = {
...event,
senderId: peerConnection.current.senderId,
streams: event.streams,
track: event.track
};
onTrack(enhancedEvent);
};
2차 문제: 검은 화면으로 표시
1차 문제 해결 후, 화면은 표시되지만 검은색으로만 보이는 현상 발생
원인 분석
로그 확인 결과:
// 첫 번째 스트림 생성 시
[RemoteStream] New stream created: {
id: '6ff418c8-...',
active: true,
tracks: Array(2)
}
// 두 번째 스트림 생성 시
[RemoteStream] New stream created: {
id: '0c6c40f2-...',
active: false, // 문제 발견
tracks: Array(2)
}
- 동일 트랙으로 여러 스트림이 생성되며 활성 상태가 손실되는 현상 확인
시도한 해결방법
- enabled 상태만 변경
stream.getTracks().forEach(track => {
track.enabled = true;
}); // ❌ 실패: 스트림 자체는 여전히 비활성
- 새 스트림에 트랙 직접 추가
const newStream = new MediaStream();
stream.getTracks().forEach(track => {
newStream.addTrack(track);
}); // ❌ 실패: 참조 문제로 인해 동일 현상 발생
- 트랙 클론 후 새 스트림 생성 (최종 해결)
const updateRemoteStream = useCallback((senderId, stream, userName) => {
if (!senderId || !stream) return;
setRemoteStreams(prev => {
const newStreams = new Map(prev);
// 기존 스트림 정리
const existingStream = newStreams.get(senderId);
if (existingStream?.stream) {
existingStream.stream.getTracks().forEach(track => track.stop());
}
// 새 스트림 생성
const clonedTracks = stream.getTracks().map(track => track.clone());
const newStream = new MediaStream(clonedTracks);
// 모든 트랙 활성화
clonedTracks.forEach(track => track.enabled = true);
newStreams.set(senderId, {
stream: newStream,
userName
});
return newStreams;
});
}, []);
교훈
-
모듈화 시 데이터 흐름 주의
- 컴포넌트 분리 시 메타데이터 전달 계획 필수
- 상태 관리 및 이벤트 전달 구조 명확히 설계 필요
-
WebRTC 객체의 특성 이해
- Event 객체의 불변성 주의
- MediaStream과 MediaStreamTrack의 생명주기 이해 중요
- 참조 vs 복사 차이 이해 필요
-
디버깅 용이성
- 모듈화로 인해 문제 발생 지점 파악이 더 수월
- 각 모듈별 상세 로깅의 중요성
-
코드 리팩토링 전략
- 큰 변화는 단계적으로 진행
- 각 단계별 테스트 필요성
- 이전 상태로의 롤백 계획 필요
향후 과제
- 3인 이상 다중 연결 시 발생하는 문제 해결 필요
- WebSocket 연결 불안정 시 재연결 로직 개선 필요
- ICE Candidate 처리 로직 최적화 필요
#WebRTC #Refactoring #BugFix #P2P
문제 배경
좀 더 원할한 디버깅을 위해서 기존의 모놀리식 WebRTCComponent를 여러 hook으로 분리하는 모듈화 작업을 진행했습니다. 모듈화 이전에는 정상 작동하던 화상연결이 모듈화 이후 여러 문제를 발생시켰습니다.
발생한 문제들 (시간순)
1차 문제: 화면 자체가 표시되지 않음
원인 분석
handleTrack함수에서 참가자의 senderId를 못 받아오는 현상 발견시도한 해결방법
2차 문제: 검은 화면으로 표시
1차 문제 해결 후, 화면은 표시되지만 검은색으로만 보이는 현상 발생
원인 분석
로그 확인 결과:
시도한 해결방법
교훈
모듈화 시 데이터 흐름 주의
WebRTC 객체의 특성 이해
디버깅 용이성
코드 리팩토링 전략
향후 과제
#WebRTC #Refactoring #BugFix #P2P