Stream과 RTP의 관계 — Cloud Recording 디버깅에서 헷갈리지 않는 법
stream은 논리적인 미디어 흐름이고 RTP는 그 미디어를 네트워크로 운반하는 패킷 프로토콜입니다. 하지만 WebRTC API의 MediaStream, Agora 운영 문맥의 stream, RTP의 SSRC packet stream은 같은 말이 아닙니다. 이 글은 track, stream, RTP, RTCP의 층위를 분리하고, muteLocalVideoStream, enableLocalVideo, stopPreview, leaveChannel이 Cloud Recording에서 어떻게 다르게 보이는지 검증된 기준으로 정리합니다.
WebRTC나 Agora Cloud Recording을 보다 보면 track, stream, RTP, RTCP가 한꺼번에 튀어나옵니다. 다 미디어와 관련된 말이라 비슷해 보이지만, 실제로는 서로 다른 층의 개념입니다.
결론부터 말하면 이렇습니다.
서비스 문맥의 stream은 "사용자가 보내는 논리적인 미디어 흐름"이고, RTP는 그 미디어를 네트워크로 운반하는 패킷 프로토콜입니다.
다만 여기서 조심해야 할 점이 하나 있습니다. WebRTC 표준 API에서 MediaStream은 track을 묶는 객체이고, 실제 송수신의 중심은 MediaStreamTrack과 RTCRtpSender/RTCRtpReceiver입니다. 반면 현장에서 "Agora stream", "host stream", "video stream"이라고 말할 때는 제품/운영 문맥의 논리적인 송출 흐름을 뜻하는 경우가 많습니다.
이 둘을 섞으면 Cloud Recording idle, mute, host 퇴장 같은 이슈를 잘못 해석하게 됩니다.
1. 먼저 큰 그림
일반적인 실시간 미디어 흐름은 이렇게 볼 수 있습니다.
표로 정리하면 더 선명합니다.
| 개념 | 계층 | 의미 |
|---|---|---|
MediaStreamTrack | 브라우저/API | 하나의 오디오 또는 비디오 소스 |
MediaStream | 브라우저/API | track들을 묶는 그룹 |
| Agora stream | 제품/운영 | 특정 UID가 publish한 오디오/비디오 흐름 |
| RTP packet | 네트워크 전송 | encoded audio/video를 잘게 나눈 패킷 |
| RTCP | 제어/통계 | 수신 품질, packet loss, jitter, sender/receiver report |
한 줄 비유로는 이렇게 설명할 수 있습니다.
2. WebRTC에서 정확한 단위는 track이다
브라우저 WebRTC에서 카메라와 마이크를 가져오면 보통 MediaStream 안에 MediaStreamTrack들이 들어 있습니다.
여기서 중요한 건 addTrack()입니다. WebRTC의 전송 단위는 stream 전체가 아니라 track입니다.
MDN도 MediaStream을 여러 track으로 구성된 미디어 콘텐츠 stream이라고 설명하고, addTrack()은 peer connection에 전송할 media track을 추가한다고 설명합니다. 또한 RTCRtpSender는 특정 MediaStreamTrack이 어떻게 인코딩되고 remote peer로 전송되는지 제어하는 객체입니다.
즉 표준 API 관점에서는 이렇게 말하는 게 가장 정확합니다.
그런데 Agora나 RTC 운영 문맥에서는 여전히 "stream"이라는 말을 많이 씁니다.
예를 들어:
이때의 stream은 브라우저 객체 MediaStream만을 뜻하지 않습니다. 보통은 "어떤 UID가 채널에 publish한 미디어 흐름"이라는 제품 레벨 표현입니다.
3. RTP에서 stream은 SSRC로 식별되는 패킷 흐름에 가깝다
RTP 쪽으로 내려가면 stream이라는 말은 다시 더 낮은 의미가 됩니다.
RFC 3550은 RTP를 실시간 오디오/비디오 같은 데이터를 전송하기 위한 프로토콜로 정의합니다. RTP 패킷에는 payload type, sequence number, timestamp 같은 정보가 들어가고, 수신자는 이 정보를 이용해 패킷 순서와 재생 타이밍을 복원합니다.
RTP에서 특히 중요한 식별자는 SSRC입니다.
SSRC는 RTP 패킷 stream의 출처를 식별합니다. 예를 들어 한 사용자의 마이크에서 나온 오디오 RTP 패킷들은 같은 SSRC와 같은 timing/sequence number 공간에 묶일 수 있습니다.
그래서 RTP 레벨에서 더 정확한 표현은 이렇습니다.
서비스 문맥의 "video stream"과 RTP 문맥의 "RTP stream"은 연결되어 있지만, 같은 말은 아닙니다.
4. RTCP는 media가 아니라 상태 리포트다
RTP가 미디어 데이터를 운반한다면, RTCP는 그 전송 상태를 관찰하고 조정하기 위한 control protocol입니다.
대표적으로 다음 정보가 RTCP 계층에서 다뤄집니다.
- packet loss
- jitter
- 송신자/수신자 report
- participant 식별 정보
- BYE 같은 세션 종료 신호
그래서 디버깅할 때는 이렇게 나눠 봐야 합니다.
5. Agora에서 mute와 leave는 다른 문제다
Agora에서 영상이 안 보인다고 해서 모두 같은 상태는 아닙니다.
아래 네 가지는 결과 화면만 보면 비슷해 보일 수 있지만, 실제 위치가 다릅니다.
enableLocalVideo(false)
카메라 캡처 또는 로컬 비디오 기능 자체를 끄는 쪽에 가깝습니다.
muteLocalVideoStream(true)
로컬 video stream의 publish를 mute하는 쪽입니다.
stopPreview()
로컬 preview 렌더링을 멈추는 동작입니다.
이 API를 "송출 중단"으로 이해하면 위험합니다. 로컬 화면에서 안 보이는 것과 네트워크로 안 나가는 것은 다른 층의 문제입니다.
leaveChannel()
채널에서 나가는 동작입니다.
Cloud Recording에서는 이 차이가 특히 중요합니다.
6. Cloud Recording은 RTP packet 하나하나가 아니라 채널 상태와 publish 상태를 본다
Agora Cloud Recording은 서버 사이드 recorder가 RTC channel에 들어가서 오디오/비디오를 녹화하는 구조입니다. 로컬 Agora 레퍼런스 기준으로 lifecycle은 다음 순서입니다.
그리고 전제는 active RTC channel과 participants입니다. 시작 시점에 사용자가 없으면 435 No users in channel 같은 에러가 발생할 수 있습니다.
여기서 흔한 오해가 나옵니다.
그렇게 단순하지 않습니다.
Cloud Recording 관점에서 먼저 봐야 하는 것은 보통 다음 세 가지입니다.
Agora Support 문서 기준으로 Cloud Recording은 recording channel에 사용자가 없는 상태가 일정 시간 지속되면 자동으로 stop하고 leave할 수 있으며, 기본값은 30초입니다. 이 시간은 maxIdleTime으로 조정할 수 있습니다.
또 다른 Agora Support 문서는 Acquire/Start가 200 OK를 반환했더라도 녹화 파일이 생성되지 않을 수 있는 원인으로 "recorder가 join한 뒤 channel에서 아무도 audio/video stream을 publish하지 않은 경우"를 설명합니다.
따라서 Cloud Recording 디버깅은 이렇게 정리하는 편이 안전합니다.
| 상태 | 해석 |
|---|---|
| channel에 사용자가 없음 | recorder가 녹화할 participant 자체가 없음 |
| 사용자는 있지만 publish된 audio/video가 없음 | session은 시작됐지만 결과 파일이 없을 수 있음 |
| host가 channel에 있지만 video만 mute | audio만 녹화되거나, video 없는 결과가 될 수 있음 |
host가 leaveChannel() 호출 | mute가 아니라 channel presence 종료 |
stopPreview()만 호출 | 로컬 미리보기 문제일 수 있으므로 publish 상태를 별도로 확인해야 함 |
7. "RTP packet 없음"과 "녹화 idle"은 같은 말이 아니다
운영 로그에서 "media packet이 없다"는 말과 "recording이 idle이다"는 말을 같은 뜻으로 쓰면 사고가 납니다.
예를 들어 사용자가 채널에 남아 있지만 카메라와 마이크를 모두 mute한 상태를 생각해봅니다.
반대로 사용자가 아예 나간 경우는 다릅니다.
둘 다 RTP packet은 없을 수 있지만, 원인은 다릅니다.
그래서 장애 분석에서는 "packet이 없다"에서 멈추면 안 됩니다. 반드시 한 단계 위의 상태를 같이 봐야 합니다.
8. 실무 디버깅 순서
Cloud Recording에서 "녹화가 비었다" 또는 "idle로 끝났다"는 이슈를 보면 이 순서로 확인합니다.
1단계: channel presence
이 단계는 RTP보다 위입니다. 사용자가 없으면 media packet도 있을 수 없습니다.
2단계: publish 상태
Agora live channel에서는 host와 audience 역할이 중요합니다. audience는 기본적으로 시청자이고, publish 주체는 host입니다.
3단계: recorder 설정
channelType이 맞지 않거나 subscribe 대상이 잘못되면 사용자가 publish 중이어도 recorder가 기대한 stream을 못 받을 수 있습니다.
4단계: media packet과 stats
이 단계에서 RTP/RTCP 관찰이 의미가 있습니다. 즉 RTP는 가장 먼저 볼 대상이 아니라, presence와 publish 상태를 확인한 뒤 내려가서 보는 전송 계층 증거입니다.
9. 정리
stream과 RTP의 관계는 이렇게 정리하면 됩니다.
가장 중요한 한 문장은 이것입니다.
RTP는 stream을 운반하는 네트워크 조각이고, Cloud Recording 디버깅은 RTP packet 단위가 아니라 channel presence, host role, publish/subscription 상태에서 시작해야 합니다.