<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Concepts on Ulai Docs</title><link>https://docs.ulai.co.in/docs/sip/concepts/</link><description>Recent content in Concepts on Ulai Docs</description><generator>Hugo</generator><language>en</language><atom:link href="https://docs.ulai.co.in/docs/sip/concepts/index.xml" rel="self" type="application/rss+xml"/><item><title>Call flows</title><link>https://docs.ulai.co.in/docs/sip/concepts/call-flows/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.ulai.co.in/docs/sip/concepts/call-flows/</guid><description>&lt;p&gt;Both legs end in the same place: a &lt;code&gt;bridgedCall&lt;/code&gt; handed to &lt;code&gt;sfugw.Run&lt;/code&gt;, which&#10;moves audio until one side stops. Everything before that differs.&lt;/p&gt;&#10;&lt;h2 id="inbound"&gt;Inbound&lt;a class="td-heading-self-link" href="#inbound" aria-label="Heading self-link"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The gateway is the answering party. &lt;code&gt;telephony.SIPRuntime&lt;/code&gt; invokes&#10;&lt;code&gt;gateway.OnInvite&lt;/code&gt; for every out-of-dialog &lt;code&gt;INVITE&lt;/code&gt;.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; carrier gateway resolver control plane&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ INVITE ────────▶ │ │ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │ 1. Resolve ───────────▶│ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │ (host, number, IP) │ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ◀── 4xx/5xx ──── │ ◀── reject ────────────│ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │ │ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │ 2. CreateSession ──────┼────────────────▶│&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ◀── 200 OK ───── │ 3. Accept │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ──── ACK ──────▶ │ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │ 4. PublishEvent CALL_ANSWERED ─▶ resolver│&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │ 5. JoinSession ────────┼────────────────▶│&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ◀═══ RTP ══════▶ │ ◀════════ bridge ══════╪═════ WebRTC ═══▶│&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Route.&lt;/strong&gt; &lt;code&gt;(host, dialled number, source IP)&lt;/code&gt; → project, trunk ACL,&#10;dispatcher rule. A rejection here is a &lt;em&gt;specific&lt;/em&gt; SIP status the carrier can&#10;act on, not a blanket &lt;code&gt;503&lt;/code&gt;. See &lt;a href="https://docs.ulai.co.in/docs/sip/concepts/routing/"&gt;routing&lt;/a&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Room.&lt;/strong&gt; An &lt;code&gt;X-Session-Id&lt;/code&gt; header on the INVITE wins if present; otherwise&#10;a session is created, carrying the dispatcher rule in its metadata so the&#10;platform can see what the room is for. The header only chooses the room — it&#10;cannot overrule admission.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Answer.&lt;/strong&gt; &lt;code&gt;200 OK&lt;/code&gt; + &lt;code&gt;ACK&lt;/code&gt;, which binds RTP.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Tell.&lt;/strong&gt; &lt;code&gt;CALL_ANSWERED&lt;/code&gt; is published &lt;em&gt;before&lt;/em&gt; the WebRTC handshake, not&#10;after. That event is what summons the agent, so the dispatcher gets to work&#10;while the gateway is still joining.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Join and bridge.&lt;/strong&gt; A seat is taken in the room, then audio flows.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;The room is joined only &lt;strong&gt;after&lt;/strong&gt; the call is answered. On this path &amp;ldquo;accepted&amp;rdquo;&#10;&lt;em&gt;is&lt;/em&gt; the pickup, so no seat is taken until there is a live call to put in it —&#10;a join ticket is only valid for about 30 seconds, and a participant appearing in&#10;the room is the agent&amp;rsquo;s cue to start talking.&lt;/p&gt;</description></item><item><title>Routing plane</title><link>https://docs.ulai.co.in/docs/sip/concepts/routing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.ulai.co.in/docs/sip/concepts/routing/</guid><description>&lt;p&gt;Everything the gateway knows about numbers, trunks and agents comes from&#10;&lt;a href="https://github.com/ulaidotin/ulai-sip-resolver"&gt;&lt;code&gt;ulai-sip-resolver&lt;/code&gt;&lt;/a&gt; over the&#10;platform&amp;rsquo;s Redis. The gateway holds no routing table of its own.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;inbound : (host, dialled number, source IP) → project, trunk ACL, dispatcher rule&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;outbound : (project, trunk id) → address, transport, digest auth&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Neither leg carries trunk details on the wire. Callers used to send host, port,&#10;transport and credentials on every origination, which put carrier passwords in&#10;every dialler&amp;rsquo;s logs and meant a trunk migration had to be rolled out to each of&#10;them.&lt;/p&gt;</description></item><item><title>Media pipeline</title><link>https://docs.ulai.co.in/docs/sip/concepts/media/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.ulai.co.in/docs/sip/concepts/media/</guid><description>&lt;h2 id="the-audio-path"&gt;The audio path&lt;a class="td-heading-self-link" href="#the-audio-path" aria-label="Heading self-link"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The carrier speaks 8 kHz G.711. The SFU speaks 48 kHz Opus. Everything between&#10;the two happens inside the gateway:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;uplink caller μ-law 8k ─decode─▶ PCM 8k ─resample─▶ PCM 48k ─encode─▶ Opus ─▶ room&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;downlink room Opus 48k ─decode─▶ PCM 48k ─resample─▶ PCM 8k ─mix─▶ μ-law ─▶ caller&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Both directions run on a 20 ms cadence: 160 μ-law bytes on the wire, 960&#10;samples per Opus frame. Opus is encoded at 24 kbit/s with complexity 5 —&#10;wideband speech without maxing out a CPU that may be carrying many concurrent&#10;calls.&lt;/p&gt;</description></item></channel></rss>