mammoth-xylophone-59929
09/22/2025, 8:33 AMAUTOSUBSCRIBING the audio track of remote participant from the local participant, can the agent do it manually?
When remote participant publishes their track does it get automatically and instantaneously subscribed without waiting for actual media start from remote to local participant?tall-airline-16756
09/22/2025, 8:33 AMtall-airline-16756
09/22/2025, 8:34 AMautoSubscribe: false when you connect to a room. Once you’ve disabled auto-subscription, you’ll need to explicitly subscribe to tracks using setSubscribed(true). Here’s a little example in JavaScript to help you get started:
let room = await room.connect(url, token, {
autoSubscribe: false,
});
// Subscribe to a track when published
room.on(RoomEvent.TrackPublished, (publication, participant) => {
publication.setSubscribed(true);
});
// Subscribe to tracks already published before joining
room.remoteParticipants.forEach((participant) => {
participant.trackPublications.forEach((publication) => {
publication.setSubscribed(true);
});
});
This method works for both audio and video tracks. If you have any questions or need a hand with the implementation, just let me know—I’m here to help!
Sources: Rooms, participants, and tracks | LiveKit Docs | Subscribing to tracks | LiveKit Docs | Sources/LiveKit/TrackPublications/RemoteTrackPublication.swift | livekit-android-sdk/src/main/java/io/livekit/android/room/participant/Local... | lib/src/publication/remote.dartmammoth-xylophone-59929
09/22/2025, 8:34 AMtall-airline-16756
09/22/2025, 8:35 AMauto_subscribe=False. This way, you get to decide exactly which tracks you want to subscribe to.
2. Subscribe to Tracks Manually: Use the RemoteTrackPublication.set_subscribed(True) method to subscribe to the specific tracks you’re interested in. You can do this when a participant joins or when a new track is published.
3. Process Subscribed Audio Tracks: Once you’ve subscribed, handle the track_subscribed event to work with the audio stream.
Here’s an example to illustrate this:
async def main():
room = rtc.Room()
# Disable auto-subscribe
await room.connect('LIVEKIT_URL', 'TOKEN', options=rtc.RoomOptions(auto_subscribe=False))
# Subscribe to audio tracks when a participant joins
@room.on("participant_connected")
def on_participant_connected(participant: rtc.RemoteParticipant):
for publication in participant.track_publications.values():
if publication.track and publication.track.kind == rtc.TrackKind.KIND_AUDIO:
asyncio.create_task(participant.subscribe(publication.track))
# Handle newly published tracks
@room.on("track_published")
def on_track_published(publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant):
if publication.track and publication.kind == rtc.TrackKind.KIND_AUDIO:
asyncio.create_task(participant.subscribe(publication.track))
# Process subscribed audio tracks
@room.on("track_subscribed")
def on_track_subscribed(track: rtc.Track, publication: rtc.RemoteTrackPublication, participant: rtc.RemoteParticipant):
if track.kind == rtc.TrackKind.KIND_AUDIO:
audio_stream = rtc.AudioStream(track)
# Process audio frames
async for event in audio_stream:
# Do something with event.frame
pass
await audio_stream.aclose()
This way, you have full control over which audio tracks your app receives and processes. If anything is unclear or you want to dive deeper, just let me know—I’m here to help!
Sources: Receiving and publishing tracks | LiveKit Docs | Processing raw media tracks | LiveKit Docs | Subscribing to tracks | LiveKit Docsmammoth-xylophone-59929
09/22/2025, 8:42 AMtall-airline-16756
09/22/2025, 8:43 AMplay_dialtone option when creating the SIP participant. This will play a dial tone (like the ETSI ringing) to everyone already connected in the room while the SIP call is connecting. Just keep in mind, this tone won’t reach the remote SIP participant until a two-way media connection is set up.
Please feel free to reach out if you'd like me to walk you through setting this up or if you have any other questions—I’m here to help!
Sources: SIP Integration | livekit/livekit_composite | DeepWiki | SIP participant | LiveKit Docs | Make outbound calls | LiveKit Docs | pkg/sip/inbound.go | livekit/livekit_sip.pb.gomammoth-xylophone-59929
09/24/2025, 6:35 AM@_room_.on("room_updated") , what info does it store? when is it called in a call lifecycle?tall-airline-16756
09/24/2025, 6:36 AM@room.on("room_updated") event and how it fits into the call lifecycle.mammoth-xylophone-59929
09/24/2025, 6:38 AMtall-airline-16756
09/24/2025, 6:39 AM@room.on("room_updated") event is a helpful feature that gets triggered whenever there's an update to the room's state during your call. This can include changes to things like:
• Room metadata: Any custom metadata you've associated with the room.
• Number of participants: When participants join or leave, this updates accordingly.
• Recording status: Whether the room is currently being recorded.
• Room settings: Adjustments to properties such as empty_timeout, max_participants, and more.
Whenever this event fires, the internal RoomInfo object refreshes with the latest room data. You can easily access properties like room.name, room.metadata, room.num_participants, and room.is_recording to get the most up-to-date information.
Here's a simple example to illustrate how you might use it:
@room.on("room_updated")
def on_room_updated():
print(f"Room updated - Name: {room.name}, Participants: {room.num_participants}, Recording: {room.is_recording}")
This event is really handy for responding to changes in real time—like updating your UI or triggering specific actions based on what's happening in the room. If you have any questions or want me to walk you through it further, just let me know! I'm here to help.
Sources: livekit-rtc/livekit/rtc/room.py | livekit-ffi/src/livekit.proto.rsmammoth-xylophone-59929
09/24/2025, 6:45 AMtall-airline-16756
09/24/2025, 6:47 AM@room.on("room_updated") event will indeed fire when the customer picks up the call in the scenario you described. This happens because the event is designed to trigger whenever there's a change in the room's state, like when the number of participants (num_participants) goes up.
Here’s a quick overview of your workflow:
1. The dialer calls the voice agent (connected via SIP).
2. When the customer answers, they join the room, which increases the participant count.
This increase in num_participants or any other updates to room-level properties (such as metadata) will activate the room_updated event. You can rely on this event to keep an eye on these changes in real time.
For instance:
@room.on("room_updated")
def on_room_updated():
print(f"Room updated. Participants: {room.num_participants}")
If you want to track exactly who joined, you might find the participant_connected event helpful as well:
@room.on("participant_connected")
def on_participant(participant):
print(f"Participant joined: {participant.identity}")
Feel free to reach out if you’d like me to walk you through anything else or if you have more questions—I'm here to help!
Sources: livekit-agents/livekit/agents/voice/room_io/room_io.py | packages/livekit-rtc/src/proto/room_pb.ts | pkg/rtc/room.go | livekit/src/room/mod.rs | livekit-rtc/livekit/rtc/room.pymammoth-xylophone-59929
09/24/2025, 6:58 AMtall-airline-16756
09/24/2025, 6:59 AMsip.callStatus attribute of the SIP participant. This attribute shows you exactly what’s happening with the call:
• dialing: The call is being initiated.
• ringing: The call is ringing on the recipient’s device.
• active: The customer has picked up the call.
• hangup: The call has ended.
For instance, you could poll the sip.callStatus attribute to spot when the call becomes active, like this:
while perf_counter() - start_time < 30:
call_status = participant.attributes.get("sip.callStatus")
if call_status == "active":
print("Customer has picked up the call")
break
elif call_status == "hangup":
print("Call ended")
break
await asyncio.sleep(0.1)
Also, LiveKit sends webhook events such as participant_joined or analytics events like SIP_CALL_STARTED when the call connects. These are great tools to help you track the call lifecycle even outside the room.
If you’d like, I’m here to help you set up these mechanisms or guide you through implementing them in your application—just let me know!
Sources: src/room/events.ts | Making calls using SIP | LiveKit Docs | Making calls using SIP | LiveKit Docs | SIP Integration | livekit/livekit_composite | DeepWiki | pkg/telemetry/events.gomammoth-xylophone-59929
09/24/2025, 7:05 AMtall-airline-16756
09/24/2025, 7:06 AMprewarm function to preload models like VAD right when the worker process starts. This really helps cut down on any delays when the agent gets dispatched.
2. Dispatch Agent Early: Another great way is to dispatch the agent early during room or token creation. The agent can connect to the room and patiently wait for participants by using ctx.wait_for_participant().
3. Keep Agent Connected: You might also keep the agent connected and active in the room. For example:
await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)
await ctx.wait_for_participant()
...
agent.start(ctx.room)
In your case, where the dialer calls the human first and then the agent, here’s a simple way to handle it:
1. Create the room and dispatch the agent at the same time.
2. Have the agent connect and wait patiently in the room.
3. Once the human joins, the agent will detect them and start the session.
This way, your agent will be nicely pre-loaded and ready to go with minimal waiting time. If you’d like, I’m here to help with any further questions or specific details you might need!
Sources: Web and mobile frontends | LiveKit Docs | External data and RAG | LiveKit Docs | agent/main.py | examples/src/realtime_turn_detector.ts