POST /webhooks/call_control_application/<id>. channelRoutes verifies the signature, then the call handler in channels/index.ts acts on call.initiated for an incoming leg.
- It wakes the call’s instance,
warmCall(from)on the conversation named by the call’s id, so that the instance is placed and running and the caller’s memory read has begun. The caller hears ringing meanwhile, typically one to three seconds. - It answers the inbound leg with the media stream requested in the same command, so the media starts the moment the leg is up.
- The media server opens a WebSocket to
/agents/<name>/<call_control_id>?media=call.mountAgentshands it, query and all, to the instance’swebSocket(), where the voice class answers the call. Themedia=callpair is what tells it a call’s media from any other socket to the conversation: an upgrade without it is a client on the agent socket protocol, and goes to the text agent’swebSocket()instead.
calls is createCallControlClient() from @telnyx/edge-runtime/voice. Its command goes out over the runtime’s own connection, so the function holds no key. warm calls warmCall on the instance’s stub, as The Messaging Webhook shows for a text.
The instance takes the call in managed/voice.ts:
webSocket(ws, req) overrides the runtime SDK’s webSocket().
- It reads the mark off the upgrade’s address:
?media=callis the media server’s socket, answered with the voice layer and never handed tosuper.webSocket(); anything else is a client on the agent socket protocol and goes tosuper.webSocket(ws, req), as on a text agent. this.answer(ws, answerOptions(spec))is thevoice()mixin’sanswer. It takes the media socket and the options fromvoice, and runs the call from then on.- Both methods start the turn engine’s first reading, the harness’s
ready()or the direct engine’swarm(), so that the first turn does not wait for it. warmCallcarries no@rpc, so over the mount it is private, and only the handler reaches it.
streaming.started, streaming.failed and call.hangup on the answered leg are logged as one line each; a call that connects but stays silent explains itself in streaming.failed. The Voice Loop is the turn taking that follows.