How the OpenAI Realtime API Integrates with the Speech‑to‑Speech Pipeline: Architecture and Code Guide
The OpenAI Realtime API integrates with the Hugging Face speech‑to‑speech pipeline through a WebSocket‑based bridge that converts OpenAI events into internal pipeline handlers, using a shared RuntimeConfig state object to synchronize VAD, STT, LLM, and TTS components across the audio‑in → transcribe → generate → synthesize flow.
The huggingface/speech-to-speech repository provides a production‑ready implementation that can replace or augment OpenAI's native Realtime API service. This article breaks down how the integration works at the source code level, from WebSocket handling to pipeline orchestration.
Core Integration Components
The OpenAI Realtime API integration comprises four tightly‑coupled modules that bridge external WebSocket connections with internal speech processing:
| Component | Role | Source File |
|---|---|---|
| RuntimeConfig | Mutable session state mirroring OpenAI's RealtimeSessionCreateRequest |
src/speech_to_speech/api/openai_realtime/runtime_config.py |
| RealtimeService | Event dispatcher parsing WebSocket events and emitting pipeline events | src/speech_to_speech/api/openai_realtime/service.py |
| WebSocket Router | FastAPI endpoint connecting external clients to the internal service | src/speech_to_speech/api/openai_realtime/websocket_router.py |
| Pipeline Builder | Constructs handler chains (VAD → STT → LLM → TTS) wired to the service | src/speech_to_speech/s2s_pipeline.py |
RuntimeConfig: The Shared Session State
In runtime_config.py, the RuntimeConfig class serves as the canonical source of truth for all pipeline parameters. It mirrors OpenAI's RealtimeSessionCreateRequest schema and provides thread‑safe access to:
- Turn detection settings —
turn_detection_enabled,interrupt_response_enabled - Audio format negotiation — input/output sample rates, encoding
- Chat history — conversation items for context preservation
The GIL guarantees atomic attribute writes, eliminating the need for explicit locks when handlers read or update configuration.
RealtimeService: Event Translation Layer
The service.py module implements RealtimeService, which translates between OpenAI's WebSocket protocol and internal pipeline events. Key methods include:
parse_client_event()— deserializes JSON events (InputAudioBufferAppend,ConversationItemCreate,SessionUpdate)dispatch_pipeline_event()— routes parsed data to appropriate handlersbuild_session_created()/build_session_updated()— constructs server‑side response events
This translation enables features like barge‑in interruption: when RuntimeConfig.interrupt_response_enabled is true, the VAD handler can signal the TTS handler to abort ongoing synthesis.
WebSocket Router and Pipeline Unit
The websocket_router.py exposes the /v1/realtime endpoint. Per connection, it:
- Creates a
RealtimeServerinstance from a connection pool - Registers a unique connection ID with
RealtimeService.register() - Instantiates a
PipelineUnitvia_build_realtime_pipeline_unit()ins2s_pipeline.py
Each PipelineUnit (defined in pipeline_unit.py) wraps the handler chain and maintains isolated state for concurrent connections.
Data Flow: From WebSocket to Synthesized Audio
Understanding the OpenAI Realtime API integration requires tracing how audio bytes become spoken responses:
- Client connects to
ws://host:8000/v1/realtimevia the FastAPI endpoint - Audio stream begins — PCM chunks arrive as
InputAudioBufferAppendevents - Service parses and dispatches —
RealtimeService.append_pcm()enqueues audio for VAD - VAD triggers STT — voice activity detection emits
PartialTranscriptionEvent - LLM generates text — transcription prompts the chat model, yielding
AssistantTextEvent - TTS synthesizes audio — text streams to the TTS handler, producing
AudioOutputchunks - Server events returned —
RealtimeServicepackages audio asAudioBufferAppendevents for the client
The entire pipeline operates on streaming data structures, minimizing latency between speech input and synthesized output.
Practical Implementation Examples
Running a Local Realtime Server
Start the complete pipeline with default handlers:
# Terminal 1: Start the server
python -m speech_to_speech.server \
--stt-handler whisper \
--llm-handler chat \
--tts-handler qwen3 \
--enable-realtime-api
# Terminal 2: Run the demo client
python scripts/listen_and_play_realtime.py \
--api-key $OPENAI_API_KEY \
--model gpt-4o-mini \
--voice "alloy"
The demo script in scripts/listen_and_play_realtime.py creates a WebSocketTransport that speaks the OpenAI Realtime protocol to your local server rather than OpenAI's hosted endpoint.
Programmatic Service Integration
For custom applications, instantiate components directly:
from speech_to_speech.api.openai_realtime.service import RealtimeService
from speech_to_speech.api.openai_realtime.runtime_config import RuntimeConfig
from speech_to_speech.s2s_pipeline import build_pipeline
# Initialize shared configuration
config = RuntimeConfig()
# Build the handler pipeline
pipeline = build_pipeline(
stt_handler="whisper",
llm_handler="chat",
tts_handler="qwen3",
runtime_config=config,
)
# Create service and register connection
service = RealtimeService(pipeline=pipeline, runtime_config=config)
connection_id = service.register()
# Stream audio data (normally from WebSocket)
service.append_pcm(
connection_id,
pcm_bytes=audio_chunk,
src_rate=16000
)
# Retrieve generated response events
response_events = service.begin_audio_response(connection_id)
This pattern mirrors websocket_router.py internals while enabling custom preprocessing or postprocessing.
Dynamic Session Updates
Modify behavior mid‑conversation using OpenAI‑compatible session updates:
from speech_to_speech.api.openai_realtime.runtime_config import RuntimeConfig
from openai.types.realtime.realtime_session_create_request import RealtimeSessionCreateRequest
# Construct partial update (unset fields preserved)
update = RealtimeSessionCreateRequest(
turn_detection=TurnDetection(
type="server_vad",
interrupt_response=False # Disable barge‑in
)
)
# Apply atomically to shared config
service.runtime_config.apply_session_update(update)
The apply_session_update() method in runtime_config.py performs a shallow merge, preserving existing values for unspecified fields.
Handler Configuration for Realtime Pipelines
The build_pipeline() function in s2s_pipeline.py accepts handler specifications that determine latency and quality tradeoffs:
| Handler | Role | Typical Latency |
|---|---|---|
silero_vad / pyannote_vad |
Voice endpoint detection | 100-300ms |
whisper / faster_whisper |
Speech-to-text transcription | 200-800ms |
chat / mlc_chat |
LLM text generation | 50-500ms/token |
qwen3 / mimic3 |
Text-to-speech synthesis | 50-200ms/chunk |
These handlers communicate through PipelineUnit queues, with backpressure management to prevent memory growth during long conversations.
Summary
- The OpenAI Realtime API integration centers on
RealtimeServiceinservice.py, which translates WebSocket events to internal pipeline events RuntimeConfigprovides thread‑safe, shared state across all pipeline handlers, enabling dynamic features like interruptible responses- The WebSocket router (
websocket_router.py) manages connection lifecycle, instantiating isolatedPipelineUnitinstances per client - Handler chains are constructed via
build_pipeline()ins2s_pipeline.py, with VAD, STT, LLM, and TTS stages interconnected through queue-based streaming - Full OpenAI protocol compatibility allows drop‑in replacement of hosted Realtime API with local or self‑hosted infrastructure
Frequently Asked Questions
What OpenAI Realtime events does the pipeline support?
The implementation handles SessionCreate, SessionUpdate, ConversationItemCreate, InputAudioBufferAppend, and ResponseCreate events from clients, and emits SessionCreated, SessionUpdated, ConversationItemCreated, and AudioBufferAppend events in response. Unsupported events are logged and discarded rather than raising errors.
Can I use custom STT or TTS models with the Realtime API integration?
Yes. The build_pipeline() function accepts any handler registered in the HANDLER_REGISTRY. Pass stt_handler="your_custom_stt" or implement a handler matching the BaseSTTHandler interface in src/speech_to_speech/handlers/base.py. The pipeline will wire your custom handler into the Realtime event flow automatically.
How does barge‑in interruption work technically?
When RuntimeConfig.interrupt_response_enabled is true, the VAD handler monitors for new speech during TTS playback. Upon detection, it emits an InterruptEvent that the PipelineUnit routes to the TTS handler's abort() method. The TTS handler clears its synthesis queue, and RealtimeService sends a ResponseCancelled event to the client, allowing immediate LLM processing of the new utterance.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →