Columbia RTP Library Example User Code


August 21, 1997

Go back to library

Sample Code to Use RTP

The following code is a test program that initiates a single member of an RTP session that is able to send and receive RTP packets, displays all packets received, and periodically displays membership information. The member initiates its CSRC list with 3 imaginary contributing members (whose SSRCs are chosen randomly). The code is fully functional except that the encryption / decryption algorithms have been removed since the code used cannot be made publicly available.

Contents:

  1. Scheduler
  2. RTPSchedule() function
  3. Callback functions
  4. The main() function
  5. Use of the RTPLib functionality

/* rtp_test.c: test ability to send / receive data Copyright 1997 Lucent Technologies; all rights reserved */

#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> 
#include <sys/uio.h>
#include "rtp_api.h"
#include "rtp_crypt.h"

#define DEFAULT_MULTI "224.119.10.10"
#define DEFAULT_PORT 5076

#define RTPSTAMPRATE 1.0


#define MAX_SCHEDULE 100

#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif

/* Below are functions that implement the scheduler */

/* Scheduler */


typedef struct {
  int Active;
  struct timeval activate_time;
  int32 opaque;
} sched_item;

/* Allow scheduling of up to MAX_SCHEDULE items */

sched_item sched[MAX_SCHEDULE];
  

/* Scheduler initialization routine */

void InitSched(){
  int i;
  for (i=0; i<MAX_SCHEDULE; i++){
    sched[i].Active = FALSE;
  }
  return;
}

/* FindInactive locates an empty slot on the scheduler array so that a new item can be scheduled there */

int FindInactive(){
  int i;
  for (i=0; i < MAX_SCHEDULE;i++){
    if (!sched[i].Active){
      return i;
    }
  }
  return -1;
}


/* Returns an item that is ready to be activated. Note that this does not return the items in any particular chronological order. */

int FindReady(){
  int i;
  struct timeval curtime;
  gettimeofday(&curtime, NULL);
  for (i=0; i<MAX_SCHEDULE; i++){
    if (sched[i].Active && (sched[i].activate_time.tv_sec < curtime.tv_sec ||
	(sched[i].activate_time.tv_sec == curtime.tv_sec &&
	 sched[i].activate_time.tv_usec < curtime.tv_usec))){
      sched[i].Active = FALSE;
      return i;
    }
  }
  return -1;
}

/* RTPSchedule() function */

/* The scheduling routine */

void RTPSchedule(context cid, int32 opaque, struct timeval *tp){
  struct timeval curtime;
  int i = FindInactive();
  if (i < 0){
    printf("error: no more room in scheduler\n");
    exit(1);
  }
  sched[i].Active = TRUE;
  sched[i].activate_time = *tp;
  sched[i].opaque = opaque;

  gettimeofday(&curtime, NULL);
  printf("Scheduled for %f seconds\n", (float) (tp->tv_sec - curtime.tv_sec) +
	 (float) (tp->tv_usec - curtime.tv_usec) / 1000000);
  return;
}

/* Callback functions */

/* The callback function to be used when a new member joins the session */

void ReportNewMember(context cid, person id_no, unsigned int flags){
  int32 new_ssrc;
  int err;
  err = RTPMemberInfoGetSSRC(cid, id_no, &new_ssrc);
  if (err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
  printf("New Member number %ld: SSRC %x\n", id_no, (int)new_ssrc);
  return;
}

/* The callback function to be used when a member expires from the session */

void ReportExpMember(context cid, person id_no, unsigned int flags){
  int32 new_ssrc;
  int err;
  err = RTPMemberInfoGetSSRC(cid, id_no, &new_ssrc);
  if (err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
  printf("Exp Member number %ld: SSRC %x\n", id_no, (int)new_ssrc);
  return;
}

/* The callback function to be used when a member becomes or returns to being a sender */

void ReportNewSender(context cid, person id_no, unsigned int flags){
  int32 new_ssrc;
  int err;
  err = RTPMemberInfoGetSSRC(cid, id_no, &new_ssrc);
  if (err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
  printf("New SENDER number %ld: SSRC %x\n", id_no, (int)new_ssrc);
  return;
}


/* The callback function to be used when a sender expires or returns to being a sender */

void ReportExpSender(context cid, person id_no, unsigned int flags){
  int32 new_ssrc;
  int err;
  err = RTPMemberInfoGetSSRC(cid, id_no, &new_ssrc);
  if (err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
  printf("Exp SENDER number %ld: SSRC %x\n", id_no, (int)new_ssrc);
  return;
}

/* The callback function to be used when a member's SDES info changes */

void ReportChangedMemberInfo(context cid, person id_no, memberinfo field,
			     char *new, char *old, unsigned int flags){
  printf("Person %ld: SDES field %d changed from %s to %s\n",
	 id_no, field, old ? old : "(NULL)", new);
  return;
}

/* The callback function to be used when 2 SSRCs are found to collide */

void ReportCollision(context cid, person id_1, person id_2,
		     unsigned int flags){
  printf("Persons %ld and %ld colliding\n", id_1, id_2);
  return;
}

/* The callback function to be used when a member's liveness status changes */

void ReportMemberAlive(context cid, person id_no, int alive, unsigned int flags){ printf("Person %ld: %s\n", id_no, alive ? "alive" : "timed out"); return; }

/* Describe Usage is called when the user incorrectly entered something on command line */

void DescribeUsage(int help){
  fprintf(stderr, "Usage: rtp_test [-help] [-tMin] [-S [tsec]] [-e[1]] [-r[0]] [[addr]/[port]]\n");
  if (help){
    fprintf(stderr, "-help : this help message\n");
    fprintf(stderr, "-tMin: run rtp_test for min minutes\n");
    fprintf(stderr, "-S[dsec] : send RTP packets at rate of 10 per dsec seconds.  default is 10\n");
    fprintf(stderr, "-e : Turn on encryption (-e1 encrypts only SDES info) default is off\n");
    fprintf(stderr, "-r : Reconsideration, -r0 turns reconsideration off.  Default is on\n");
    fprintf(stderr, "[addr]/[port] : address (multicast or unicast) and / or port to use.\n");
    fprintf(stderr, "Default address is multicast %s, default port is %d\n",
	    DEFAULT_MULTI, DEFAULT_PORT);
  }
  exit(2);
}

/* The main() function */


void main(int argc, char **argv){
  char addr[20];
  int i, j, parts, ssrc_count, fromlen, count, rtpcount, runtime, encryption,
    reconsideration, is_sender, sendrate, port;
  struct timeval curtime, endtime, next_RTP_send, last_RTP_send, tinytime;
  person cur_mem;
  member_iterator the_iter;
  rtcp_bye_block byeblock;
  double rtptimechange;
  char usekey[9] = "DESKEY01\0";
  char payload[1000], theload[10000], *pktparts[100];
  rtp_packet rtppkt;
  rtcp_packet rtcppkt;
  rtcp_report_block the_block;
  rtcp_sdes_item cur_item;
  struct sockaddr fromaddr;
  context my_context;
  int32 csrc_list[10], csrcguy, cur_ssrc;
  int loaduse;
  rtperror the_err;
  socktype rtpsock, rtcpsock;
  int maxfd = 0;
  fd_set selection;

  

/* Establish default encryption / time, etc. */

/* Default is encryption not used */

  encryption = 2; 

/* run for 10 min */

  runtime = 10; 

/* Set reconsideration to on by default */

  reconsideration = 3; 

/* By default, not a sender */

  is_sender = FALSE; 
  sendrate = 10;
  port = DEFAULT_PORT;
  sprintf(addr, "%s", DEFAULT_MULTI);
    

  for (i=1; i< argc; i++){
    if (argv[i][0] == '-'){
      if (strlen(argv[i]) == 1){
	fprintf(stderr, "rtp_test: option must follow a '-'\n");
	DescribeUsage(FALSE);
      }
      switch(argv[i][1]){
      case 'S':
	is_sender = TRUE;
	if (strlen(argv[i])==2){
	  break;
	}
	sendrate = atoi(argv[i]+2);
	break;
      case 't':
	if (strlen(argv[i]) == 2){
	  fprintf(stderr, "rtp_test: option t requires integer\n");
	  DescribeUsage(FALSE);
	}
	runtime = atoi(argv[i]+2);
	break;
      case 'h':
	DescribeUsage(TRUE);
      case 'e':
	encryption = 0;
	if (strlen(argv[i]) > 2){
	  if (argv[i][2] == '1'){
	    encryption = 1;
	  }
	}
	break;
      case 'r':
	reconsideration = 1;
	if (strlen(argv[i]) > 2){
	  if (argv[i][2] == '0'){
	    reconsideration = 0;
	  }
	}
	break;
      default:
	fprintf(stderr, "rtp_test: illegal option -- %c\n", argv[i][1]);
	DescribeUsage(FALSE);
      }
    }
    else {
      j = 1;
      if (argv[i][0] != '/'){
	strncpy(addr, argv[i], 20);
	for (j=0; j<20 && addr[j]!='\0'; j++){
	  if (addr[j] == '/'){
	    addr[j] = '\0';
	    j++;
	    break;
	  }
	}
      }
      if (argv[i][j] != '\0'){
	port = atoi(argv[i]+j);
      }
    }
  }
  printf("Using address %s/%d\n", addr, port);

	  

  

/* The following is used if RTP is going to track memory allocation (useful for debugging memory leaks */

#ifdef _RTP_WATCH_ALLOCATION  
  InitMallocs();
#endif

  tinytime.tv_sec = 0;
  tinytime.tv_usec = 100000;

  

/* Initialize the scheduler */

  InitSched();
  gettimeofday(&curtime, NULL);
  endtime = curtime;
  next_RTP_send = curtime;



  endtime.tv_sec += 60 * runtime;
  

/* Receiver has 3 CSRCs */

  for (i=0; i<3; i++){
    csrc_list[i] = (int32) curtime.tv_usec + i;
  }

  

/* Use of the RTPLib functionality */

/* Start a new context */

  the_err = RTPCreate(&my_context);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }

  

/* Install the callback functions */

  the_err = RTPSetNewMemberCallBack(my_context, &ReportNewMember);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
  the_err = RTPSetExpiredMemberCallBack(my_context, &ReportExpMember);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
  the_err = RTPSetNewSenderCallBack(my_context, &ReportNewSender);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  } 
  the_err = RTPSetChangedMemberInfoCallBack(my_context,
					    &ReportChangedMemberInfo);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
  the_err = RTPSetExpiredSenderCallBack(my_context, &ReportExpSender);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
  the_err = RTPSetCollidedMemberCallBack(my_context, &ReportCollision);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }

  

/* Set the address that we are sending RTP / RTCP packets to. If it's a multicast address, we are going to join the group on that address. */

  the_err = RTPSessionSetAddr(my_context, htonl(inet_addr(addr)));
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }

  

/* Our FreeBSD machine is hidden behind a firewall. We need to set the local address for it to work correctly. NOTE: The local address has been altered within this code. */

#ifdef _RTP_ARCH_FreeBSD
  the_err = RTPSessionSetLocalAddr(my_context, ntohl(inet_addr("0.0.0.0")));
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
#endif

  

/* Here, we pick a random CNAME for the receiver */

  gethostname(payload, 1000);
  sprintf(theload, "I am %s:%ld",payload, curtime.tv_usec);
  the_err = RTPMemberInfoSetSDES(my_context, 0, 1, theload);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }


  

/* Set the CSRC list for the local member */

  the_err = RTPSessionSetCSRCList(my_context, csrc_list, 3);
  if (the_err != RTP_OK){ 
    printf("%s\n", RTPStrError());
  } 
  for (i=0; i<3; i++){
    

/* Set CNAMEs for each of the CSRC members. */

/* First, we need to retrieve the CSRC member's unique ID */

    the_err = RTPSessionGetUniqueIDForCSRC(my_context, csrc_list[i], &csrcguy);
    if (the_err != RTP_OK){
      printf("%s\n", RTPStrError());
    }
    

/* Now set the CNAME */

    sprintf(theload, "I am CSRC %d from %s:%ld", i, payload, 
	    curtime.tv_usec);
    the_err = RTPMemberInfoSetSDES(my_context, csrcguy, 1, theload);
    if (the_err != RTP_OK){
      printf("%s\n", RTPStrError());
    }
  }


  

/* Set the port (for sending and receiving) */

  the_err = RTPSessionSetPort(my_context, port);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
  
			      

  

/* Install encryption functions */

  the_err = RTPSessionSetEncryptionFuncs(my_context,
					 &RTPInit,
    					 &RTPEncrypt,
					 &RTPDecrypt); 
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }

  

/* Set encryption to what user specified */

  the_err = RTPSessionSetEncryption(my_context, encryption);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }

  

/* Set reconsideration to what user specified */

  the_err = RTPSessionSetReconsideration(my_context, reconsideration);


  

/* Set the encryption key */

  the_err = RTPSessionSetKey(my_context, (void*) usekey);

  

/* RTPStamprates are initialized by default, but we can change the rate if we want to */

  the_err = RTPSessionSetRTPStampRate(my_context, 3, RTPSTAMPRATE);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }

  

/* Open the connection (and become a member of the RTP / RTCP session */

  the_err = RTPOpenConnection(my_context);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }



  

/* Get the sockets being used for RTP send and RTCP send / receive */

  the_err = RTPSessionGetRTPSocket(my_context, &rtpsock);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
  if (maxfd < rtpsock.sock)
    maxfd = rtpsock.sock;
  the_err = RTPSessionGetRTCPSocket(my_context, &rtcpsock);
  if (the_err != RTP_OK){
    printf("%s\n", RTPStrError());
  }
  if (maxfd < rtcpsock.sock)
    maxfd = rtcpsock.sock;

  count = 0;
  rtpcount = 0;
  

/* Now go into receiver / sender mode for the specified amount of time */

  while (curtime.tv_sec < endtime.tv_sec){

  

/* Get my SSRC and print it to the screen */

    RTPMemberInfoGetSSRC(my_context, 0, &cur_ssrc);
    if (the_err != RTP_OK){
      printf("%s\n", RTPStrError());
    }
    printf("My SSRC is %x\n", (int)cur_ssrc);

    

/* First, see if anything on the schedule is ready to be executed */

    gettimeofday(&curtime, NULL);
    i = FindReady();
    if (i != -1){
      RTPExecute(my_context, sched[i].opaque); 
    }

    

/* Now check the RTP and RTCP sockets for incoming packets using a .1 second blocking select call (as set in the tinytime variable) */

    
    FD_ZERO(&selection);
    FD_SET(rtpsock.sock, &selection);
    FD_SET(rtcpsock.sock, &selection);
    the_err = select(maxfd + 1, &selection, NULL, NULL, &tinytime); 
    if (the_err < 0){
      printf("select error: %d\n", errno);
      exit(1);
    }
    if (FD_ISSET(rtpsock.sock, &selection)){

      

/* There is something on the RTP socket */

      loaduse = 10000; 

      

/* Receive the RTP packet (RTP membership info will be handled internally automatically by this call */

      the_err = RTPReceive(my_context, rtpsock.sock, theload, &loaduse);
      
      

/* First make sure this packet wasn't sent by me */

      if (the_err == RTP_PACKET_LOOPBACK){
	printf("Got my own RTP packet\n");
      }
      
      

/* Now check for an error */

      else if (the_err != RTP_OK){
	printf("%s\n", RTPStrError());
      }

      

/* Everything ok. So let's display the packet's contents to stdout */

      else {
	

/* First convert the byte stream to an easily-readable RTP packet structure */

	rtppkt = RTPGetRTPPacket(theload, loaduse);

	rtpcount++;
	

	

/* First, some details about the packet */

	printf("%d: RTP len=%d v=%d p=%d x=%d cc=%d m=%d pt=%d\n",
	       (int)rtpcount, 
	       (int)loaduse, 
	       (int)rtppkt.RTP_header->version, 
	       (int)rtppkt.RTP_header->p, 
	       (int)rtppkt.RTP_header->x, 
	       (int)rtppkt.RTP_header->cc, 
	       (int)rtppkt.RTP_header->m, 
	       (int)rtppkt.RTP_header->pt); 

	

/* Now print the payload out as well */

	memcpy(payload, rtppkt.payload, (int) rtppkt.payload_len);
	payload[rtppkt.payload_len] = '\0'; 
	printf("%s\n", payload); 
      }
    }

    if (FD_ISSET(rtcpsock.sock, &selection)){
      

/* There is something on the RTCP socket */


      loaduse = 10000;

      

/* Receive the RTP packet (RTP membership info will be handled internally automatically by this call */

      the_err = RTPReceive(my_context, rtcpsock.sock, theload, &loaduse);

      

/* First make sure this packet wasn't sent by me */

      if (the_err == RTP_PACKET_LOOPBACK){
	printf("Got my own RTCP packet\n");
      }
      

/* Now check for an error */

      else if (the_err != RTP_OK){
	printf("%s\n", RTPStrError());
      }

      

/* Everything ok. So let's display the packet's contents to stdout */

      else {
	printf("Got RTCP pkt len %d\n", (int)loaduse);

	

/* RTCP packets come in as a compound packet. We first split the compound packet into parts, and then process each part individually */


	parts = RTPSplitCompoundRTCP(theload, pktparts, loaduse);
	for (i=0; i < parts; i++){

	  

/* Convert the byte stream into an easily-readable RTCP packet structure */

	  rtcppkt = RTPGetRTCPPacket(pktparts[i]);

	  

/* Now figure out what type the current RTCP packet is */

	  switch (rtcppkt.overlay->pt){
	  case 200: 
	    

/* This is an SR packet */

	    printf(" (SR ssrc=0x%x p=%d count=%d len=%d\n",
		   (int)rtcppkt.overlay->rtcp_hdr_variant.sr.ssrc,
		   (int)rtcppkt.overlay->p,
		   (int)rtcppkt.overlay->rc,
		   (int)rtcppkt.overlay->len);
	    printf("ntp=%ld.%ld ts=%ld psent=%ld osent=%ld\n",
		   (long)rtcppkt.overlay->rtcp_hdr_variant.sr.ntp_stamp_msw,
		   (long)rtcppkt.overlay->rtcp_hdr_variant.sr.ntp_stamp_lsw,
		   (long)rtcppkt.overlay->rtcp_hdr_variant.sr.rtp_stamp,
		   (long)rtcppkt.overlay->rtcp_hdr_variant.sr.pkt_count,
		   (long)rtcppkt.overlay->rtcp_hdr_variant.sr.oct_count);
	    for (j=0; j<rtcppkt.overlay->rc;j++){
	      the_block = RTPGetReportBlock(&rtcppkt, j);
	      printf("  (ssrc=%x fraction=%d lost=%ld last_seq=%ld jit=%ld lsr=%ld dlsr=%ld)\n",
		     (int)the_block.ssrc,
		     (int)the_block.frac_lost,
		     (long)the_block.cum_lost,
		     (long)the_block.highest_seqno,
		     (long)the_block.jitter,
		     (long)the_block.lsr,
		     (long)the_block.dlsr);
	    }
	    printf(" )\n");
	    
	    break;

	  case 201:
	    

/* This is an RR packet */

	    printf(" (RR ssrc=0x%x p=%d count=%d len=%d\n",
		   (int)rtcppkt.overlay->rtcp_hdr_variant.rr.ssrc,
		   (int)rtcppkt.overlay->p,
		   (int)rtcppkt.overlay->rc,
		   (int)rtcppkt.overlay->len);
	    for (j=0; j<rtcppkt.overlay->rc;j++){
	      the_block = RTPGetReportBlock(&rtcppkt, j);
	      printf("  (ssrc=%x fraction=%d lost=%ld last_seq=%ld jit=%ld lsr=%ld dlsr=%ld)\n",
		     (int)the_block.ssrc,
		     (int)the_block.frac_lost,
		     (long)the_block.cum_lost,
		     (long)the_block.highest_seqno,
		     (long)the_block.jitter,
		     (long)the_block.lsr,
		     (long)the_block.dlsr);
	    }
	    printf(" )\n");
	    
	    break;

	  case 202:
	    

/* This is an SDES packet */

	    printf(" (SDES p=%d count=%d len=%d\n",
		   (int)rtcppkt.overlay->p,
		   (int)rtcppkt.overlay->rc,
		   (int)rtcppkt.overlay->len);
	    if (rtcppkt.overlay->rc == 0){
	      printf(" )\n");
	      break;
	    }
	    cur_ssrc = 0;
	    ssrc_count = 0;
	    cur_item = InitSDESItemIter(&rtcppkt);
	    while (ssrc_count < rtcppkt.overlay->rc && cur_item.type != 0){
	      if (cur_ssrc != cur_item.ssrc){
		cur_ssrc = cur_item.ssrc;
		printf("(src=0x%x ", (int)cur_item.ssrc); 
	      }
	      printf("F%d=", cur_item.type); 
	      for (j=0; j<cur_item.len;j++){
		printf("%c",cur_item.description[j]);
	      }
	      printf(" ");
	      cur_item = GetNextItem(&cur_item);
	      while (cur_item.type == 0 && ssrc_count < rtcppkt.overlay->rc){
		ssrc_count++;
		if (ssrc_count < rtcppkt.overlay->rc){
		  cur_item = GetNextItem(&cur_item);
		}
		printf(" )\n");
	      }
	    }
	    printf(" )\n");
	    break;

	  case 203:
	    

/* This is a BYE packet */

	    printf(" (BYE p=%d count=%d len=%d\n",
		   (int)rtcppkt.overlay->p,
		   (int)rtcppkt.overlay->rc,
		   (int)rtcppkt.overlay->len);
	    for (ssrc_count = 0; ssrc_count < rtcppkt.overlay->rc; 
		 ssrc_count++){
	      byeblock = RTPGetByeBlock(&rtcppkt, ssrc_count);
	      printf("for %x, ", (int)byeblock.ssrccsrc);
	    }
	    printf(" )\n");
	  }
	
	}
      }
      
      

/* List the current members in the session by unique ID and ssrc and (if it exists) the CNAME */

      printf("My members:\n");

      

/* Initialize an iterator over the current list of members */

      RTPSessionGetMemberList(my_context, &the_iter);

      

/* RTPCurrentMember() will place the unique ID of the current member in cur_mem */

      while (RTPCurrentMember(my_context, &the_iter, &cur_mem) == RTP_OK){

	

/* Obtain the ssrc for the member with unique ID cur_mem */

	RTPMemberInfoGetSSRC(my_context, cur_mem, &cur_ssrc);
	printf("%ld : ssrc %x :", cur_mem, (int) cur_ssrc);

	

/* Get the SDES info for the member with unique ID cur_mem (if it's available) */

	if (RTPMemberInfoGetSDES(my_context, cur_mem, RTP_MI_CNAME, payload)
	    != RTP_OK){
	  sprintf(payload, "NO-INFO");
	}
	else if (payload==NULL){
	  sprintf(payload, "NULL");
	}
	printf(": CNAME %s\n", payload);
	
	
	

/* Go on to the next member */

	RTPNextMember(my_context, &the_iter, &cur_mem);
      }
    }
    fflush(0);
    
    

/* If I am a sender, then send a packet when it's the appropriate time */


    if (is_sender && (next_RTP_send.tv_sec < curtime.tv_sec ||
	      (next_RTP_send.tv_sec == curtime.tv_sec &&
	       next_RTP_send.tv_usec <= curtime.tv_usec))){
	       
      count++;
      sprintf(theload, "This is packet %d", count);
      printf("Sending %s\n", theload);
      
      rtptimechange = ((double) (curtime.tv_sec - last_RTP_send.tv_sec) *
		       1000000 + (double) (curtime.tv_usec -
					   last_RTP_send.tv_usec)) /
      RTPSTAMPRATE;
      the_err = RTPSend(my_context, (int32) rtptimechange, 0, 3,
			theload, strlen(theload));
      if (the_err != RTP_OK){
	printf("%s\n", RTPStrError());
      }
      next_RTP_send.tv_usec += (long int)
	(((double)sendrate/10.0 - floor((double)sendrate/10.0)) * 1000000);
      if (next_RTP_send.tv_usec > 1000000){
	next_RTP_send.tv_sec++;
	next_RTP_send.tv_usec -= 1000000;
      }
      next_RTP_send.tv_sec += (long int)floor((double)sendrate / 10.0);
      last_RTP_send = curtime;
    }
  }
  
  

/* Terminate the connection. This will send a BYE packet announcing that we have left the session. */

  the_err = RTPCloseConnection(my_context);
  if (the_err != RTP_OK){
    printf("CloseConn failed: error %d\n", the_err);
  }
  the_err = RTPDestroy(my_context);
  if (the_err != RTP_OK){
    printf("Error %d raised\n", the_err);
  }

  

/* If we were performing allocation debugging in RTP, print out the results here */

#ifdef _RTP_WATCH_ALLOCATION  
  CheckMallocs();
#endif
  exit(0);
}

Go back to library