Esempio n. 1
0
/* The library calls this function when it needs to schedule an event.
 *
 * Note that if we were running more than one stream at once we'd need
 * some way of corrolating the event to run with the context ID this
 * function gets passed.
 */
void RTPSchedule(context cid, rtp_opaque_t opaque, struct timeval *tp)
{
  struct evt_queue_elt *elt;

  elt = (struct evt_queue_elt *) malloc(sizeof(struct evt_queue_elt));
  if (elt == NULL)
    return;

  elt->cid = cid;
  elt->event_opaque = opaque;
  elt->event_time = tv2dbl(*tp);
  
  insert_in_evt_queue(elt);

  return;
}
void RtpSession::send_rtcp()
{
	RtcpPacket *p;
	struct timeval tv;
	gettimeofday(&tv, NULL);
	ntp_t ntp = timeval_to_ntp( tv );
	
	uint8_t type = m_event_queue->type;

	switch ( m_event_queue->type ) {

	case RTCP_SR:  /* We want to send an RTCP Sender Report. */
		p = new RtcpPacket( RTCP_SR );
		p->set_count( 0 );
		p->set_sr_ssrc( m_ssrc );
		p->set_sr_ntp_sec( ntp.secs );
		p->set_sr_ntp_frac( ntp.frac );
		p->set_sr_rtp_ts( m_last_timestamp );
		p->set_sr_psent( m_psent );
		p->set_sr_osent( m_osent );
		break;
	
	case RTCP_RR:
		p = new RtcpPacket( RTCP_RR );
		p->set_count( 1 );
	
	default: p = NULL;
	}

	if ( ! p )
		return;

	send_rtcp_pkt( p );

	/* Advance the queue */
	event_t *next = (event_t *)m_event_queue->next;
	free( m_event_queue );
	m_event_queue = next;

	/* Schedule a new RTCP packet */
	event_t *e = (event_t*)malloc( sizeof( event_t ) );
 	e->type = type;
	e->time = tv2dbl( tv ) + compute_rtcp_interval();
	e->next = NULL;
	insert_event( e );
}
uint16_t RtpSession::receive_rtp_packet(void *buf )
{
	struct timeval start_time_tv;

	if ( ! m_preceived ) {
		/* This is the 1th packet that we receive-
		 * Here we should send an RTCP SDES packet with all the 
		 * infos...
		 */
		gettimeofday(&start_time_tv, NULL);
		m_start_time = tv2dbl(start_time_tv);
#if 0		
		/*! Build the SDES CNAME packet */
		uint16_t s = 10 + strlen( m_cname );
		/* Align to 32 bit boundary .. */
		s = (uint16_t)ceil( (double)s /4 ) * 4;
		
		m_sdes_pkt = (rtcp_t *)calloc( s , 1 );
		RtcpPacket *p = new RtcpPacket( m_sdes_pkt, s );
		p->set_version( 2 );
		p->set_padding( 0 );
		p->set_count( 1 );
		p->set_type( RTCP_SDES );
		p->set_length( (uint16_t)s/4 - 1 );
		m_sdes_pkt->r.sdes.src = htonl( m_ssrc );
		m_sdes_pkt->r.sdes.item->type = RTCP_SDES_CNAME;
		m_sdes_pkt->r.sdes.item->length = strlen( m_cname );
		memcpy( m_sdes_pkt->r.sdes.item[0].data, m_cname, strlen(m_cname) );
		m_sdes_pkt_size = s;

		/*! Schedule an RTCP RR.. */
		event_t *e = (event_t*)malloc( sizeof( event_t ) );
 		e->type = RTCP_RR;
		e->time = m_start_time + 5.0;
		e->next = NULL;
		insert_event( e );
		send_rtcp();
#endif
	}
	
	int event = 0;
	int retval;
	double timeout, now;
	struct timeval timeout_tv, now_tv;
	fd_set sockets;

	/*! Here we check for events or things to do... */
	while ( 1 ) {

		gettimeofday(&now_tv, NULL);
		now = tv2dbl(now_tv);

		if (    m_event_queue != NULL ) {
			event = 1;
			timeout = m_event_queue->time - now;
		} else {
			event = 0;
			timeout = 0.5; /* Arbitrary value.. to be trimmed.. */
		}
		if ( timeout < 0 )
			timeout = 0;
		timeout_tv = dbl2tv( timeout );

		FD_ZERO( &sockets );
		FD_SET( m_rtp_sock, &sockets );
		FD_SET( m_rtcp_sock, &sockets );

		int max_fd = ((m_rtp_sock > m_rtcp_sock) ? m_rtp_sock : m_rtcp_sock ) + 1;

		retval = select(max_fd, &sockets, NULL, NULL, &timeout_tv);
		if ( retval < 0 ) {
			perror("select");
			return false;
		} else if ( retval > 0 ) { // There are some events...
			if (FD_ISSET(m_rtp_sock, &sockets)) {
				/* There's an RTP packet to be read... 
				 */
				return receive_rtp( buf );
			}
			
			if (FD_ISSET(m_rtcp_sock, &sockets)) {
				receive_rtcp();
			}
		}  else { /* retval == 0, select timed out */
			if (event) {
				gettimeofday( &now_tv, NULL );
				now = tv2dbl( now_tv );
				while ( m_event_queue != NULL &&
					m_event_queue->time <= now ) {
					/* There is a pending RTCP packet to send) */
					send_rtcp();
				}
			} 
		}
	}
}
bool RtpSession::send_rtp_packet(void *buf, uint16_t size, uint32_t ts_inc )
{
	uint32_t timestamp;
	struct timeval start_time_tv, now_tv;
	double play_time, now;
	
	timestamp = m_prev_timestamp + ts_inc;
	m_prev_timestamp = timestamp;
	
	if ( !buf || !size ) {
	  printf("Cannot send packet.\n");
	  return false;
	}
	
	if ( ! m_psent ) {
		/* This is the 1th packet that we send.
		 * Here we should send an RTCP SDES packet with all the 
		 * infos...
		 */
		gettimeofday(&start_time_tv, NULL);
		m_start_time = tv2dbl(start_time_tv);
		
		/*! Build the SDES CNAME packet */
		uint16_t s = 10 + strlen( m_cname );
		/* Align to 32 bit boundary .. */
		s = (uint16_t)ceil( (double)s /4 ) * 4;
		
		m_sdes_pkt = (rtcp_t *)calloc( s , 1 );
		RtcpPacket *p = new RtcpPacket( m_sdes_pkt, s );
		p->set_version( 2 );
		p->set_padding( 0 );
		p->set_count( 1 );
		p->set_type( RTCP_SDES );
		p->set_length( (uint16_t)s/4 - 1 );
		m_sdes_pkt->r.sdes.src = htonl( m_ssrc );
		m_sdes_pkt->r.sdes.item->type = RTCP_SDES_CNAME;
		m_sdes_pkt->r.sdes.item->length = strlen( m_cname );
		memcpy( m_sdes_pkt->r.sdes.item[0].data, m_cname, strlen(m_cname) );
		m_sdes_pkt_size = s;

		/*! Schedule an RTCP for now.. */
		event_t *e = (event_t*)malloc( sizeof( event_t ) );
 		e->type = RTCP_SR;
		e->time = 0.0;
		e->next = NULL;
		insert_event( e );
		send_rtcp();
	}

	/** OK, we build the real RTP packet... */
	RtpPacket *pkt = new RtpPacket( (uint8_t*)buf, size );
	pkt->set_ssrc( m_ssrc );
	pkt->set_payload_type( m_payload_type );
	pkt->set_sequence( m_seq++ );
	pkt->set_timestamp( timestamp );
	delete pkt;

	if ( ! send_pkt( buf, size ) ) {
		/* Problems sending packet.. probably the client closed
		 * the connection..
		 */
		return false;
	}

	/* *************************************************** */
	/*! Here we check for events or things to do... */

	/* Schedule the times to play packets as an absolute offset from
	 * our start time, rather than a relative offset from the initial
	 * packet.  (We're less vulnerable to drifting clocks that way).
	 * Alternative version based on timestamps and RTP clock..
	 */
	play_time = m_start_time + ((double)(timestamp - m_base_timestamp)/ m_rtp_clock);
	// printf("play_time: %f - difference: %f sec.\n", play_time,
	//		((double)(timestamp - m_base_timestamp)/ m_rtp_clock));

	while (gettimeofday(&now_tv, NULL), (now = tv2dbl(now_tv)) < play_time) {

		int event = 0;
		int retval;
		double timeout;
		struct timeval timeout_tv;
		fd_set sockets;

		if (	m_event_queue != NULL && 
			m_event_queue->time < play_time ) {
			event = 1;
			timeout = m_event_queue->time - now;
		} else {
			event = 0;
			timeout = play_time - now;
		}
		if ( timeout < 0 )
			timeout = 0;
		timeout_tv = dbl2tv( timeout );

		FD_ZERO( &sockets );
		FD_SET( m_rtp_sock, &sockets );
		FD_SET( m_rtcp_sock, &sockets );

		int max_fd = ((m_rtp_sock > m_rtcp_sock) ? m_rtp_sock : m_rtcp_sock ) + 1;

		retval = select(max_fd, &sockets, NULL, NULL, &timeout_tv);
		if ( retval < 0 ) {
			perror("select");
			exit(1);
		} else if ( retval > 0 ) { // There are some events...
			if (FD_ISSET(m_rtp_sock, &sockets)) {
				/* There's an RTP packet to be read... 
				 * We should receive, validate and .. trash it..
				 */
				receive_rtp( (void*)m_buf );
			}
			
			if (FD_ISSET(m_rtcp_sock, &sockets)) {
				receive_rtcp();
			}
		}  else { /* retval == 0, select timed out */
			if (event) {
				gettimeofday( &now_tv, NULL );
				now = tv2dbl( now_tv );
				while ( m_event_queue != NULL &&
					m_event_queue->time <= now ) {
					/* There is a pending RTCP packet to send) */
					send_rtcp();
				}
			} else
				break;  /* Time for the next packet */
		}
	}
	/* **************************************************** */
	return true;
}
Esempio n. 5
0
int main(int argc, char *argv[])
{
  /* The context id the RTP library gives us to keep track of our RTP
     stream. */
  context cid;
  /* The two socket fds (RTP and RTCP) we need to select on. */
  socktype sock[2];
  /* The highest file descriptor we've seen, of those we need to select
     on. */
  int nfds;

  /* The audio file we're playing. */
  FILE *input;
  /* Play 20 ms packets outgoing. */
#define BUFFER_SIZE 160
  /* The buffer for our outgoing data. */
  char buffer[BUFFER_SIZE];
  /* Maximum size of a UDP packet. */
#define RECEIVE_BUFFER_SIZE 65536
  /* The buffer incoming data accumulates in.  We don't actually care
   * about the contents of this data, but we must call RTPReceive() so our
   * sender reports and receiver reports are correct. */
  char receive_buffer[RECEIVE_BUFFER_SIZE];

  /* Some values for keeping track of amount of data read from the file */
  int bytes_read, total_read, last_read;
  /* Some values for keeping track of when to send packets. */
  struct timeval start_time_tv, now_tv;
  double start_time, play_time, now;
  /* Information about the media stream we're using. */
  double sample_rate, byte_rate;

  /* The amount to increment the RTP timestamp for a given packet */
  int tsinc;
  /* The RTP marker bit; initially, it's set. */
  char marker = 1;

  /* Error values that the RTP library returns. */
  rtperror err;
 



  /* 8khz 8-bit mulaw */
  sample_rate = byte_rate = 1/8000.0;

  if (argc < 3) {
    fprintf(stderr, "usage: %s file port\n", argv[0]);
    exit(2);
  }

  input = fopen(argv[1], "r");
  if (input == NULL) {
    perror(argv[1]);
    exit(1);
  }

  if ((nfds = setup_connection(argv[2], &cid, sock)) < 0) {
    exit(1);
  }
  
  total_read = 0;
  last_read = BUFFER_SIZE; /* Arbitrary initial setting. */
  gettimeofday(&start_time_tv, NULL);
  start_time = tv2dbl(start_time_tv);

  while((bytes_read = fread(buffer, 1, BUFFER_SIZE, input)) > 0) {
    /* The tsinc (time-stamp increment) is equal to the number of samples
     * played in the *previous* packet -- it's the amount to increment the 
     * RTP timestamp from the previous packet to this one. */
    tsinc = last_read * (sample_rate/byte_rate);
    /* Send the data we just read to the network.
     * We're assuming here that the payload is always Mulaw-8.
     * See comments above for explanations of the other arguments. */
    err = RTPSend(cid, tsinc, marker, PAYLOAD_TYPE_MULAW_8, buffer,
		  bytes_read);
    if (err != RTP_OK) {
      fprintf(stderr, "%s\n", RTPStrError(err));
      exit(1);
    }
    /* The marker bit doesn't get set for any packet but the first. */
    marker = 0;

    total_read += bytes_read;
    last_read = bytes_read;

    /* Schedule the times to play packets as an absolute offset from
     * our start time, rather than a relative offset from the initial
     * packet.  (We're less vulnerable to drifting clocks that way). */
    play_time = start_time + (total_read * byte_rate);

    /* Handle RTP events and received RTP and RTCP packets until the next
     * play time. */
    while (gettimeofday(&now_tv, NULL),
	   (now = tv2dbl(now_tv)) < play_time) {
      int event;
      int retval, i;
      double timeout;
      struct timeval timeout_tv;
      fd_set sockets;

      /* If we have pending events which are coming before the next packet,
       * timeout for them rather than for the next packet to play. */
      if (evt_queue != NULL && evt_queue->event_time < play_time) {
	event = 1;
	timeout = evt_queue->event_time - now;
      }
      else {
	event = 0;
	timeout = play_time - now;
      }
      if (timeout < 0) timeout = 0;
      timeout_tv = dbl2tv(timeout);
      
      FD_ZERO(&sockets);
      FD_SET(sock[0], &sockets);
      FD_SET(sock[1], &sockets);

      retval = select(nfds + 1, &sockets, NULL, NULL, &timeout_tv);
      if (retval < 0) { /* select returned an error */
	perror("select");
	exit(1);
      }
      else if (retval > 0) { /* select reported readable fd's. */
	for (i = 0; i < 2; i++) {
	  if (FD_ISSET(sock[i], &sockets)) {
	    int recbuflen = RECEIVE_BUFFER_SIZE;
	    /* We don't care about the contents of the received packet;
	     * we're only a sender.  However, we still have to call
	     * RTPReceive to ensure that our sender reports and 
	     * receiver reports are correct. */
	    err = RTPReceive(cid, sock[i], receive_buffer, &recbuflen);
	    if (err != RTP_OK && err != RTP_PACKET_LOOPBACK) {
	      fprintf(stderr, "RTPReceive %s (%d): %s\n",
		      i ? "RTCP" : "RTP", sock[i],
		      RTPStrError(err));
	    }
	  }
	}
      }
      else { /* retval == 0, select timed out */
	if (event) {
	  struct evt_queue_elt *next;
	  gettimeofday(&now_tv, NULL);
	  now = tv2dbl(now_tv);
	  while (evt_queue != NULL && evt_queue->event_time <= now) {
	    /* There is a pending RTP event (currently this means there's
	     * an RTCP packet to send), so run it. */
	    RTPExecute(evt_queue->cid, evt_queue->event_opaque);
	    /* Advance the queue */
	    next = evt_queue->next;
	    free(evt_queue);
	    evt_queue = next;
	  }
	}
	else
	  break; /* Time for the next audio packet */
      }
    }
  }

  /* We're done sending now, so close the connection. */
  /* This sends the RTCP BYE packet and closes our sockets. */
  if ((err = RTPCloseConnection(cid, "Goodbye!")) != RTP_OK) {
    fprintf(stderr, "%s\n", RTPStrError(err));
  }

  /* De-allocate all the data structures reserved for the connection.
   * (This would also close the connection, as well, if we hadn't just done
   * it above.) */
  if ((err = RTPDestroy(cid)) != RTP_OK) {
    fprintf(stderr, "%s\n", RTPStrError(err));
  }

  return 0;
}
Esempio n. 6
0
int main(int argc, char *argv[])
{
  /* The context id the RTP library gives us to keep track of our RTP
     stream. */
  context cid;
  /* The two socket fds (RTP and RTCP) we need to select on. */
  socktype sock[2];
  /* The highest file descriptor we've seen, of those we need to select
     on. */
  int nfds;

  /* Maximum size of a UDP packet. */
#define RECEIVE_BUFFER_SIZE 65536
  /* The buffer incoming data accumulates in.  We don't actually care
   * about the contents of this data, but we must call RTPReceive() so our
   * sender reports and receiver reports are correct. */
  char receive_buffer[RECEIVE_BUFFER_SIZE];

  /* Some values for keeping track of when to send packets. */
  struct timeval now_tv;
  double now;

  /* Error values that the RTP library returns. */
  rtperror err = RTP_OK;
#ifdef WIN32
  WORD wVersionRequested;
  WSADATA wsaData;
  int err2;
 
  wVersionRequested = MAKEWORD( 2, 0 );
 
  err2 = WSAStartup( wVersionRequested, &wsaData );
  if ( err2 != 0 ) {
	  /* Tell the user that we couldn't find a usable */
	  /* WinSock DLL.                                  */
	  return(-1);
  }
#endif
  if (argc < 2) {
    fprintf(stderr, "usage: %s address/port/ttl\n", argv[0]);
    exit(2);
  }

  if ((nfds = setup_connection(argv[1], &cid, sock)) < 0) {
    exit(1);
  }

  /* Set up our signal handler. */
  signal(SIGINT, done);
  signal(SIGTERM, done);

#ifdef __unix
  signal(SIGHUP, done);
#endif
  
  while (!finished) {
    int event;
    int retval, i;
    double timeout;
    struct timeval timeout_tv, *timeout_tvp;
    fd_set sockets;

    gettimeofday(&now_tv, NULL);
    now = tv2dbl(now_tv);
    
    /* If we have pending events which are coming before the next packet,
     * timeout for them rather than for the next packet to play. */
    if (evt_queue != NULL) {
      event = 1;
      timeout = evt_queue->event_time - now;
      if (timeout < 0) timeout = 0;
      timeout_tv = dbl2tv(timeout);
      timeout_tvp = &timeout_tv;
    }
    else {
      event = 0;
      timeout_tvp = NULL;
    }
    
    FD_ZERO(&sockets);
    FD_SET(sock[0], &sockets);
    FD_SET(sock[1], &sockets);
    
    retval = select(nfds + 1, &sockets, NULL, NULL, timeout_tvp);
    if (retval < 0) { /* select returned an error */

#ifdef __unix
      if (errno == EINTR) {
	/* We probably got a signal */
	continue;
      }
#endif
      /* Otherwise something's wrong */
      perror("select");
      exit(1);
    }
    else if (retval > 0) { /* select reported readable fd's. */
      for (i = 0; i < 2; i++) {
	if (FD_ISSET(sock[i], &sockets)) {
	  int recbuflen = RECEIVE_BUFFER_SIZE;
	  /* We don't care about the contents of the received packet per se.
	   * However, all of our callbacks, reporting information about other
	   * members, are called by code that occurs underneath RTPReceive.
	   * Plus this makes sure all our reciver reports are correct. */
	  err = RTPReceive(cid, sock[i], receive_buffer, &recbuflen);
	  /* Packet loopback is normal with multicast */
	  if (err != RTP_OK && err != RTP_PACKET_LOOPBACK) {
	    fprintf(stderr, "RTPReceive %s (%d): %s\n",
		    i ? "RTCP" : "RTP", sock[i],
		    RTPStrError(err));
	  }

	  if(i == 1) PrintReporting(cid);
	}
      }
    }
    else { /* retval == 0, select timed out */
      if (event) {
	struct evt_queue_elt *next;
	gettimeofday(&now_tv, NULL);
	now = tv2dbl(now_tv);
	while (evt_queue != NULL && evt_queue->event_time <= now) {
	  /* There is a pending RTP event (currently this means there's
	   * an RTCP packet to send), so run it. */
	  RTPExecute(evt_queue->cid, evt_queue->event_opaque);
	  /* Advance the queue */
	  next = evt_queue->next;
	  free(evt_queue);
	  evt_queue = next;
	}
      }
      else
	continue; /* This shouldn't happen, so just loop. */
    }
  }

  /* We're done sending now, so close the connection. */
  /* This sends the RTCP BYE packet and closes our sockets. */
  if ((err = RTPCloseConnection(cid,"Goodbye!")) != RTP_OK) {
    fprintf(stderr, "%s\n", RTPStrError(err));
  }

  /* De-allocate all the data structures reserved for the connection.
   * (This would also close the connection, as well, if we hadn't just done
   * it above.) */
  if ((err = RTPDestroy(cid)) != RTP_OK) {
    fprintf(stderr, "%s\n", RTPStrError(err));
  }

  return 0;
}