Exemplo n.º 1
0
// Update official timestamp, own timestamp and sequence number in the RTP header. 
// The actual RTP message is stored in tx.udp_payload.
int update_RTP(libnet_t *l, libnet_ptag_t t)
{
	u_int8_t *ptr;
	struct mz_timestamp ts;
	
	tx.rtp_sqnr++;
	tx.rtp_stmp+=160; // TODO: different values for different codecs
	
	// update SQNR
	ptr = (u_int8_t*) &tx.rtp_sqnr;
	tx.udp_payload[2] = *(ptr+1);
	tx.udp_payload[3] = *ptr;

	// update official timestamp
	ptr = (u_int8_t*) &tx.rtp_stmp;
	tx.udp_payload[4] = *(ptr+3);
	tx.udp_payload[5] = *(ptr+2);
	tx.udp_payload[6] = *(ptr+1);
	tx.udp_payload[7] = *ptr;

   
	// update own timestamp
	getcurtime(&ts); // Now add TX timestamp:
	mops_hton4 ((u_int32_t*) &ts.sec,  &tx.udp_payload[16]);
	mops_hton4 ((u_int32_t*) &ts.nsec, &tx.udp_payload[20]);
   
	t = libnet_build_udp(tx.sp, 
			     tx.dp, 
			     tx.udp_len, 
			     tx.udp_sum,
			     tx.udp_payload,
			     tx.udp_payload_s,
			     l, 
			     t);

	if (t == -1) {
		fprintf(stderr," mz/send_frame: RTP header update failed!\n");
		exit (1);
	}
	return 0;
}
Exemplo n.º 2
0
int create_rtp_packet()
{
	u_int8_t byte1,	byte2;
	u_int16_t seqnr;
	u_int8_t ssrc[4] = {0,0,0,0} ;
	int ssrc_s = 0;
	u_int8_t *ptr;
	char argval[MAX_PAYLOAD_SIZE];
	unsigned int rtp_payload_size=160;
	struct mz_timestamp ts;
	
	if ( (getarg(tx.arg_string,"help", NULL)==1) && (mode==RTP) ) {
		if (mz_port)
		{
			cli_print(gcli, "%s", MZ_RTP_HELP);
			return -1;
		}
		else
		{
			
			fprintf(stderr,"\n" 
				MAUSEZAHN_VERSION
				"\n%s", MZ_RTP_HELP);
			exit(0);
		}
	}
	
	
	if (getarg(tx.arg_string,"pld", argval)==1) {
		rtp_payload_size = (unsigned int) str2int(argval);
	}
	
	if (getarg(tx.arg_string,"codec", argval)==1) {
		tx.delay = 20000;
	}

	if (getarg(tx.arg_string,"ssrc", argval)==1) {
		ssrc_s = str2hex(argval, ssrc, 4);
		if (ssrc_s<0) {
			fprintf(stderr, " mz/rtp: invalid ssrc!\n");
			return -1;
		}
	}

   // TODO: Optional arguments for RTP
   
   
   // Create header: //

   // Byte 1    
   // 
   // +--+--+--+--+--+--+--+--+
   // | ver | P| X| CSRC Count|
   // +--+--+--+--+--+--+--+--+
   // 
   // Default: ver=2, Padding=0, Extension_Header=1, CSRC_Count=0 => 10 0 1 0000 = 0x90

	byte1 = 0x90;
   
   // Byte 2
   // 
   // +--+--+--+--+--+--+--+--+
   // | M|    Payload Type    |
   // +--+--+--+--+--+--+--+--+
   // 
   // Marker=0, Payload Type=0 (or 8 alternatively)

	byte2 = 0x00;
   
   // Bytes 3,4
   // 
   // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
   // |               Sequence Number                 |
   // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

	seqnr = 0x0000;
   
   // Bytes 5,6,7,8
   // 
   //	Timestamp  /* done below */
   //
   
   
   // Bytes 9,10,11,12
   //
   //   Synchronization Source Identifier
   // 
   
	if (ssrc_s==0) str2hex("ca:fe:fe:ed", ssrc, 4);
	
   // Bytes 13,14,15,16
   // 
   //     CSRC - Contributing Source Identifiers (optional, only used by mixers)
   //
   //   csrc = 0x00000000; 
   
   // Bytes 17,18,19,20
   // 
   //   Header Extension (optional) NOT USED HERE!
   // 

   // !!! Thus payload begins with index 16 in a C array !!!

   // ------------ Now combine all fields: ----------------
   tx.udp_payload[0] = byte1;
   tx.udp_payload[1] = byte2;
   
   ptr = (u_int8_t*) &seqnr;
   tx.udp_payload[2] = *(ptr+1);
   tx.udp_payload[3] = *ptr;
   
   // TIMESTAMP: will be linearly increased, e.g. using 20msec G.711: 0, 160, 320, ...
   tx.udp_payload[4] = 0x00;
   tx.udp_payload[5] = 0x00;
   tx.udp_payload[6] = 0x00;
   tx.udp_payload[7] = 0x00;

   tx.udp_payload[8] = ssrc[0];
   tx.udp_payload[9] = ssrc[1];
   tx.udp_payload[10] = ssrc[2];
   tx.udp_payload[11] = ssrc[3];
   
   /*
   ptr = (u_int8_t*) &csrc;
   tx.udp_payload[12] = *(ptr+3);
   tx.udp_payload[13] = *(ptr+2);
   tx.udp_payload[14] = *(ptr+1);
   tx.udp_payload[15] = *ptr;
   */
   
   // Add the NEW Mausezahn extension header (see mops_ext_rtp.c)
   tx.udp_payload[12] = 0xca;  // identifier
   tx.udp_payload[13] = 0xca;
   tx.udp_payload[14] = 0x00;
   tx.udp_payload[15] = 0x04;  // length
   getcurtime(&ts); // Now add TX timestamp:
   mops_hton4 ((u_int32_t*) &ts.sec,  &tx.udp_payload[16]);
   mops_hton4 ((u_int32_t*) &ts.nsec, &tx.udp_payload[20]);
   // NOTE: The remaining 8 bytes of this extension header are set to zero
   // via the following code.
   
   memset(&tx.udp_payload[24], 0x00, (rtp_payload_size-12)); // payload (considering our 8 byte timestamp)
   tx.udp_payload_s = 12 + rtp_payload_size; // the latter ist the payload size
   
   // ---------- now hand over to UDP -----------------

   tx.dp = 30000;
   tx.sp = 30000;
     
   tx.udp_len = 8 + tx.udp_payload_s;
   
   return 0;
}
Exemplo n.º 3
0
// Handler function to do something when RTP messages are received
void got_rtp_packet(u_char *args,
		    const struct pcap_pkthdr *header, // statistics about the packet (see 'struct pcap_pkthdr')
		    const u_char *packet)             // the bytestring sniffed
{
	const struct struct_ethernet *ethernet;
	const struct struct_ip       *ip;
	const struct struct_udp      *udp;
	const struct struct_rtp      *rtp;
	
	int size_ethernet = sizeof(struct struct_ethernet);
	int size_ip = sizeof(struct struct_ip);
	int size_udp = sizeof(struct struct_udp);
	// int size_rtp = sizeof(struct struct_rtp);
   	// 
	ethernet = (struct struct_ethernet*)(packet);
	ip       = (struct struct_ip*)(packet+size_ethernet);
	udp      = (struct struct_udp*)(packet+size_ethernet+size_ip);
	rtp      = (struct struct_rtp*)(packet+size_ethernet+size_ip+size_udp);
	
	struct mz_timestamp 
		deltaTX,
		deltaRX;
	
	u_int32_t 
		i,
		jitter_abs,
		jitter_avg,
		jitter_max,
		jitter_min,
		curtime=0;

	int32_t ltemp;
	
	u_int8_t *x,*y;
	
	char dummy[256];
	char ts_hms[10];
	unsigned char *dum;
	static u_int32_t drop_last=0, drop_prev=0;
	int s1, s2;
	
	// check if the RTP packet is really from a Mausezahn instance:
	if (compare4B((u_int8_t*) &rtp->ssrc, mz_ssrc)==0) {
		// we got a valid RTP packet from a Mausezahn instance
		// Get current SQNR and store it in 'sqnr_cur' in host byte order
		x  = (u_int8_t*) &rtp->sqnr;
		y  = (u_int8_t*) &sqnr_cur;
		
		*y = *(x+1);
		y++;
		*y = *x;

		/////////////////////////////////////////////////////////////////////
		// Packet drop and disorder detection:
		if (sqnr0_flag) {
			if (sqnr_next==sqnr_cur) {  // correct SQNR received
				sqnr_next++;
				sqnr_last++;
			} else if (sqnr_last>sqnr_cur) { // disordered sequence
				dis++;
				if (drop) drop--; // don't get below 0
				else { // drop reached zero: resync (restarted RTP stream?)
					sqnr_last = sqnr_cur; 
					sqnr_next = (++sqnr_last);
					dis=0;
				}
			} else {  // packet drop
				drop += (sqnr_cur-sqnr_next);
				sqnr_last = sqnr_cur;
				sqnr_next = (++sqnr_last);
			}
		} else { 
			// initial synchronization with observed SQNR:
			sqnr_last = sqnr_cur;
			sqnr_next = (++sqnr_last);
			sqnr0_flag++;
		}
		//
		/////////////////////////////////////////////////////////////////////

		
		// Get RX timestamp from pcap header
		timeRX[gind].sec  = header->ts.tv_sec;
		timeRX[gind].nsec = header->ts.tv_usec *1000;

		// Get TX timestamp from the packet 
		mops_hton4((u_int32_t*) &rtp->time_sec,  (u_int8_t*) &timeTX[gind].sec);
		mops_hton4((u_int32_t*) &rtp->time_nsec, (u_int8_t*) &timeTX[gind].nsec);

//		printf("%li %li\n", (long int) timeTX[gind].sec, (long int) timeTX[gind].nsec);
		
		gind++;
	
		////////////////////////////////////////////////////////////////
		if (gind == gind_max) { // array full, now calculate statistics
			gind=0;
			gtotal++;
			
			jitter_avg = 0;
			jitter_min = 0xffffffff;
			jitter_max = 0;
			
			
			///////////////////////////////////////////////////////
			// calculate deltas and jitters
			for (i=2; i<gind_max; i++) { // omit the first 2 data 
				                     // entries because of 
				                     // artificial high TX-delta!
						     // 
				///////////////////////////////////////////////
				// calculate deltaTX and deltaRX
				//
				s1=timestamp_subtract (&timeTX[i], &timeTX[i-1], &deltaTX);
				s2=timestamp_subtract (&timeRX[i], &timeRX[i-1], &deltaRX);
				if (s1) fprintf(stderr, " ***  ***\n");
				
				// Then calculate the precise jitter by considering 
				// also TX-jitter: (pseudo)jitter = deltaRX - deltaTX, 
				// hence we have positive and negative jitter (delay 
				// deviations) jitter entries are in +/- nanoseconds
				jitter[i] = (deltaRX.sec*1000000000L + deltaRX.nsec)
					  - (deltaTX.sec*1000000000L + deltaTX.nsec);
				// Calculate RFC 3550 jitter estimation. According to 
				// that RFC the jitter should be measured in timestamp 
				// units; however currently Mausezahn uses nanoseconds.
				// (If we want to solve this: G.711 timestamp units are 
				// 125 usec, so jitter/=125 would be sufficient, AFAIK)
				ltemp = labs(jitter[i]) - jitter_rfc;
				jitter_rfc += (ltemp>>4);  
				// Add previous pseudojitter to get the true jitter 
				// (See Documentation!)
				jitter[i] += jitter[i-1];
				//
				////////////////////////////////////////////////
		  


		  
				////////////////////////////////////////////////
				// Determine avg, min, and max jitter within this time frame:
				jitter_abs = labs(jitter[i]);
				jitter_avg += jitter_abs;
				if (jitter_abs < jitter_min) jitter_min = jitter_abs;
				if (jitter_abs > jitter_max) jitter_max = jitter_abs;
				//
				////////////////////////////////
		  
				/// PRINT IN FILE_2: Detailed jitter data ///
				if (rtp_log==2) {
					// Calculate relative timestamp for column 1 of the datafile 
					curtime = timeRX[i].sec*1000000+timeRX[i].nsec/1000;
					if (time0_flag) {
						curtime = curtime - time0;
					} else { // this is only done once during the Mausezahn process
						time0 = curtime;
						time0_flag=1;
						curtime = curtime - time0;
					}
					fprintf(fp2, "%lu, %li\n", 
						(long unsigned int) curtime, 
						(long int) jitter[i]);
					fflush(fp2); // save everything immediately 
					             // (CHECK if fsync() is additionally needed)
				}
			} // end for (i=2; i<gind_max; i++)
			//
			////////////////////////////////////////////////////////
	     
	     
			jitter_avg = jitter_avg / (gind_max-2);    // average true jitter, always positive

			if (drop>=drop_prev) { // because the total drop count may decrease(!) if disordered packets appear lately
				drop_last = drop - drop_prev;
				drop_prev=drop;
			} else drop_last=0; 
			
			// PRINT ON CLI: statistics data
			switch (rtp_dm) {
			 case TEXT:
				dum =  (unsigned char*) &ip->src;
				fprintf(stdout, 
					"Got %u packets from host %u.%u.%u.%u: %lu lost (%lu absolute lost, %lu out of order)\n"
					"  Jitter_RFC (low pass filtered) = %li usec\n"
					"  Samples jitter (min/avg/max)   = %lu/%lu/%lu usec\n",
					gind_max,
					*(dum),*(dum+1),*(dum+2),*(dum+3),
					(long unsigned int) drop_last, 
					(long unsigned int) drop, 
					(long unsigned int) dis,
					(long int) jitter_rfc/1000,
					(long unsigned int) jitter_min/1000,
					(long unsigned int) jitter_avg/1000,
					(long unsigned int) jitter_max/1000);
				break;
				
			 case BAR:
				print_jitterbar(jitter_rfc/1000, drop_last);
				break;
				
			 case NCURSES: // would be nice...?
				break;
				
			 default:
				break;
			}

			// Determine whether some packets got lost:
			// 
			// 
			// 
			// 
	     
	     
	     
			/// PRINT IN FILE_1: statistics only ///
			if (rtp_log) {
				ts_hms[0]=0x00;
				timestamp_hms (ts_hms);
				fprintf(fp, 
					"%s, %lu, %lu, %lu, %li, %u, %u\n",
					ts_hms,
					(long unsigned int) jitter_min/1000,
					(long unsigned int) jitter_avg/1000,
					(long unsigned int) jitter_max/1000,
					(long int) jitter_rfc/1000,
					drop,
					dis);
				fflush(fp);
			}
	     
	     
	     
			// Open another file if current file reaches a limit
			// 
			if ((rtp_log==2) && (gtotal>MAX_DATA_BLOCKS)) { // file big enough, 
				gtotal=0;
				if (fclose(fp2) == EOF) {
					perror("fclose");
					exit(1);
				}
		  
				if (verbose) 
					fprintf(stderr, " mz: %s written.\n",filename);
		  
				timestamp_human(filename, "rtp_");  // get a new filename
				strncpy(dummy, path, 128);
				strncat(dummy, filename, 64);
		  
				if (verbose) fprintf(stderr, " mz: Will open %s\n", dummy);
		  
				if  ( (fp2 = fopen (dummy, "w+")) == NULL) {
					if (errno != EAGAIN) {
						perror("fopen");
						exit (-1);
					}
				}
				fprintf(fp2, "# Jitter measurements by Mausezahn " 
					MAUSEZAHN_VERSION_SHORT ".\n");
				fprintf(fp2, "# Timestamp (usec) , true jitter (nsec)\n");
			}
		} // statistics end *********************************************************************