Azure OpenAI Realtime Audio SDK

repository·main·Indexed 21 days ago

https://github.com/azure-samples/aoai-realtime-audio-sdk

Documentation, libraries, and samples for the Azure OpenAI /realtime API, enabling low-latency, multimodal (audio/text) conversational interactions using the GPT-4o model family via WebSockets. Includes guidance for .NET integration using RealtimeConversationClient (available in openai-dotnet v2.1.0-beta.1+), session management, and audio abstractions using NAudio for live microphone and speaker interaction.

Tokens
33.4K
Snippets
90
Records
124
Agent score
73%

What's inside aoai-realtime-audio-sdk

  1. Overview of Azure OpenAI /realtime API

    main

    The /realtime API is a low-latency, WebSocket-based endpoint designed for "speech in, speech out" conversational interactions using the gpt-4o-realtime-preview model family. It supports text messages, function tool calling, and asynchronous streaming communication.

    Important Architecture Note: The API is designed to be used via a trusted, intermediate service (a "middle tier") that manages connections between end users and the model. It is not intended to be used directly from untrusted end-user devices. The API handles model communication, while the middle tier handles user-side audio capture, rendering, and authentication.

  2. Overview of Realtime API Integration Samples

    main

    This repository provides sample implementations for building intermediary service layers (middle-tier) and frontends that interact with Azure OpenAI or OpenAI Realtime APIs.

    Using an intermediary service layer is recommended to:

    • Simplify client-side implementation.
    • Provide a consistent interface regardless of the backend provider.
    • Improve security and credential management.
    • Enable protocol extensions and customizations.
  3. Understand the RTClient Chat Sample project structure

    main

    The application is organized as follows:

    • src/app/page.tsx: The main entry point for the Next.js application.
    • src/components/ui/: Contains shadcn/ui components used for the interface.
    • src/lib/audio.ts: Contains utility functions for audio processing.
    • src/chat-interface.tsx: The core component managing the chat logic and real-time interactions.
  4. Understand the Custom Communication Protocol

    main

    The service uses a custom WebSocket protocol for client-server communication. The protocol is divided into several message types:

    • Control Messages: Manage connection status and lifecycle actions (e.g., connected, speech_started, text_done).
    • User Messages: Used to send text inputs from the client (user_message).
    • Transcriptions: Sent by the server to provide transcribed text from audio inputs (transcription).
    • Text Deltas: Used to stream partial text responses to the client (text_delta).

    Message Schema (Java Types)

    Below are the structural definitions for the protocol messages:

    class TextDelta {
        String id;
        MessageType type = MessageType.TEXT_DELTA;
        String delta;
    }
    
    class UserMessage {
        String id;
        MessageType type = MessageType.USER_MESSAGE;
        String text;
    }
    
    class TranscriptionMessage {
        String id;
        MessageType type = MessageType.TRANSCRIPTION;
        String text;
    }
    
    class ControlMessage {
        MessageType type = MessageType.CONTROL;
        String action;
        String greeting;
        String id;
    }
    class TextDelta {
        String id;
        MessageType type = MessageType.TEXT_DELTA;
        String delta;
    }
    
    class UserMessage {
        String id;
        MessageType type = MessageType.USER_MESSAGE;
        String text;
    }
    
    class TranscriptionMessage {
        String id;
        MessageType type = MessageType.TRANSCRIPTION;
        String text;
    }
    
    class ControlMessage {
        MessageType type = MessageType.CONTROL;
        String action;
        String greeting;
        String id;
    }
  5. How /realtime sessions, conversations, and items work

    main

    The /realtime API follows a hierarchical structure for managing interactions:

    • Session: Established when a caller connects to /realtime. The session manages shared settings like audio behavior, voice activity detection (VAD), and tool configurations. A session automatically creates a default conversation.
    • Conversation: An accumulation of input signals (audio/text) within a session. Currently, one session supports one active conversation.
    • Response: Triggered either by a direct command (e.g., response.create) or automatically via voice activity detection. A response generates output from the model.
    • Items: A response consists of one or more items. Items can encapsulate messages, function calls, or other information.
    • Content Parts: Each message item can contain multiple content_parts, allowing a single item to represent multiple modalities (e.g., both text and audio) simultaneously.
  6. Understand the /realtime Middle Tier architecture

    main

    The middle tier acts as a bridge between a frontend client and the AI model. The core logic is implemented in the RealtimeMiddleTierController.

    Connection Lifecycle:

    1. The controller accepts a WebSocket connection from the frontend client.
    2. The controller establishes a connection to the configured /realtime endpoint (Azure OpenAI or OpenAI).
    3. The controller starts and blocks on receive loop tasks for both connections simultaneously to facilitate real-time communication.

    Communication Protocol: The communication between the frontend client and the middle tier uses a simplified protocol defined by classes in the ClientMessages folder.

  7. Understand the custom Realtime communication protocol

    main

    The middle-tier uses a lightweight, custom protocol for WebSocket communication. The protocol consists of several message types:

    • Control Messages: Manage connection status and lifecycle actions (e.g., connected, speech_started, text_done).
    • User Messages: Used to send text inputs from the user (user_message).
    • Transcriptions: Sent by the server to provide transcribed text from audio inputs (transcription).
    • Text Deltas: Used to stream partial text responses to the client (text_delta).

    Protocol Type Definitions

    The following Python TypedDict structures define the message shapes:

    class TextDelta(TypedDict):
        id: str
        type: Literal["text_delta"]
        delta: str
    
    class Transcription(TypedDict):
        id: str
        type: Literal["transcription"]
        text: str
    
    class UserMessage(TypedDict):
        id: str
        type: Literal["user_message"]
        text: str
    
    class ControlMessage(TypedDict):
        type: Literal["control"]
        action: str
        greeting: str | None = None
        id: str | None = None
  8. Understand the audio abstractions in the .NET console sample

    main

    The console sample uses two minimal multimedia abstractions built on top of the NAudio library to handle pcm16 (24 KHz, 16-bit mono PCM) audio. Note that these are intended for demonstration purposes and are not designed for production use.

    • MicrophoneAudioStream: Presents audio from the system's default capture device as a Stream.
    • SpeakerOutput: Provides simple play and clear abstractions for outputting audio to the system's default render device.
  9. How to use RealtimeConversationClient and RealtimeConversationSession

    main

    The /realtime API is accessed via the RealtimeConversationClient. This client is obtained from a top-level OpenAIClient (or AzureOpenAIClient for Azure resources).

    Lifecycle and Configuration

    1. Instantiate Client: Call .GetRealtimeConversationClient() on your existing OpenAI client.
    2. Start Session: Call ConversationClient.StartConversationSessionAsync() to create a RealtimeConversationSession (which implements IDisposable).
    3. Configure Session: Use session.ConfigureSessionAsync(sessionOptions) where sessionOptions is a ConversationSessionOptions object. This object allows you to define:
      • Input and output audio formats
      • Turn end detection behavior
      • Model instructions
      • Tools

    Sending Data

    • Text/Tools: Use AddItemAsync() to add non-audio content (like text or tool responses) to the conversation history.
    • Audio: Use SendInputAudioAsync(Stream) to automatically chunk and transmit audio from a stream, or SendInputAudioAsync(BinaryData) for individual message transmissions.

    Receiving Updates

    Use ReceiveUpdatesAsync() to get an IAsyncEnumerable<ConversationUpdate>. Each update's Kind property (of type ConversationUpdateKind) maps to the wire protocol's type field.

    // Conceptual usage pattern
    var client = azureOpenAIClient.GetRealtimeConversationClient();
    using var session = await client.StartConversationSessionAsync();
    await session.ConfigureSessionAsync(new ConversationSessionOptions { /* ... */ });
    
    // Send audio
    await session.SendInputAudioAsync(audioStream);
    
    // Receive updates
    await foreach (var update in session.ReceiveUpdatesAsync()) 
    {
        // Handle update
    }
  10. How the interactive session lifecycle works

    main

    The application follows a specific lifecycle to manage the real-time conversation:

    1. Initialization: Configures a client from environment variables and connects a new session.
    2. Session Configuration: Enables input audio transcription and a custom "I'm finished" tool (allowing the model to decide when to end the conversation).
    3. Audio Setup: Starts playback to the default output device.
    4. Command Processing Loop:
      • Session Start: Once the session starts, microphone input begins.
      • Speech Detection: When user speech is detected, any active audio output is aborted and cleared.
      • Transcription Feedback: When user audio input transcription is finished, the transcript is printed to the console.
      • Streaming: Incremental transcripts and audio data are immediately printed or rendered to the speaker.
      • Termination: The loop ends if an output item invokes the "I'm finished" tool or if an error is received.
  11. Understand the /realtime client implementation

    main

    The web sample utilizes a custom modification of the official OpenAI JavaScript SDK to introduce a new realtime client.

    Note: This is an unofficial modification of the SDK and is subject to change. It may not represent the final public API surface of the SDK.

    Key logic for connecting to /realtime, sending inference configuration messages, and handling the message stream is located in src/main.ts.

  12. Getting Started with Middle-Tier Samples

    main

    To run a full implementation, follow these steps:

    1. Set up a backend:
      • For Node.js, follow the instructions in node-express/.
      • For Python, follow the instructions in python-fastapi/.
    2. Set up the frontend:
      • Follow the instructions in generic-frontend/.
      • Important: Configure the frontend's WebSocket endpoint to point to your running backend server.
    3. Configure environment variables: Set up your Azure OpenAI or OpenAI credentials as required by your chosen backend.