LEARN ASTERISK PBX FROM SCRATCH IN C
Learn Asterisk/PBX: Building a Telephony System from Scratch in C
Goal: Deeply understand how Asterisk and PBX systems work—from VoIP protocols (SIP, RTP) to audio codecs, call routing, and real-time communication—by building your own telephony system from the ground up in C.
Why Learn How Asterisk Works?
Asterisk is the Linux of telephony. It’s an open-source communications framework that powers everything from small office phone systems to carrier-grade call centers. Understanding how to build something like Asterisk means mastering:
- Real-time networking: UDP sockets, RTP streams, jitter buffers
- Protocol implementation: SIP (Session Initiation Protocol), SDP (Session Description Protocol)
- Audio engineering: Codecs (G.711, Opus), echo cancellation, audio mixing
- Concurrent programming: Handling thousands of simultaneous calls
- Systems architecture: Modular design, plugin systems, event-driven programming
- Telecommunications standards: How the global phone network actually works
After completing these projects, you will:
- Understand every layer of VoIP communication
- Build SIP clients and servers from raw sockets
- Handle real-time audio streaming with RTP
- Create a working PBX with call routing, voicemail, and IVR
- Implement audio conferencing and call recording
- Connect your system to the real phone network (PSTN)
Core Concept Analysis
The VoIP Stack
┌─────────────────────────────────────────────────────────────────────────┐
│ APPLICATION LAYER │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Voicemail │ │ IVR │ │ Conferencing│ │ Call Queue │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│ CALL CONTROL LAYER │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ DIALPLAN ENGINE │ │
│ │ "Route calls based on patterns, time of day, caller ID..." │ │
│ └─────────────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│ SIGNALING LAYER │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ SIP │ │ IAX2 │ │ H.323 │ │ MGCP │ │
│ │ RFC 3261 │ │ Asterisk │ │ Legacy │ │ Gateway │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│ MEDIA LAYER │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ RTP / RTCP │ │
│ │ Real-time Transport Protocol (audio/video streaming) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ G.711 │ │ G.729 │ │ Opus │ │ Speex │ │
│ │ (PCM/μ-law)│ │ (Compressed)│ │ (Modern) │ │ (Legacy) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────────────┤
│ TRANSPORT LAYER │
│ ┌───────────────────────────┐ ┌───────────────────────────────────┐ │
│ │ UDP (Port 5060) │ │ TCP / TLS / WebSocket │ │
│ │ (SIP Signaling + RTP) │ │ (Secure communications) │ │
│ └───────────────────────────┘ └───────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
How a VoIP Call Works
Phone A (Caller) PBX/Asterisk Phone B (Callee)
│ │ │
│ ──── SIP INVITE ──────────────> │ │
│ (I want to call ext 200) │ │
│ │ ──── SIP INVITE ──────────────> │
│ │ (Incoming call for you) │
│ │ │
│ │ <───── SIP 180 Ringing ──────── │
│ <───── SIP 180 Ringing ──────── │ │
│ (Ring ring...) │ │
│ │ │
│ │ <───── SIP 200 OK ───────────── │
│ <───── SIP 200 OK ───────────── │ (I answered!) │
│ │ │
│ ═══════════════════════════════ RTP Audio Stream ═════════════════│
│ (Actual voice data flows directly) │
│ │ │
│ ──── SIP BYE ──────────────────>│ │
│ (Hanging up) │ ──── SIP BYE ──────────────────>│
│ │ │
│ <───── SIP 200 OK ───────────── │ <───── SIP 200 OK ───────────── │
│ │ │
SIP Message Format
INVITE sip:bob@biloxi.com SIP/2.0
Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bK776asdhds
Max-Forwards: 70
To: Bob <sip:bob@biloxi.com>
From: Alice <sip:alice@atlanta.com>;tag=1928301774
Call-ID: a84b4c76e66710@pc33.atlanta.com
CSeq: 314159 INVITE
Contact: <sip:alice@pc33.atlanta.com>
Content-Type: application/sdp
Content-Length: 142
v=0
o=alice 2890844526 2890844526 IN IP4 pc33.atlanta.com
s=Session SDP
c=IN IP4 pc33.atlanta.com
t=0 0
m=audio 49170 RTP/AVP 0
a=rtpmap:0 PCMU/8000
Key Concepts Explained
1. SIP (Session Initiation Protocol)
- Purpose: Signaling—setting up, modifying, and tearing down calls
- Transport: Usually UDP port 5060 (or TCP/TLS for security)
- Key Methods: INVITE, ACK, BYE, CANCEL, REGISTER, OPTIONS
- RFC: 3261 (the main SIP specification)
2. SDP (Session Description Protocol)
- Purpose: Describes media sessions (what codecs, which ports)
- Embedded in: SIP messages (in the body of INVITE/200 OK)
- Format: Text-based, key=value lines
- RFC: 4566
3. RTP (Real-time Transport Protocol)
- Purpose: Actually carrying the audio/video data
- Transport: UDP (usually high-numbered ports)
- Features: Sequence numbers, timestamps for synchronization
- Companion: RTCP for statistics and control
- RFC: 3550
4. Audio Codecs
| Codec | Bandwidth | Quality | Use Case | |——-|———–|———|———-| | G.711 μ-law | 64 kbps | Excellent | PSTN quality, low CPU | | G.711 A-law | 64 kbps | Excellent | European variant | | G.729 | 8 kbps | Good | WAN links, mobile | | Opus | 6-510 kbps | Excellent | Modern, adaptive | | GSM | 13 kbps | Acceptable | Legacy mobile |
5. NAT Traversal
┌──────────────────────┐ ┌──────────────────────┐
│ Private Network │ │ Internet │
│ ┌──────────────┐ │ │ ┌──────────────┐ │
│ │ SIP Phone │ │ NAT │ │ SIP Server │ │
│ │ 192.168.1.50 │───┼──────────────────┼───│ 203.0.113.5 │ │
│ │ │ │ Translates │ │ │ │
│ └──────────────┘ │ 192.168.1.50 │ └──────────────┘ │
│ │ ↔ 198.51.100.1 │ │
└──────────────────────┘ └──────────────────────┘
Solutions:
- STUN: Discover your public IP/port
- TURN: Relay media through a server
- ICE: Try multiple paths, pick the best
Project List
The following 15 projects will take you from understanding raw network packets to building a complete PBX system.
Project 1: SIP Message Parser
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Python, Rust, Go
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 2: Intermediate
- Knowledge Area: Protocol Parsing / Text Processing
- Software or Tool: Wireshark, tcpdump
- Main Book: “SIP: Understanding the Session Initiation Protocol” by Alan B. Johnston
What you’ll build: A library that parses SIP messages from raw bytes into structured data—extracting headers (From, To, Via, Call-ID), parsing URIs, and handling the SDP body.
Why it teaches Asterisk internals: SIP is the nervous system of VoIP. Every call starts with SIP messages. Understanding the wire format is foundational to everything else.
Core challenges you’ll face:
- Parsing request line vs status line → maps to distinguishing requests from responses
- Handling multiple Via headers → maps to understanding call routing
- Parsing SIP URIs → maps to user@host:port;parameters
- Extracting SDP body → maps to Content-Length and media negotiation
Resources for key challenges:
- RFC 3261 Section 7 - SIP Message Format
- “SIP: Understanding the Session Initiation Protocol” Ch. 2-4 by Alan B. Johnston
- Wireshark SIP dissector source code
Key Concepts:
- SIP Grammar: RFC 3261 Section 25 (ABNF specification)
- Header Parsing: “TCP/IP Sockets in C” Ch. 4 - Donahoo & Calvert
- State Machines: “C Interfaces and Implementations” Ch. 2 - David R. Hanson
Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: C programming, basic networking (sockets), understanding of HTTP-like protocols
Real world outcome:
$ ./sip_parser capture.pcap
Message 1: SIP Request
Method: INVITE
Request-URI: sip:bob@biloxi.com
From: "Alice" <sip:alice@atlanta.com>;tag=1928301774
To: <sip:bob@biloxi.com>
Call-ID: a84b4c76e66710@pc33.atlanta.com
CSeq: 314159 INVITE
Via[0]: SIP/2.0/UDP pc33.atlanta.com:5060;branch=z9hG4bK776asdhds
Contact: <sip:alice@pc33.atlanta.com>
Content-Type: application/sdp
SDP Body:
Origin: alice 2890844526 2890844526 IN IP4 pc33.atlanta.com
Connection: IN IP4 pc33.atlanta.com
Media: audio 49170 RTP/AVP 0
Attribute: rtpmap:0 PCMU/8000
Message 2: SIP Response
Status: 180 Ringing
...
Implementation Hints:
The SIP message format is similar to HTTP but with key differences. Start by identifying the message type:
Request: METHOD Request-URI SIP/2.0\r\n
Response: SIP/2.0 Status-Code Reason-Phrase\r\n
Then parse headers until you hit a blank line (\r\n\r\n), and the rest is the body.
Key questions to guide your implementation:
- How do you handle folded headers (line continuation with whitespace)?
- How do you parse header parameters (semicolon-separated key=value)?
- How do you handle multiple headers with the same name (Via, Record-Route)?
- What’s the difference between
<uri>(addr-spec) and"Name" <uri>(name-addr)?
Learning milestones:
- Parse request/response line → Identify message type
- Extract all headers → Build header dictionary
- Parse SIP URIs → Handle user, host, port, parameters
- Parse SDP body → Extract media information
Project 2: UDP Socket Server for SIP
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Go, Rust
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 2: Intermediate
- Knowledge Area: Network Programming / UDP Sockets
- Software or Tool: netcat, Wireshark
- Main Book: “The Sockets Networking API: UNIX Network Programming” by W. Richard Stevens
What you’ll build: A UDP server that listens on port 5060, receives SIP messages, and sends responses—forming the network foundation for your PBX.
Why it teaches Asterisk internals: Asterisk is fundamentally a network server. Understanding how it handles thousands of concurrent UDP packets is essential.
Core challenges you’ll face:
- Non-blocking I/O → maps to handling many clients simultaneously
- Message framing → maps to SIP over UDP is message-based, not stream-based
- Address management → maps to tracking who sent what from where
- Event loop design → maps to poll/epoll/select patterns
Resources for key challenges:
- “The Sockets Networking API” Ch. 8 (UDP) - Stevens
- “The Linux Programming Interface” Ch. 63 (Alternative I/O Models) - Kerrisk
- Beej’s Guide to Network Programming (online, free)
Key Concepts:
- UDP Sockets: “The Sockets Networking API” Ch. 8
- Non-blocking I/O: “The Linux Programming Interface” Ch. 63
- Event-Driven Programming: “Linux System Programming” Ch. 2 - Robert Love
Difficulty: Intermediate Time estimate: 1 week Prerequisites: Project 1 (SIP Parser), basic C, understanding of sockets
Real world outcome:
$ ./sip_server
[INFO] SIP Server listening on 0.0.0.0:5060
[INFO] Received 423 bytes from 192.168.1.100:5080
INVITE sip:100@192.168.1.50 SIP/2.0
From: <sip:200@192.168.1.100>
...
[INFO] Sending 180 Ringing to 192.168.1.100:5080
[INFO] Sending 200 OK to 192.168.1.100:5080
[INFO] Received BYE from 192.168.1.100:5080
[INFO] Call ended, duration: 00:01:23
Implementation Hints:
Basic structure:
1. Create UDP socket: socket(AF_INET, SOCK_DGRAM, 0)
2. Bind to port 5060: bind(sockfd, ...)
3. Event loop:
- Use poll()/epoll() to wait for data
- recvfrom() to get packet + sender address
- Parse SIP message
- Generate response
- sendto() to reply
Key considerations:
- SIP messages can be up to 64KB (though typically much smaller)
- Keep track of transactions using Call-ID + branch parameter
- Handle retransmissions (SIP over UDP requires reliability at the application layer)
Learning milestones:
- Echo server works → Basic UDP I/O functioning
- Parse incoming SIP → Integration with Project 1
- Generate valid responses → Can reply to OPTIONS requests
- Handle multiple clients → Non-blocking I/O working
Project 3: SIP Registration Server
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Go, Python
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 2: Intermediate
- Knowledge Area: SIP Protocol / User Registration
- Software or Tool: Linphone, Zoiper (soft phones)
- Main Book: “SIP: Understanding the Session Initiation Protocol” by Alan B. Johnston
What you’ll build: A SIP registrar that handles REGISTER requests from SIP phones, maintains a location database, and authenticates users.
Why it teaches Asterisk internals: Registration is how phones “check in” with the PBX. Understanding the REGISTER transaction is key to managing users.
Core challenges you’ll face:
- REGISTER transaction handling → maps to understanding SIP registration flow
- Location database → maps to mapping AOR to Contact URI
- Digest authentication → maps to SIP security model
- Expiration handling → maps to registration timeouts and refresh
Resources for key challenges:
- RFC 3261 Section 10 - Registrations
- RFC 2617 - HTTP Digest Authentication (used by SIP)
- “SIP: Understanding the Session Initiation Protocol” Ch. 6
Key Concepts:
- Address of Record (AOR): The canonical address (sip:alice@domain.com)
- Contact URI: The actual location (sip:alice@192.168.1.100:5060)
- Binding: The association between AOR and Contact
- Digest Auth: Challenge-response authentication
Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Projects 1-2, understanding of hashing (MD5)
Real world outcome:
$ ./sip_registrar
[INFO] Registrar listening on 0.0.0.0:5060
# Using Linphone or Zoiper to register...
[INFO] REGISTER from sip:alice@example.com
[INFO] Sending 401 Unauthorized (challenge)
[INFO] REGISTER from sip:alice@example.com (with credentials)
[INFO] Authentication successful
[INFO] Registered: alice@example.com -> 192.168.1.100:5062 (expires: 3600s)
$ ./sip_registrar --list
Registered Users:
alice@example.com -> 192.168.1.100:5062 (expires in 3542s)
bob@example.com -> 192.168.1.101:5060 (expires in 1823s)
Implementation Hints:
REGISTER flow:
Phone Registrar
│ │
│ ──── REGISTER ───────────────────> │
│ (no credentials) │
│ │
│ <──── 401 Unauthorized ─────────── │
│ (WWW-Authenticate header │
│ with realm, nonce) │
│ │
│ ──── REGISTER ───────────────────> │
│ (Authorization header with │
│ username, nonce, response) │
│ │
│ <──── 200 OK ──────────────────── │
│ (registered!) │
Digest authentication:
HA1 = MD5(username:realm:password)
HA2 = MD5(method:uri)
response = MD5(HA1:nonce:HA2)
Key questions:
- How do you store registrations efficiently (hash table by AOR)?
- How do you handle registration expiration (timer or lazy check)?
- How do you support multiple Contacts per AOR (forking)?
Learning milestones:
- Accept REGISTER → Parse and echo back
- Implement 401 challenge → Send proper WWW-Authenticate
- Verify credentials → Digest auth working
- Maintain location database → Store and lookup bindings
Project 4: RTP Audio Receiver
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Rust, Go
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 3: Advanced
- Knowledge Area: Real-time Media / Audio Processing
- Software or Tool: ffmpeg, Audacity
- Main Book: “Computer Networks” by Andrew Tanenbaum (RTP section)
What you’ll build: An RTP receiver that accepts audio streams, handles packet reordering, and outputs the audio to speakers or a file.
Why it teaches Asterisk internals: RTP is how actual audio flows in VoIP. Understanding real-time media handling is crucial for audio quality.
Core challenges you’ll face:
- RTP header parsing → maps to sequence numbers, timestamps, payload type
- Jitter buffer → maps to smoothing out network timing variations
- Packet loss handling → maps to concealment techniques
- Audio playback → maps to interfacing with audio subsystem
Resources for key challenges:
- RFC 3550 - RTP: A Transport Protocol for Real-Time Applications
- “Computer Networks” by Tanenbaum - Multimedia Networking chapter
- PortAudio documentation (for audio output)
Key Concepts:
- RTP Header: “Computer Networks” Ch. 7 - Tanenbaum
- Jitter Buffering: VoIP academic papers
- Playout Delay: Real-time systems concepts
Difficulty: Advanced Time estimate: 2-3 weeks Prerequisites: Projects 1-3, understanding of audio basics
Real world outcome:
$ ./rtp_receiver -p 10000 -o output.wav
[INFO] Listening for RTP on port 10000
[INFO] Received first RTP packet (SSRC: 0x12345678, PT: 0 PCMU)
[INFO] Jitter buffer depth: 3 packets (60ms)
[INFO] Packets: 5000 | Lost: 12 (0.24%) | Jitter: 15ms
[INFO] Stream ended. Duration: 00:01:40. Saved to output.wav
# Or playback directly to speakers
$ ./rtp_receiver -p 10000 --playback
[INFO] Playing audio through default device...
Implementation Hints:
RTP header format (12 bytes minimum):
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Jitter buffer concept:
Network arrival: [P1] [P3] [P2] [P4] [P5]
↓ ↓ ↓ ↓ ↓
Jitter Buffer: [P1][P2][P3][P4][P5] ←──── Reordered
↓
Playout: [P1][P2][P3][P4][P5] ←──── Smooth timing
Key questions:
- How large should the jitter buffer be? (trade-off: delay vs. quality)
- How do you handle late packets? (play silence, interpolate, drop)
- How do you synchronize playback rate with incoming rate?
Learning milestones:
- Receive and parse RTP → Extract audio payload
- Implement jitter buffer → Reorder packets
- Decode audio → Convert μ-law to PCM
- Play or save audio → Complete pipeline
Project 5: RTP Audio Sender
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Rust, Go
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 3: Advanced
- Knowledge Area: Real-time Media / Audio Capture
- Software or Tool: PortAudio, ALSA
- Main Book: “TCP/IP Illustrated, Volume 1” by W. Richard Stevens
What you’ll build: An RTP sender that captures audio from a microphone or file and streams it as RTP packets with proper timing.
Why it teaches Asterisk internals: The other half of media handling. Sending audio with correct timing is essential for call quality.
Core challenges you’ll face:
- Audio capture → maps to microphone input, sample rates
- Packetization → maps to splitting audio into RTP packets
- Timing accuracy → maps to sending packets at correct intervals
- Codec encoding → maps to converting PCM to μ-law/G.729
Resources for key challenges:
- RFC 3550 - RTP specification
- PortAudio documentation
- “The Art of Writing Efficient Programs” for timing
Key Concepts:
- Sample Rate: Samples per second (8000 Hz for telephony)
- Packet Time: Duration of audio per packet (typically 20ms)
- Payload Type: Codec identifier in RTP header
Difficulty: Advanced Time estimate: 2 weeks Prerequisites: Project 4 (RTP Receiver), audio fundamentals
Real world outcome:
# Stream from microphone
$ ./rtp_sender -d 192.168.1.100:10000 --mic
[INFO] Capturing from default microphone (48000 Hz -> 8000 Hz)
[INFO] Encoding: PCMU (G.711 μ-law)
[INFO] Packet size: 160 bytes (20ms)
[INFO] Streaming to 192.168.1.100:10000...
[INFO] Sent 3000 packets | Duration: 00:01:00
# Stream from file
$ ./rtp_sender -d 192.168.1.100:10000 -f audio.wav
[INFO] Reading from audio.wav
[INFO] Streaming to 192.168.1.100:10000...
Implementation Hints:
Timing is critical for RTP:
For 20ms packets at 8000 Hz:
- Samples per packet: 160 (8000 × 0.020)
- Packets per second: 50
- Timestamp increment: 160 per packet
Timing approach:
1. Calculate next send time
2. Capture/encode audio
3. Sleep until next send time
4. Send packet
5. Repeat
μ-law encoding (compress 16-bit PCM to 8-bit):
Input: Linear PCM sample (-32768 to 32767)
Output: μ-law encoded byte (0-255)
μ = 255
F(x) = sign(x) × ln(1 + μ|x|) / ln(1 + μ)
Key questions:
- How do you handle microphone sample rate mismatch (48kHz vs 8kHz)?
- How do you maintain accurate timing without drift?
- How do you handle system clock resolution limitations?
Learning milestones:
- Send static RTP → Fixed pattern, correct headers
- Read from file → Packetize pre-recorded audio
- Capture from mic → Real-time audio input
- Accurate timing → No jitter or gaps
Project 6: SIP Call Flow Implementation
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Go, Python
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 2. The “Micro-SaaS / Pro Tool”
- Difficulty: Level 3: Advanced
- Knowledge Area: SIP Protocol / Call State Machine
- Software or Tool: Linphone, Wireshark
- Main Book: “SIP: Understanding the Session Initiation Protocol” by Alan B. Johnston
What you’ll build: A complete SIP call handler that manages INVITE transactions, handles offer/answer, and connects two endpoints for a voice call.
Why it teaches Asterisk internals: This is the core of what Asterisk does—managing calls. The INVITE transaction state machine is fundamental.
Core challenges you’ll face:
- INVITE transaction → maps to the complete call setup sequence
- Offer/Answer model → maps to SDP negotiation
- Dialog management → maps to maintaining call state
- Media path setup → maps to connecting RTP endpoints
Resources for key challenges:
- RFC 3261 Section 13 (Initiating a Session), Section 17 (Transactions)
- RFC 3264 - An Offer/Answer Model with SDP
- “SIP: Understanding the Session Initiation Protocol” Ch. 5
Key Concepts:
- INVITE Transaction States: RFC 3261 Section 17.1
- Dialog: Peer-to-peer SIP relationship
- Offer/Answer: SDP negotiation model
Difficulty: Advanced Time estimate: 2-3 weeks Prerequisites: Projects 1-5
Real world outcome:
$ ./sip_call_handler
[INFO] SIP Server ready on 0.0.0.0:5060
# Alice calls Bob through your server
[INFO] Received INVITE from alice (sip:alice@192.168.1.100)
[INFO] To: sip:bob@example.com
[INFO] SDP Offer: audio 192.168.1.100:20000 (PCMU)
[INFO] Sending 100 Trying
[INFO] Looking up bob@example.com -> 192.168.1.101:5060
[INFO] Forwarding INVITE to bob
[INFO] Bob responded: 180 Ringing
[INFO] Bob responded: 200 OK
[INFO] SDP Answer: audio 192.168.1.101:30000 (PCMU)
[INFO] Sending 200 OK to alice (with bob's SDP)
[INFO] Received ACK from alice
[INFO] Call established: alice <-> bob
[INFO] RTP: 192.168.1.100:20000 <-> 192.168.1.101:30000
# 60 seconds later
[INFO] Received BYE from alice
[INFO] Sending BYE to bob
[INFO] Call ended. Duration: 00:01:00
Implementation Hints:
INVITE client transaction state machine:
┌─────────────────────────────────────────┐
│ │
▼ Timer A fires │
┌──────────┐ (resend INVITE) │
│ Calling │─────────────────────┐ │
└──────────┘ │ │
│ │ │
1xx │ 2xx │ │
▼ │ │
┌──────────┐ │ │
│Proceeding│ │ │
└──────────┘ │ │
│ │ │
2xx │ │ │
▼ │ │
┌──────────┐ Send ACK │ │
│Completed │──────────────┐ │ │
└──────────┘ │ │ │
│ ▼ ▼ │
Timer D ┌──────────┐ │
│ │Terminated│ │
└───────────────────>└──────────┘ │
Offer/Answer basics:
Caller's INVITE (Offer):
m=audio 20000 RTP/AVP 0 8
(I can do PCMU and PCMA, send to port 20000)
Callee's 200 OK (Answer):
m=audio 30000 RTP/AVP 0
(I chose PCMU, send to my port 30000)
Learning milestones:
- Handle INVITE → Proper state machine
- Parse SDP → Extract media parameters
- Forward calls → Basic B2BUA functionality
- Handle BYE → Clean call teardown
Project 7: Dialplan Engine
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Rust, Go
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 3. The “Service & Support” Model
- Difficulty: Level 3: Advanced
- Knowledge Area: DSL Design / Pattern Matching
- Software or Tool: Asterisk (for reference)
- Main Book: “Language Implementation Patterns” by Terence Parr
What you’ll build: A dialplan interpreter that routes calls based on patterns—like Asterisk’s extensions.conf but simpler.
Why it teaches Asterisk internals: The dialplan is the brain of Asterisk. It defines how every call is handled.
Core challenges you’ll face:
- Pattern matching → maps to extension patterns like
_1NXXNXXXXXX - Application execution → maps to calling functions like Dial(), Voicemail()
- Variable substitution → maps to channel variables and expressions
- Context switching → maps to organizing dialplan into sections
Resources for key challenges:
- “Asterisk: The Definitive Guide” Ch. 6-7
- “Language Implementation Patterns” Ch. 1-4 by Terence Parr
- Asterisk dialplan documentation
Key Concepts:
- Context: A named group of extensions
- Extension: A pattern that matches dialed digits
- Priority: Order of execution within an extension
- Application: An action to take (Answer, Dial, Voicemail)
Difficulty: Advanced Time estimate: 2-3 weeks Prerequisites: Projects 1-6, basic interpreter concepts
Real world outcome:
; dialplan.conf
[internal]
exten = 100,1,Answer()
exten = 100,2,SayDigits(100)
exten = 100,3,Hangup()
exten = _1XX,1,Dial(SIP/${EXTEN})
exten = 9911,1,Dial(SIP/emergency@trunk)
[incoming]
exten = s,1,Answer()
exten = s,2,Playback(welcome)
exten = s,3,Goto(internal,${CALLERID})
$ ./dialplan_engine dialplan.conf
[INFO] Loaded dialplan: 2 contexts, 4 extensions
[INFO] Incoming call to extension 101
[INFO] Matched: _1XX in context [internal]
[INFO] Priority 1: Dial(SIP/101)
[INFO] Bridging call to SIP/101...
Implementation Hints:
Pattern syntax (simplified):
X = any digit 0-9
Z = any digit 1-9
N = any digit 2-9
[1-5] = any digit 1,2,3,4,5
. = one or more of anything
! = zero or more of anything
Pattern matching algorithm:
// Match extension pattern against input
bool match_pattern(const char *pattern, const char *input) {
while (*pattern && *input) {
switch (*pattern) {
case 'X': if (!isdigit(*input)) return false; break;
case 'N': if (*input < '2' || *input > '9') return false; break;
case 'Z': if (*input < '1' || *input > '9') return false; break;
case '.': return true; // Matches rest
default: if (*pattern != *input) return false; break;
}
pattern++; input++;
}
return (*pattern == '\0' && *input == '\0');
}
Learning milestones:
- Parse dialplan file → Load contexts and extensions
- Pattern matching → Match dialed numbers to extensions
- Execute applications → Call handler functions
- Variable substitution → Replace ${EXTEN}, ${CALLERID}
Project 8: Audio Codec Library
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Rust
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 1. The “Resume Gold”
- Difficulty: Level 3: Advanced
- Knowledge Area: Digital Signal Processing / Audio
- Software or Tool: Audacity, ffmpeg
- Main Book: “Digital Signal Processing” by Smith
What you’ll build: A codec library supporting G.711 (μ-law/A-law), with interfaces for encode/decode and transcoding between formats.
Why it teaches Asterisk internals: Codecs are how audio is compressed for network transmission. G.711 is the universal fallback codec.
Core challenges you’ll face:
- μ-law encoding → maps to logarithmic companding
- A-law encoding → maps to European variant
- Sample format conversion → maps to endianness, bit depth
- Transcoding → maps to converting between codecs
Resources for key challenges:
- ITU-T G.711 specification
- “Digital Signal Processing” by Smith (online, free)
- Wikipedia article on μ-law algorithm (surprisingly good)
Key Concepts:
- Companding: Compression + Expansion for dynamic range
-
μ-law Formula: F(x) = sign(x) × ln(1 + μ x ) / ln(1 + μ) - Quantization: Reducing bit depth
Difficulty: Advanced Time estimate: 1-2 weeks Prerequisites: Basic DSP concepts, C bitwise operations
Real world outcome:
$ ./codec_test input.wav
[INFO] Input: 16-bit PCM, 8000 Hz, 10 seconds
[INFO] Encoding to μ-law...
[INFO] Output: 80000 bytes (vs 160000 bytes PCM)
[INFO] Compression ratio: 2:1
[INFO] Decoding back to PCM...
[INFO] SNR: 38 dB (excellent)
$ ./transcode --from=pcmu --to=pcma input.raw output.raw
[INFO] Transcoded 80000 samples
Implementation Hints:
μ-law encoding table approach (faster than math):
// Pre-computed encoding table (16-bit to 8-bit)
static const uint8_t ulaw_table[65536] = { ... };
uint8_t linear_to_ulaw(int16_t sample) {
return ulaw_table[(uint16_t)sample];
}
// Decoding is simpler (table lookup)
static const int16_t ulaw_decode[256] = {
-32124, -31100, -30076, ..., 30076, 31100, 32124
};
int16_t ulaw_to_linear(uint8_t sample) {
return ulaw_decode[sample];
}
For understanding, the algorithm:
1. Get sign and absolute value
2. Add bias (132 for μ-law)
3. Find exponent (highest bit position)
4. Extract mantissa (4 bits after exponent)
5. Combine: sign (1 bit) + exponent (3 bits) + mantissa (4 bits)
Learning milestones:
- Understand companding → Why logarithmic compression helps
- Implement μ-law encode → Table or algorithm
- Implement decode → Reverse process
- Add A-law → Similar but different formula
Project 9: Interactive Voice Response (IVR)
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Python, Go
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 3. The “Service & Support” Model
- Difficulty: Level 2: Intermediate
- Knowledge Area: Telephony Applications / DTMF
- Software or Tool: Audacity (for prompts), Festival TTS
- Main Book: “Asterisk: The Definitive Guide” by Jim Van Meggelen
What you’ll build: An IVR system that plays prompts, collects DTMF input, and routes callers based on their choices.
Why it teaches Asterisk internals: IVR is one of the most common PBX features. Understanding prompt playback and DTMF detection is essential.
Core challenges you’ll face:
- Audio file playback → maps to streaming prompts to callers
- DTMF detection → maps to recognizing keypad presses
- Menu state machine → maps to navigating IVR trees
- Timeout handling → maps to what if caller doesn’t press anything?
Resources for key challenges:
- RFC 4733 - RTP Payload for DTMF Digits
- “Asterisk: The Definitive Guide” Ch. 16
- Goertzel algorithm for DTMF detection
Key Concepts:
- DTMF: Dual-Tone Multi-Frequency signaling
- RFC 2833: DTMF over RTP
- Goertzel Algorithm: Efficient single-frequency detection
Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Projects 4-5 (RTP), Project 7 (Dialplan)
Real world outcome:
Caller experience:
"Welcome to Acme Corporation."
"Press 1 for Sales."
"Press 2 for Support."
"Press 0 for Operator."
*Caller presses 2*
"Please hold while we connect you to Support."
*Ring ring*
$ ./ivr_server
[INFO] IVR loaded: 3 menu items
[INFO] Incoming call...
[INFO] Playing: welcome.wav
[INFO] Playing: menu_options.wav
[INFO] Waiting for DTMF (timeout: 10s)
[INFO] DTMF received: 2
[INFO] Routing to queue: support
Implementation Hints:
DTMF frequencies:
1209 Hz 1336 Hz 1477 Hz 1633 Hz
697 Hz 1 2 3 A
770 Hz 4 5 6 B
852 Hz 7 8 9 C
941 Hz * 0 # D
DTMF detection approaches:
- In-band (audio): Goertzel algorithm to detect frequencies
- RFC 2833: DTMF events in RTP payload (easier)
IVR state machine:
┌──────────────────────────────────────┐
▼ │
┌──────────────┐ │
│ Play Prompt │ │
└──────────────┘ │
│ │
▼ │
┌──────────────┐ timeout ┌──────────────┐│
│ Wait DTMF │────────────>│ Play Invalid ││
└──────────────┘ └──────────────┘│
│ digit │ │
▼ └────────┘
┌──────────────┐
│ Route Call │
└──────────────┘
Learning milestones:
- Play audio prompts → Stream WAV files to caller
- Detect DTMF → RFC 2833 or Goertzel
- Menu navigation → State machine working
- Complete IVR → Full menu system functional
Project 10: Voicemail System
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Go, Python
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 3. The “Service & Support” Model
- Difficulty: Level 2: Intermediate
- Knowledge Area: Telephony Applications / Storage
- Software or Tool: SQLite, filesystem
- Main Book: “Asterisk: The Definitive Guide” by Jim Van Meggelen
What you’ll build: A voicemail system that records messages, stores them, and allows users to retrieve them with a phone interface.
Why it teaches Asterisk internals: Voicemail combines audio recording, storage, and phone-based UI—a classic PBX feature.
Core challenges you’ll face:
- Recording audio → maps to capturing RTP to file
- Message storage → maps to organizing mailboxes and messages
- MWI (Message Waiting) → maps to notifying users of new messages
- Playback controls → maps to rewind, fast-forward, delete
Resources for key challenges:
- RFC 3842 - Message Summary and Message Waiting Indication
- “Asterisk: The Definitive Guide” Ch. 8 (Voicemail)
- WAV file format specification
Key Concepts:
- MWI: Message Waiting Indicator (light on phone)
- Greeting Types: Unavailable, busy, custom
- Message Envelope: Caller ID, timestamp, duration
Difficulty: Intermediate Time estimate: 2 weeks Prerequisites: Projects 4-5 (RTP), Project 9 (IVR)
Real world outcome:
Leaving a message:
*Call goes to voicemail*
"You have reached extension 100."
"Please leave a message after the tone."
*BEEP*
*Caller speaks*
*Caller hangs up*
"Message saved."
Checking messages:
*Caller dials voicemail*
"Enter your mailbox number."
*Enters 100*
"Enter your PIN."
*Enters 1234*
"You have 2 new messages."
"First message, received today at 3:45 PM, from 555-1234."
*Plays message*
"Press 7 to delete. Press 9 to save."
Implementation Hints:
Mailbox structure:
/var/spool/voicemail/
├── 100/
│ ├── INBOX/
│ │ ├── msg0000.wav
│ │ └── msg0000.txt (envelope: callerid, timestamp)
│ ├── Old/
│ └── greet.wav
├── 101/
│ └── ...
MWI (SIP NOTIFY):
NOTIFY sip:100@192.168.1.100 SIP/2.0
Event: message-summary
Content-Type: application/simple-message-summary
Messages-Waiting: yes
Voice-Message: 2/5 (2 new, 5 total)
Learning milestones:
- Record to file → Capture RTP as WAV
- Store messages → Mailbox organization
- Playback interface → Phone menu for retrieval
- MWI notification → Tell phone about new messages
Project 11: Conference Bridge
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Go, Rust
- Coolness Level: Level 4: Hardcore Tech Flex
- Business Potential: 3. The “Service & Support” Model
- Difficulty: Level 4: Expert
- Knowledge Area: Audio Mixing / Real-time Processing
- Software or Tool: PortAudio, ALSA
- Main Book: “Computer Systems: A Programmer’s Perspective” by Bryant & O’Hallaron
What you’ll build: A conference bridge that mixes audio from multiple participants in real-time.
Why it teaches Asterisk internals: Audio mixing is computationally intensive and requires understanding of real-time constraints.
Core challenges you’ll face:
- Audio mixing → maps to combining multiple audio streams
- Synchronization → maps to aligning streams with different timing
- Echo cancellation → maps to preventing feedback loops
- Scalability → maps to handling many participants efficiently
Resources for key challenges:
- “Digital Signal Processing” by Smith (mixing chapter)
- speexdsp for echo cancellation
- Academic papers on conference mixing
Key Concepts:
- Audio Summation: Adding PCM samples (with clipping prevention)
- N-1 Mixing: Each participant hears everyone except themselves
- Timing Source: Master clock for synchronization
Difficulty: Expert Time estimate: 3-4 weeks Prerequisites: Projects 4-5, DSP basics
Real world outcome:
$ ./conference_bridge --room 1234
[INFO] Conference room 1234 ready
[INFO] Participant joined: Alice (192.168.1.100)
[INFO] Participant joined: Bob (192.168.1.101)
[INFO] Participant joined: Charlie (192.168.1.102)
[INFO] Mixing: 3 participants
[INFO] CPU usage: 5% | Latency: 20ms
[INFO] Participant left: Charlie
[INFO] Participants: 2
Implementation Hints:
Simple mixing (2 participants):
// Each hears the other
for (int i = 0; i < samples; i++) {
alice_output[i] = bob_input[i];
bob_output[i] = alice_input[i];
}
N-participant mixing:
// For N participants, each hears the sum of all others
int16_t sum[FRAME_SIZE] = {0};
// Sum all inputs
for (int p = 0; p < num_participants; p++) {
for (int i = 0; i < FRAME_SIZE; i++) {
sum[i] += participants[p].input[i];
}
}
// Each participant gets sum minus their own voice
for (int p = 0; p < num_participants; p++) {
for (int i = 0; i < FRAME_SIZE; i++) {
int32_t mixed = sum[i] - participants[p].input[i];
// Clamp to prevent overflow
if (mixed > 32767) mixed = 32767;
if (mixed < -32768) mixed = -32768;
participants[p].output[i] = mixed;
}
}
Learning milestones:
- Mix 2 participants → Basic audio combination
- Scale to N → N-1 mixing algorithm
- Handle timing → Jitter buffer per participant
- Optimize → Reduce CPU usage
Project 12: SIP Trunk Connection (PSTN Gateway)
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Go
- Coolness Level: Level 3: Genuinely Clever
- Business Potential: 4. The “Open Core” Infrastructure
- Difficulty: Level 3: Advanced
- Knowledge Area: VoIP / Carrier Integration
- Software or Tool: Telnyx, Voip.ms, Twilio
- Main Book: “SIP: Understanding the Session Initiation Protocol” by Alan B. Johnston
What you’ll build: Integration with a SIP trunking provider to make and receive calls from real phone numbers.
Why it teaches Asterisk internals: Connecting to the PSTN is where your PBX meets the real world. Understanding carrier integration is essential.
Core challenges you’ll face:
- Provider authentication → maps to registering with trunk
- DID handling → maps to routing incoming calls by number
- Caller ID → maps to presenting correct number on outbound
- Codec negotiation → maps to matching carrier capabilities
Resources for key challenges:
- Your chosen provider’s documentation (Telnyx, Voip.ms)
- RFC 3261 - Registration and authentication
- “Asterisk: The Definitive Guide” Ch. 7 (SIP Trunking)
Key Concepts:
- DID: Direct Inward Dialing (your phone number)
- Trunk: Connection to a carrier
- E.164: International phone number format
Difficulty: Advanced Time estimate: 1-2 weeks Prerequisites: Projects 1-6
Real world outcome:
$ ./pstn_gateway --config trunk.conf
[INFO] Connecting to provider: voip.ms
[INFO] Registering as: youraccount
[INFO] Registration successful
[INFO] DIDs: +1-555-123-4567, +1-555-987-6543
# Incoming call from cell phone
[INFO] Incoming call on DID +1-555-123-4567
[INFO] Caller ID: +1-555-222-3333
[INFO] Routing to extension 100...
# Outbound call
$ ./dial 15557778888
[INFO] Outbound call to +1-555-777-8888
[INFO] Caller ID: +1-555-123-4567
[INFO] Connected!
Implementation Hints:
Trunk registration:
Your PBX SIP Provider
│ │
│ ──── REGISTER ─────────────────────> │
│ To: sip:voip.ms │
│ From: sip:youraccount@voip.ms │
│ │
│ <──── 401 Unauthorized ──────────── │
│ (challenge) │
│ │
│ ──── REGISTER (with auth) ─────────> │
│ │
│ <──── 200 OK ────────────────────── │
│ (registered for 3600s) │
Outbound call flow:
1. Dial number (e.g., 15557778888)
2. Format as E.164: +15557778888
3. Create INVITE to trunk:
INVITE sip:+15557778888@voip.ms
4. Include your DID as From/P-Asserted-Identity
5. Handle 18x/200 responses
6. Bridge media
Learning milestones:
- Register with provider → Authentication working
- Receive inbound calls → DID routing
- Make outbound calls → Caller ID correct
- Handle real conversations → End-to-end working
Project 13: WebRTC Gateway
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Go, JavaScript (for client)
- Coolness Level: Level 5: Pure Magic (Super Cool)
- Business Potential: 4. The “Open Core” Infrastructure
- Difficulty: Level 4: Expert
- Knowledge Area: WebRTC / Modern Communications
- Software or Tool: libsrtp, OpenSSL
- Main Book: “Real-Time Communication with WebRTC” by Salvatore Loreto
What you’ll build: A gateway between WebRTC (browser-based calling) and your SIP PBX.
Why it teaches Asterisk internals: WebRTC is how modern web applications do voice/video. Bridging to SIP is essential for unified communications.
Core challenges you’ll face:
- WebSocket signaling → maps to SIP-over-WebSocket
- DTLS/SRTP → maps to encrypted media
- ICE negotiation → maps to NAT traversal
- Codec transcoding → maps to Opus ↔ PCMU
Resources for key challenges:
- “Real-Time Communication with WebRTC” by Loreto & Romano
- RFC 7118 - SIP over WebSocket
- RFC 5764 - DTLS-SRTP
Key Concepts:
- ICE: Interactive Connectivity Establishment
- DTLS: Datagram TLS (key exchange for SRTP)
- SRTP: Secure RTP (encrypted audio/video)
Difficulty: Expert Time estimate: 4-6 weeks Prerequisites: Projects 1-12, TLS/crypto basics
Real world outcome:
<!-- Browser client -->
<button onclick="call()">Call Extension 100</button>
<script>
async function call() {
const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
stream.getTracks().forEach(t => pc.addTrack(t, stream));
// Connect to your gateway via WebSocket
const ws = new WebSocket("wss://pbx.example.com:8089");
// ... signaling ...
}
</script>
$ ./webrtc_gateway
[INFO] WebSocket server on wss://0.0.0.0:8089
[INFO] STUN server on 0.0.0.0:3478
[INFO] Browser connected: Chrome 120
[INFO] ICE negotiation complete
[INFO] DTLS handshake successful
[INFO] SRTP established (AES-128-CM)
[INFO] Transcoding: Opus -> PCMU
[INFO] Bridged to SIP extension 100
Implementation Hints:
WebRTC to SIP bridge:
Browser (WebRTC) Gateway SIP Phone
│ │ │
│ ─── SDP Offer ───────────> │ │
│ (Opus, DTLS-SRTP) │ │
│ │ ─── SIP INVITE ───> │
│ │ (PCMU, RTP) │
│ │ │
│ │ <── 200 OK ──────── │
│ <── SDP Answer ─────────── │ │
│ │ │
│ ══ DTLS/SRTP ════════════> │ ══ RTP ══════════> │
│ (Opus) │ (PCMU) │
│ [Transcode] │
Key components:
- WebSocket server for SIP-over-WS
- DTLS implementation for key exchange
- SRTP for encrypted media
- Opus codec support
- ICE/STUN for NAT traversal
Learning milestones:
- WebSocket signaling → Browser can initiate calls
- DTLS handshake → Keys exchanged
- SRTP decrypt → Receive browser audio
- Transcode and bridge → Full WebRTC-SIP call
Project 14: Call Recording and CDR
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Go, Python
- Coolness Level: Level 2: Practical but Forgettable
- Business Potential: 3. The “Service & Support” Model
- Difficulty: Level 2: Intermediate
- Knowledge Area: Telephony / Compliance
- Software or Tool: SQLite/PostgreSQL, ffmpeg
- Main Book: “Asterisk: The Definitive Guide” by Jim Van Meggelen
What you’ll build: Call recording (saving conversations) and CDR (Call Detail Records) for billing/analytics.
Why it teaches Asterisk internals: Recording and CDRs are essential for business use. Understanding media forking and event logging is practical.
Core challenges you’ll face:
- Media forking → maps to copying audio stream for recording
- Mixed vs. separate → maps to one file or per-leg
- CDR generation → maps to start, answer, end times
- Storage management → maps to organizing recordings
Resources for key challenges:
- “Asterisk: The Definitive Guide” Ch. 21 (CDR)
- WAV file format for recording
- SQLite documentation for CDR storage
Key Concepts:
- CDR Fields: src, dst, start, answer, end, duration, disposition
- Recording Formats: WAV (uncompressed), MP3, Opus
- Media Forking: Copying RTP to recording engine
Difficulty: Intermediate Time estimate: 1-2 weeks Prerequisites: Projects 4-5 (RTP), SQL basics
Real world outcome:
$ ./cdr_query --today
┌────────────────────────────────────────────────────────────────────┐
│ Call Detail Records │
├──────────┬────────────┬──────────┬──────────┬────────────┬─────────┤
│ Call ID │ From │ To │ Start │ Duration │ Status │
├──────────┼────────────┼──────────┼──────────┼────────────┼─────────┤
│ 1001 │ 100 │ 200 │ 10:15:32 │ 00:02:45 │ ANSWERED│
│ 1002 │ +15551234 │ 100 │ 10:18:00 │ 00:00:00 │ NO ANSWR│
│ 1003 │ 100 │ +15555678│ 10:22:15 │ 00:05:12 │ ANSWERED│
└──────────┴────────────┴──────────┴──────────┴────────────┴─────────┘
$ ls recordings/
2024-01-15-101532-100-200.wav
2024-01-15-102215-100-15555678.wav
Implementation Hints:
CDR table schema:
CREATE TABLE cdr (
id INTEGER PRIMARY KEY,
callid TEXT NOT NULL,
src TEXT NOT NULL,
dst TEXT NOT NULL,
start_time DATETIME NOT NULL,
answer_time DATETIME,
end_time DATETIME NOT NULL,
duration INTEGER,
billsec INTEGER,
disposition TEXT,
recording_path TEXT
);
Recording approach:
┌─────────────────┐
RTP In ────>│ Media Engine │──── RTP Out
│ │
│ ┌───────────┐ │
│ │ Record │ │
│ │ Buffer │ │
│ └─────┬─────┘ │
└────────│────────┘
│
▼
WAV File
Learning milestones:
- Generate CDRs → Log call events to database
- Record single channel → Save one side of call
- Mix and record → Both parties in one file
- Query and report → CDR analytics
Project 15: Complete Mini-PBX
- File: LEARN_ASTERISK_PBX_FROM_SCRATCH_IN_C.md
- Main Programming Language: C
- Alternative Programming Languages: Rust, Go
- Coolness Level: Level 5: Pure Magic (Super Cool)
- Business Potential: 4. The “Open Core” Infrastructure
- Difficulty: Level 5: Master
- Knowledge Area: Systems Integration / Complete System
- Software or Tool: All previous projects
- Main Book: All previous books
What you’ll build: A complete PBX system combining all previous projects: registration, call routing, voicemail, IVR, conferencing, and PSTN connectivity.
Why it teaches Asterisk internals: This is the culmination—building a production-ready telephony system from scratch.
Core challenges you’ll face:
- Integration → maps to making all components work together
- Configuration → maps to user-friendly setup
- Reliability → maps to handling failures gracefully
- Scalability → maps to supporting many simultaneous calls
Resources for key challenges:
- All previous project resources
- “The Art of Multiprocessor Programming” for concurrency
- Production systems design patterns
Time estimate: 2-3 months Prerequisites: All previous projects
Real world outcome:
$ ./mini-pbx --config /etc/mini-pbx/pbx.conf
[INFO] Mini-PBX v1.0 starting...
[INFO] Loaded configuration: 15 extensions, 2 trunks
[INFO] SIP listening on 0.0.0.0:5060
[INFO] RTP range: 10000-20000
[INFO] Voicemail enabled: /var/spool/voicemail
[INFO] Conference rooms: 1000-1099
[INFO] PSTN trunk registered: voip.ms
[INFO] Ready for calls!
[INFO] Registration: alice (192.168.1.100)
[INFO] Registration: bob (192.168.1.101)
[INFO] Call: alice -> bob (internal)
[INFO] Call: +15551234 -> IVR (incoming)
[INFO] Conference: alice + bob + charlie (room 1001)
[INFO] Voicemail: bob (2 new messages)
Implementation Hints:
Architecture:
┌─────────────────────────────────────────────────────────────────┐
│ Mini-PBX │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ Config │ │ Logger │ │ Event Manager │ │
│ │ Parser │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ SIP Stack (UDP/TCP/TLS) ││
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐││
│ │ │Registrar │ │ Location │ │ Dialog │ │ Transaction │││
│ │ │ │ │ Service │ │ Manager │ │ Layer │││
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────────┘││
│ └─────────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Media Engine ││
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐││
│ │ │ RTP │ │ Codec │ │ Bridge │ │ Recording │││
│ │ │ Handler │ │ Engine │ │ │ │ │││
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────────┘││
│ └─────────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Applications ││
│ │ ┌─────────┐ ┌──────────┐ ┌───────────┐ ┌─────────────┐ ││
│ │ │ Dialplan│ │Voicemail │ │Conference │ │ IVR │ ││
│ │ └─────────┘ └──────────┘ └───────────┘ └─────────────┘ ││
│ └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
Learning milestones:
- Basic calls work → Registration + internal calls
- Applications work → Voicemail, IVR, conference
- PSTN connected → External calls work
- Production ready → Stable, configurable, monitored
Project Comparison Table
| # | Project | Difficulty | Time | Key Skill | Fun |
|---|---|---|---|---|---|
| 1 | SIP Message Parser | ⭐⭐ | 1-2 weeks | Protocol Parsing | ⭐⭐⭐ |
| 2 | UDP Socket Server | ⭐⭐ | 1 week | Network Programming | ⭐⭐⭐ |
| 3 | SIP Registration | ⭐⭐ | 1-2 weeks | SIP Protocol | ⭐⭐⭐ |
| 4 | RTP Receiver | ⭐⭐⭐ | 2-3 weeks | Real-time Media | ⭐⭐⭐⭐ |
| 5 | RTP Sender | ⭐⭐⭐ | 2 weeks | Audio Capture | ⭐⭐⭐⭐ |
| 6 | SIP Call Flow | ⭐⭐⭐ | 2-3 weeks | Call State Machine | ⭐⭐⭐⭐ |
| 7 | Dialplan Engine | ⭐⭐⭐ | 2-3 weeks | DSL/Interpreter | ⭐⭐⭐⭐ |
| 8 | Audio Codec Library | ⭐⭐⭐ | 1-2 weeks | DSP | ⭐⭐⭐ |
| 9 | IVR System | ⭐⭐ | 1-2 weeks | DTMF/Prompts | ⭐⭐⭐⭐ |
| 10 | Voicemail System | ⭐⭐ | 2 weeks | Recording/Storage | ⭐⭐⭐ |
| 11 | Conference Bridge | ⭐⭐⭐⭐ | 3-4 weeks | Audio Mixing | ⭐⭐⭐⭐⭐ |
| 12 | PSTN Gateway | ⭐⭐⭐ | 1-2 weeks | Carrier Integration | ⭐⭐⭐⭐ |
| 13 | WebRTC Gateway | ⭐⭐⭐⭐ | 4-6 weeks | WebRTC/Encryption | ⭐⭐⭐⭐⭐ |
| 14 | Recording & CDR | ⭐⭐ | 1-2 weeks | Compliance | ⭐⭐⭐ |
| 15 | Complete Mini-PBX | ⭐⭐⭐⭐⭐ | 2-3 months | Integration | ⭐⭐⭐⭐⭐ |
Recommended Learning Path
Phase 1: Protocol Foundations (4-6 weeks)
- Project 1: SIP Parser - Understand the signaling protocol
- Project 2: UDP Server - Network foundation
- Project 3: Registration - First working SIP feature
Phase 2: Media Handling (4-6 weeks)
- Project 4: RTP Receiver - Receive audio
- Project 5: RTP Sender - Send audio
- Project 8: Codec Library - Encode/decode audio
Phase 3: Call Management (4-6 weeks)
- Project 6: Call Flow - Handle complete calls
- Project 7: Dialplan - Route calls intelligently
Phase 4: Applications (4-6 weeks)
- Project 9: IVR - Interactive menus
- Project 10: Voicemail - Message storage
- Project 14: Recording/CDR - Compliance features
Phase 5: Advanced Features (6-8 weeks)
- Project 11: Conference Bridge - Multi-party audio
- Project 12: PSTN Gateway - Real phone numbers
Phase 6: Modern & Integration (8-12 weeks)
- Project 13: WebRTC Gateway - Browser calling
- Project 15: Complete Mini-PBX - Full integration
Summary
| # | Project | Main Language |
|---|---|---|
| 1 | SIP Message Parser | C |
| 2 | UDP Socket Server for SIP | C |
| 3 | SIP Registration Server | C |
| 4 | RTP Audio Receiver | C |
| 5 | RTP Audio Sender | C |
| 6 | SIP Call Flow Implementation | C |
| 7 | Dialplan Engine | C |
| 8 | Audio Codec Library | C |
| 9 | Interactive Voice Response (IVR) | C |
| 10 | Voicemail System | C |
| 11 | Conference Bridge | C |
| 12 | SIP Trunk Connection (PSTN Gateway) | C |
| 13 | WebRTC Gateway | C |
| 14 | Call Recording and CDR | C |
| 15 | Complete Mini-PBX | C |
Resources
Essential Books
- “SIP: Understanding the Session Initiation Protocol” by Alan B. Johnston - The definitive SIP book
- “Asterisk: The Definitive Guide” by Jim Van Meggelen et al. - Practical PBX reference
- “The Sockets Networking API” by W. Richard Stevens - Network programming bible
- “Real-Time Communication with WebRTC” by Loreto & Romano - WebRTC deep dive
- “Computer Networks” by Tanenbaum - RTP and multimedia networking
RFCs (Standards)
- RFC 3261 - SIP: Session Initiation Protocol
- RFC 4566 - SDP: Session Description Protocol
- RFC 3550 - RTP: Real-time Transport Protocol
- RFC 3264 - Offer/Answer Model with SDP
- RFC 2617 - HTTP Digest Authentication (used by SIP)
- RFC 4733 - RTP Payload for DTMF Digits
- RFC 5764 - DTLS-SRTP
Open Source References
- Asterisk Source Code: https://github.com/asterisk/asterisk
- PJSIP: https://github.com/pjsip/pjproject (SIP library in C)
- oRTP: https://gitlab.linphone.org/BC/public/ortp (RTP library)
- libsrtp: https://github.com/cisco/libsrtp (SRTP library)
Tools
- Wireshark - Packet capture and SIP/RTP analysis
- Linphone/Zoiper - SIP soft phones for testing
- SIPVicious - SIP security testing
- pjsua - Command-line SIP client
Carriers for PSTN Testing
- Telnyx - Developer-friendly SIP trunking
- Voip.ms - Low-cost SIP provider
- Twilio - API-first communications
Total Estimated Time: 8-12 months of dedicated study
After completion: You’ll understand telephony systems from the packet level to the user experience. You’ll be able to build, debug, and extend PBX systems, implement custom telephony applications, and bridge traditional and modern communication technologies. These skills are valuable for telecom companies, unified communications platforms, call centers, and any business that needs custom telephony solutions.