1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 //TODO(hlundin): Reformat file to meet style guide. 12 13 /* header includes */ 14 #include <float.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #ifdef WIN32 19 #include <winsock2.h> 20 #include <io.h> 21 #endif 22 #ifdef WEBRTC_LINUX 23 #include <netinet/in.h> 24 #endif 25 26 #include <assert.h> 27 28 #include "testing/gtest/include/gtest/gtest.h" 29 #include "webrtc/typedefs.h" 30 31 /*********************/ 32 /* Misc. definitions */ 33 /*********************/ 34 35 #define FIRSTLINELEN 40 36 #define CHECK_NOT_NULL(a) if((a)==NULL){ \ 37 fprintf(stderr,"\n %s \n line: %d \nerror at %s\n",__FILE__,__LINE__,#a ); \ 38 return(-1);} 39 40 struct arr_time { 41 float time; 42 uint32_t ix; 43 }; 44 45 int filelen(FILE *fid) 46 { 47 fpos_t cur_pos; 48 int len; 49 50 if (!fid || fgetpos(fid, &cur_pos)) { 51 return(-1); 52 } 53 54 fseek(fid, 0, SEEK_END); 55 len = ftell(fid); 56 57 fsetpos(fid, &cur_pos); 58 59 return (len); 60 } 61 62 int compare_arr_time(const void *x, const void *y); 63 64 int main(int argc, char* argv[]) 65 { 66 unsigned int dat_len, rtp_len, Npack, k; 67 arr_time *time_vec; 68 char firstline[FIRSTLINELEN]; 69 unsigned char* rtp_vec = NULL; 70 unsigned char** packet_ptr = NULL; 71 unsigned char* temp_packet = NULL; 72 const unsigned int kRtpDumpHeaderSize = 4 + 4 + 4 + 2 + 2; 73 uint16_t len; 74 uint32_t *offset; 75 76 /* check number of parameters */ 77 if (argc != 4) { 78 /* print help text and exit */ 79 printf("Apply jitter on RTP stream.\n"); 80 printf("Reads an RTP stream and packet timing from two files.\n"); 81 printf("The RTP stream is modified to have the same jitter as described in " 82 "the timing files.\n"); 83 printf("The format of the RTP stream file should be the same as for \n"); 84 printf("rtpplay, and can be obtained e.g., from Ethereal by using\n"); 85 printf("Statistics -> RTP -> Show All Streams -> [select a stream] -> " 86 "Save As\n\n"); 87 printf("Usage:\n\n"); 88 printf("%s RTP_infile dat_file RTP_outfile\n", argv[0]); 89 printf("where:\n"); 90 91 printf("RTP_infile : RTP stream input file\n\n"); 92 93 printf("dat_file : file with packet arrival times in ms\n\n"); 94 95 printf("RTP_outfile : RTP stream output file\n\n"); 96 97 return(0); 98 } 99 100 FILE* in_file=fopen(argv[1],"rb"); 101 CHECK_NOT_NULL(in_file); 102 printf("Input file: %s\n",argv[1]); 103 FILE* dat_file=fopen(argv[2],"rb"); 104 CHECK_NOT_NULL(dat_file); 105 printf("Dat-file: %s\n",argv[2]); 106 FILE* out_file=fopen(argv[3],"wb"); 107 CHECK_NOT_NULL(out_file); 108 printf("Output file: %s\n\n",argv[3]); 109 110 // add 1000 bytes to avoid (rare) strange error. 111 time_vec = (arr_time *) malloc(sizeof(arr_time) 112 *(filelen(dat_file)/sizeof(float)) + 1000); 113 if (time_vec==NULL) { 114 fprintf(stderr, "Error: could not allocate memory for reading dat file\n"); 115 goto closing; 116 } 117 118 dat_len=0; 119 while(fread(&(time_vec[dat_len].time),sizeof(float),1,dat_file)>0) { 120 time_vec[dat_len].ix=dat_len; 121 dat_len++; 122 } 123 124 if (dat_len == 0) { 125 fprintf(stderr, "Error: dat_file is empty, no arrival time is given.\n"); 126 goto closing; 127 } 128 129 qsort(time_vec,dat_len,sizeof(arr_time),compare_arr_time); 130 131 132 rtp_vec = (unsigned char *) malloc(sizeof(unsigned char)*filelen(in_file)); 133 if (rtp_vec==NULL) { 134 fprintf(stderr,"Error: could not allocate memory for reading rtp file\n"); 135 goto closing; 136 } 137 138 // read file header and write directly to output file 139 EXPECT_TRUE(fgets(firstline, FIRSTLINELEN, in_file) != NULL); 140 EXPECT_GT(fputs(firstline, out_file), 0); 141 EXPECT_EQ(kRtpDumpHeaderSize, fread(firstline, 1, kRtpDumpHeaderSize, 142 in_file)); 143 EXPECT_EQ(kRtpDumpHeaderSize, fwrite(firstline, 1, kRtpDumpHeaderSize, 144 out_file)); 145 146 // read all RTP packets into vector 147 rtp_len=0; 148 Npack=0; 149 150 // read length of first packet. 151 len=(uint16_t) fread(&rtp_vec[rtp_len], sizeof(unsigned char), 2, in_file); 152 while(len==2) { 153 len = ntohs(*((uint16_t *)(rtp_vec + rtp_len))); 154 rtp_len += 2; 155 if(fread(&rtp_vec[rtp_len], sizeof(unsigned char), 156 len-2, in_file)!=(unsigned) (len-2)) { 157 fprintf(stderr,"Error: currupt packet length\n"); 158 goto closing; 159 } 160 rtp_len += len-2; 161 Npack++; 162 163 // read length of next packet. 164 len=(uint16_t) fread(&rtp_vec[rtp_len], sizeof(unsigned char), 2, in_file); 165 } 166 167 if (Npack == 0) { 168 fprintf(stderr, "Error: No RTP packet found.\n"); 169 goto closing; 170 } 171 172 packet_ptr = (unsigned char **) malloc(Npack*sizeof(unsigned char*)); 173 174 packet_ptr[0]=rtp_vec; 175 k=1; 176 while(k<Npack) { 177 len = ntohs(*((uint16_t *) packet_ptr[k-1])); 178 packet_ptr[k]=packet_ptr[k-1]+len; 179 k++; 180 } 181 182 for(k=0; k<dat_len && k<Npack; k++) { 183 if(time_vec[k].time < FLT_MAX && time_vec[k].ix < Npack){ 184 temp_packet = packet_ptr[time_vec[k].ix]; 185 offset = (uint32_t *) (temp_packet+4); 186 if ( time_vec[k].time >= 0 ) { 187 *offset = htonl((uint32_t) time_vec[k].time); 188 } 189 else { 190 *offset = htonl((uint32_t) 0); 191 fprintf(stderr, "Warning: negative receive time in dat file transformed" 192 " to 0.\n"); 193 } 194 195 // write packet to file 196 if (fwrite(temp_packet, sizeof(unsigned char), 197 ntohs(*((uint16_t*) temp_packet)), 198 out_file) != 199 ntohs(*((uint16_t*) temp_packet))) { 200 return -1; 201 } 202 } 203 } 204 205 206 closing: 207 free(time_vec); 208 free(rtp_vec); 209 if (packet_ptr != NULL) { 210 free(packet_ptr); 211 } 212 fclose(in_file); 213 fclose(dat_file); 214 fclose(out_file); 215 216 return(0); 217 } 218 219 220 221 int compare_arr_time(const void *xp, const void *yp) { 222 223 if(((arr_time *)xp)->time == ((arr_time *)yp)->time) 224 return(0); 225 else if(((arr_time *)xp)->time > ((arr_time *)yp)->time) 226 return(1); 227 228 return(-1); 229 } 230