diff options
author | Daniel Borkmann <dborkman@redhat.com> | 2013-05-13 13:53:27 +0200 |
---|---|---|
committer | Daniel Borkmann <dborkman@redhat.com> | 2013-05-13 15:10:16 +0200 |
commit | d0009856814c13d13770db5aadd7b2fabf947776 (patch) | |
tree | 6d18a94439f27f3c2685f05c57435116673f40cc /staging/mops_ext_rtp.c | |
parent | 2b100f7515dbd01032967c2d1b81d2f8d63bf9b5 (diff) |
staging: add mausezahn staging directory
After some back and forth, we decided that it is easier to maintain
mausezahn in a staging directory until it is fully reworked and
cleaned up to be ready to be fully integrated. This way, it is better
than having it in a separate branch, and we can also accept patches
from outside more easily. Also, while at it, fix up some function
mismatches with libcli.
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
Diffstat (limited to 'staging/mops_ext_rtp.c')
-rw-r--r-- | staging/mops_ext_rtp.c | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/staging/mops_ext_rtp.c b/staging/mops_ext_rtp.c new file mode 100644 index 0000000..2bc3813 --- /dev/null +++ b/staging/mops_ext_rtp.c @@ -0,0 +1,243 @@ +/* + * Mausezahn - A fast versatile traffic generator + * Copyright (C) 2008-2010 Herbert Haas + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see http://www.gnu.org/licenses/gpl-2.0.html + * +*/ + +#include "mz.h" +#include "mops.h" +#include "cli.h" + + + +// Initialization function - specify defaults here! +// +int mops_init_pdesc_rtp(struct mops *mp) +{ + struct mops_ext_rtp * pd; + + if (mp->p_desc == NULL) return 1; // p_desc not properly assigned + pd = mp->p_desc; + + // set RTP defaults + pd->v = 2; + pd->p = 0; + pd->x = 0; + pd->cc = 0; + pd->m = 0; + + pd->pt = 8; // 0=PCMU, 8=PCMA + pd->sqnr = 0; + pd->tst = 0; + pd->tst_inc = 160; + pd->ssrc = mz_rand32(); // Default Mausezahn stream would be 0xCAFEBABE + pd->source = 0; // don't use /dev/dsp (but user may configure source = DSP_SOURCE) + pd->cc_real = 0; + + pd->x_type = 0; // no extension by default + + // General packet parameters + mp->dp = 30000; + mp->sp = 30002; + mp->ndelay.tv_sec = 0; + mp->ndelay.tv_nsec = 20000000; + + memset(&pd->payload, 0x00, MOPS_RTP_MAX_PAYLOAD_SIZE); + + return 0; +} + + +/* + * Standard RTP header according RFC 3550 + * + * 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 | + * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * | contributing source (CSRC) identifiers | + * | .... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * !!! NOTE !!! -- This function should be used only to prepare the RTP + * header once. It does not update dynamic fields. To update dynamic fields + * each time a subsequent RTP packet is sent, use the function + * mops_update_rtp_dynamics(). + * + */ +int mops_update_rtp (struct mops * mp) +{ + struct mops_ext_rtp * pd; + int i,j; + + pd = mp->p_desc; + if (pd==NULL) return 1; // no valid pointer to a p_desc + mp->msg_s = 0; // !! IMPORTANT !! Otherwise the msg would get longer and longer after each call! + + // 1st byte + mops_msg_add_byte (mp, pd->cc); + mops_msg_add_field (mp, pd->v, 6); + mops_msg_add_field (mp, pd->p, 5); + mops_msg_add_field (mp, pd->x, 4); + + // 2nd byte + mops_msg_add_byte (mp, pd->pt); + mops_msg_add_field (mp, pd->m, 7); + + // remaining + mops_msg_add_2bytes (mp, pd->sqnr); + mops_msg_add_4bytes (mp, pd->tst); + mops_msg_add_4bytes (mp, pd->ssrc); + + // Add CSRC list? + if ((j=pd->cc_real)) { + if (j>16) { j=16; pd->cc_real=16; } // silent self healing if desired :-) + for (i=0; i<j; i++) + mops_msg_add_4bytes (mp, pd->csrc[i]); + } + pd->rtp_header_len = 12 + j*4; + + /* + * Add Extension header? + * + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | defined by profile | length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | header extension | + * | .... | + */ + + switch (pd->x_type) { + case 0: // none + break; + case 1: // set aero, 8 bytes in total -- TODO -- + break; + case 42: // Mausezahn extension header: + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | MOPS_RTP_EXT_MZID | length=4 | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | TX-timestamp sec | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | TX-timestamp nsec | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Estimated Peer TX-timestamp sec | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Estimated Peer TX-timestamp nsec | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + mops_msg_add_2bytes (mp, MOPS_RTP_EXT_MZID); + mops_msg_add_2bytes (mp, 2); + mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet + mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet + mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet + mops_msg_add_4bytes (mp, 0); // only placeholders, must be updated each packet + + pd->rtp_header_len += 20; + break; + default: + return 1; + break; // paranoid? + } + + // Now add the payload + switch (pd->pt) { + case 0: + case 8: + mp->msg_s = 160 + pd->rtp_header_len; // simply set total RTP PDU length (the RTP payload is still undefined) + mp->ndelay.tv_sec = 0; + mp->ndelay.tv_nsec = 20000000; + break; + default: + break; + } + + return 0; +} + + + +// This function directly updates the dynamic RTP fields +// within the mops frame (=be quick here). +// +// This function is typically called from within the transmission loops, +// see e. g. mops_tx_thread_native() +// +// This includes: +// +// - RTP SQNR +// - RTP Timestamp +// - Mausezahn extension header if any +// - The RTP payload +// +int mops_update_rtp_dynamics (struct mops * mp) +{ + struct mops_ext_rtp * pd; + struct timespec ct; + int j, i = mp->begin_MSG; + + pd = mp->p_desc; if (pd==NULL) return 1; + + + // The following variables must be incremented AFTER assignment to frame, + // so the initial values are also used! + // + mops_hton2 (&pd->sqnr, &mp->frame[i+2]); + pd->sqnr++; + + mops_hton4 (&pd->tst, &mp->frame[i+4]); + pd->tst += pd->tst_inc; + + + // Extension header: + // Timestamp must be updated BEFORE assignment to frame + // + switch (pd->x_type) { + case 42: // Mausezahn extension header: Update timestamps + j = i + pd->rtp_header_len; // points to first byte of timestamp of MZ extension header + clock_gettime(CLOCK_MONOTONIC, &ct); + mops_hton4 ((u_int32_t*) &ct.tv_sec, &mp->frame[j-16]); + mops_hton4 ((u_int32_t*) &ct.tv_nsec, &mp->frame[j-12]); +//[TODO] **** estimated peer timestamp **** PSEUDOCODE FOLLOWING: +// if (peer_exists) { +// get_peer_timestamp_estimation(&est); +// mops_hton4 ((u_int32_t*) &est.sec, &mp->frame[j-8]); +// mops_hton4 ((u_int32_t*) &est.nsec, &mp->frame[j-4]); +// } + break; + default: + return 0; + break; + } + + // The pd->payload contains either zeroes or realtime voice data + // The pd->payload is initialized with zeroes and IFF a reading thread + // exists, it may copy voice segments (e. g. from /dev/dsp) to + // pd->payload. + // NOTE that there is NO NEED to protect pd->payload with mutexes, because + // only if the reading thread is finished it (itself!) will call THIS function. + if (pd->source == DSP_SOURCE) { + memcpy((void*) &mp->frame[j], (void*) pd->payload, pd->payload_s); + } + + return 0; +} + |