Description
session.repeatAudio(pcmString) in LITE mode sends audio chunks correctly via WebSocket but produces no visible lip-sync and no audio output for custom VIDEO avatars. The server fires rapid AVATAR_SPEAK_STARTED / AVATAR_SPEAK_ENDED events per chunk (~20ms each) instead of treating them as a single utterance.
Environment
- SDK version:
@heygen/liveavatar-web-sdk@0.0.12
- Avatar type: Custom VIDEO avatar (created from uploaded video)
- Session mode:
LITE
- Browser: Chrome 130+ (also tested Firefox)
Steps to Reproduce
- Create a session token with
mode: "LITE" and a custom VIDEO avatar
- Connect and wait for
SESSION_STREAM_READY
- Generate PCM audio (24kHz, 16-bit mono, binary string) — tested with both
OfflineAudioContext resampling and manual linear interpolation from a 22050Hz WAV source
- Call
session.repeatAudio(pcmString)
Expected Behavior
- Avatar lip-syncs to the provided audio
- Audio plays through the LiveKit audio track
- Single
AVATAR_SPEAK_STARTED at the beginning, single AVATAR_SPEAK_ENDED at the end
Actual Behavior
- No lip movement on the avatar
- No audio output through the stream
- Rapid cycling of
AVATAR_SPEAK_STARTED → AVATAR_SPEAK_ENDED events (one pair per ~20ms chunk, hundreds of pairs for a 3-second audio clip)
Console output:
[useHeyGenAvatar] Avatar lip-sync started
[useHeyGenAvatar] Avatar lip-sync ended
[useHeyGenAvatar] Avatar lip-sync started
[useHeyGenAvatar] Avatar lip-sync ended
... (repeats 100+ times in rapid succession)
Verification Steps Taken
We verified the issue is not in our PCM encoding:
-
Attempt 1 — OfflineAudioContext resampling: Fetched WAV (22050Hz) → decoded with AudioContext.decodeAudioData → resampled to 24kHz via OfflineAudioContext → Float32 to Int16 → binary string → repeatAudio(). Same rapid start/stop, no lip-sync.
-
Attempt 2 — Manual WAV parsing + linear interpolation: Parsed WAV header manually → extracted raw Int16 PCM → resampled 22050→24000 with linear interpolation → binary string → repeatAudio(). Identical result.
-
FULL mode works: The same avatar works perfectly with session.repeat(text) in FULL mode — lip-sync, audio, and speaking lifecycle events all function correctly.
-
LITE mode session connects fine: SESSION_STREAM_READY fires, video stream renders, SESSION_STATE_CHANGED: CONNECTED fires. The session itself is healthy.
PCM Diagnostics
WAV: 22050Hz, 16bit, 1ch, 45678 bytes
Extracted 22000 mono samples, duration: 1.00s
Resampled 22000 (22050Hz) → 24000 (24000Hz)
Binary string: 48000 chars (24000 samples, 1.00s)
Calling repeatAudio with 48000 chars PCM
The PCM data matches the format expected by splitPcm24kStringToChunks() (960 bytes = 20ms at 24kHz mono 16-bit).
Use Case
We want to use an external TTS engine (Vachana AI, Indian English) to provide the voice while using HeyGen's avatar for lip-sync. This is the intended use case of LITE mode + repeatAudio() per the SDK architecture, but it doesn't work for custom VIDEO avatars.
Question
Is repeatAudio() in LITE mode supported for custom VIDEO avatars? If not, are there plans to support it? This would unlock third-party TTS integration which is a significant use case for non-English voices.
Description
session.repeatAudio(pcmString)in LITE mode sends audio chunks correctly via WebSocket but produces no visible lip-sync and no audio output for custom VIDEO avatars. The server fires rapidAVATAR_SPEAK_STARTED/AVATAR_SPEAK_ENDEDevents per chunk (~20ms each) instead of treating them as a single utterance.Environment
@heygen/liveavatar-web-sdk@0.0.12LITESteps to Reproduce
mode: "LITE"and a custom VIDEO avatarSESSION_STREAM_READYOfflineAudioContextresampling and manual linear interpolation from a 22050Hz WAV sourcesession.repeatAudio(pcmString)Expected Behavior
AVATAR_SPEAK_STARTEDat the beginning, singleAVATAR_SPEAK_ENDEDat the endActual Behavior
AVATAR_SPEAK_STARTED→AVATAR_SPEAK_ENDEDevents (one pair per ~20ms chunk, hundreds of pairs for a 3-second audio clip)Console output:
[useHeyGenAvatar] Avatar lip-sync started
[useHeyGenAvatar] Avatar lip-sync ended
[useHeyGenAvatar] Avatar lip-sync started
[useHeyGenAvatar] Avatar lip-sync ended
... (repeats 100+ times in rapid succession)
Verification Steps Taken
We verified the issue is not in our PCM encoding:
Attempt 1 —
OfflineAudioContextresampling: Fetched WAV (22050Hz) → decoded withAudioContext.decodeAudioData→ resampled to 24kHz viaOfflineAudioContext→ Float32 to Int16 → binary string →repeatAudio(). Same rapid start/stop, no lip-sync.Attempt 2 — Manual WAV parsing + linear interpolation: Parsed WAV header manually → extracted raw Int16 PCM → resampled 22050→24000 with linear interpolation → binary string →
repeatAudio(). Identical result.FULL mode works: The same avatar works perfectly with
session.repeat(text)in FULL mode — lip-sync, audio, and speaking lifecycle events all function correctly.LITE mode session connects fine:
SESSION_STREAM_READYfires, video stream renders,SESSION_STATE_CHANGED: CONNECTEDfires. The session itself is healthy.PCM Diagnostics
WAV: 22050Hz, 16bit, 1ch, 45678 bytes
Extracted 22000 mono samples, duration: 1.00s
Resampled 22000 (22050Hz) → 24000 (24000Hz)
Binary string: 48000 chars (24000 samples, 1.00s)
Calling repeatAudio with 48000 chars PCM
The PCM data matches the format expected by
splitPcm24kStringToChunks()(960 bytes = 20ms at 24kHz mono 16-bit).Use Case
We want to use an external TTS engine (Vachana AI, Indian English) to provide the voice while using HeyGen's avatar for lip-sync. This is the intended use case of LITE mode +
repeatAudio()per the SDK architecture, but it doesn't work for custom VIDEO avatars.Question
Is
repeatAudio()in LITE mode supported for custom VIDEO avatars? If not, are there plans to support it? This would unlock third-party TTS integration which is a significant use case for non-English voices.