SIPp Media Handling Workflow
SIPp’s four media handling modes: RTP Streaming [1a-1f] for file playback, PCAP Playback [2a-2f] for replaying captures, RTP Echo [3a-3e] for reflecting media, and DTMF Generation [4a-4e] for RFC 4733 tones. Key entry points are scenario parsing in scenario.cpp [1a,2a,4a], SDP parsing in call.cpp [2b], and the core engines in rtpstream.cpp [1c-1f,3a-3e], prepare_pcap.c [2c,4b-4d], and send_packets.c [2d-2f,4e].
1. RTP Streaming File Playback
Triggers when scenario executes – plays audio files over RTP using threaded playback engine
1a. Parse rtp_stream XML action (scenario.cpp:1686)
Scenario parser extracts rtp_stream action and sets action type based on command (play, pause, resume, pattern)
else if ((cptr = xp_get_value("rtp_stream"))) {
1b. Cache audio file in memory (actions.cpp:885)
Action execution loads file into global cache once, configures codec parameters based on payload type
if (rtpstream_cache_file(
M_rtpstream_actinfo.filename,
pattern_mode /* 0: FILE - 1: PATTERN */,
M_rtpstream_actinfo.pattern_id,
M_rtpstream_actinfo.bytes_per_packet,
stream_type) < 0) {
1c. Bind local RTP socket (rtpstream.cpp:2414)
rtpstream_play() allocates UDP port from min_rtp_port range, binds RTP/RTCP sockets
rtpstream_get_local_audioport(callinfo);
1d. Signal playback start (rtpstream.cpp:2436)
Sets TI_PLAYFILE flag to trigger playback thread to begin sending packets
taskinfo->flags |= TI_PLAYFILE;
1e. Create playback thread (rtpstream.cpp:1456)
rtpstream_start_task() spawns new pthread if no threads have capacity, adds task to thread pool
if (pthread_create(&threadID, nullptr, rtpstream_playback_thread, threaddata)) {
1f. Send RTP packet (rtpstream.cpp:728)
Playback thread builds RTP header with seq/timestamp/SSRC, copies payload, sends via UDP socket
rc = send(taskinfo->audio_rtp_socket, audio_out.data(), audio_out.size(), 0);
2. PCAP Playback
Triggers when scenario executes – replays pre-recorded RTP using raw sockets
2a. Parse play_pcap_audio action (scenario.cpp:1657)
Scenario parser sets E_AT_PLAY_PCAP_AUDIO action type with PCAP filename
} else if ((ptr = xp_get_keyword_value("play_pcap_audio"))) {
tmpAction->setPcapArgs(ptr);
tmpAction->setActionType(CAction::E_AT_PLAY_PCAP_AUDIO);
2b. Extract remote media address (call.cpp:198)
get_remote_media_addr() parses SDP from 200 OK to extract destination IP and audio port
std::string port = find_in_sdp("m=audio ", msg);
if (!port.empty()) {
gai_getsockaddr(&play_args_a.to, host.c_str(), port.c_str(),
AI_NUMERICHOST | AI_NUMERICSERV, family);
2c. Parse PCAP file (prepare_pcap.c:213)
prepare_pkts() opens PCAP, extracts UDP/RTP frames, pre-computes partial checksums
pcap = pcap_open_offline(file, errbuf);
if (!pcap)
ERROR("Can't open PCAP file '%s': %s", file, errbuf);
2d. Create raw socket (send_packets.c:177)
send_packets() creates raw UDP socket (requires root privileges) for PCAP replay
sock = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if (sock < 0) {
ERROR("Can't create raw IPv4 socket (need to run as root?): %s", strerror(errno));
2e. Adjust UDP ports (send_packets.c:234)
Modifies source/destination ports relative to SDP-negotiated base port from original capture
udp->uh_sport = htons(port_diff + ntohs(*from_port));
udp->uh_dport = htons(port_diff + ntohs(*to_port));
2f. Send with original timing (send_packets.c:256)
Sleeps to match inter-packet timing from capture, then sends packet via raw socket
do_sleep ((struct timeval *) &pkt_index->ts, &last, &didsleep,
&start);
ret = sendto(sock, buffer, pkt_index->pktlen, MSG_DONTWAIT,
3. RTP Echo
Triggers when -rtp_echo flag is set – reflects incoming RTP back to sender via dedicated echo threads
3a. Spawn echo thread (rtpstream.cpp:3180)
rtpstream_rtpecho_startaudio() creates pthread for audio echo, sets up SRTP contexts if USE_TLS
if (pthread_create(&pthread_audioecho_id, nullptr, (void *(*) (void *)) rtpstream_audioecho_thread, p.p) == -1) {
3b. Receive RTP packet (rtpstream.cpp:2695)
Echo thread loops on recvfrom() to receive incoming RTP packets on media port
nr = recvfrom(sock, audio_packet_in.data(), audio_packet_in.size(), MSG_DONTWAIT /* NON-BLOCKING */, (sockaddr *) (void *) &remote_rtp_addr, &len);
3c. Decrypt SRTP (if enabled) (rtpstream.cpp:2726)
If SRTP is active, decrypts incoming packet using JLSRTP library
rc = g_rxUASAudio.processIncomingPacket(seq_num, audio_packet_in, rtp_header, payload_data);
3d. Encrypt for echo (if enabled) (rtpstream.cpp:2768)
Re-encrypts packet for transmission back to sender using SRTP
rc = g_txUASAudio.processOutgoingPacket(seq_num, rtp_header, payload_data, audio_packet_out);
3e. Echo packet back (rtpstream.cpp:2777)
Sends packet back to source address, completing echo loop
ns = sendto(sock, audio_packet_out.data(), sizeof(rtp_header_t) + g_txUASAudio.getSrtpPayloadSize() + g_txUASAudio.getAuthenticationTagSize(), MSG_DONTWAIT, (sockaddr *) (void *) &remote_rtp_addr, len);
4. DTMF Generation
Triggers when scenario executes – generates RFC 4733 DTMF event packets
4a. Parse play_dtmf action (scenario.cpp:1672)
Scenario parser sets E_AT_PLAY_DTMF action type with DTMF digit string
} else if ((cptr = xp_get_value("play_dtmf"))) {
tmpAction->setMessage(cptr);
tmpAction->setActionType(CAction::E_AT_PLAY_DTMF);
4b. Generate DTMF start packets (prepare_pcap.c:452)
prepare_dtmf_digit_start() builds RFC 4733 event packets with marker bit set for each digit
fill_default_dtmf(dtmfpacket, !marked,
*n_pkts + start_seq_no, n_digits * tone_len * 2 + timestamp_start,
uc_digit, 0, cur_tone_len);
4c. Generate DTMF end packets (prepare_pcap.c:492)
prepare_dtmf_digit_end() creates 3 packets with end-of-event flag set per RFC 4733
fill_default_dtmf(dtmfpacket, 0,
*n_pkts + start_seq_no, n_digits * tone_len * 2 + timestamp_start,
uc_digit, 1, tone_len);
4d. Build packet list (prepare_pcap.c:436)
Dynamically allocates packet list and stores generated DTMF packets with timestamps
pkts->pkts = realloc(pkts->pkts, sizeof(*pkts->pkts) * (*n_pkts + 1));
pkt_index->data = malloc(pktlen);
4e. Send DTMF packets (send_packets.c:260)
send_packets() sends DTMF packets using same raw socket path as PCAP playback with timing
ret = sendto(sock, buffer, pkt_index->pktlen, MSG_DONTWAIT,