LiveKit은 WebRTC 기반의 SFU(Selective Forwarding Unit) 플랫폼으로, WebRTC 위에 룸 모델, 권한 관리, 확장 기능을 제공합니다. 순수 WebRTC P2P와 달리, 각 클라이언트가 SFU로 한 번만 업로드하고 SFU가 다른 참가자에게 선택적으로 전달하는 구조입니다.
“livekit-server-sdk만으로는 충분하지 않나요?”라는 질문을 자주 받습니다. 절대적으로 LiveKit 서버가 필요합니다!
livekit-server-sdk: JWT 토큰 생성, API 호출 등의 유틸리티 라이브러리
LiveKit 서버: WebRTC SFU 미디어 서버 (실제 통신 담당)
기능
livekit-server-sdk
LiveKit 서버
토큰 생성
✅
❌
WebRTC 연결
❌
✅
미디어 포워딩
❌
✅
LiveKit은 P2P가 아닌 SFU 방식이므로 중앙 미디어 서버가 반드시 필요합니다.
설정 파일 예시:
# livekit.yamlrtc: node_ip: "127.0.0.1" # localhost 강제 설정 port_range_start: 7882 port_range_end: 7892
2. WebRTC 구조와 LiveKit 매핑
2.1 WebRTC 핵심 구조 (기존 다이어그램)
flowchart LR
Signaling server for SDP and ICE exchange
SIG[Signaling server<br/>SDP and ICE exchange]
Between PeerConnections
PCA <-->|ICE connectivity checks| PCB
PCA <-->|DTLS handshake| PCB
Peer B mirrored, App at far right
subgraph PeerB[Peer B]
direction LR
PCB[RTCPeerConnection B]
AT_B[MediaStreamTrack<br/>audio]
VT_B[MediaStreamTrack<br/>video]
MSB[MediaStream]
DCB[RTCDataChannel]
AppB[App]
PCB -->|ontrack| AT_B
PCB -->|ontrack| VT_B
AT_B --> MSB
VT_B --> MSB
MSB --> AppB
PCB -->|ondatachannel| DCB
DCB <-->|file send and onmessage| AppB
end
2.2 LiveKit 3개 컴포넌트 매핑
WebRTC 구성 요소
LiveKit 컴포넌트
역할
Peer A App
Frontend (React)
사용자 인터페이스, 미디어 제어
Signaling Server
Backend + LiveKit Server
SDP/ICE 교환, 토큰 인증
RTCPeerConnection
LiveKit Client SDK
WebRTC 연결 추상화
Media Routing
LiveKit Server (SFU)
미디어 선택적 포워딩
🔑 핵심 차이점:
순수 WebRTC: Peer A ↔ Peer B (직접 P2P)
LiveKit: Frontend ↔ LiveKit Server ↔ Other Clients (SFU 중재)
3. 실제 통신 흐름
💡 JWT 토큰은 어떻게 전달되나요?
“Backend가 LiveKit 서버로 토큰을 중계하나요?”라는 질문을 받습니다. 아니요, Frontend가 직접 연결합니다!
sequenceDiagram
autonumber
participant User as 👤 사용자
participant Frontend as 🌐 Frontend<br/>(React)
participant Backend as 🖥️ Backend<br/>(Node.js)
participant LiveKit as 🎥 LiveKit Server<br/>(Docker/Cloud)
participant Other as 👥 다른 참가자
User->>Frontend: 룸 입장 요청
Frontend->>Backend: JWT 토큰 요청<br/>POST /api/token
Backend->>Backend: LiveKit Server SDK로<br/>JWT 토큰 생성
Backend->>Frontend: JWT 토큰 응답
Frontend->>LiveKit: 토큰과 함께<br/>WebSocket 연결
LiveKit->>Frontend: 연결 성공 응답<br/>(Room 상태 정보)
Frontend->>LiveKit: 로컬 미디어 트랙 전송<br/>(오디오/비디오)
LiveKit->>Other: 미디어 스트림<br/>선택적 포워딩
Other->>LiveKit: 원격 미디어 응답
LiveKit->>Frontend: 다른 참가자<br/>미디어 수신
Frontend->>User: 실시간 화상회의<br/>화면 표시
3.2 각 단계 상세 설명
사용자 룸 입장 요청: 웹 UI에서 방 이름과 참가자 이름 입력
JWT 토큰 요청: Frontend가 Backend API에 인증 토큰 요청
토큰 생성: Backend가 LiveKit Server SDK로 JWT 생성 (권한 포함)
sequenceDiagram
autonumber
participant Backend as 🤖 Backend Agent
participant LiveKit as 🎥 LiveKit Server
participant User as 👤 사용자
Backend->>Backend: AI 봇용 JWT 토큰 생성
Backend->>LiveKit: 토큰으로 룸 참가
LiveKit->>Backend: 연결 성공
User->>LiveKit: 음성 메시지 전송
LiveKit->>Backend: 음성 스트림 수신
Backend->>Backend: STT → LLM → TTS 파이프라인
Backend->>LiveKit: AI 응답 음성 전송
LiveKit->>User: AI 응답 재생
5.3 핵심 구현 예시
// AIBotAgent.ts 예시export class AIBotAgent { async joinRoom(roomName: string) { // 1. 봇용 토큰 생성 const token = new AccessToken(apiKey, apiSecret, { identity: 'AI-Assistant', name: 'Gemini Bot' }); // 2. 룸 참가 const room = new Room(); await room.connect(serverUrl, token); // 3. 이벤트 리스너 등록 room.on(RoomEvent.TrackSubscribed, this.handleAudioTrack); } private async handleAudioTrack(track: RemoteAudioTrack) { // STT → LLM → TTS 파이프라인 const text = await this.sttService.transcribe(track); const response = await this.llmService.generate(text); const audio = await this.ttsService.synthesize(response); // AI 응답 전송 await this.publishAudio(audio); }}