void AmRtpStream::recvPacket()
{
  AmRtpPacket* p = mem.newPacket();
  if (!p) {
    // drop received data
    AmRtpPacket dummy;
    dummy.recv(l_sd);
    return;
  }
  
  if(p->recv(l_sd) > 0){
    int parse_res = p->parse();
    gettimeofday(&p->recv_time,NULL);
    
    if (parse_res == -1) {
      DBG("error while parsing RTP packet.\n");
      clearRTPTimeout(&p->recv_time);
      mem.freePacket(p);	  
    } else {
      bufferPacket(p);
    }
  } else {
    mem.freePacket(p);
  }
}
int AmRtpStream::ping()
{
  // TODO:
  //  - we'd better send an empty UDP packet 
  //    for this purpose.

  unsigned char ping_chr[2];

  ping_chr[0] = 0;
  ping_chr[1] = 0;

  AmRtpPacket rp;
  rp.payload = payload;
  rp.marker = true;
  rp.sequence = sequence++;
  rp.timestamp = 0;   
  rp.ssrc = l_ssrc;
  rp.compile((unsigned char*)ping_chr,2);

  rp.setAddr(&r_saddr);
  if(rp.send(l_sd) < 0){
    ERROR("while sending RTP packet.\n");
    return -1;
  }
 
  return 2;
}
void AmRtpReceiver::run()
{
  unsigned int   tmp_nfds = 0;
  struct pollfd* tmp_fds  = new struct pollfd[MAX_RTP_SESSIONS];

  while(true){
	
    fds_mut.lock();
    tmp_nfds = nfds;
    memcpy(tmp_fds,fds,nfds*sizeof(struct pollfd));
    fds_mut.unlock();

    int ret = poll(tmp_fds,tmp_nfds,RTP_POLL_TIMEOUT);
    if(ret < 0)
      ERROR("AmRtpReceiver: poll: %s\n",strerror(errno));

    if(ret < 1)
      continue;

    for(unsigned int i=0; i<tmp_nfds; i++) {

      if(!(tmp_fds[i].revents & POLLIN))
	continue;

      streams_mut.lock();
      Streams::iterator it = streams.find(tmp_fds[i].fd);
      if(it != streams.end()) {
	AmRtpPacket* p = it->second->newPacket();
	if (!p) {
	  // drop received data
 	  AmRtpPacket dummy;
 	  dummy.recv(tmp_fds[i].fd);
	  streams_mut.unlock();
	  continue;
	}

	if(p->recv(tmp_fds[i].fd) > 0){
	  int parse_res = p->parse();
	  gettimeofday(&p->recv_time,NULL);
		
	  if (parse_res == -1) {
	    DBG("error while parsing RTP packet.\n");
	    it->second->clearRTPTimeout(&p->recv_time);
	    it->second->freePacket(p);	  
	  } else {
	    it->second->bufferPacket(p);
	  }
	} else {
	  it->second->freePacket(p);
	}
      }
      streams_mut.unlock();      
    }
  }
}
int AmRtpStream::send( unsigned int ts, unsigned char* buffer, unsigned int size )
{
  if ((mute) || (hold))
    return 0;

  if(!size)
    return -1;

  AmRtpPacket rp;
  rp.payload = payload;
  rp.marker = false;
  rp.sequence = sequence++;
  rp.timestamp = ts;   
  rp.ssrc = l_ssrc;
  rp.compile((unsigned char*)buffer,size);

  rp.setAddr(&r_saddr);

#ifdef WITH_ZRTP
  if (session->zrtp_audio) {
    zrtp_status_t status = zrtp_status_fail;
    unsigned int size = rp.getBufferSize();
    status = zrtp_process_rtp(session->zrtp_audio, (char*)rp.getBuffer(), &size);
    switch (status) {
    case zrtp_status_drop: {
      DBG("ZRTP says: drop packet! %u - %u\n", size, rp.getBufferSize());
      return 0;
    } 
    case zrtp_status_ok: {
      //      DBG("ZRTP says: ok!\n");
      if (rp.getBufferSize() != size)
//       DBG("SEND packet size before: %d, after %d\n", 
// 	   rp.getBufferSize(), size);
      rp.setBufferSize(size);
    } break;
    default:
    case zrtp_status_fail: {
      DBG("ZRTP says: fail!\n");
      //      DBG("(f)");
      return 0;
    }

    }
    
  }
#endif

  if(rp.send(l_sd) < 0){
    ERROR("while sending RTP packet.\n");
    return -1;
  }
 
  return size;
}
int AmRtpStream::send_raw( char* packet, unsigned int length )
{
  if ((mute) || (hold))
    return 0;

  AmRtpPacket rp;
  rp.compile_raw((unsigned char*)packet, length);
  rp.setAddr(&r_saddr);

  if(rp.send(l_sd) < 0){
    ERROR("while sending raw RTP packet.\n");
    return -1;
  }
 
  return length;
}
int AmRtpStream::nextPacket(AmRtpPacket& p)
{
  if (!receiving && !passive)
    return RTP_EMPTY;

  struct timeval now;
  struct timeval diff;
  gettimeofday(&now,NULL);

  receive_mut.lock();
  timersub(&now,&last_recv_time,&diff);
  if(AmConfig::DeadRtpTime && 
     (diff.tv_sec > 0) &&
     ((unsigned int)diff.tv_sec > AmConfig::DeadRtpTime)){
    WARN("RTP Timeout detected. Last received packet is too old.\n");
    DBG("diff.tv_sec = %i\n",(unsigned int)diff.tv_sec);
    receive_mut.unlock();
    return RTP_TIMEOUT;
  }

  if(receive_buf.empty()){
    receive_mut.unlock();
    return RTP_EMPTY;
  }

  AmRtpPacket& pp = receive_buf.begin()->second;
  p.copy(&pp);
  receive_buf.erase(receive_buf.begin());
  receive_mut.unlock();

  return 1;
}
int AmRtpStream::receive( unsigned char* buffer, unsigned int size,
			  unsigned int& ts, int &out_payload)
{
  AmRtpPacket* rp = NULL;
  int err = nextPacket(rp);
    
  if(err <= 0)
    return err;

  if (!rp)
    return 0;

  handleSymmetricRtp(rp);

  /* do we have a new talk spurt? */
  begin_talk = ((last_payload == 13) || rp->marker);
  last_payload = rp->payload;

  if(!rp->getDataSize()) {
    mem.freePacket(rp);
    return RTP_EMPTY;
  }

  if (rp->payload == getLocalTelephoneEventPT())
    {
      dtmf_payload_t* dpl = (dtmf_payload_t*)rp->getData();

      DBG("DTMF: event=%i; e=%i; r=%i; volume=%i; duration=%i; ts=%u\n",
	  dpl->event,dpl->e,dpl->r,dpl->volume,ntohs(dpl->duration),rp->timestamp);
      session->postDtmfEvent(new AmRtpDtmfEvent(dpl, getLocalTelephoneEventRate(), rp->timestamp));
      mem.freePacket(rp);
      return RTP_DTMF;
    }

  assert(rp->getData());
  if(rp->getDataSize() > size){
    ERROR("received too big RTP packet\n");
    mem.freePacket(rp);
    return RTP_BUFFER_SIZE;
  }

  memcpy(buffer,rp->getData(),rp->getDataSize());
  ts = rp->timestamp;
  out_payload = rp->payload;

  int res = rp->getDataSize();
  mem.freePacket(rp);
  return res;
}
int AmRtpStream::send( unsigned int ts, unsigned char* buffer, unsigned int size )
{
  if ((mute) || (hold))
    return 0;

  if(!size)
    return -1;

  AmRtpPacket rp;
  rp.payload = payload;
  rp.marker = false;
  rp.sequence = sequence++;
  rp.timestamp = ts;   
  rp.ssrc = l_ssrc;
  rp.compile((unsigned char*)buffer,size);

  rp.setAddr(&r_saddr);
  if(rp.send(l_sd) < 0){
    ERROR("while sending RTP packet.\n");
    return -1;
  }
 
  return size;
}
int AmRtpStream::receive( unsigned char* buffer, unsigned int size,
			  unsigned int& ts, int &out_payload)
{
  AmRtpPacket* rp = NULL;
  int err = nextPacket(rp);
    
  if(err <= 0)
    return err;

  if (!rp)
    return 0;

#ifndef SUPPORT_IPV6
  if(passive) {
    // #ifdef SUPPORT_IPV6
    //     struct sockaddr_storage recv_addr;
    // #else
    struct sockaddr_in recv_addr;
    rp->getAddr(&recv_addr);

    // symmetric RTP
    if ((recv_addr.sin_port != r_saddr.sin_port)
	|| (recv_addr.sin_addr.s_addr 
	    != r_saddr.sin_addr.s_addr)) {
		
      string addr_str = get_addr_str(recv_addr.sin_addr);
      int port = ntohs(recv_addr.sin_port);
      setRAddr(addr_str,port);
      DBG("Symmetric RTP: setting new remote address: %s:%i\n",
	  addr_str.c_str(),port);
      // avoid comparing each time sender address
    } else {
      DBG("Symmetric RTP: remote end sends RTP from advertised address. Leaving passive mode.\n");
    }
    passive = false;
  }
#endif

  /* do we have a new talk spurt? */
  begin_talk = ((last_payload == 13) || rp->marker);
  last_payload = rp->payload;

  if(!rp->getDataSize()) {
    mem.freePacket(rp);
    return RTP_EMPTY;
  }

  if (telephone_event_pt.get() && rp->payload == telephone_event_pt->payload_type)
    {
      dtmf_payload_t* dpl = (dtmf_payload_t*)rp->getData();

      DBG("DTMF: event=%i; e=%i; r=%i; volume=%i; duration=%i\n",
	  dpl->event,dpl->e,dpl->r,dpl->volume,ntohs(dpl->duration));
      session->postDtmfEvent(new AmRtpDtmfEvent(dpl, getTelephoneEventRate()));
      mem.freePacket(rp);
      return RTP_DTMF;
    }

  assert(rp->getData());
  if(rp->getDataSize() > size){
    ERROR("received too big RTP packet\n");
    mem.freePacket(rp);
    return RTP_BUFFER_SIZE;
  }

  memcpy(buffer,rp->getData(),rp->getDataSize());
  ts = rp->timestamp;
  out_payload = rp->payload;

  int res = rp->getDataSize();
  mem.freePacket(rp);
  return res;
}