Real-time digital-human interaction protocol
1. Overview
The Nuwa platform provides an open API protocol for real-time digital-human interaction, enabling developers to integrate digital-human capabilities. The protocol consists of two cooperating components:
1.1 Signaling
The client establishes a signaling channel with the Nuwa platform over WebSocket. This channel manages sessions and business logic, including:
- WebSocket connection verification: Verify the digital-human identity.
- Media negotiation: Negotiate audio/video transport protocols.
- Voice/text reporting: Send user input.
- Business notifications: Receive digital-human status and response text.
1.2 Live audio and video
The client uses WebRTC or RTMP to pull the digital-human's live audio/video stream from the negotiated address.
Example
Tips
If you only need ASR capabilities, see: Nuwa ASR real-time speech recognition protocol
2. Before development
- Get an API key:
Before you begin, complete these steps on the NuwaAI platform:
- Register a NuwaAI account and sign in.
- Record your user ID.
- Create a digital human and record its ID.
- Create and securely record an API key.
Get an API key, digital-human ID, and user ID
Get an access token:
- Use the authentication API to obtain an access token and securely verify user permissions.
Interaction flow:
- WebRTC interaction flow
sequenceDiagram
participant Client
participant Platform as Nuwa Platform
participant Service as Nuwa Digital Human Service
Client->>Platform: 1. Open a WebSocket connection
Platform-->>Client: 2. Return avator-connect (authentication result)
Client->>Platform: 3. playStream (with local SDP)
Platform-->>Client: 4. Return avator-play (remote SDP)
Client->>Client: 5. Parse the SDP and initialize WebRTC stream reception
Service-->>Client: 6. Send the audio/video stream
Service-->>Client: 7. avator-playstop (opening message complete)
Client-->>Platform: 8. 16 kHz mono audio data
Platform-->>Service: Forward the audio data
Client-->>Platform: 9. Send a conversation message (optional)
Platform-->>Client: 10. chat_begin (conversation started)
Platform-->>Client: 11. chat (conversation in progress)
Platform-->>Client: 12. chat_end (conversation ended)
Service-->>Client: 13. avator-text (digital-human response text)
Service-->>Client: 14. avator-text (subsequent text)
Service-->>Client: 15. avator-playstop (response complete)
- RTMP interaction flow
sequenceDiagram
participant C as Client 📱
participant P as Nuwa Platform ☁️
participant S as Nuwa Digital Human Service 🤖
participant R as RTMP receiver 📡
%% 1. Connection and authentication
C->>P: 1. Open a WebSocket connection
P-->>C: 2. Return avator-connet (authentication result)
%% 2. Start the RTMP stream
C->>P: 3. playRtmp (with rmtp_url)
P->>S: 4. playRtmp (forward rmtp_url)
%% 3. Platform notifies the client that playback can begin
S-->>P: 5. Stream ready (internal status)
P-->>C: 6. Return avator-play (start playback)
%% 4. Digital-human service streams to the receiver
S->>R: 7. RTMP stream (video)
%% 5. Opening-message completion notification
S-->>P: 8. avator-playstop (opening message complete)
P-->>C: 9. Forward avator-playstop
%% 6. Voice-input phase
C->>P: 10. 16 kHz mono audio data
P->>S: 11. Forward the audio data
%% 7. Conversation-message notifications (optional)
P-->>C: 12. chat_begin (conversation started)
P-->>C: 13. chat (conversation in progress)
P-->>C: 14. chat_end (conversation ended)
%% 8. Response
S-->>P: 15. avator-text (digital-human response)
P-->>C: 16. Forward avator-text
S-->>P: 17. avator-text (subsequent text)
P-->>C: 18. Forward avator-text
S-->>P: 19. avator-playstop (response complete)
P-->>C: 20. Forward avator-playstop
3. WebSocket signaling
3.1 Verify the WebSocket connection
Create a WebSocket connection
wss://wsapi.nuwaai.com/websk/humanAgent/humanchat/{protocol}/{avatorid}/{bizid}?access_token={token}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| protocol | String | No | Stream protocol: webrtc (default) or rtmp. |
| avatorid | String | Yes | Digital-human role ID. |
| bizid | String | Yes | Business ID (asr when ASR is enabled for humanctrl; otherwise 0). |
| token | String | Yes | Token obtained through authentication. |
Tips
For digital-human control only (speech, actions, expressions, and similar operations), use:
wss://wsapi.nuwaai.com/websk/humanAgent/humanctrl/{protocol}/{avatorid}/{bizid}?access_token={token}
3.1.2 Wait for verification response
Protocol: JSON text message
{
"code": {code},
"msg": {message},
"type": "avator-connect",
"data": {
"question": {question},
"sessionid": {sessionid}
}
}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| code | int | Yes | Response code: 200 means OK; other values indicate an error described by message. |
| message | String | No | Detailed error message. |
| type | String | Yes | Message type: avator-connect. |
| data | Object | Yes | Message payload. |
| data.question | Array | Yes | Three suggested questions. |
| data.sessionid | String | Yes | Session ID. |
// WebSocket connection example
const protocol = 'webrtc'; // or 'rtmp'
const avatorId = 'your-avator-id';
const bizId = '0'; // or 'asr' (when ASR is enabled for humanctrl)
const token = 'your-access-token';
const wsUrl = `wss://wsapi.nuwaai.com/websk/humanAgent/humanchat/${protocol}/${avatorId}/${bizId}?access_token=${token}`;
const ws = new WebSocket(wsUrl);
// Connection established
ws.onopen = function() {
console.log('WebSocket connection established');
};
// Receive messages
ws.onmessage = function(event) {
const message = JSON.parse(event.data);
console.log('Message received:', message);
// Handle the connection-verification response
if (message.type === 'avator-connect') {
if (message.code === 200) {
console.log('Connection verified; session ID:', message.data.sessionid);
console.log('Suggested questions:', message.data.question);
// After verification succeeds, continue to the next operation
} else {
console.error('Connection verification failed:', message.msg);
}
}
};
// Connection closed
ws.onclose = function() {
console.log('WebSocket connection closed');
};
// Connection error
ws.onerror = function(error) {
console.error('WebSocket connection error:', error);
};
3.2 Media negotiation
Send media-negotiation requests over WebSocket. WebRTC and RTMP are supported; the WebSocket protocol parameter must match the negotiated protocol.
3.2.1 WebRTC protocol
Send a media-negotiation request
Protocol: JSON text message
{
"type": "playStream",
"data": {
"sdp": {sdp}
}
}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| type | String | Yes | Message type: playStream. |
| data | Object | Yes | Message payload. |
| data.sdp | String | Yes | Local SDP. |
Wait for negotiation response
Protocol: JSON text message
{
"code": {code},
"msg": {message},
"type": "avator-play",
"data": {
"sdp": {sdp}
}
}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| code | int | Yes | Response code: 200 means OK; otherwise see message. |
| message | String | No | Detailed error message. |
| type | String | Yes | Message type: avator-play. |
| data | Object | Yes | Message payload. |
| data.sdp | sdp | Yes | Remote SDP information. |
// Send a WebRTC media-negotiation request
function sendPlayStream(ws, localSdp) {
const playStreamMessage = {
type: 'playStream',
data: {
sdp: localSdp
}
};
ws.send(JSON.stringify(playStreamMessage));
console.log('playStream request sent:', playStreamMessage);
}
// Handle the WebRTC negotiation response
function handleAvatorPlay(message) {
if (message.code === 200) {
const remoteSdp = message.data.sdp;
console.log('avator-play response received; remote SDP:', remoteSdp);
// Establish the WebRTC connection with the remote SDP
// Handle this according to your WebRTC implementation
// For example:
// pc.setRemoteDescription(new RTCSessionDescription({ type: 'answer', sdp: remoteSdp }));
} else {
console.error('Media negotiation failed:', message.msg);
}
}
// Example: add this to the WebSocket message handler
ws.onmessage = function(event) {
const message = JSON.parse(event.data);
console.log('Message received:', message);
if (message.type === 'avator-connect') {
// Handle the connection-verification response...
} else if (message.type === 'avator-play') {
// Handle the media-negotiation response
handleAvatorPlay(message);
}
};
3.2.2 RTMP protocol
Send a media-negotiation request
Protocol: JSON text message
{
"type": "playRtmp",
"data": {
"url": {url},
"rate": {
"default": 6000000,
"max": 8000000,
"min": 4000000
}
"codec": {
"type": "H264",
"profile": "baseline",
"gop": 30,
"width": 1280,
"height": 720
}
}
}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| type | String | Yes | Message type: playRtmp. |
| data | Object | Yes | Message payload. |
| data.url | String | Yes | Digital-human stream URL. |
| data.rate | Object | No | Bitrate settings. |
| data.rate.default | int | Yes | Initial bitrate. |
| data.rate.max | int | Yes | Maximum bitrate. |
| data.rate.min | int | Yes | Minimum bitrate. |
| data.codec | Object | No | Encoder settings. |
| data.codec.type | str | Yes | Encoder type; only H.264 is supported. |
| data.codec.profile | str | Yes | baseline, main, or high. |
| data.codec.gop | int | Yes | Greater than 10. |
| data.codec.width | int | No | Multiple of 2. |
| data.codec.height | int | No | Multiple of 2. |
Tips
If data.codec.width or height is provided, both values are required. If only one is set, neither value takes effect.
Wait for negotiation response
Protocol: JSON text message
{
"code": {code},
"msg": {message},
"type": "avator-play"
}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| code | int | Yes | Response code: 200 means OK; otherwise see message. |
| message | String | No | Detailed error message. |
| type | String | Yes | Message type: avator-play. |
// Send an RTMP media-negotiation request
function sendPlayRtmp(ws, rtmpUrl) {
const playRtmpMessage = {
type: 'playRtmp',
data: {
url: rtmpUrl
}
};
ws.send(JSON.stringify(playRtmpMessage));
console.log('playRtmp request sent:', playRtmpMessage);
}
// Handle the RTMP negotiation response
function handleAvatorPlayRtmp(message) {
if (message.code === 200) {
console.log('RTMP media negotiation succeeded');
// Begin receiving the audio/video stream over RTMP
// Handle this according to your RTMP player implementation
// For example, load the RTMP stream with video.js or another player
} else {
console.error('RTMP media negotiation failed:', message.msg);
}
}
// Example: add this to the WebSocket message handler
ws.onmessage = function(event) {
const message = JSON.parse(event.data);
console.log('Message received:', message);
if (message.type === 'avator-connect') {
// Handle the connection-verification response...
} else if (message.type === 'avator-play') {
// Handle the media-negotiation response
handleAvatorPlayRtmp(message);
}
};
3.3 Send conversation messages
For voice conversations, send 16 kHz mono PCM data in 60 ms chunks. Send text conversations as JSON messages.
3.3.1 Text conversation protocol
Protocol: JSON text message
{
"type": "agent",
"data": {
"content": {text}
}
}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| type | String | Yes | Message type: agent. |
| data | Object | Yes | Message payload. |
| data.content | String | Yes | Conversation content. |
// Send a text conversation message
function sendTextMessage(ws, text) {
const textMessage = {
type: 'agent',
data: {
content: text
}
};
ws.send(JSON.stringify(textMessage));
console.log('Text message sent:', textMessage);
}
// Example: send a text message
// sendTextMessage(ws, '你好,数字人!');
// Handle conversation responses
function handleChatMessages(message) {
switch (message.type) {
case 'chat_begin':
console.log('Conversation started');
break;
case 'chat':
console.log('Language-model response:', message.data.content);
break;
case 'chat_end':
console.log('Conversation ended');
break;
case 'avator-text':
console.log('Digital-human response:', message.data.text);
break;
case 'avator-playstop':
console.log('Digital-human response complete');
break;
}
}
// Example: add this to the WebSocket message handler
ws.onmessage = function(event) {
const message = JSON.parse(event.data);
console.log('Message received:', message);
if (message.type === 'avator-connect') {
// Handle the connection-verification response...
} else if (message.type === 'avator-play') {
// Handle the media-negotiation response...
} else if (['chat_begin', 'chat', 'chat_end', 'avator-text', 'avator-playstop'].includes(message.type)) {
// Handle conversation responses
handleChatMessages(message);
}
};
3.3.2 Digital-human control messages
Valid only for humanctrl connections.
Protocol: JSON text message
{
"type": "avatar",
"data": {
"content": {text},
"audio": {
"segment": {segment},
"speech": {speech},
"music": {music}
}
}
}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| type | String | Yes | Message type: avatar. |
| data | Object | Yes | Message payload. |
| data.content | String | Yes | Digital-human speech content. |
| data.audio | Object | No | 16 kHz mono PCM audio data. |
| data.audio.segment | Number | Yes | Audio segment index; -1 is the final segment and 0 is the first. |
| data.audio.speech | String | Yes | Base64-encoded voice data; each segment ≤10 KB. |
| data.audio.music | String | Yes | Base64-encoded voice+music mix; each segment ≤10 KB. |
Tips
Only base64-encoded 16 kHz mono PCM audio is supported.
When audio is provided, speech drives lip movements and music is used for playback.
Without audio, the digital human converts content to speech for playback.
// Send a digital-human control message (valid only for humanctrl connections)
function sendAvatarControlMessage(ws, content) {
const controlMessage = {
type: 'avatar',
data: {
content: content
}
};
ws.send(JSON.stringify(controlMessage));
console.log('Digital-human control message sent:', controlMessage);
}
// Example: send a digital-human control message
// sendAvatarControlMessage(ws, '欢迎使用 Nuwa 数字人服务!');
// Handle digital-human control responses
function handleAvatarControlResponse(message) {
if (message.type === 'avator-ctrl') {
console.log('Digital-human control message:', message.data);
} else if (message.type === 'avator-playstop') {
console.log('Digital-human response complete');
}
}
// Example: add this to the WebSocket message handler
ws.onmessage = function(event) {
const message = JSON.parse(event.data);
console.log('Message received:', message);
if (message.type === 'avator-connect') {
// Handle the connection-verification response...
} else if (message.type === 'avator-ctrl' || message.type === 'avator-playstop') {
// Handle digital-human control responses
handleAvatarControlResponse(message);
}
};
3.3.2 Interrupt the digital human
Valid only for humanctrl connections. Interrupt the digital human's speech.
Protocol: JSON text message
{
"type": "interrupt_chat"
}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| type | String | Yes | Message type: interrupt_chat. |
// Send a digital-human interruption message (valid only for humanctrl connections)
function sendInterruptChatMessage(ws) {
const interrupt_chat_message = {
type: 'interrupt_chat'
};
ws.send(JSON.stringify(interrupt_chat_message));
console.log('Digital-human interruption message sent:', interrupt_chat_message);
}
3.4 Business notifications
After the digital-human connection is established, the service sends business notifications over WebSocket.
Protocol: JSON text message
{
"code": {code},
"msg": {message},
"type": {type},
"data": {data}
}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| code | int | Yes | Response code: 200 means OK; otherwise see message. |
| message | String | No | Detailed error message. |
| type | String | Yes | Message type. |
| data | json | No | Payload determined by type. |
Message types
| type | Description |
|---|---|
| avator-load | Digital-human loading notification |
| avator-connect | Digital-human connection notification (see authentication) |
| avator-play | Digital-human SDP notification |
| avator-text | Current digital-human speech text (captions) |
| avator-playstop | Digital-human response complete |
| avator-ctrl | Digital-human control message |
| asr-text | Full real-time user speech text |
| asr-commit | User speech committed to the language model |
| chat_begin | Language-model response started |
| chat | Language-model response text |
| chat_end | Language-model response complete |
data values
type: avator-text
{
"text": {text}
}
| Name | Type | Required | Description |
|---|---|---|---|
| text | String | Yes | Text content. |
type: asr-text / asr-commit / chat
{
"content": {text}
}
| Name | Type | Required | Description |
|---|---|---|---|
| text | String | Yes | Text content. |
type: avator-ctrl
{
"cmd": {cmd},
"action": {action},
"src": {src}
}
| Name | Type | Required | Description |
|---|---|---|---|
| cmd | String | Yes | Control operation: picture or video. |
| action | String | Yes | Action type, for example ppt. |
| src | String | Yes | Path to the picture or video. |
4. Live audio and video protocol
4.1 WebRTC live-stream protocol
WebRTC (Web Real-Time Communication) is an open standard for real-time voice and video in browsers. Nuwa uses it to deliver the digital human's live stream.
4.1.1 Protocol overview
- Transport: UDP-based peer-to-peer transmission.
- Media formats: H.264 video and Opus audio.
- Latency: Low latency for interactive scenarios.
- Security: Built-in encryption.
4.1.2 Connection flow
- Open a WebSocket connection using the configured URL.
- Receive connection verification: Handle
avator-connectand obtain the session ID. - Start media negotiation: Create an
RTCPeerConnectionand add audio/video receivers. - Send the negotiation request: Send
playStreamwith local SDP. - Handle the response: Receive
avator-playand obtain remote SDP. - Set the remote description on the peer connection.
- Receive the media stream through the
ontrackevent.
sequenceDiagram
participant Client
participant Platform as Nuwa Platform
participant Service as Nuwa Digital Human Service
Client->>Platform: 1. Open a WebSocket connection
Platform-->>Client: 2. Return avator-connect (session ID)
Client->>Client: 3. Create an RTCPeerConnection
Client->>Client: 4. Add audio and video receivers
Client->>Client: 5. Use createOffer to obtain the local SDP
Client->>Client: 6. Use setLocalDescription to set the local SDP
Client->>Platform: 7. Send playStream (with local SDP)
Platform->>Service: 8. Forward the playStream request
Service-->>Platform: 9. Return the remote SDP
Platform-->>Client: 10. Return avator-play (remote SDP)
Client->>Client: 11. Use setRemoteDescription to set the remote SDP
Service-->>Client: 12. Send the audio/video stream
Client->>Client: 13. Receive the stream through the ontrack event
4.1.3 WebRTC implementation example
// WebRTC connection example
let peerConnection = null;
let peerStream = null;
// Start media negotiation
function startMediaNegotiation(socket, videoElementId) {
// Create an RTCPeerConnection
peerConnection = new RTCPeerConnection(null);
// Create a MediaStream
peerStream = new MediaStream();
// Set the video element source
const video = document.getElementById(videoElementId);
video.srcObject = peerStream;
video.onplay = function() {
video.muted = false;
};
// Handle the audio/video stream
peerConnection.ontrack = function(event) {
console.log('Video stream received: ' + event.streams.length + ' stream(s)');
peerStream.addTrack(event.track);
};
// Add audio and video receivers
peerConnection.addTransceiver('audio', { direction: 'recvonly' });
peerConnection.addTransceiver('video', { direction: 'recvonly' });
// Create and send the SDP
peerConnection.createOffer().then(offer => {
return peerConnection.setLocalDescription(offer);
}).then(() => {
const message = {
type: 'playStream',
data: {
sdp: peerConnection.localDescription.sdp
}
};
socket.send(JSON.stringify(message));
console.log('WebRTC negotiation request sent');
}).catch(error => {
console.error('WebRTC negotiation error: ' + error);
});
}
// Handle the SDP answer
function handleSdpAnswer(sdp) {
if (peerConnection) {
const remoteDescription = new RTCSessionDescription({ type: 'answer', sdp: sdp });
peerConnection.setRemoteDescription(remoteDescription).then(() => {
console.log('WebRTC negotiation succeeded');
}).catch(error => {
console.error('WebRTC negotiation-answer error: ' + error);
});
}
}
// Close the WebRTC connection
function disconnectWebRTC() {
if (peerConnection) {
peerConnection.close();
peerConnection = null;
}
if (peerStream) {
peerStream.getTracks().forEach(track => track.stop());
peerStream = null;
}
console.log('WebRTC connection closed');
}
// Example: add this to the WebSocket message handler
function handleWebSocketMessage(message, socket) {
switch (message.type) {
case 'avator-connect':
if (message.code === 200) {
console.log('Authentication succeeded; session ID: ' + message.data.sessionid);
// Start media negotiation
startMediaNegotiation(socket, 'remote-video');
} else {
console.log('Authentication failed: ' + message.msg);
}
break;
case 'avator-play':
if (message.code === 200 && message.data && message.data.sdp) {
// Handle the SDP answer
handleSdpAnswer(message.data.sdp);
}
break;
// Handle other messages...
}
}
4.1.4 Error handling
| Error | Possible cause | Solution |
|---|---|---|
| ICE connection failed | NAT traversal failed | Configure a TURN server. |
| Media cannot play | Invalid SDP | Check the SDP format. |
| Audio/video stutters | Insufficient bandwidth | Adjust resolution or bitrate. |
| Connection dropped | Unstable network | Implement reconnection. |
4.2 RTMP live-stream protocol
RTMP (Real-Time Messaging Protocol) transports audio/video streams. Nuwa uses it to deliver the digital human's live stream.
4.2.1 Protocol overview
- Transport: TCP-based streaming.
- Media formats: H.264 video and AAC audio.
- Latency: Moderate latency, suitable for live streaming.
- Compatibility: Widely supported by media players.
4.2.2 Connection flow
- Obtain a stream URL: The client provides an RTMP stream URL.
- Send a negotiation request: Send
playRtmpover WebSocket. - Wait for a response: Receive the platform's
avator-playresponse. - Pull the stream: Use an RTMP player to retrieve audio/video from the URL.
sequenceDiagram
participant Client
participant Platform as Nuwa Platform
participant Service as Nuwa Digital Human Service
participant Player as RTMP player
Client->>Platform: 1. playRtmp (with rmtp_url)
Platform->>Service: 2. Forward the playRtmp request
Service-->>Platform: 3. Stream ready
Platform-->>Client: 4. Return avator-play (start playback)
Service->>Player: 5. RTMP stream (video)
Player-->>Client: 6. Display audio and video
4.2.3 RTMP implementation example
// RTMP player example (using video.js)
// First, include video.js and the videojs-flash plugin
// <script src="https://cdn.jsdelivr.net/npm/video.js@7.15.4/dist/video.min.js"></script>
// <script src="https://cdn.jsdelivr.net/npm/videojs-flash@2.2.1/dist/videojs-flash.min.js"></script>
// Initialize the player
const player = videojs('remote-video', {
techOrder: ['html5', 'flash'],
autoplay: true,
controls: true,
sources: [
{
src: 'rtmp://your-rtmp-server/live/stream',
type: 'rtmp/flv'
}
]
});
// Listen for player events
player.on('play', function() {
console.log('Player started playback');
});
player.on('error', function() {
console.error('Player error:', player.error());
});
player.on('ended', function() {
console.log('Playback ended');
});
// Send a playRtmp request
function sendPlayRtmp(ws, rtmpUrl) {
const playRtmpMessage = {
type: 'playRtmp',
data: {
url: rtmpUrl
}
};
ws.send(JSON.stringify(playRtmpMessage));
console.log('playRtmp request sent:', playRtmpMessage);
}
// Handle the avator-play response
function handleAvatorPlay(message) {
if (message.code === 200) {
console.log('RTMP media negotiation succeeded; starting playback');
// The configured player starts playback automatically
} else {
console.error('RTMP media negotiation failed:', message.msg);
}
}
4.2.4 Error handling
| Error | Possible cause | Solution |
|---|---|---|
| Connection failed | Incorrect RTMP server URL | Check the RTMP URL. |
| Stream cannot play | Streaming has not started | Wait for the digital-human service to be ready. |
| Audio/video stutters | Insufficient bandwidth | Adjust resolution or use a more stable network. |
| Player error | Player does not support RTMP | Use an RTMP-capable player such as video.js with a Flash plugin. |
5. Best practices
5.1 Connection management
- Reconnect automatically when the WebSocket closes unexpectedly.
- Set reasonable timeouts to avoid indefinite waits.
- Track connection state so users know whether they are connected.
5.2 Performance optimization
- Send voice data in 100–200 ms chunks.
5.3 Error handling
- Implement comprehensive error callbacks.
- Retry recoverable errors such as transient network failures.
- Log errors for troubleshooting.
5.4 Security
- Keep API keys secure; never expose them in client-side code.
- Use HTTPS and WSS to encrypt traffic.
6. FAQ
6.1 Connection
Q: What should I do if the WebSocket connection fails?
A: Verify that:
- The
access_tokenis valid. - The network connection is working.
- The digital-human ID is correct.
- The error code does not identify another specific cause.
Q: Why is there no authentication response after connecting?
A: Network latency or slow model loading may delay the response. Increase the timeout and verify the WebSocket state.
6.2 Audio/video
Q: What should I do if audio/video stutters?
A: Check that:
- Network bandwidth is sufficient.
- The client device meets H.264 decoding requirements.
- No other application is consuming bandwidth.
Q: Why can't I pull the audio/video stream?
A: Confirm that:
- Media negotiation succeeded.
- SDP is parsed correctly.
- The firewall allows the required ports.
6.3 Messages
Q: Why is there no response after sending voice data?
A: Check that:
- Voice data is 16 kHz mono PCM.
- Chunk sizes are correct (100–200 ms recommended).
Q: Why is received text garbled?
A: Parse message content using UTF-8 encoding.