Fall back to _turn_context_id in get_active_audio_context_id

TTS services whose wire protocol does not echo the context_id back on
incoming audio (Sarvam, Smallest, Soniox, Inworld, ...) call
``get_active_audio_context_id()`` to tag each chunk. That accessor
returned only ``_playing_context_id`` — the playback-side cursor set
asynchronously by ``_audio_context_task_handler`` when it pops a context
off the serialization queue.

Result: incoming audio that arrived in the gap between contexts or at
the very start of a turn (before the playback loop popped) had
``context_id=None`` and was dropped with
``unable to append audio to context: no context ID provided``.

Fall back to ``_turn_context_id`` (the synthesis-side cursor, set as
soon as the turn's context is created) so the gap is covered without
prematurely nulling the playback cursor.
This commit is contained in:
Aleix Conchillo Flaqué
2026-05-14 13:22:00 -07:00
parent 49bda11ae8
commit b76831e677

View File

@@ -1283,10 +1283,17 @@ class TTSService(AIService):
def get_active_audio_context_id(self) -> str | None:
"""Get the active audio context ID.
Returns the playback cursor when set (during active playback), falling
back to the current turn's synthesis context_id. The fallback covers
the gap between contexts and the start of a turn before the playback
task has popped the just-created context off the serialization queue —
important for services whose wire protocol does not echo context_id
back on incoming audio.
Returns:
The active context ID, or None if no context is active.
The active context ID, or None if neither cursor is set.
"""
return self._playing_context_id
return self._playing_context_id or self._turn_context_id
async def remove_active_audio_context(self):
"""Remove the active audio context."""