콘텐츠로 이동

이벤트·세션 제어

클라이언트 제어 이벤트는 WebRTC 데이터채널 oai-events의 JSON 메시지로 오갑니다. 오디오는 데이터채널의 base64 payload가 아니라 RTP 트랙을 사용합니다. Gateway는 데이터채널이 열리기 전에 발생한 서버 이벤트를 제한된 큐에 보관한 뒤 open 시 순서대로 전송합니다.

클라이언트 → Gateway → /sohri

클라이언트 이벤트 백엔드 동작
session.update 언어·EPD·DM 파라미터 또는 conversation engine을 검증·전달하고 session.updated 회신
conversation.item.create input_text를 text{message}로 전달
response.create 최초 선인사 또는 현재 자동 DM lifecycle과 연결; OpenAI 엔진이면 realtime_event로 전달
response.cancel / cancel_response 백엔드에 cancel_response, 로컬 playout 취소
output_audio_buffer.clear 대기 playout 무효화 후 output_audio_buffer.cleared 회신
input_audio_buffer.* 무해하게 폐기; 실제 입력은 RTP→PCM 경로

지원하지 않는 타입과 내용 없는 입력은 연결을 끊지 않고 무해하게 폐기할 수 있습니다. 단, JSON 구문 오류·파라미터 충돌·범위 오류는 데이터채널 error로 알려 줍니다.

/sohri → Gateway → 클라이언트

백엔드는 표준 봉투 {type,data,timestamp}, 클래스명 봉투, top-level raw event를 혼용합니다. Gateway가 이를 정규화한 뒤 다음 핵심 이벤트를 변환합니다.

/sohri 이벤트 데이터채널 이벤트
connection_established session.created
speech_candidate[_cancelled] sohri.speech_candidate[_cancelled]
speech_started 계열 input_audio_buffer.speech_started
stop_recording 계열 input_audio_buffer.speech_stopped
stt_result conversation.item.input_audio_transcription.completed
dm_processing response.created
dialog_response transcript delta/done과 response.done lifecycle
dialog_text 첫 가청 TTS 시점의 sohri.dialog_text
dm_scenario_updated 적용값을 담은 session.updated
conversation_session_updated 엔진 ACK를 담은 session.updated
realtime_event{event} 내장 provider 이벤트를 원형 전달
분석·대화 완료 sohri.analysis.*, sohri.dialog_complete
오류 계열 OpenAI 형태의 error

전체 필드와 커스텀 이벤트는 엔드포인트·이벤트 참조를 확인하세요.

session.update와 엔진 선택

권장 확장 위치는 session.sohri입니다.

{
  "type": "session.update",
  "session": {
    "sohri": {
      "conversationEngine": "openai_realtime",
      "instructions": "간결하게 답하세요.",
      "externalUser": {"id": "user-42"}
    }
  }
}

현재 통합 브랜치의 엔진 상태 전이는 다음과 같습니다.

  1. 미지정 엔진은 sohri입니다.
  2. openai_realtime 선택 시 Gateway가 conversation_session_update를 WSS로 보냅니다.
  3. 백엔드의 conversation_session_updated ACK 뒤에만 runtime을 활성화합니다.
  4. 초기 ACK 대기 중 session.update는 최신 snapshot으로 병합되고 response.create는 마지막 하나만 보류됩니다.
  5. 최초 설정 실패·timeout·ACK 불일치는 오류 후 세션 종료입니다. ready 이후 재설정 실패는 마지막 승인 snapshot으로 복구해 통화를 유지합니다.
  6. 세션이 시작된 뒤 엔진을 다른 값으로 바꿀 수 없습니다.

instructions는 session.sohri.instructions 또는 top-level sohri.instructions에서만 받으며 12,000 UTF-16 code unit 이하입니다. OpenAI 표준 session.instructions나 URL 쿼리는 이 값의 입력 경로가 아닙니다. openai_realtime은 DM scenario, botFirst, SOHRI TTS 선택 파라미터와 동시에 사용할 수 없습니다.

SOHRI 응답 lifecycle

Gateway는 backend 이벤트에 응답 ID를 부여해 response.created, transcript, TTS stream, response.done을 상관시킵니다. 사용자 텍스트 후에는 socket-backend가 자동으로 DM 응답을 시작하므로 추가 response.create가 새 선인사를 만들지 않습니다. response.cancel은 활성 응답과 현재 playout을 함께 취소하며 terminal 이벤트가 오지 않을 때를 위한 제한된 fallback이 있습니다.

dm_scenario_update의 scenarioGraph는 DataChannel message 상한과 backend WSS 64 KB 계약을 넘지 않아야 합니다. 병합 결과가 상한을 넘으면 상태를 적용하거나 WSS로 보내지 않고 scenario_graph_too_large 오류를 돌려줍니다.

OpenAI 엔진 패스스루

OpenAI 엔진에서도 Gateway가 공급자에 직접 연결하지 않습니다. socket-backend가 provider WebSocket을 소유하고 다음을 중계합니다.

  • JSON: realtime_event{event} ↔ oai-events
  • 오디오: tts_stream_start와 raw PCM ↔ 공통 Opus playout
  • 중단: realtime_playback_interrupt → 로컬 재생 취소 → realtime_playback_truncated{itemId,audioEndMs}

audioEndMs는 가청 샘플만 센 값이 아니라 무음을 포함해 실제 트랙에 기록한 재생 timeline입니다.