제6장: Phase 3 - 스트리밍 프로토콜
"실시간 감정 분석은 라이브 상호작용, 화상 회의, 게임, 운전자 모니터링 등에서 필수적입니다. Phase 3는 지연 시간을 최소화하고 연속적인 감정 데이터 스트림을 제공하는 WebSocket 프로토콜을 정의합니다."
6.1 실시간 WebSocket 프로토콜
6.1.1 연결 설정
# WebSocket 연결 URL
wss://stream.{provider}.com/wia/emotion/v1/stream
# 연결 요청 예시
GET /wia/emotion/v1/stream HTTP/1.1
Host: stream.provider.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Authorization: Bearer {access_token}
X-WIA-Version: 1.0.0
6.1.2 핸드셰이크 프로세스
| 단계 |
방향 |
메시지 |
| 1 |
클라이언트 → 서버 |
WebSocket 업그레이드 요청 |
| 2 |
서버 → 클라이언트 |
101 Switching Protocols |
| 3 |
클라이언트 → 서버 |
세션 초기화 (session.start) |
| 4 |
서버 → 클라이언트 |
세션 확인 (session.started) |
| 5 |
양방향 |
데이터 스트리밍 시작 |
6.1.3 세션 초기화
// 클라이언트 → 서버: 세션 시작
{
"type": "session.start",
"session_id": "client-generated-uuid",
"timestamp": "2025-01-15T14:30:00.000Z",
"config": {
"modalities": ["facial", "voice"],
"facial_config": {
"frame_rate": 15,
"detect_action_units": true,
"detect_micro_expressions": true,
"resolution": "640x480"
},
"voice_config": {
"sample_rate": 16000,
"encoding": "LINEAR16",
"language": "ko-KR"
},
"output_config": {
"include_dimensional": true,
"include_raw_scores": false,
"confidence_threshold": 0.5,
"emit_interval_ms": 100
}
}
}
// 서버 → 클라이언트: 세션 확인
{
"type": "session.started",
"session_id": "server-assigned-session-id",
"timestamp": "2025-01-15T14:30:00.050Z",
"config_applied": {
"modalities": ["facial", "voice"],
"max_frame_rate": 15,
"session_timeout_seconds": 3600
},
"server_info": {
"version": "1.0.0",
"region": "ap-northeast-2"
}
}
6.2 이벤트 기반 스트리밍
6.2.1 메시지 타입
| 타입 |
방향 |
설명 |
| session.start |
C → S |
세션 초기화 요청 |
| session.started |
S → C |
세션 초기화 확인 |
| data.frame |
C → S |
비디오/오디오 프레임 전송 |
| emotion.event |
S → C |
감정 분석 결과 |
| emotion.aggregate |
S → C |
집계된 감정 요약 |
| heartbeat.ping |
양방향 |
연결 유지 핑 |
| heartbeat.pong |
양방향 |
핑 응답 |
| session.end |
C → S |
세션 종료 요청 |
| session.ended |
S → C |
세션 종료 확인 |
| error |
S → C |
오류 알림 |
6.2.2 데이터 프레임 전송
// 비디오 프레임 전송
{
"type": "data.frame",
"modality": "facial",
"timestamp": "2025-01-15T14:30:01.000Z",
"sequence": 150,
"data": {
"frame": "{base64_encoded_frame}",
"format": "jpeg",
"resolution": "640x480"
}
}
// 오디오 청크 전송
{
"type": "data.frame",
"modality": "voice",
"timestamp": "2025-01-15T14:30:01.000Z",
"sequence": 450,
"data": {
"audio": "{base64_encoded_audio_chunk}",
"encoding": "LINEAR16",
"duration_ms": 100
}
}
6.2.3 감정 이벤트 수신
// 서버 → 클라이언트: 감정 이벤트
{
"type": "emotion.event",
"event_id": "evt-12345-abcde",
"timestamp": "2025-01-15T14:30:01.100Z",
"sequence": 150,
"latency_ms": 85,
"emotions": [
{
"category": "happiness",
"intensity": 0.78,
"confidence": 0.91
}
],
"action_units": [
{
"au": "AU6",
"intensity": 0.72,
"confidence": 0.89
},
{
"au": "AU12",
"intensity": 0.81,
"confidence": 0.93
}
],
"dimensional": {
"valence": 0.72,
"arousal": 0.55
},
"source_modality": "facial",
"face_detected": true,
"micro_expression": false
}
6.2.4 집계 이벤트
// 서버 → 클라이언트: 주기적 집계 (매 5초)
{
"type": "emotion.aggregate",
"timestamp": "2025-01-15T14:30:05.000Z",
"window_start": "2025-01-15T14:30:00.000Z",
"window_end": "2025-01-15T14:30:05.000Z",
"frame_count": 75,
"aggregate": {
"dominant_emotion": "happiness",
"emotion_distribution": {
"happiness": 0.65,
"neutral": 0.25,
"surprise": 0.10
},
"average_valence": 0.68,
"average_arousal": 0.52,
"emotional_stability": 0.85,
"engagement_score": 0.72
},
"modality_quality": {
"facial": {
"average_confidence": 0.88,
"frames_processed": 75,
"frames_dropped": 0
},
"voice": {
"average_confidence": 0.82,
"segments_processed": 50
}
}
}
6.3 프레임 레이트 및 지연시간 요구사항
6.3.1 프레임 레이트 권장사항
| 모달리티 |
최소 |
권장 |
최대 |
| 표정 분석 |
5 fps |
15 fps |
30 fps |
| 미세표정 |
25 fps |
30 fps |
60 fps |
| 음성 분석 |
100ms 청크 |
100ms 청크 |
50ms 청크 |
6.3.2 지연시간 요구사항
| 사용 사례 |
최대 지연시간 |
목표 지연시간 |
| 실시간 화상 통화 |
200ms |
100ms |
| 게임/인터랙션 |
100ms |
50ms |
| 운전자 모니터링 |
150ms |
75ms |
| 고객 서비스 |
500ms |
250ms |
| 녹화 분석 |
N/A |
실시간 아님 |
6.3.3 품질 vs 지연시간 트레이드오프
// 저지연 모드 설정
{
"type": "session.start",
"config": {
"mode": "low_latency",
"facial_config": {
"frame_rate": 15,
"detect_action_units": false,
"detect_micro_expressions": false,
"lightweight_model": true
},
"output_config": {
"include_dimensional": true,
"include_raw_scores": false,
"emit_interval_ms": 50
}
}
}
// 고품질 모드 설정
{
"type": "session.start",
"config": {
"mode": "high_quality",
"facial_config": {
"frame_rate": 30,
"detect_action_units": true,
"detect_micro_expressions": true,
"high_precision_model": true
},
"output_config": {
"include_dimensional": true,
"include_raw_scores": true,
"emit_interval_ms": 200
}
}
}
6.4 보안 및 인증
6.4.1 연결 보안
| 요구사항 |
사양 |
| 전송 암호화 |
TLS 1.3 필수 (최소 TLS 1.2) |
| WebSocket 보안 |
wss:// 프로토콜만 허용 |
| 인증서 |
신뢰할 수 있는 CA 발급 필수 |
| 암호화 스위트 |
AES-256-GCM, CHACHA20-POLY1305 |
6.4.2 인증 토큰
// JWT 토큰 구조
{
"header": {
"alg": "RS256",
"typ": "JWT"
},
"payload": {
"sub": "user-12345",
"iss": "https://auth.provider.com",
"aud": "wia-emotion-stream",
"iat": 1705329000,
"exp": 1705332600,
"scope": ["stream:read", "stream:write"],
"session_limit": 5,
"rate_limit": {
"frames_per_second": 30,
"max_concurrent_sessions": 3
}
},
"signature": "..."
}
6.4.3 세션 보안
// 보안 세션 설정
{
"type": "session.start",
"security": {
"encryption": {
"enable_payload_encryption": true,
"algorithm": "AES-256-GCM"
},
"consent": {
"user_consent_token": "{signed_consent_token}",
"consent_scope": ["emotion_analysis", "data_storage"],
"consent_timestamp": "2025-01-15T14:25:00.000Z"
},
"data_handling": {
"store_raw_data": false,
"anonymize_results": true,
"retention_period": "session_only"
}
}
}
6.5 오류 처리
6.5.1 오류 메시지 형식
{
"type": "error",
"error_code": "PROCESSING_FAILED",
"message": "프레임 처리에 실패했습니다",
"timestamp": "2025-01-15T14:30:05.000Z",
"details": {
"sequence": 155,
"modality": "facial",
"reason": "face_not_detected"
},
"severity": "warning",
"recoverable": true,
"action": "skip_frame"
}
6.5.2 오류 코드
| 오류 코드 |
심각도 |
설명 |
조치 |
| AUTH_EXPIRED |
critical |
인증 토큰 만료 |
재인증 필요 |
| SESSION_TIMEOUT |
critical |
세션 시간 초과 |
세션 재시작 |
| RATE_LIMITED |
warning |
속도 제한 초과 |
프레임 레이트 감소 |
| PROCESSING_FAILED |
warning |
프레임 처리 실패 |
프레임 건너뛰기 |
| MODALITY_UNAVAILABLE |
warning |
모달리티 일시 불가 |
다른 모달리티 사용 |
| QUALITY_LOW |
info |
입력 품질 낮음 |
품질 개선 권장 |
| SERVER_OVERLOAD |
critical |
서버 과부하 |
재연결 대기 |
6.5.3 재연결 프로토콜
// 재연결 로직
{
"reconnection_policy": {
"max_attempts": 5,
"backoff_strategy": "exponential",
"initial_delay_ms": 1000,
"max_delay_ms": 30000,
"backoff_multiplier": 2.0,
"jitter": 0.1
},
"session_resumption": {
"enabled": true,
"resume_token": "{session_resume_token}",
"resume_from_sequence": 155,
"max_gap_seconds": 30
}
}
6.6 연결 관리
6.6.1 하트비트
// 클라이언트 → 서버: 핑
{
"type": "heartbeat.ping",
"timestamp": "2025-01-15T14:30:30.000Z",
"client_sequence": 500
}
// 서버 → 클라이언트: 퐁
{
"type": "heartbeat.pong",
"timestamp": "2025-01-15T14:30:30.050Z",
"client_sequence": 500,
"server_sequence": 495,
"latency_ms": 50
}
6.6.2 세션 종료
// 클라이언트 → 서버: 세션 종료 요청
{
"type": "session.end",
"timestamp": "2025-01-15T15:00:00.000Z",
"reason": "user_initiated",
"request_summary": true
}
// 서버 → 클라이언트: 세션 종료 확인
{
"type": "session.ended",
"session_id": "session-12345",
"timestamp": "2025-01-15T15:00:00.100Z",
"duration_seconds": 1800,
"summary": {
"total_frames_processed": 27000,
"total_events_emitted": 18000,
"dominant_emotion": "neutral",
"average_engagement": 0.68,
"average_valence": 0.35
}
}
6.6.3 연결 상태
| 상태 |
설명 |
| connecting |
WebSocket 연결 시도 중 |
| authenticating |
인증 진행 중 |
| initializing |
세션 초기화 중 |
| streaming |
데이터 스트리밍 활성 |
| paused |
스트리밍 일시 중지 |
| reconnecting |
재연결 시도 중 |
| closing |
세션 종료 중 |
| closed |
연결 종료됨 |
6.7 요약
Phase 3는 실시간 감정 분석을 위한 WebSocket 스트리밍 프로토콜을 정의합니다:
- 연결 관리: 세션 초기화, 하트비트, 재연결
- 이벤트 스트리밍: 데이터 프레임 전송 및 감정 이벤트 수신
- 성능 요구사항: 프레임 레이트 및 지연시간 사양
- 보안: TLS 암호화, JWT 인증, 데이터 보호
- 오류 처리: 복구 가능한 오류 및 재연결 전략
홍익인간 (弘益人間): 널리 인간을 이롭게 하라
실시간 감정 분석은 교육, 헬스케어, 안전 등 다양한 분야에서 사람들을 도울 수 있습니다.
← 이전: 제5장 - Phase 2: API 인터페이스 | 다음: 제7장 - Phase 4: 통합 →