?? packet_data_agent.cpp
字號:
/*
==========================================================================================
ITU-T Telecommunications Standardization Sector Document: VCEG-M77
Study Group 16 Question 6 Filename: packet_data_agent.cc
Video Coding Experts Group (VCEG) Generated: 29 June, 2001
----------------------------------------
Thirteenth meeting: Austin, Texas, 2-4 April, 2001
Intention:
~~~~~~~~~~~~
Simple offline software simulator for RTP/IP over 3GPP/3GPP2 bearers
Source:
~~~~~~~
Thomas Stockhammer, Guenther Liebl Tel: +49 89 28923473
Institute for Communications Engineering Fax: +49 89 28923490
Munich University of Technology Email: {stockhammer,liebl}@ei.tum.de
80290 Munich, Germany
==========================================================================================
*/
#include "packet_data_agent.h"
// constructor
PACKET_DATA_AGENT::PACKET_DATA_AGENT()
{
int32 i;
// basic initialization
ModuleName = "PACKET-DATA-AGENT";
agent_header_size = 0;
compressed_Internet_header_size = 0;
for (i=0;i<PACKET_BUFFER_SIZE;i++)
{
RTP_Buffer[i].size = 0;
RTP_Buffer[i].timestamp = 0;
}
RTP_buffer_read_position = 0;
RTP_buffer_write_position = 0;
RTP_buffer_length = 0;
total_packets_counter = 0;
total_lost_packets_counter = 0;
packet_loss_rate = 0;
total_correct_bits_counter = 0;
total_correct_payload_bits_counter = 0;
effective_bitrate = 0.;
effective_net_bitrate = 0.;
simulation_time = 0;
}
// destructor
PACKET_DATA_AGENT::~PACKET_DATA_AGENT()
{
fclose(InputFile_ptr);
fclose(OutputFile_ptr);
}
// initialize the packet data agent from the given parameter file
void PACKET_DATA_AGENT::initialize(FILE *ParameterFile_ptr, FILE *CommonLogFile_ptr)
{
int32 file_size;
LogFile_ptr = CommonLogFile_ptr;
fprintf(LogFile_ptr,"%s: start initialization process\n",ModuleName);
// get the location of the input RTP stream from the parameter file
fscanf(ParameterFile_ptr,"- file containing the input RTP stream: %s\n",InputFile);
if ( (InputFile_ptr=fopen(InputFile,"rb")) == NULL )
{
fprintf(stderr,"!!error in module %s: couldn't open file %s \n",ModuleName,InputFile);
exit(-1);
}
else
{
fprintf(LogFile_ptr,"%s: reading RTP input stream from binary file %s\n",ModuleName,InputFile);
}
// determine length of the input file
if ( fseek(InputFile_ptr,0L,SEEK_END) )
{
fprintf(stderr,"!!error in module %s: can't fseek to end of file %s\n",ModuleName,InputFile);
exit(-1);
}
if ( (file_size = ftell(InputFile_ptr)) == -1 )
{
fprintf(stderr,"!!error in module %s: can't get size of file %s\n",ModuleName,InputFile);
exit(-1);
}
else if ( file_size == 0 )
{
fprintf(stderr,"!!error in module %s: input file %s is empty\n",ModuleName,InputFile);
exit(-1);
}
else
{
fprintf(LogFile_ptr,"%s: input file is of size %d bytes\n",ModuleName,file_size);
}
fseek(InputFile_ptr,0L,SEEK_SET);
// get the location of the output RTP stream from the parameter file
fscanf(ParameterFile_ptr,"- file containing the output RTP stream: %s\n",OutputFile);
if ( (OutputFile_ptr=fopen(OutputFile,"wb")) == NULL )
{
fprintf(stderr,"!!error in module %s: couldn't open file %s for writing\n",ModuleName,OutputFile);
exit(-1);
}
else
{
fprintf(LogFile_ptr,"%s: writing RTP output stream to binary file %s\n",ModuleName,OutputFile);
}
// get the size of the compressed Internet header from the parameter file
fscanf(ParameterFile_ptr,"- compressed RTP/UDP/IP header size (in bytes): %d\n",&compressed_Internet_header_size);
if ( compressed_Internet_header_size <= 0 )
{
fprintf(stderr,"!!error in module %s: illegal value %d for the compressed RTP/UDP/IP header size\n",ModuleName,compressed_Internet_header_size);
exit(-1);
}
else
{
fprintf(LogFile_ptr,"%s: compressing each RTP/UDP/IP header to %d bytes\n",ModuleName,compressed_Internet_header_size);
}
// get the header size of the packet data agent from the parameter file
fscanf(ParameterFile_ptr,"- packet agent header size (in bytes): %d\n",&agent_header_size);
if ( agent_header_size <= 0 )
{
fprintf(stderr,"!!error in module %s: illegal value %d for the packet agent header size\n",ModuleName,agent_header_size);
exit(-1);
}
else
{
fprintf(LogFile_ptr,"%s: adding %d bytes of header info to each PDU\n",ModuleName,agent_header_size);
}
fprintf(LogFile_ptr,"%s: end initialization process\n",ModuleName);
}
// if already available, read new RTP packet from file, compress the header, form a PDU and pass it to the
// calling module
// return values: 0: succeeded
// 1: failed: input file still contains data, but the timestamp is younger than the current simulation time
// 2: failed: end of input file already reached
int32 PACKET_DATA_AGENT::get_PDU(int32 current_time,VIRTUAL_PDU *PDU_in)
{
int32 packet_size, packet_timestamp, compressed_packet_size;
fpos_t FilePosition;
// check for possible RTP buffer overflow before reading new RTP packet from file
if ( RTP_buffer_length >= PACKET_BUFFER_SIZE )
{
fprintf(stderr,"!!error in module %s: RTP buffer overflow -> increase the value for PACKET_BUFFER_SIZE in the source code\n",ModuleName);
exit(-1);
}
// check, if the end of the input file has already been reached
if ( feof(InputFile_ptr) != 0 )
{
fprintf(LogFile_ptr,"%s: end of input file %s has already been reached before\n",ModuleName,InputFile);
PDU_in->internal_identifier = -1;
PDU_in->size = 0;
return 2;
}
// store actual read position in file for later use
if ( fgetpos(InputFile_ptr,&FilePosition) != 0 )
{
fprintf(stderr,"!!error in module %s: could not get actual read position in file %s\n",ModuleName,InputFile);
exit(-1);
}
packet_size = 0;
packet_timestamp = 0;
// read the size and timestamp of the next RTP packet, and check the timestamp with respect to the current time
if ( fread(&packet_size,sizeof(int32),1,InputFile_ptr) != 1 )
{
if ( feof(InputFile_ptr) != 0 )
{
fprintf(LogFile_ptr,"%s: end of input file %s has been reached\n",ModuleName,InputFile);
PDU_in->internal_identifier = -1;
PDU_in->size = 0;
return 2;
}
else
{
fprintf(stderr,"!!error in module %s: could not read size of next RTP packet from file %s\n",ModuleName,InputFile);
exit(-1);
}
}
else if ( packet_size <= 0 )
{
fprintf(stderr,"!!error in module %s: illegal value %d for the RTP packet size\n",ModuleName,packet_size);
exit(-1);
}
else if ( fread(&packet_timestamp,sizeof(int32),1,InputFile_ptr) != 1 )
{
fprintf(stderr,"!!error in module %s: could not read timestamp of next RTP packet from file %s\n",ModuleName,InputFile);
exit(-1);
}
else if ( packet_timestamp > current_time )
{
fprintf(LogFile_ptr,"%s: incorrect timing between RTP stream and simulation time scale\n",ModuleName);
if ( fsetpos(InputFile_ptr,&FilePosition) != 0 )
{
fprintf(stderr,"!!error in module %s: could not restore old read position in file $s\n",ModuleName,InputFile);
exit(-1);
}
PDU_in->internal_identifier = -1;
PDU_in->size = 0;
return 1;
}
// timestamp is valid -> read new RTP packet data from file and store it in the buffer
RTP_Buffer[RTP_buffer_write_position].size = packet_size;
RTP_Buffer[RTP_buffer_write_position].timestamp = packet_timestamp;
if ( (RTP_Buffer[RTP_buffer_write_position].data = (byte *)malloc(packet_size)) == NULL )
{
fprintf(stderr,"!!error in module %s: cannot allocate enough memory to store new RTP packet\n",ModuleName);
exit(-1);
}
else if ( fread(RTP_Buffer[RTP_buffer_write_position].data,sizeof(byte),packet_size,InputFile_ptr) != packet_size )
{
fprintf(stderr,"!!error in module %s: could not read %d data bytes from file %s\n",ModuleName,packet_size,InputFile);
exit(-1);
}
// printf("size before compression: %d\n",RTP_Buffer[RTP_buffer_write_position].size);
// perform header compression on the new RTP packet
compressed_packet_size = compress_Internet_header(&(RTP_Buffer[RTP_buffer_write_position]));
// generate PDU for calling module
PDU_in->internal_identifier = RTP_buffer_write_position;
PDU_in->size = compressed_packet_size + agent_header_size;
// printf("size after compression: %d\n",PDU_in->size);
// adjust buffer length and position markers
RTP_buffer_length++;
RTP_buffer_write_position++;
if ( RTP_buffer_write_position == PACKET_BUFFER_SIZE )
{
RTP_buffer_write_position = 0; // wrap around circular RTP buffer
}
return 0;
}
// remove RTP packet that corresponds to succesfully transmitted PDU from buffer, adjust the timestamp, and write
// it to file; update statistics; adjust buffer status
void PACKET_DATA_AGENT::put_PDU(int32 current_time,VIRTUAL_PDU *PDU_out)
{
int32 packet_size;
// check, if next RTP packet in buffer corresponds to the PDU
if ( PDU_out->internal_identifier != RTP_buffer_read_position )
{
fprintf(stderr,"!!error in module %s: buffer out of sync while reading\n",ModuleName);
exit(-1);
}
else
{
packet_size = RTP_Buffer[RTP_buffer_read_position].size;
}
// adjust timestamp
if ( RTP_Buffer[RTP_buffer_read_position].timestamp <= current_time )
{
RTP_Buffer[RTP_buffer_read_position].timestamp = current_time;
}
else
{
fprintf(stderr,"!!error in module %s: time reference corrupted\n",ModuleName);
exit(-1);
}
// write RTP packet to file
if ( fwrite(&(RTP_Buffer[RTP_buffer_read_position].size),sizeof(int32),1,OutputFile_ptr) != 1 )
{
fprintf(stderr,"!!error in module %s: could not write size of next RTP packet to file %s\n",ModuleName,OutputFile);
exit(-1);
}
else if ( fwrite(&(RTP_Buffer[RTP_buffer_read_position].timestamp),sizeof(int32),1,OutputFile_ptr) != 1 )
{
fprintf(stderr,"!!error in module %s: could not write timestamp of next RTP packet to file %s\n",ModuleName,OutputFile);
exit(-1);
}
else if ( fwrite(RTP_Buffer[RTP_buffer_read_position].data,sizeof(byte),packet_size,OutputFile_ptr) != packet_size )
{
fprintf(stderr,"!!error in module %s: could not write %d data bytes to file %s\n",ModuleName,packet_size,OutputFile);
exit(-1);
}
//update statistics
total_packets_counter++;
total_correct_bits_counter += packet_size*8;
total_correct_payload_bits_counter += (PDU_out->size - agent_header_size - compressed_Internet_header_size)*8;
simulation_time = current_time;
// adjust buffer content, length and position markers
free(RTP_Buffer[RTP_buffer_read_position].data);
RTP_Buffer[RTP_buffer_read_position].size = 0;
RTP_Buffer[RTP_buffer_read_position].timestamp = 0;
RTP_buffer_length--;
RTP_buffer_read_position++;
if ( RTP_buffer_read_position == PACKET_BUFFER_SIZE )
{
RTP_buffer_read_position = 0; // wrap around circular RTP buffer
}
// printf("actual time: %d\n",simulation_time);
// if ( total_packets_counter == 12 )
// {
// // exit(0);
// }
}
// remove RTP packet that corresponds to corrupted PDU from buffer; update statistics; adjust buffer status
void PACKET_DATA_AGENT::discard_PDU(int32 current_time, VIRTUAL_PDU *PDU_out)
{
// check, if next RTP packet in buffer corresponnds to the PDU
if ( PDU_out->internal_identifier != RTP_buffer_read_position )
{
fprintf(stderr,"!!error in module %s: buffer out of sync while discarding\n",ModuleName);
exit(-1);
}
//update statistics
total_packets_counter++;
total_lost_packets_counter++;
simulation_time = current_time;
// adjust buffer content, length and position markers
free(RTP_Buffer[RTP_buffer_read_position].data);
RTP_Buffer[RTP_buffer_read_position].size = 0;
RTP_Buffer[RTP_buffer_read_position].timestamp = 0;
RTP_buffer_length--;
RTP_buffer_read_position++;
if ( RTP_buffer_read_position == PACKET_BUFFER_SIZE )
{
RTP_buffer_read_position = 0; // wrap around circular RTP buffer
}
}
// write transmission statistics at the end of the simulation
void PACKET_DATA_AGENT::write_statistics(FILE *StatisticsFile_ptr)
{
//calculate statistics first
packet_loss_rate = (double)total_lost_packets_counter/(double)total_packets_counter;
effective_bitrate = (double)total_correct_bits_counter/(double)simulation_time;
effective_net_bitrate = (double)total_correct_payload_bits_counter/(double)simulation_time;
// write statistics to file
fprintf(StatisticsFile_ptr,"----------------------------------------------------------------------------\n");
fprintf(StatisticsFile_ptr,"%s: Statistics:\n\n",ModuleName);
fprintf(StatisticsFile_ptr,"total number of RTP packets transmitted: %10d\n",total_packets_counter);
fprintf(StatisticsFile_ptr,"number of lost RTP packets: %10d\n",total_lost_packets_counter);
fprintf(StatisticsFile_ptr,"packet loss rate: %e\n\n",packet_loss_rate);
fprintf(StatisticsFile_ptr,"effective bitrate (including RTP header): %f kbit/s\n",effective_bitrate);
fprintf(StatisticsFile_ptr,"effective net bitrate (excluding RTP header): %f kbit/s\n",effective_net_bitrate);
//fprintf(StatisticsFile_ptr,"----------------------------------------------------------------------------\n");
}
// simplified procedure for compressing RTP/UDP/IP header
// return value: total size of compressed packet in bytes
int32 PACKET_DATA_AGENT::compress_Internet_header(RTP_PACKET *Uncompressed_RTP_Buffer)
{
int32 header_size, payload_size;
// up to now, only the standard RTP header is compressed (together with the UDP/IP header)
// all extensions and CSRC fields are left untouched
header_size = MIN_RTP_HEADER_SIZE;
payload_size = Uncompressed_RTP_Buffer->size - header_size;
if ( payload_size <= 0 )
{
fprintf(stderr,"!!error in module %s: RTP packet does not contain any data part\n",ModuleName);
}
return (payload_size + compressed_Internet_header_size);
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -