介紹如何通過 AOQ、WebRTC、WebSocket 三種協議接入 Realtime API 模型或應用,包含各協議的串連流程、時序圖和程式碼範例。
前提條件
體驗 Demo
阿里雲百鍊提供適用於 Android 平台的 Demo,可用於快速驗證 AOQ 接入效果。下載 APK 並配置 API Key 和 workspaceId 後,即可體驗部分模型。
掃描以下二維碼下載 Demo:
AOQ 接入
AOQ 基於 QUIC 協議深度定製,適合移動端原生應用,支援音頻/視頻/資料混合傳輸,內建極致抗弱網能力。以下以即時全模態(Omni)的 iOS Demo 為例介紹 AOQ 接入流程。AOQ SDK API 詳情請參見AOQ用戶端SDK。
整體流程時序圖
建立引擎並設定回調
let config = AoqCreateConfig()
config.workDir = workDir
config.enableDumpAudio = false
engine = AoqClientEngine.createEngine(config, delegate: self)
實現 AoqEngineDelegate 協議監聽 onConnectionStatusChange、onDataMsg、onError 等回調。
啟動音頻採集與播放
// 音頻採集
let capCfg = AoqAudioCaptureConfig()
capCfg.channel = 1; capCfg.isExternal = false
engine.startAudioCapture(capCfg)
// 音頻播放
let playCfg = AoqAudioPlaybackConfig()
playCfg.channel = 1; playCfg.isExternal = false
engine.startAudioPlayer(playCfg)
// 視頻採集(可選)
let vidCfg = AoqVideoCaptureConfig()
vidCfg.width = 720; vidCfg.height = 1280; vidCfg.fps = 15
engine.startVideoCapture(vidCfg)
擷取串連憑證
由業務 AppServer 代理百鍊請求,參見Token鑒權。
設定編解碼及建立串連
設定編解碼參數後調用 connect:
// 音頻編解碼配置
let encCfg = AoqAudioCodecConfig()
encCfg.codecType = .audioPCM; encCfg.sampleRate = 16000; encCfg.channel = 1
engine.setAudioEncoderConfig(encCfg)
engine.setAudioDecoderConfig(encCfg)
// connect 前關閉媒體發送,待 session.updated 後再開啟
engine.enableSendMediaStream(.audio, enable: false)
let config = AoqConnectConfig()
config.token = token
config.sid = sid
config.certFingerprint = certificate
config.relayEndpoints = relayEndpoints
config.workspaceIdHash = workspaceIdHash
config.publishTracks = [audioTrack, dataTrack]
config.subscribeTracks = [audioTrack, dataTrack]
engine.connect(config)
重要重要:AOQ SDK 在建連後會預設發送媒體資料,此樣本示範了在串連模型時先關閉媒體發送,待會話就緒後再開啟的流程。
配置 AI 會話
串連成功後發送 session.update 的樣本,詳見用戶端事件:
func onConnectionStatusChange(_ status: AoqConnectionStatus) {
if status == .connected { sendSessionUpdate() }
}
private func sendSessionUpdate() {
let json = """
{
// 該事件的id,由用戶端產生
"event_id": "event_ToPZqeobitzUJnt3QqtWg",
// 事件類型,固定為session.update
"type": "session.update",
// 會話配置
"session": {
// 輸出模態,支援設定為["text"](僅輸出文本)或["text","audio"](輸出文本與音頻)。
"modalities": [
"text",
"audio"
],
// 輸出音訊音色
"voice": "Ethan",
// 輸入音頻格式,當前僅支援設定為pcm。輸入音頻為16 kHz採樣率的PCM音頻流。
"input_audio_format": "pcm",
// 輸出音頻格式,當前僅支援設定為pcm。輸出音頻為24 kHz採樣率的PCM音頻流。
"output_audio_format": "pcm",
// 系統訊息,用於設定模型的目標或角色。
"instructions": "你是某五星級酒店的AI客服專員,請準確且友好地解答客戶關於房型、設施、價格、預訂政策的諮詢。請始終以專業和樂於助人的態度回應,杜絕提供未經證實或超出酒店服務涵蓋範圍的資訊。",
// 是否開啟語音活動檢測。若需啟用,需傳入一個設定物件,服務端將據此自動檢測語音起止。
// 設定為null表示由用戶端決定何時發起模型響應。
"turn_detection": {
// VAD類型,取值為server_vad或semantic_vad。使用qwen3.5-omni-realtime系列模型時推薦設為semantic_vad。
"type": "semantic_vad",
// VAD檢測閾值。建議在嘈雜的環境中增加,在安靜的環境中降低。
"threshold": 0.5,
// 檢測語音停止的靜音期間,超過此值後會觸發模型響應
"silence_duration_ms": 800
}
}
}
"""
let msg = AoqDataMsg()
msg.data = json.data(using: .utf8)!
engine.send(msg)
}
收到 session.updated 後開啟媒體發送
收到模型回複 session.updated 的樣本,詳見服務端事件:
func onDataMsg(_ msg: AoqDataMsg) {
guard let obj = try? JSONSerialization.jsonObject(with: msg.data) as? [String: Any],
let type = obj["type"] as? String else { return }
if type == "session.updated" {
engine.enableSendMediaStream(.audio, enable: true)
engine.enableSendMediaStream(.video, enable: true)
}
}
重要
-
必須在收到
session.updated後才開啟媒體流發送,否則服務端可能尚未準備好接收資料。 -
建連時添加的音頻軌道和視頻軌道(即 AOQ 媒體通道)會自動將資料轉送到服務端。
- 音頻:通過音頻軌道直接傳輸,無需發送
input_audio_buffer.append事件。 - 視頻:通過視頻軌道發送畫面幀,無需發送
input_image_buffer.append事件。
- 音頻:通過音頻軌道直接傳輸,無需發送
中斷連線與銷毀引擎
engine.disconnect()
AoqClientEngine.destroy()
WebRTC 接入
WebRTC 不提供專用 SDK。Web 端可直接使用瀏覽器原生 JavaScript API 接入,其他端可通過開源 WebRTC 庫或支援標準 WebRTC 協議的第三方 RTC 服務接入。以下以 Web 端 JavaScript 為例進行介紹。
整體流程圖
建立串連
# pip install aiortc aiohttp certifi
import asyncio, aiohttp, ssl, certifi
from aiortc import RTCPeerConnection, RTCConfiguration, RTCSessionDescription
from aiortc.mediastreams import AudioStreamTrack
API_KEY = "your-api-key"
MODEL = "目標模型"
SIGNALING_URL = f"https://{{endpoint}}/api/v1/webrtc/realtime?model={MODEL}"
async def connect():
pc = RTCPeerConnection(RTCConfiguration(iceServers=[]))
# 添加音頻軌道,確保 Offer SDP 包含 m=audio(服務端必需)
pc.addTrack(AudioStreamTrack())
# 建立 DataChannel 以觸發 SDP 協商(名稱可自訂,服務端會通過名為 "txt" 的通道推送事件)
pc.createDataChannel("oai-events")
# SDP 交換:建立 Offer 並發送到服務端
offer = await pc.createOffer()
await pc.setLocalDescription(offer)
async with aiohttp.ClientSession() as session:
async with session.post(
SIGNALING_URL,
ssl=ssl.create_default_context(cafile=certifi.where()),
data=offer.sdp.encode("utf-8"),
headers={
"Content-Type": "application/sdp",
"Authorization": f"Bearer {API_KEY}",
},
) as resp:
if not resp.ok:
raise Exception(f"SDP 交換失敗: {resp.status} {await resp.text()}")
answer_sdp = await resp.text()
print("=== Offer SDP ===")
print(offer.sdp)
print("=== Answer SDP ===")
print(answer_sdp)
# ICE 建連自動完成
await pc.setRemoteDescription(RTCSessionDescription(sdp=answer_sdp, type="answer"))
print("WebRTC 串連已建立")
return pc
配置目標模型參數
監聽模型通過 DataChannel 返回的訊息,確保互動時序正確:
pc.ondatachannel = (event) => {
const ch = event.channel;
ch.onmessage = (e) => {
let obj;
try { obj = JSON.parse(e.data); }
catch (err) {
return;
}
if (obj?.type === "session.created") {
sendUpdate(event.channel);
//開始推送音視頻
audioSender?.replaceTrack(audioTrack);
videoSender?.replaceTrack(videoTrack);
}
};
};
收發媒體資料
建連時添加的音頻軌道和視頻軌道(即 RTP 媒體通道)會自動將資料轉送到服務端。
- 音頻:通過音頻軌道(RTP)直接傳輸,無需發送
input_audio_buffer.append事件。 - 圖片:通過視頻軌道(RTP)發送畫面幀,不支援
input_image_buffer.append事件。
說明WebRTC 僅支援服務端 VAD 模式(server_vad 或 semantic_vad),不支援手動模式。
Demo 源碼
前提條件
- 使用支援 WebRTC 的現代瀏覽器(Chrome、Edge、Firefox、Safari 等)。
- 瀏覽器需要麥克風許可權。
- 瀏覽器受跨域安全性原則限制,無法直接向服務端發起建連請求,因此需要通過終端執行 curl 命令完成串連建立。
運行樣本
建立一個 HTML 檔案,命名為 webrtc_demo.html,並將以下代碼複製到檔案中:
在瀏覽器中開啟此檔案,按以下步驟操作:
- 點擊開始會話,頁面會自動產生 Offer SDP 和對應的 curl 命令。
- 點擊複製 curl 命令,在終端中執行。命令返回的內容即為 Answer SDP。
- 將 Answer SDP 粘貼到頁面的 Answer SDP 文字框中,點擊設定 Answer 即可建立串連並開始語音對話。
WebSocket 接入
不同模型的接入方式和流程不同,詳情請參見: