Architecture
This guide provides a comprehensive overview of Parrot's architecture, including process supervision trees, state machines, and message flows.
The architecture follows the SIP protocol specification defined in RFC 3261 and related RFCs.
System Architecture Overview
graph TB
subgraph "Parrot Application"
App[Parrot.Application]
App --> MainSup[Parrot.Supervisor]
MainSup --> TransSup[Transport.Supervisor]
MainSup --> TxnSup[Transaction.Supervisor]
MainSup --> DialogSup[Dialog.Supervisor]
MainSup --> HandlerSup[HandlerAdapter.Supervisor]
MainSup --> MediaSup[MediaSession.Supervisor]
subgraph "Transport Layer"
TransSup --> StateMachine[Transport.StateMachine<br/>gen_statem]
StateMachine --> UDP[Transport.UDP<br/>GenServer]
StateMachine --> TCP[Transport.TCP<br/>GenServer]
StateMachine --> WS[Transport.WebSocket<br/>GenServer]
end
subgraph "Transaction Layer"
TxnSup --> TxnStatem[Transaction.Statem<br/>gen_statem]
TxnStatem --> ClientTxn[Client Transaction<br/>gen_statem]
TxnStatem --> ServerTxn[Server Transaction<br/>gen_statem]
end
subgraph "Dialog Layer"
DialogSup --> DialogStatem[Dialog.Statem<br/>gen_statem]
DialogSup --> DialogReg[Dialog.Registry]
end
subgraph "Application Layer"
HandlerSup --> HandlerCore[HandlerAdapter.Core<br/>gen_statem]
HandlerCore --> UserHandler[User Handler<br/>Behaviour]
end
subgraph "Media Layer"
MediaSup --> MediaSession[MediaSession<br/>gen_statem]
MediaSession --> Pipeline[Membrane Pipeline<br/>GenServer]
end
end
style App fill:#f9f,stroke:#333,stroke-width:4px
style MainSup fill:#bbf,stroke:#333,stroke-width:2px
style StateMachine fill:#fbb,stroke:#333,stroke-width:2px
style TxnStatem fill:#fbb,stroke:#333,stroke-width:2px
style DialogStatem fill:#fbb,stroke:#333,stroke-width:2px
style HandlerCore fill:#fbb,stroke:#333,stroke-width:2px
style MediaSession fill:#fbb,stroke:#333,stroke-width:2px
Process Communication Flow
sequenceDiagram
participant Net as Network
participant UDP as UDP Transport
participant Conn as Connection
participant Parser as Parser
participant TxnSrv as Transaction Statem
participant Dialog as Dialog Server
participant Handler as Handler Adapter
participant App as User Application
participant Media as Media Session
Net->>UDP: UDP Packet
UDP->>Conn: Raw Data
Conn->>Parser: Parse SIP Message
Parser->>UDP: Parsed Message
UDP->>TxnSrv: Route to Transaction
alt New Transaction
TxnSrv->>Handler: Create Handler Instance
Handler->>App: Call Handler Callback
App->>Handler: Response Decision
else Existing Transaction
TxnSrv->>Dialog: Check Dialog State
Dialog->>Handler: Route to Handler
end
Handler->>Media: Start Media Session
Media->>Media: Create RTP Pipeline
Handler->>TxnSrv: Send Response
TxnSrv->>UDP: Send Message
UDP->>Net: UDP Packet
State Machine: Transaction Layer
The transaction state machines are implemented according to RFC 3261 Section 17:
stateDiagram-v2
[*] --> Init: create_transaction
state "Client Transaction" as client {
Init --> Calling: send_request
Calling --> Proceeding: rcv_provisional
Calling --> Completed: rcv_final_response
Proceeding --> Completed: rcv_final_response
Completed --> Terminated: timer_D
}
state "Server Transaction" as server {
Init --> Trying: rcv_request
Trying --> Proceeding: send_provisional
Trying --> Completed: send_final_response
Proceeding --> Completed: send_final_response
Completed --> Confirmed: rcv_ACK
Confirmed --> Terminated: timer_I
}
Terminated --> [*]
note right of Calling: Timer A: Retransmit<br/>Timer B: Timeout
note right of Completed: Timer D: Wait time<br/>Timer K: Termination
note left of Confirmed: Timer I: ACK wait<br/>Timer H: ACK timeout
State Machine: Dialog Layer
Dialog state management follows RFC 3261 Section 12:
stateDiagram-v2
[*] --> Init: new_dialog
Init --> Early: rcv_provisional
Early --> Confirmed: rcv_2xx
Early --> Terminated: rcv_final_error
Confirmed --> Terminated: rcv_BYE
Terminated --> [*]
note right of Early: Dialog established<br/>with early media
note right of Confirmed: Full dialog<br/>Media flowing
note right of Terminated: Cleanup resources<br/>Stop media
State Machine: Handler Adapter
stateDiagram-v2
[*] --> Idle: init
Idle --> TransactionTrying: rcv_INVITE
TransactionTrying --> TransactionProceeding: send_provisional
TransactionProceeding --> WaitingForAck: send_200_OK
WaitingForAck --> InCall: rcv_ACK
InCall --> Terminating: rcv_BYE
Terminating --> Idle: send_200_OK
note right of TransactionTrying: Notify app<br/>Start negotiation
note right of InCall: Media flowing<br/>Call established
note right of Terminating: Stop media<br/>Cleanup
SIP Call Flow with Process Interaction
This flow demonstrates how Parrot implements the basic call flow from RFC 3665 Section 3.1:
sequenceDiagram
participant Alice as Alice<br/>(UAC)
participant Transport as Transport<br/>Layer
participant TxnStatem as Transaction<br/>Statem
participant Dialog as Dialog<br/>Server
participant Handler as Handler<br/>Adapter
participant App as Application<br/>Handler
participant Media as Media<br/>Session
participant Bob as Bob<br/>(UAS)
Alice->>Transport: INVITE
Transport->>TxnStatem: new_server_transaction
TxnStatem->>TxnStatem: Start Timer C
TxnStatem->>Handler: handle_invite
Handler->>App: handle_invite callback
App->>Media: start_session
Media->>Media: Allocate RTP port
App->>Handler: {respond, 180, "Ringing"}
Handler->>TxnStatem: send_response
TxnStatem->>Transport: 180 Ringing
Transport->>Alice: 180 Ringing
Note over App: User answers call
App->>Handler: {respond, 200, "OK", SDP}
Handler->>Dialog: create_dialog
Dialog->>Dialog: Register dialog ID
Handler->>TxnStatem: send_response
TxnStatem->>Transport: 200 OK + SDP
Transport->>Alice: 200 OK + SDP
Alice->>Transport: ACK
Transport->>TxnStatem: process_ACK
TxnStatem->>Dialog: confirm_dialog
Dialog->>Handler: handle_ack
Handler->>Media: start_streaming
Note over Alice,Bob: RTP Media Flow
Media-->Alice: RTP Audio
Alice-->Media: RTP Audio
Alice->>Transport: BYE
Transport->>Dialog: in_dialog_request
Dialog->>Handler: handle_bye
Handler->>Media: stop_session
Media->>Media: Cleanup pipeline
Handler->>Dialog: terminate_dialog
Handler->>TxnStatem: send_response
TxnStatem->>Transport: 200 OK
Transport->>Alice: 200 OK
Media Negotiation Flow
sequenceDiagram
participant UAC as Alice UAC
participant Handler as Parrot Handler
participant Media as Media Session
participant SDP as SDP Parser
participant Pipeline as Membrane Pipeline
participant RTP as RTP Endpoint
UAC->>Handler: INVITE with SDP Offer
Handler->>Media: process_offer(sdp)
Media->>SDP: parse(offer)
SDP->>Media: {codecs: [PCMU, PCMA], port: 30000}
Media->>Media: Select compatible codec
Media->>Pipeline: create_pipeline(codec: PCMU)
Pipeline->>RTP: bind(local_port: 40000)
RTP->>Pipeline: ready
Pipeline->>Media: pipeline_ready
Media->>SDP: generate_answer
SDP->>Media: SDP Answer
Media->>Handler: {ok, sdp_answer}
Handler->>UAC: 200 OK with SDP Answer
Note over UAC,RTP: Media Path Established
UAC->>Handler: ACK
Handler->>Media: start_media
Media->>Pipeline: start_streaming
loop RTP Stream
UAC-->>RTP: RTP Packets (PCMU)
RTP-->>Pipeline: Decode/Process
Pipeline-->>RTP: Encode/Send
RTP-->>UAC: RTP Packets (PCMU)
end
Process Registry and Discovery
graph LR
subgraph "Process Registry"
ViaReg[Via Registry<br/>Branch → Transaction PID]
DialogReg[Dialog Registry<br/>Dialog ID → Dialog PID]
MediaReg[Media Registry<br/>Call ID → Media PID]
end
subgraph "Message Routing"
MSG[Incoming Message]
MSG --> ViaCheck{Via Branch?}
ViaCheck -->|Found| TxnPID[Transaction Process]
ViaCheck -->|Not Found| DialogCheck{Dialog ID?}
DialogCheck -->|Found| DialogPID[Dialog Process]
DialogCheck -->|Not Found| NewTxn[Create Transaction]
end
subgraph "Resource Management"
Supervisor[Supervisor]
Supervisor --> Monitor[Monitor Processes]
Monitor --> Cleanup[Cleanup on Exit]
Cleanup --> Unregister[Unregister from Registry]
end
Fault Tolerance and Supervision
graph TB
subgraph "Supervision Strategy"
Root[Root Supervisor<br/>one_for_one]
Root --> Transport[Transport Sup<br/>one_for_one]
Root --> Transaction[Transaction Sup<br/>simple_one_for_one]
Root --> Dialog[Dialog Sup<br/>simple_one_for_one]
Root --> Media[Media Sup<br/>one_for_all]
Transport --> UDP1[UDP:5060]
Transport --> UDP2[UDP:5061]
Transaction --> Txn1[Txn 1]
Transaction --> Txn2[Txn 2]
Transaction --> TxnN[Txn N]
Dialog --> Dlg1[Dialog 1]
Dialog --> Dlg2[Dialog 2]
Dialog --> DlgN[Dialog N]
Media --> Session1[Session 1]
Media --> Session2[Session 2]
Media --> SessionN[Session N]
end
subgraph "Failure Handling"
Crash[Process Crash]
Crash --> Restart[Supervisor Restart]
Restart --> Recover[State Recovery]
Recover --> Resume[Resume Operation]
end
Performance Characteristics
The architecture is designed for:
- High Concurrency: Each call/transaction in its own process
- Fault Isolation: Crashes don't affect other calls
- Scalability: Distribute across nodes
- Low Latency: Direct process messaging
- Resource Efficiency: Processes cleaned up after use
Key Design Decisions
- gen_statem over GenServer: For complex protocol state machines
- Process per Transaction: Isolation and garbage collection
- Registry-based Discovery: Fast process lookup
- Supervision Trees: Automatic recovery from failures
- Layered Architecture: Clear separation of concerns
Integration Points
- SIP Handler Behavior: Implement
Parrot.SipHandler
callbacks for SIP protocol events - Media Handler Behavior: Implement
Parrot.MediaHandler
callbacks for media session control - Transport Plugins: Add new transport protocols beyond UDP
- Codec Support: Extend with additional audio/video codecs
Handler Architecture
UasHandler
The Parrot.UasHandler
behaviour provides callbacks for SIP protocol events as a User Agent Server:
handle_invite/2
- Process incoming callshandle_ack/2
- Handle call confirmationhandle_bye/2
- Handle call terminationhandle_cancel/2
- Handle call cancellation- Transaction state callbacks for fine-grained control
MediaHandler
The Parrot.MediaHandler
behaviour provides callbacks for media control:
init/1
- Initialize handler statehandle_session_start/3
- Media session lifecyclehandle_stream_start/3
- Begin media streaminghandle_play_complete/2
- Audio playback eventshandle_codec_negotiation/3
- Influence codec selectionhandle_rtp_stats/2
- Monitor call qualityhandle_stream_error/3
- Error recovery
Both handlers work together to provide complete control over SIP calls and their associated media streams.