trafgen: allow to schedule packets on specific CPUs
[netsniff-ng.git] / src / mops_ext_rtp.c
blob2bc381316935b63e2d08e457a2b95c53fb2d1d3b
1 /*
2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License version 2 as published by the
7 * Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12 * details.
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html
19 #include "mz.h"
20 #include "mops.h"
21 #include "cli.h"
25 // Initialization function - specify defaults here!
26 //
27 int mops_init_pdesc_rtp(struct mops *mp)
29 struct mops_ext_rtp * pd;
31 if (mp->p_desc == NULL) return 1; // p_desc not properly assigned
32 pd = mp->p_desc;
34 // set RTP defaults
35 pd->v = 2;
36 pd->p = 0;
37 pd->x = 0;
38 pd->cc = 0;
39 pd->m = 0;
41 pd->pt = 8; // 0=PCMU, 8=PCMA
42 pd->sqnr = 0;
43 pd->tst = 0;
44 pd->tst_inc = 160;
45 pd->ssrc = mz_rand32(); // Default Mausezahn stream would be 0xCAFEBABE
46 pd->source = 0; // don't use /dev/dsp (but user may configure source = DSP_SOURCE)
47 pd->cc_real = 0;
49 pd->x_type = 0; // no extension by default
51 // General packet parameters
52 mp->dp = 30000;
53 mp->sp = 30002;
54 mp->ndelay.tv_sec = 0;
55 mp->ndelay.tv_nsec = 20000000;
57 memset(&pd->payload, 0x00, MOPS_RTP_MAX_PAYLOAD_SIZE);
59 return 0;
64 * Standard RTP header according RFC 3550
66 * 0 1 2 3
67 * 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
68 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 * |V=2|P|X| CC |M| PT | sequence number |
70 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 * | timestamp |
72 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73 * | synchronization source (SSRC) identifier |
74 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
75 * | contributing source (CSRC) identifiers |
76 * | .... |
77 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79 * !!! NOTE !!! -- This function should be used only to prepare the RTP
80 * header once. It does not update dynamic fields. To update dynamic fields
81 * each time a subsequent RTP packet is sent, use the function
82 * mops_update_rtp_dynamics().
85 int mops_update_rtp (struct mops * mp)
87 struct mops_ext_rtp * pd;
88 int i,j;
90 pd = mp->p_desc;
91 if (pd==NULL) return 1; // no valid pointer to a p_desc
92 mp->msg_s = 0; // !! IMPORTANT !! Otherwise the msg would get longer and longer after each call!
94 // 1st byte
95 mops_msg_add_byte (mp, pd->cc);
96 mops_msg_add_field (mp, pd->v, 6);
97 mops_msg_add_field (mp, pd->p, 5);
98 mops_msg_add_field (mp, pd->x, 4);
100 // 2nd byte
101 mops_msg_add_byte (mp, pd->pt);
102 mops_msg_add_field (mp, pd->m, 7);
104 // remaining
105 mops_msg_add_2bytes (mp, pd->sqnr);
106 mops_msg_add_4bytes (mp, pd->tst);
107 mops_msg_add_4bytes (mp, pd->ssrc);
109 // Add CSRC list?
110 if ((j=pd->cc_real)) {
111 if (j>16) { j=16; pd->cc_real=16; } // silent self healing if desired :-)
112 for (i=0; i<j; i++)
113 mops_msg_add_4bytes (mp, pd->csrc[i]);
115 pd->rtp_header_len = 12 + j*4;
118 * Add Extension header?
120 * 0 1 2 3
121 * 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
122 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
123 * | defined by profile | length |
124 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
125 * | header extension |
126 * | .... |
129 switch (pd->x_type) {
130 case 0: // none
131 break;
132 case 1: // set aero, 8 bytes in total -- TODO --
133 break;
134 case 42: // Mausezahn extension header:
135 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
136 // | MOPS_RTP_EXT_MZID | length=4 |
137 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
138 // | TX-timestamp sec |
139 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
140 // | TX-timestamp nsec |
141 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
142 // | Estimated Peer TX-timestamp sec |
143 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
144 // | Estimated Peer TX-timestamp nsec |
145 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
147 mops_msg_add_2bytes (mp, MOPS_RTP_EXT_MZID);
148 mops_msg_add_2bytes (mp, 2);
149 mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet
150 mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet
151 mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet
152 mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet
154 pd->rtp_header_len += 20;
155 break;
156 default:
157 return 1;
158 break; // paranoid?
161 // Now add the payload
162 switch (pd->pt) {
163 case 0:
164 case 8:
165 mp->msg_s = 160 + pd->rtp_header_len; // simply set total RTP PDU length (the RTP payload is still undefined)
166 mp->ndelay.tv_sec = 0;
167 mp->ndelay.tv_nsec = 20000000;
168 break;
169 default:
170 break;
173 return 0;
178 // This function directly updates the dynamic RTP fields
179 // within the mops frame (=be quick here).
181 // This function is typically called from within the transmission loops,
182 // see e. g. mops_tx_thread_native()
184 // This includes:
186 // - RTP SQNR
187 // - RTP Timestamp
188 // - Mausezahn extension header if any
189 // - The RTP payload
191 int mops_update_rtp_dynamics (struct mops * mp)
193 struct mops_ext_rtp * pd;
194 struct timespec ct;
195 int j, i = mp->begin_MSG;
197 pd = mp->p_desc; if (pd==NULL) return 1;
200 // The following variables must be incremented AFTER assignment to frame,
201 // so the initial values are also used!
203 mops_hton2 (&pd->sqnr, &mp->frame[i+2]);
204 pd->sqnr++;
206 mops_hton4 (&pd->tst, &mp->frame[i+4]);
207 pd->tst += pd->tst_inc;
210 // Extension header:
211 // Timestamp must be updated BEFORE assignment to frame
213 switch (pd->x_type) {
214 case 42: // Mausezahn extension header: Update timestamps
215 j = i + pd->rtp_header_len; // points to first byte of timestamp of MZ extension header
216 clock_gettime(CLOCK_MONOTONIC, &ct);
217 mops_hton4 ((u_int32_t*) &ct.tv_sec, &mp->frame[j-16]);
218 mops_hton4 ((u_int32_t*) &ct.tv_nsec, &mp->frame[j-12]);
219 //[TODO] **** estimated peer timestamp **** PSEUDOCODE FOLLOWING:
220 // if (peer_exists) {
221 // get_peer_timestamp_estimation(&est);
222 // mops_hton4 ((u_int32_t*) &est.sec, &mp->frame[j-8]);
223 // mops_hton4 ((u_int32_t*) &est.nsec, &mp->frame[j-4]);
224 // }
225 break;
226 default:
227 return 0;
228 break;
231 // The pd->payload contains either zeroes or realtime voice data
232 // The pd->payload is initialized with zeroes and IFF a reading thread
233 // exists, it may copy voice segments (e. g. from /dev/dsp) to
234 // pd->payload.
235 // NOTE that there is NO NEED to protect pd->payload with mutexes, because
236 // only if the reading thread is finished it (itself!) will call THIS function.
237 if (pd->source == DSP_SOURCE) {
238 memcpy((void*) &mp->frame[j], (void*) pd->payload, pd->payload_s);
241 return 0;