2 * Mausezahn - A fast versatile traffic generator
3 * Copyright (C) 2008-2010 Herbert Haas
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.
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
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
25 // Initialization function - specify defaults here!
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
41 pd
->pt
= 8; // 0=PCMU, 8=PCMA
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)
49 pd
->x_type
= 0; // no extension by default
51 // General packet parameters
54 mp
->ndelay
.tv_sec
= 0;
55 mp
->ndelay
.tv_nsec
= 20000000;
57 memset(&pd
->payload
, 0x00, MOPS_RTP_MAX_PAYLOAD_SIZE
);
64 * Standard RTP header according RFC 3550
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73 * | synchronization source (SSRC) identifier |
74 * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
75 * | contributing source (CSRC) identifiers |
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
;
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!
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);
101 mops_msg_add_byte (mp
, pd
->pt
);
102 mops_msg_add_field (mp
, pd
->m
, 7);
105 mops_msg_add_2bytes (mp
, pd
->sqnr
);
106 mops_msg_add_4bytes (mp
, pd
->tst
);
107 mops_msg_add_4bytes (mp
, pd
->ssrc
);
110 if ((j
=pd
->cc_real
)) {
111 if (j
>16) { j
=16; pd
->cc_real
=16; } // silent self healing if desired :-)
113 mops_msg_add_4bytes (mp
, pd
->csrc
[i
]);
115 pd
->rtp_header_len
= 12 + j
*4;
118 * Add Extension header?
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 |
129 switch (pd
->x_type
) {
132 case 1: // set aero, 8 bytes in total -- TODO --
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;
161 // Now add the payload
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;
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()
188 // - Mausezahn extension header if any
191 int mops_update_rtp_dynamics (struct mops
* mp
)
193 struct mops_ext_rtp
* pd
;
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]);
206 mops_hton4 (&pd
->tst
, &mp
->frame
[i
+4]);
207 pd
->tst
+= pd
->tst_inc
;
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]);
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
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
);