<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Shubhanshu Tiwari on Medium]]></title>
        <description><![CDATA[Stories by Shubhanshu Tiwari on Medium]]></description>
        <link>https://medium.com/@shubhanshutiwari74156?source=rss-0c3985c29880------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*_I74FJ7kJXq79Y5m</url>
            <title>Stories by Shubhanshu Tiwari on Medium</title>
            <link>https://medium.com/@shubhanshutiwari74156?source=rss-0c3985c29880------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 24 May 2026 02:27:11 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@shubhanshutiwari74156/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[ How I Used My Windows PC’s Internet on Android Using Tailscale (No VPN Setup Hassle)]]></title>
            <link>https://medium.com/@shubhanshutiwari74156/how-i-used-my-windows-pcs-internet-on-android-using-tailscale-no-vpn-setup-hassle-6f13ed9d53c6?source=rss-0c3985c29880------2</link>
            <guid isPermaLink="false">https://medium.com/p/6f13ed9d53c6</guid>
            <category><![CDATA[vpn]]></category>
            <category><![CDATA[share-internet-data]]></category>
            <category><![CDATA[tunneling]]></category>
            <category><![CDATA[tailscale]]></category>
            <category><![CDATA[share-internet]]></category>
            <dc:creator><![CDATA[Shubhanshu Tiwari]]></dc:creator>
            <pubDate>Wed, 11 Feb 2026 16:15:57 GMT</pubDate>
            <atom:updated>2026-02-11T16:15:57.723Z</atom:updated>
            <content:encoded><![CDATA[<p>Have you ever wanted to use your <strong>home computer’s internet connection on your phone</strong> when you’re outside?</p><p>Maybe to:</p><ul><li>Access region-restricted content</li><li>Use your home IP address</li><li>Secure your public WiFi connection</li><li>Run downloads on your PC’s network</li><li>Save mobile data</li></ul><p>I had the same problem.</p><p>I wanted my Android phone to route all its internet traffic through my Windows PC — <strong>without complicated VPN servers, port forwarding, or networking headaches.</strong></p><p>And I found the perfect solution:</p><p>👉 <strong>Tailscale.</strong></p><p>In this article, I’ll show you exactly how to set it up in under 5 minutes.</p><p>🚀 What Is Tailscale?</p><p>Tailscale is a tool built on WireGuard that creates a <strong>private, encrypted network</strong> between your devices.</p><p>Think of it like:</p><blockquote><em>Your own personal VPN between your devices.</em></blockquote><p>It works across:</p><ul><li>Different networks</li><li>Different countries</li><li>Mobile data / WiFi</li><li>NAT / firewalls</li></ul><p>No manual configuration required.</p><h3>🎯 What We’re Building</h3><p>After this setup, your connection will look like this:</p><pre>Android Phone → Tailscale → Windows PC → Internet</pre><p>So all your phone’s traffic goes through your PC.</p><p>Your phone will appear online using your PC’s IP address.</p><h3>✅ What You Need</h3><p>Before starting, make sure you have:</p><ul><li>A Windows 10/11 PC (always ON when using VPN)</li><li>An Android phone</li><li>Internet connection on both</li><li>A Google/Microsoft/GitHub account</li></ul><p>That’s it.</p><h3>🟢 Step 1: Create a Tailscale Account</h3><p>Go to:</p><p>👉 <a href="https://tailscale.com">https://tailscale.com</a></p><p>Sign in using Google, Microsoft, or GitHub.</p><p>Use the <strong>same account on all devices.</strong></p><h3>🟢 Step 2: Install Tailscale on Windows</h3><ol><li>Download from: <a href="https://tailscale.com/download">https://tailscale.com/download</a></li><li>Install and open it</li><li>Sign in with your account</li><li>Authorize the device</li></ol><p>Your PC is now connected.</p><h3>🟢 Step 3: Install Tailscale on Android</h3><ol><li>Open Play Store</li><li>Install <strong>Tailscale</strong></li><li>Open the app</li><li>Sign in with the same account</li><li>Tap <strong>Connect</strong></li></ol><p>Now both devices are on the same private network.</p><h3>🟢 Step 4: Enable Exit Node on Windows</h3><p>This step allows your PC to share its internet.</p><p>On Windows:</p><ol><li>Open <strong>PowerShell as Administrator</strong></li><li>Run:</li></ol><pre>tailscale up --advertise-exit-node</pre><p>Then open:</p><p>👉 <a href="https://login.tailscale.com/admin/machines">https://login.tailscale.com/admin/machines</a></p><p>Find your PC and enable:</p><p>✔️ <strong>Exit Node</strong></p><h3>🟢 Step 5: Use Windows Internet on Android</h3><p>On your Android phone:</p><ol><li>Open Tailscale</li><li>Tap your Windows PC</li><li>Enable <strong>Use as Exit Node</strong></li></ol><p>That’s it 🎉</p><p>Your phone is now using your PC’s internet.</p><h3>🟢 Step 6: Test Your Connection</h3><p>Open a browser on your phone and visit:</p><pre>https://whatismyipaddress.com</pre><p>You should see your home/PC IP address.</p><p>If yes — it’s working ✅</p><h3>⚡ Optional: Always-On Protection (Recommended)</h3><p>For better privacy:</p><p>On Android:</p><p>Tailscale → Settings → VPN</p><p>Enable:</p><ul><li>Always-on VPN</li><li>Block connections without VPN</li></ul><p>This ensures all traffic goes through Tailscale.</p><h3>💡 Why I Prefer Tailscale Over Traditional VPNs</h3><p>FeatureTraditional VPNTailscaleSetupComplexVery EasyPort ForwardingRequiredNot NeededNAT IssuesCommonNoneSpeedMediumHighSecurityGoodExcellent</p><p>Tailscale removes almost all networking pain.</p><h3>⚠️ Important Things to Remember</h3><h3>1️⃣ Your PC Must Be ON</h3><p>If your PC is off, your phone won’t connect.</p><h3>2️⃣ Speed Depends on PC Internet</h3><p>Your phone’s speed = your PC’s speed.</p><h3>3️⃣ Mobile Data Is Still Used</h3><p>Your phone still needs internet to connect to Tailscale.</p><p>But downloads and browsing use your PC’s network.</p><h3>🌍 Real Use Cases</h3><p>Here’s how I use this setup:</p><p>✅ Secure browsing on public WiFi<br> ✅ Access home network remotely<br> ✅ Use home IP while traveling<br> ✅ Run scripts via home network<br> ✅ Avoid regional blocks (legally)</p><h3>🏁 Final Thoughts</h3><p>If you’ve ever struggled with VPN servers, port forwarding, or complicated networking — Tailscale is a game changer.</p><p>With just a few clicks, you get:</p><p>✔ Your own private VPN<br> ✔ No maintenance<br> ✔ Strong encryption<br> ✔ Works anywhere</p><p>And best of all — it’s free for personal use.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6f13ed9d53c6" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using Asterisk ARI to Control Calls, Channels, and Media with REST APIs]]></title>
            <link>https://medium.com/@shubhanshutiwari74156/using-asterisk-ari-to-control-calls-channels-and-media-with-rest-apis-92866a88fc50?source=rss-0c3985c29880------2</link>
            <guid isPermaLink="false">https://medium.com/p/92866a88fc50</guid>
            <category><![CDATA[asterisk]]></category>
            <category><![CDATA[asterisk-rest-interface]]></category>
            <category><![CDATA[ai-call-agent]]></category>
            <category><![CDATA[pipecat]]></category>
            <dc:creator><![CDATA[Shubhanshu Tiwari]]></dc:creator>
            <pubDate>Sun, 11 Jan 2026 09:56:40 GMT</pubDate>
            <atom:updated>2026-01-11T09:57:03.654Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*yHlrBZ-3MQxnXvJ1.png" /></figure><p>Modern telephony applications increasingly demand <strong>programmable control</strong> over calls — far beyond what traditional dialplans can offer. This is where <strong>ARI (Asterisk REST Interface)</strong> becomes a game-changer.</p><p>In this article, we’ll walk through <strong>how to use ARI to manipulate channels, create bridges, connect multiple calls into a single room, and even stream audio to an external AI agent</strong> using AudioSocket and custom transport logic.</p><h3>What Is Asterisk ARI?</h3><p><strong>Asterisk ARI (Asterisk REST Interface)</strong> exposes call control through <strong>REST APIs and WebSocket events</strong>. Instead of writing complex logic in the dialplan, ARI allows you to:</p><ul><li>Control call flow programmatically</li><li>Create and destroy channels</li><li>Mix multiple callers into bridges</li><li>React to call events in real time</li><li>Integrate external systems like AI agents or media processors</li></ul><p>ARI shifts Asterisk from <em>dialplan-driven</em> to <em>application-driven</em> telephony.</p><h3>Required Configuration Files</h3><p>Before using ARI, you need to enable and configure it in Asterisk.</p><h3>1. http.conf</h3><p>ARI is served over HTTP, so the internal HTTP server must be enabled.</p><pre>[general]<br>enabled = yes<br>bindaddr = 0.0.0.0<br>bindport = 8088</pre><h3>2. ari.conf</h3><p>This file defines ARI users and permissions.</p><pre>[general]<br>enabled = yes</pre><pre>[ariuser]<br>type = user<br>read_only = no<br>password = strongpassword</pre><p>This user will authenticate REST requests and WebSocket event streams.</p><h3>3. extensions.conf (Dialplan)</h3><p>To hand control of a call to ARI, the channel must enter <strong>Stasis</strong>.</p><pre>[default]<br>exten =&gt; 1000,1,Answer()<br> same =&gt; n,Stasis(my_stasis_app)<br> same =&gt; n,Hangup()</pre><blockquote><strong><em>Why Stasis matters:</em></strong><em><br> A channel only becomes controllable via ARI </em><strong><em>after it enters Stasis</em></strong><em>. This step registers your application name with Asterisk and pauses dialplan execution.</em></blockquote><h3>Registering a Stasis Application</h3><p>When a channel enters Stasis(my_stasis_app):</p><ul><li>Asterisk fires a StasisStart event</li><li>Your ARI application receives it via WebSocket</li><li>You now control the channel lifecycle using REST APIs</li></ul><p>Your application typically:</p><ol><li>Opens a <strong>WebSocket connection</strong> to /ari/events</li><li>Subscribes to the Stasis app</li><li>Listens for channel and bridge events</li></ol><h3>Manipulating Channels via ARI</h3><p>Once inside Stasis, you can:</p><ul><li>Answer or hang up calls</li><li>Play media</li><li>Redirect calls</li><li>Add or remove channels from bridges</li></ul><p>Example REST call:</p><pre>POST /ari/channels/{channelId}/answer</pre><p>ARI gives <strong>full real-time control</strong> over active channels.</p><h3>Creating a Conference Room Using Bridges</h3><p>To connect multiple callers into a single room, ARI uses <strong>bridges</strong>.</p><h3>Mixing Bridge (Most Common)</h3><pre>POST /ari/bridges<br>{<br>  &quot;type&quot;: &quot;mixing&quot;,<br>  &quot;name&quot;: &quot;conference-room-1&quot;<br>}</pre><p>Then add channels:</p><pre>POST /ari/bridges/{bridgeId}/addChannel?channel={channelId}</pre><h3>Why Mixing Bridges?</h3><ul><li>Automatically mixes audio</li><li>Supports many participants</li><li>Ideal for conferencing and AI-powered rooms</li></ul><p>By reacting to ARI events (like StasisStart), you can dynamically add each incoming channel to the same bridge.</p><h3>Listening to ARI Events via WebSocket</h3><p>ARI events are delivered over a <strong>persistent WebSocket connection</strong>.</p><p>Key events include:</p><ul><li>StasisStart</li><li>StasisEnd</li><li>ChannelDestroyed</li><li>BridgeCreated</li></ul><p>This event-driven model lets your application behave like a <strong>real-time call controller</strong>, not just a passive API client.</p><h3>Connecting External Agents with AudioSocket</h3><p>To stream call audio to an external service (like an AI agent), Asterisk provides <strong>AudioSocket</strong>.</p><p>AudioSocket:</p><ul><li>Uses <strong>TCP</strong>, not UDP</li><li>Sends <strong>raw PCM audio frames</strong></li><li>Requires manual handling of audio payloads</li></ul><p>This is especially useful when your agent:</p><ul><li>Runs on a different machine</li><li>Needs real-time bidirectional audio</li><li>Must process audio outside Asterisk</li></ul><p>Official documentation:<br><a href="https://docs.asterisk.org/Configuration/Channel-Drivers/AudioSocket/">https://docs.asterisk.org/Configuration/Channel-Drivers/AudioSocket/</a></p><h3>Why You Need a TCP Bridge</h3><p>Since AudioSocket works over TCP:</p><ul><li>You must handle framing, buffering, and timing manually</li><li>You must support <strong>different audio payload formats</strong></li><li>You need a transport layer that can multiplex audio streams</li></ul><p>In my implementation, I created a <strong>custom transport logic</strong> that:</p><ul><li>Receives PCM audio from Asterisk</li><li>Normalizes and buffers frames</li><li>Streams audio reliably to an external system</li></ul><h3>Integrating with an AI Agent (Pipecat)</h3><p>I connected this AudioSocket pipeline to <strong>Pipecat</strong>, a powerful library for building <strong>real-time AI voice agents</strong>.</p><p>The flow looks like this:</p><ol><li>Caller enters Stasis</li><li>Channel is added to a mixing bridge</li><li>External media channel is created</li><li>AudioSocket streams PCM audio over TCP</li><li>Custom transport forwards audio to Pipecat</li><li>AI agent processes audio and responds</li><li>Response audio is injected back into the bridge</li></ol><p>This architecture enables:</p><ul><li>AI call assistants</li><li>Voice bots</li><li>Real-time transcription</li><li>Intelligent IVR systems</li></ul><h3>Final Thoughts</h3><p>Using <strong>Asterisk ARI</strong>, you move from static telephony to <strong>fully programmable voice applications</strong>.</p><p>With ARI + Stasis:</p><ul><li>Calls become software objects</li><li>Bridges become virtual rooms</li><li>Audio becomes data you can route anywhere</li></ul><p>And by combining <strong>ARI, AudioSocket, and AI frameworks like Pipecat</strong>, you can build next-generation voice systems that go far beyond traditional PBX behavior.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=92866a88fc50" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Real-Time AI Voice Agents with Asterisk AudioSocket: Build Conversational Telephony Systems in…]]></title>
            <link>https://medium.com/@shubhanshutiwari74156/real-time-ai-voice-agents-with-asterisk-audiosocket-build-conversational-telephony-systems-in-4768a7a80a76?source=rss-0c3985c29880------2</link>
            <guid isPermaLink="false">https://medium.com/p/4768a7a80a76</guid>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[asterisk]]></category>
            <dc:creator><![CDATA[Shubhanshu Tiwari]]></dc:creator>
            <pubDate>Thu, 09 Oct 2025 07:10:14 GMT</pubDate>
            <atom:updated>2025-10-09T07:10:14.887Z</atom:updated>
            <content:encoded><![CDATA[<h3>Real-Time AI Voice Agents with Asterisk AudioSocket: Build Conversational Telephony Systems in Python</h3><p>The future of customer service isn’t human operators — it’s intelligent voice agents that understand natural language, respond in real-time, and never sleep. This technical deep-dive explores AudioSocket, Asterisk’s TCP-based audio streaming protocol that enables bidirectional voice communication between PBX systems and AI applications. Whether building automated support lines, AI receptionists, or outbound calling campaigns, this architecture provides the foundation for production-grade conversational AI.</p><h3>Why AudioSocket for AI Telephony?</h3><p>Traditional Asterisk integrations like AGI and EAGI operate in blocking modes with limited audio access. The Asterisk REST Interface (ARI) offers external media capabilities but requires WebRTC expertise and complex RTP handling. AudioSocket simplifies this entirely by establishing a direct TCP connection that streams raw PCM audio bidirectionally — perfect for machine learning pipelines requiring real-time processing.</p><p>Key advantages include:</p><ul><li>Minimal latency through persistent TCP connections rather than HTTP polling</li><li>Simple binary protocol requiring no SIP or RTP knowledge</li><li>Native support in Asterisk 18+ without third-party modules</li><li>Synchronous bidirectional audio enabling interrupt-driven conversations</li><li>Language-agnostic implementation compatible with Python, Node.js, Go, and more</li></ul><h3>The AI Voice Agent Architecture</h3><p>Understanding the complete signal flow is essential before diving into configuration. When a call connects, Asterisk’s dialplan routes the channel to the AudioSocket application, which establishes a TCP connection to the AI server. The server receives 8kHz 16-bit PCM audio in 320-byte frames (20ms chunks), processes speech through ASR (Automatic Speech Recognition), generates responses via LLM (Large Language Model), synthesizes audio with TTS (Text-to-Speech), and streams it back through the same connection.</p><p>The modularity allows swapping services freely — use Deepgram for transcription, OpenAI GPT-4 for dialogue, and ElevenLabs for voice synthesis, or replace any component with open-source alternatives like Whisper, Llama, and Coqui TTS. Some platforms like OpenAI Realtime API offer speech-to-speech capabilities, bypassing the separate ASR/LLM/TTS pipeline entirely.</p><h3>Audio Format Specifications</h3><p>AudioSocket delivers telephony-grade audio matching PSTN standards. The format uses 8kHz sampling rate (sufficient for voice frequency range 300–3400 Hz), 16-bit signed linear PCM encoding (providing 96 dB dynamic range), mono channel configuration, and 320-byte frames representing exactly 20 milliseconds of audio. These specifications ensure compatibility with virtually all speech processing services while maintaining manageable bandwidth — 128 kbps per active connection.</p><h3>Prerequisites and System Requirements</h3><p>Starting with a properly configured foundation prevents frustrating troubleshooting later. Requirements include a running Asterisk server version 18 or newer with the app_audiosocket module enabled, Python 3.7+ environment for the AudioSocket server implementation, configured SIP trunk (Twilio, Telnyx, or local provider), basic Asterisk dialplan knowledge, and network connectivity between the Asterisk server and Python application.</p><h3>Verifying AudioSocket Module</h3><h3>Checking Module Status</h3><p>Before configuration, confirm AudioSocket support exists in the Asterisk installation. Connect to the Asterisk CLI and query module status:</p><pre>asterisk -rx &quot;module show like audiosocket&quot;</pre><p>The output should display app_audiosocket.so with a loaded status. If missing, install the asterisk-modules package on Debian/Ubuntu systems or asterisk-contrib on RedHat-based distributions.</p><h3>Loading the Module</h3><p>Manually load the module if not automatically initialized during startup:</p><pre>asterisk -rx &quot;module load app_audiosocket&quot;</pre><p>Verify successful loading by checking module status again or reviewing /var/log/asterisk/messages for initialization messages.</p><h3>Configuring PJSIP Transport</h3><h3>Understanding NAT Traversal</h3><p>Public internet deployments require careful transport configuration for proper media and signaling routing. Edit /etc/asterisk/pjsip.conf with transport settings specifying the public IP address:</p><pre>[transport-udp]<br>type=transport<br>protocol=udp<br>bind=0.0.0.0<br>external_media_address=YOUR_PUBLIC_IP<br>external_signaling_address=YOUR_PUBLIC_IP<br>local_net=YOUR_PUBLIC_IP/32</pre><p>The external_media_address parameter ensures RTP streams correctly traverse NAT by advertising the public address in SDP (Session Description Protocol) messages. The external_signaling_address similarly handles SIP INVITE and response routing. Replace YOUR_PUBLIC_IP with the actual server address visible to the internet.</p><h3>Local Network Configuration</h3><p>The local_net parameter defines internal network ranges for determining when to apply external address rewriting. For cloud VPS deployments with single network interfaces, specify the public IP with /32 CIDR notation.</p><h3>Configuring the Twilio Trunk</h3><h3>Endpoint Definition</h3><p>Establish the SIP trunk connection to Twilio’s Elastic SIP Trunking infrastructure. Add endpoint configuration to /etc/asterisk/pjsip.conf:</p><pre>[twilio_trunk]<br>type=endpoint<br>context=from-twilio<br>disallow=all<br>allow=ulaw,alaw<br>aors=twilio_trunk<br>outbound_auth=twilio_auth<br>from_domain=YOUR_TRUNK_NAME.pstn.twilio.com</pre><p>The codec restriction to G.711 formats (ulaw for North America, alaw for Europe) ensures maximum compatibility and minimal transcoding overhead. The context parameter defines which dialplan section handles incoming calls.</p><h3>Address of Record Configuration</h3><p>Define the contact URI for reaching Twilio’s SIP infrastructure:</p><pre>[twilio_trunk]<br>type=aor<br>contact=sip:YOUR_USERNAME@YOUR_TRUNK_NAME.pstn.twilio.com</pre><p>Replace placeholders with actual Twilio Elastic SIP Trunk credentials obtained from the console. The contact address specifies where Asterisk sends outbound INVITE requests.</p><h3>Authentication Credentials</h3><p>Configure credential list authentication or IP ACL-based access control:</p><pre>[twilio_auth]<br>type=auth<br>auth_type=userpass<br>username=YOUR_TWILIO_USERNAME<br>password=YOUR_TWILIO_PASSWORD</pre><p>For IP-only authentication, remove the outbound_auth line from the endpoint configuration and whitelist the server IP in Twilio&#39;s trunk settings.</p><h3>Endpoint Identification</h3><p>Map incoming traffic from Twilio’s domain to the correct endpoint:</p><pre>[twilio_identify]<br>type=identify<br>endpoint=twilio_trunk<br>match=YOUR_TRUNK_NAME.pstn.twilio.com</pre><p>This configuration ensures calls originating from Twilio route to the appropriate endpoint context without authentication failures.</p><h3>Building the AI Dialplan</h3><h3>Outbound Call Context</h3><p>Create a dialplan context for initiating AI-powered outbound calls in /etc/asterisk/extensions.conf:</p><pre>[ai-outbound]<br>exten =&gt; _+X.,1,NoOp(=== AI outbound call to ${EXTEN} ===)<br> same =&gt; n,Set(CALLERID(num)=YOUR_TWILIO_NUMBER)<br> same =&gt; n,Dial(PJSIP/${EXTEN}@twilio_trunk,30,U(AUDIOHOOK_IN^1^1))<br> same =&gt; n,Hangup()</pre><p>The pattern _+X. matches E.164 formatted numbers. The U(AUDIOHOOK_IN^1^1) option executes a subroutine when the called party answers, enabling seamless AudioSocket connection without interrupting the call flow.</p><h3>AudioSocket Connection Subroutine</h3><p>Define the subroutine that bridges the call to the AI server:</p><pre>[AUDIOHOOK_IN]<br>exten =&gt; s,1,NoOp(=== External call answered, connecting AudioSocket ===)<br> same =&gt; n,Answer()<br> same =&gt; n,AudioSocket(${UUID()},YOUR_SERVER_IP:9092)<br> same =&gt; n,Hangup()</pre><p>The AudioSocket() application accepts two parameters: a unique identifier (using UUID function for tracking) and the TCP endpoint address. Replace YOUR_SERVER_IP:9092 with the actual Python server location. Port 9092 is arbitrary—choose any available port and configure firewall rules accordingly.</p><h3>Inbound Call Handling</h3><p>Optionally create a context for AI-handled inbound calls:</p><pre>[from-twilio]<br>exten =&gt; _X.,1,NoOp(=== Incoming call from ${CALLERID(num)} ===)<br> same =&gt; n,Answer()<br> same =&gt; n,AudioSocket(${UUID()},127.0.0.1:9092)<br> same =&gt; n,Hangup()</pre><p>This routes all incoming calls directly to the AI agent without ringing internal extensions.</p><h3>Understanding the AudioSocket Protocol</h3><h3>Message Structure</h3><p>AudioSocket uses a simple framing protocol with three-byte headers preceding variable-length payloads. The header consists of a single byte message type (0x00–0xff), followed by a two-byte big-endian unsigned integer specifying payload length. This design enables efficient parsing and minimal protocol overhead.</p><h3>Message Types</h3><p>Five message types comprise the complete protocol:</p><p>UUID (0x01): The first message sent by Asterisk after connection establishment, containing a 16-byte binary UUID identifying the call session. Servers should store this identifier for logging and correlation with other systems.</p><p>AUDIO (0x10): Bidirectional audio frames containing exactly 320 bytes of signed 16-bit PCM data. Asterisk sends these continuously during active speech, and servers send them back to inject audio into the call.</p><p>DTMF (0x03): Single-byte payload containing the ASCII representation of a pressed telephone keypad digit (0–9, *, #, A-D). Useful for building interactive menu systems within AI conversations.</p><p>HANGUP (0x00): Sent by Asterisk when the call terminates, signaling the server to close the TCP connection gracefully. No payload accompanies this message type.</p><p>ERROR (0xff): Indicates protocol violations or processing failures within Asterisk. The single-byte payload contains an error code for diagnostic purposes.</p><h3>Implementing the Python AudioSocket Server</h3><h3>Basic Server Structure</h3><p>Create a multi-threaded TCP server to handle concurrent calls. The following implementation demonstrates core functionality:</p><pre>import socket<br>import threading<br>import wave<br>import io<br>import struct</pre><pre>HOST = &quot;0.0.0.0&quot;<br>PORT = 9092</pre><pre># AudioSocket message types<br>MSG_HANGUP = 0x00<br>MSG_UUID = 0x01<br>MSG_DTMF = 0x03<br>MSG_AUDIO = 0x10<br>MSG_ERROR = 0xff</pre><p>These constants define the message type byte values used throughout the protocol.</p><h3>Reading Protocol Messages</h3><p>Implement robust message parsing handling partial reads and network fragmentation:</p><pre>def read_message(conn):<br>    &quot;&quot;&quot;Read a complete AudioSocket message&quot;&quot;&quot;<br>    header = conn.recv(3)<br>    if len(header) &lt; 3:<br>        return None, None<br>    <br>    msg_type = header[0]<br>    payload_length = struct.unpack(&#39;&gt;H&#39;, header[1:3])[0]<br>    <br>    payload = b&#39;&#39;<br>    while len(payload) &lt; payload_length:<br>        chunk = conn.recv(payload_length - len(payload))<br>        if not chunk:<br>            break<br>        payload += chunk<br>    <br>    return msg_type, payload</pre><p>The big-endian unsigned integer unpacking (&#39;&gt;H&#39;) matches AudioSocket&#39;s wire format specification. The loop ensures complete payload reception even if TCP delivers fragmented packets.</p><h3>Sending Audio Responses</h3><p>Format outgoing audio according to protocol requirements:</p><pre>def send_audio(conn, audio_data):<br>    &quot;&quot;&quot;Send audio back to Asterisk via AudioSocket&quot;&quot;&quot;<br>    if len(audio_data) != 320:<br>        if len(audio_data) &lt; 320:<br>            audio_data = audio_data + b&#39;\x00&#39; * (320 - len(audio_data))<br>        else:<br>            audio_data = audio_data[:320]<br>    <br>    msg_type = MSG_AUDIO<br>    length = len(audio_data)<br>    header = struct.pack(&#39;B&#39;, msg_type) + struct.pack(&#39;&gt;H&#39;, length)<br>    conn.sendall(header + audio_data)</pre><p>AudioSocket strictly expects 320-byte audio frames. Padding shorter frames with silence bytes prevents desynchronization, while trimming longer data maintains timing accuracy.</p><h3>Connection Handler Implementation</h3><p>Process individual call sessions in isolated threads:</p><pre>def handle_client(conn, addr):<br>    print(f&quot;[+] New AudioSocket connection from {addr}&quot;)<br>    <br>    conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)<br>    <br>    audio_buffer = io.BytesIO()<br>    call_uuid = None<br>    <br>    try:<br>        msg_type, payload = read_message(conn)<br>        <br>        if msg_type == MSG_UUID and len(payload) == 16:<br>            call_uuid = payload.hex()<br>            print(f&quot;[UUID] Call UUID: {call_uuid}&quot;)<br>        <br>        while True:<br>            msg_type, payload = read_message(conn)<br>            <br>            if msg_type is None:<br>                break<br>            <br>            if msg_type == MSG_HANGUP:<br>                print(&quot;[HANGUP] Received hangup signal&quot;)<br>                break<br>            <br>            elif msg_type == MSG_AUDIO:<br>                audio_buffer.write(payload)<br>                send_audio(conn, payload)  # Echo for testing<br>            <br>            elif msg_type == MSG_DTMF:<br>                dtmf_digit = chr(payload[0])<br>                print(f&quot;[DTMF] Received digit: {dtmf_digit}&quot;)<br>            <br>            elif msg_type == MSG_ERROR:<br>                error_code = payload[0] if payload else 0<br>                print(f&quot;[ERROR] Asterisk error code: {error_code}&quot;)<br>                break<br>    <br>    except Exception as e:<br>        print(f&quot;[!] Error: {e}&quot;)<br>    <br>    finally:<br>        if audio_buffer.tell() &gt; 0:<br>            output_file = f&quot;recorded_{call_uuid or addr[1]}.wav&quot;<br>            with wave.open(output_file, &quot;wb&quot;) as wf:<br>                wf.setnchannels(1)<br>                wf.setsampwidth(2)<br>                wf.setframerate(8000)<br>                wf.writeframes(audio_buffer.getvalue())<br>            print(f&quot;[✓] Audio saved to {output_file}&quot;)<br>        <br>        conn.close()</pre><p>Enabling TCP_NODELAY disables Nagle’s algorithm, reducing latency by immediately transmitting small packets rather than buffering them. The echo implementation demonstrates bidirectional flow — replace this with actual AI processing for production systems.</p><h3>Main Server Loop</h3><p>Accept and dispatch connections to handler threads:</p><pre>def main():<br>    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:<br>        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)<br>        s.bind((HOST, PORT))<br>        s.listen()<br>        print(f&quot;🎧 AudioSocket server listening on {HOST}:{PORT}&quot;)<br>        <br>        while True:<br>            conn, addr = s.accept()<br>            threading.Thread(target=handle_client, args=(conn, addr), daemon=True).start()</pre><pre>if __name__ == &quot;__main__&quot;:<br>    main()</pre><p>Daemon threads automatically terminate when the main program exits, preventing orphaned processes. The SO_REUSEADDR socket option allows immediate rebinding if the server crashes and restarts.</p><h3>Applying Configuration Changes</h3><h3>Reloading Without Downtime</h3><p>Asterisk supports hot-reloading configuration files without disrupting active calls. Apply PJSIP changes:</p><pre>asterisk -rx &quot;pjsip reload&quot;</pre><p>Reload dialplan modifications:</p><pre>asterisk -rx &quot;dialplan reload&quot;</pre><h3>Verification Commands</h3><p>Confirm transport configuration:</p><pre>asterisk -rx &quot;pjsip show transports&quot;</pre><p>Check endpoint registration status:</p><pre>asterisk -rx &quot;pjsip show endpoints&quot;</pre><p>Examine active AudioSocket connections:</p><pre>asterisk -rx &quot;core show channels&quot;</pre><h3>Testing the Complete System</h3><h3>Starting the Python Server</h3><p>Launch the AudioSocket server before initiating calls:</p><pre>python3 audiosocket_server.py</pre><p>Successful startup displays the listening message with host and port information. Monitor the terminal for connection logs during testing.</p><h3>Originating Test Calls</h3><p>Connect to Asterisk CLI with verbose logging enabled:</p><pre>asterisk -rvvv</pre><p>Manually originate an outbound call:</p><pre>channel originate Local/+1234567890@ai-outbound extension s@default</pre><p>Replace the phone number with a valid test destination. Watch both Asterisk CLI output and Python server logs for connection establishment and audio flow indicators.</p><h3>Monitoring Audio Exchange</h3><p>The Python server prints periodic progress updates showing accumulated audio duration. Verify bidirectional flow by speaking into the phone and confirming audio reception in server logs. The echo implementation plays back received audio after a brief delay.</p><h3>Troubleshooting Common Issues</h3><h3>Module Not Found Errors</h3><p>If AudioSocket application fails to load, verify module installation status:</p><pre>asterisk -rx &quot;module show like audiosocket&quot;</pre><p>Install missing packages on Ubuntu/Debian:</p><pre>apt-get install asterisk-modules</pre><p>Force module loading from CLI:</p><pre>asterisk -rx &quot;module load app_audiosocket&quot;</pre><h3>Connection Refused</h3><p>TCP connection failures typically indicate firewall blocking or incorrect address binding. Verify Python server is running and listening:</p><pre>netstat -tlnp | grep 9092</pre><p>Check firewall rules allow inbound connections:</p><pre>sudo ufw allow 9092/tcp</pre><p>For remote servers, ensure the address in dialplan matches the actual server location rather than 127.0.0.1.</p><h3>No Audio Received</h3><p>Silent calls despite successful connection suggest codec negotiation problems or media routing failures. Verify allowed codecs in endpoint configuration match Twilio’s capabilities:</p><pre>asterisk -rx &quot;pjsip show endpoint twilio_trunk&quot;</pre><p>Enable verbose logging to trace audio path:</p><pre>asterisk -rvvv</pre><p>Confirm AudioSocket application executes in dialplan by watching for connection messages.</p><h3>Authentication Failures</h3><p>407 Proxy Authentication Required responses indicate credential mismatches. Double-check username and password in [twilio_auth] section exactly match Twilio console values. Alternatively, configure IP ACL authentication in Twilio trunk settings and remove outbound_auth from endpoint configuration.</p><h3>Frame Size Violations</h3><p>Protocol errors mentioning frame sizes usually stem from incorrect audio format handling. Ensure all sent audio uses exactly 320 bytes per frame. Verify no transcoding occurs between Asterisk and the audio processing pipeline.</p><h3>Integrating AI Services</h3><h3>Speech-to-Text Pipeline</h3><p>Replace the echo implementation with real-time ASR processing. Deepgram, Google Speech-to-Text, and Whisper provide streaming APIs accepting PCM audio chunks:</p><pre>elif msg_type == MSG_AUDIO:<br>    audio_buffer.write(payload)<br>    <br>    # Send to STT service<br>    transcript = stt_service.transcribe(payload)<br>    <br>    if transcript:<br>        print(f&quot;[TRANSCRIPT] {transcript}&quot;)</pre><p>Streaming ASR services return partial results during speech and final transcriptions at sentence boundaries. Buffer these results until detecting silence or end-of-utterance markers.</p><h3>LLM Conversation Management</h3><p>Feed transcribed text into language model APIs maintaining conversation context:</p><pre># Process with LLM<br>    response_text = llm_service.generate_response(transcript, context)<br>    <br>    # Update conversation history<br>    context.append({&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: transcript})<br>    context.append({&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: response_text})</pre><p>OpenAI’s GPT-4, Anthropic’s Claude, and locally-hosted models like Llama accept conversation histories enabling contextual understanding across multiple turns.</p><h3>Text-to-Speech Synthesis</h3><p>Convert generated responses back to audio format matching AudioSocket specifications:</p><pre># Convert to audio with TTS<br>    response_audio = tts_service.synthesize(response_text, format=&quot;pcm&quot;, <br>                                           sample_rate=8000, bit_depth=16)<br>    <br>    # Send back to caller in 320-byte chunks<br>    for i in range(0, len(response_audio), 320):<br>        chunk = response_audio[i:i+320]<br>        send_audio(conn, chunk)</pre><p>ElevenLabs, Google TTS, and Coqui provide high-quality synthesis with customizable voices and speaking styles. Request PCM output at 8kHz to avoid resampling overhead.</p><h3>Speech-to-Speech Direct Integration</h3><p>Modern services like OpenAI Realtime API bypass the separate STT/LLM/TTS pipeline entirely:</p><pre>elif msg_type == MSG_AUDIO:<br>    # Send directly to speech-to-speech service<br>    response_audio = sts_service.process(payload)<br>    <br>    # Stream response back immediately<br>    send_audio(conn, response_audio)</pre><p>This approach reduces latency significantly by eliminating transcription and synthesis steps. Alternatives include ElevenLabs Conversational AI and Deepgram’s speech-to-speech APIs.</p><h3>Production Deployment Considerations</h3><h3>Scalability and Load Balancing</h3><p>Single-threaded Python servers handle dozens of concurrent calls, but production systems require horizontal scaling. Deploy multiple AudioSocket server instances behind load balancers, ensuring Asterisk distributes connections evenly. Container orchestration with Docker and Kubernetes simplifies scaling and resource management.</p><h3>Error Handling and Recovery</h3><p>Robust error handling prevents single call failures from affecting other sessions. Wrap audio processing in try-except blocks, log exceptions with call UUIDs for debugging, and gracefully close connections on errors. Implement automatic reconnection logic if external AI services experience temporary outages.</p><h3>Monitoring and Analytics</h3><p>Track key metrics including average call duration, speech recognition accuracy, LLM response latency, and audio quality indicators. Store conversation logs for quality assurance and model training. Integrate with observability platforms like Prometheus and Grafana for real-time system monitoring.</p><h3>Security Hardening</h3><p>Restrict AudioSocket server binding to internal networks rather than 0.0.0.0 when possible. Implement TLS tunneling via stunnel or SSH port forwarding for encrypted transport. Validate all protocol messages before processing to prevent malformed data exploits. Sanitize conversation logs to remove sensitive personal information before storage.</p><h3>Cost Optimization</h3><p>AI service costs accumulate rapidly at scale. Use local speech recognition models like Vosk or Silero for cost-sensitive applications. Implement conversation timeouts to prevent runaway LLM charges from stuck calls. Cache common TTS outputs rather than synthesizing identical phrases repeatedly.</p><h3>Advanced Use Cases</h3><h3>Multi-Language Support</h3><p>Configure language detection in ASR services to automatically identify caller language. Switch TTS voices dynamically based on detected or configured language preferences. OpenAI and Anthropic models handle multilingual conversations natively without specialized configuration.</p><h3>Interrupt Handling</h3><p>Implement barge-in detection allowing callers to interrupt AI responses. Monitor incoming audio volume during TTS playback and stop speech generation when detecting human voice. This creates natural conversation flow mimicking human interaction patterns.</p><h3>Transfer to Human Agents</h3><p>When AI agents encounter complex queries beyond their capabilities, seamlessly transfer calls to human operators. Use Asterisk’s transfer applications within the AudioSocket dialplan context, passing conversation context to agent screens via CRM integration.</p><h3>Call Recording and Quality Assurance</h3><p>The provided Python server saves complete audio to WAV files for analysis. Extend this functionality to store conversation transcripts, LLM responses, and caller sentiment scores. Review recordings to identify common failure patterns and improve AI prompts accordingly.</p><h3>Open Source Reference Implementations</h3><p>The Agent Voice Response (AVR) project provides production-ready infrastructure demonstrating these concepts. The open-source codebase includes Docker-based deployment, modular ASR/LLM/TTS integration, conversation management logic, and extensive documentation. Explore the GitHub organization at <a href="https://github.com/agentvoiceresponse"><strong>https://github.com/agentvoiceresponse</strong></a> for complete examples and community support.</p><h3>Next Steps</h3><p>This foundation enables building sophisticated conversational AI systems rivaling commercial offerings. Experiment with different language models to find the optimal balance between response quality and latency. Test various TTS voices to identify those best matching brand identity and user preferences. Monitor real-world performance metrics and continuously refine prompts based on actual conversation patterns.</p><p>The complete source code repository including the Python server implementation and Asterisk configuration examples is available in the project documentation. Join the Asterisk community and AI telephony Discord servers for ongoing support and collaboration opportunities.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4768a7a80a76" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a Complete Asterisk PBX with Twilio Integration: A Developer’s Guide to VoIP at Scale]]></title>
            <link>https://medium.com/@shubhanshutiwari74156/building-a-complete-asterisk-pbx-with-twilio-integration-a-developers-guide-to-voip-at-scale-8d069b641dfa?source=rss-0c3985c29880------2</link>
            <guid isPermaLink="false">https://medium.com/p/8d069b641dfa</guid>
            <category><![CDATA[configuration]]></category>
            <category><![CDATA[setup]]></category>
            <category><![CDATA[voip]]></category>
            <category><![CDATA[asterisk]]></category>
            <category><![CDATA[pbx]]></category>
            <dc:creator><![CDATA[Shubhanshu Tiwari]]></dc:creator>
            <pubDate>Thu, 09 Oct 2025 06:20:41 GMT</pubDate>
            <atom:updated>2025-10-09T06:20:41.890Z</atom:updated>
            <content:encoded><![CDATA[<p>The world of telephony has evolved dramatically, and today developers can build enterprise-grade calling systems from scratch. This comprehensive guide walks through setting up Asterisk PBX on Ubuntu and integrating it with Twilio’s Elastic SIP Trunking to enable automated outbound calling — perfect for building AI-powered calling agents, contact centers, or automated notification systems.</p><h3>Why Asterisk + Twilio?</h3><p>Asterisk is the Swiss Army knife of open-source communications, powering everything from small office PBX systems to massive call centers. When combined with Twilio’s cloud infrastructure, developers gain access to global phone numbers, reliable PSTN connectivity, and pay-as-you-go pricing without maintaining physical telephony hardware.</p><p>Key benefits include:</p><ul><li>Full control over call routing and dialplan logic</li><li>Integration capabilities with custom applications via REST APIs and WebSockets</li><li>Cost-effective international calling through Twilio’s network</li><li>Scalability from proof-of-concept to production workloads</li></ul><h3>Understanding the Architecture</h3><p>Before diving into configuration, understanding the call flow is crucial. When making an outbound call, Asterisk acts as your private PBX, processing dialplan logic and routing the call through Twilio’s SIP trunk to reach the public telephone network (PSTN).</p><p>The typical message sequence follows the SIP protocol: INVITE initiates the call, 100 Trying acknowledges processing, 180 Ringing indicates alerting, 200 OK confirms connection, and ACK establishes the media session. RTP (Real-time Transport Protocol) then carries the actual audio between endpoints.</p><h3>System Prerequisites</h3><p>Starting with a clean Ubuntu server (physical or virtual) sets the foundation. Basic Linux command-line familiarity and an active Twilio account with a phone number are essential prerequisites. The installation process requires several build dependencies and approximately 30–45 minutes of configuration time.</p><h3>Installing Asterisk from Source</h3><h3>Preparing the System</h3><p>Begin by updating package repositories and installing compilation dependencies. The required libraries include XML parsing, SQLite database support, OpenSSL for encryption, Jansson for JSON handling, SRTP for secure media, and audio codec libraries:</p><pre>sudo apt update<br>sudo apt upgrade<br>sudo apt install build-essential git menuselect libxml2-dev libncurses5-dev libsqlite3-dev openssl libssl-dev libjansson-dev libsrtp2-dev libspeex-dev libspeexdsp-dev libogg-dev libvorbis-dev libasound2-dev libcurl4-openssl-dev uuid-dev</pre><h3>Downloading and Compiling</h3><p>Navigate to /usr/src and download the latest stable Asterisk release from the official repository. Extract the archive, run the configure script, and use menuselect to customize the build. Critical modules to enable include chan_pjsip.so for modern SIP support, res_hep.so for packet capture, and app_say.so for audio playback.</p><p>The compilation commands sequence through configure, make, installation, and sample generation:</p><pre>cd /usr/src<br>sudo wget http://downloads.asterisk.org/pub/telephony/asterisk/asterisk-18-current.tar.gz<br>sudo tar xvfz asterisk-18-current.tar.gz<br>cd asterisk-18*/<br>sudo ./configure<br>sudo make menuselect<br>sudo make &amp;&amp; sudo make install<br>sudo make config &amp;&amp; sudo make samples</pre><h3>Starting and Enabling Asterisk</h3><p>Use systemd to manage the Asterisk service, ensuring it starts automatically on boot. Verify the service status shows “active (running)” before proceeding to network configuration.</p><pre>sudo systemctl start asterisk<br>sudo systemctl enable asterisk<br>sudo systemctl status asterisk</pre><h3>Firewall Configuration</h3><p>Proper firewall rules prevent connectivity issues. SIP signaling requires UDP port 5060 (or TCP 5061 for TLS). RTP media uses a wide range, typically 10000–60000 UDP, though Twilio’s documentation should be consulted for current recommendations. Essential ports should be opened using ufw or iptables.</p><h3>Configuring PJSIP for Twilio</h3><h3>Understanding PJSIP vs Chan_SIP</h3><p>Modern Asterisk deployments should use PJSIP rather than the deprecated chan_sip driver. PJSIP offers better NAT traversal, IPv6 support, and cleaner configuration syntax.</p><h3>Creating the Trunk Configuration</h3><p>Edit /etc/asterisk/pjsip.conf to define the Twilio trunk connection. The configuration consists of four main sections: transport, endpoint, address-of-record (AOR), and authentication.</p><p>The transport section binds Asterisk to all network interfaces on UDP. The endpoint defines codec preferences (ulaw and alaw for compatibility), associates authentication credentials, and specifies the Twilio domain. Replace placeholders with actual Twilio Elastic SIP Trunk credentials from the console:</p><pre>[transport-udp]<br>type=transport<br>protocol=udp<br>bind=0.0.0.0</pre><pre>[twilio_trunk]<br>type=endpoint<br>context=from-twilio<br>disallow=all<br>allow=ulaw,alaw<br>aors=twilio_trunk<br>outbound_auth=twilio_auth<br>from_domain=YOUR_TRUNK_NAME.pstn.twilio.com</pre><pre>[twilio_trunk]<br>type=aor<br>contact=sip:YOUR_USERNAME@YOUR_TRUNK_NAME.pstn.twilio.com</pre><pre>[twilio_auth]<br>type=auth<br>auth_type=userpass<br>username=YOUR_USERNAME<br>password=YOUR_PASSWORD</pre><pre>[twilio_identify]<br>type=identify<br>endpoint=twilio_trunk<br>match=YOUR_TRUNK_NAME.pstn.twilio.com</pre><h3>Building the Dialplan</h3><h3>Dialplan Fundamentals</h3><p>Asterisk’s dialplan in /etc/asterisk/extensions.conf defines call routing logic. Each context contains extensions with pattern-matching capabilities and sequential priority steps.</p><h3>Outbound Calling Context</h3><p>Create a context for internal callers to reach external numbers through Twilio. The pattern _+X. matches any E.164 formatted number starting with a plus sign. Set the caller ID to the Twilio-purchased number, dial through the PJSIP trunk, and hang up after completion:</p><pre>[from-internal]<br>exten =&gt; _+X.,1,NoOp(Outbound call to ${EXTEN} via Twilio)<br>same =&gt; n,Set(CALLERID(num)=YOUR_TWILIO_NUMBER)<br>same =&gt; n,Dial(PJSIP/${EXTEN}@twilio_trunk,60)<br>same =&gt; n,Hangup()</pre><h3>Reloading Configuration</h3><p>After editing configuration files, reload without service interruption using Asterisk CLI commands. Use pjsip reload for PJSIP changes and dialplan reload for extensions modifications.</p><h3>Twilio Console Configuration</h3><h3>Creating the SIP Trunk</h3><p>Navigate to Elastic SIP Trunking in the Twilio Console and create a new trunk with a descriptive name. Configure termination settings by adding the Asterisk server’s public IP address to the IP Access Control List. This whitelist prevents unauthorized trunk usage.</p><p>Set the Termination URI to point at your Asterisk server: sip:YOUR_ASTERISK_IP:5060. For production deployments, credential authentication provides stronger security than IP-only ACLs.</p><h3>Associating Phone Numbers</h3><p>Purchase or assign an existing Twilio number to the trunk. Configure the number’s voice handling to use “SIP Trunk” and select the newly created trunk. This routes inbound calls to your Asterisk server through the origination URI.</p><h3>Origination URI Configuration</h3><p>For inbound calls, configure the Origination SIP URI pointing to your Asterisk: sip:twilio@YOUR_ASTERISK_IP:5060. Twilio automatically populates the user part with the dialed number, enabling flexible dialplan routing.</p><h3>Testing Your Setup</h3><h3>Accessing the Asterisk CLI</h3><p>Connect to the interactive CLI for diagnostics and manual call origination:</p><pre>sudo asterisk -rvvv</pre><p>Enable verbose PJSIP logging to troubleshoot connection issues:</p><pre>pjsip set logger on</pre><h3>Originating Test Calls</h3><p>From the CLI, manually initiate an outbound call to verify trunk connectivity. The channel originate command creates a local channel in your dialplan context, which then routes through Twilio:</p><pre>channel originate Local/+1234567890@from-internal extension s@default</pre><h3>Monitoring Call Progress</h3><p>Watch for SIP messages in the CLI output. Successful calls show INVITE, 100 Trying, 183 Session Progress, 200 OK, and ACK sequences. Media establishment appears as “Audio is at” followed by IP and port information.</p><h3>Troubleshooting Common Issues</h3><h3>Authentication Failures</h3><p>407 Proxy Authentication Required errors indicate credential mismatches. Verify username and password exactly match Twilio’s credential list. Ensure authentication configuration uses outbound_auth in the endpoint section.</p><h3>One-Way Audio</h3><p>Media flow problems often stem from firewall blocking RTP ports or incorrect NAT configuration. Enable Symmetric RTP in Twilio trunk settings if behind NAT. Confirm UDP ports 10000–60000 are open inbound.</p><h3>Call Rejected with 400 Bad Request</h3><p>Number format errors cause immediate rejection. All outbound numbers must use E.164 format with a plus prefix: +12125551234. Check the dialplan ensures incoming extensions include the plus sign.</p><h3>No Route to Destination</h3><p>Missing or incorrect AOR contact addresses prevent call routing. Verify the contact URI in pjsip.conf points to the correct Twilio domain. Use pjsip show endpoints in CLI to confirm trunk registration status.</p><h3>Production Considerations</h3><h3>High Availability</h3><p>Twilio provides multiple edge locations for geographic redundancy. Configure multiple termination URIs with priority and weight values for automatic failover. Localized endpoints like ashburn.twilio.com, dublin.twilio.com, and singapore.twilio.com reduce latency.</p><h3>Security Hardening</h3><p>Enable TLS encryption for SIP signaling and SRTP for media to prevent eavesdropping. Import Twilio’s root CA certificates into Asterisk for certificate validation. Use strong passwords in credential lists and rotate them regularly.</p><h3>Call Quality Monitoring</h3><p>Implement RTCP for media quality metrics and enable call recording for compliance or quality assurance. Monitor concurrent call capacity and scale server resources accordingly — plan 100kbps per simultaneous call.</p><h3>Cost Optimization</h3><p>Review Twilio’s per-minute pricing for different destinations and optimize routing for cost-effective termination. Set maximum call duration limits in the dialplan to prevent runaway charges.</p><h3>Advanced Use Cases</h3><h3>AI Agent Integration</h3><p>Connect speech recognition and text-to-speech engines to build intelligent IVR systems. Use Asterisk’s ARI (Asterisk REST Interface) to control calls programmatically from external applications. WebSocket audio streaming enables real-time AI agent interactions.</p><h3>CRM Integration</h3><p>Trigger outbound campaigns from customer databases using AMI (Asterisk Manager Interface) or ARI. Screen-pop functionality passes caller information to agent workstations during inbound calls.</p><h3>Multi-Tenant Configurations</h3><p>Separate contexts and PJSIP templates enable hosting multiple organizations on a single Asterisk instance. Database-driven dialplan configuration scales to thousands of users.</p><h3>Next Steps</h3><p>This foundation enables building sophisticated telephony applications combining Asterisk’s flexibility with Twilio’s global reach. Experiment with advanced dialplan applications like voicemail (app_voicemail), conferencing (app_confbridge), and call queues (app_queue). Explore Asterisk’s extensive module ecosystem and Twilio’s programmable voice APIs for endless possibilities.</p><p>The complete source code and configuration examples are available in the <a href="https://docs.asterisk.org/"><strong>Asterisk documentation</strong></a> and <a href="https://www.twilio.com/docs/sip-trunking"><strong>Twilio’s SIP Trunking guides</strong></a>. Join the Asterisk community forums and Twilio developer community for ongoing support and collaboration.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8d069b641dfa" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>