示例#1
0
static int do_turn_relays(STREAM_XMIT_NODE_T *pStream, NET_PROGRESS_T *progressTurn) {
  //int rc = 0;
  STREAM_RTP_MULTI_T *pRtpMulti = NULL;
  int idxDest;
  STREAM_RTP_DEST_T *pDest = NULL;
  NETIO_SOCK_T *pnetsock;

  if(progressTurn) {
    memset(progressTurn, 0, sizeof(NET_PROGRESS_T));
  }

  pRtpMulti = pStream->pRtpMulti;
  while(pRtpMulti) {

    if(g_proc_exit) {
      return -1;
    } else if(*pStream->prunning != STREAMER_STATE_RUNNING) {
      continue;
    }

    for(idxDest = 0; idxDest < pRtpMulti->numDests; idxDest++) {

      if(!(pDest = &pRtpMulti->pdests[idxDest]) || !pDest->isactive) {
        continue;
      }
      //LOG(X_DEBUG("DO_TURN_RELAYS.... idxDest:%d, pnetsock: 0x%x"), idxDest, STREAM_RTP_PNETIOSOCK(*pDest));
      if(progressTurn) {
        pnetsock = STREAM_RTP_PNETIOSOCK(*pDest);
        if(pnetsock->turn.use_turn_indication_in || pnetsock->turn.use_turn_indication_out) {
          progressTurn->numTotal++;
          if(pnetsock->turn.have_error) {
            progressTurn->numError++;
          } else if(turn_can_send_data(&pnetsock->turn)) {
            progressTurn->numCompleted++;
          }
        }
      }

    }

    pRtpMulti = pRtpMulti->pnext;
  } // end of while(pRtpMulti...

  if(!progressTurn) {
    return 0;
  } if(progressTurn->numError > 0) {
    return -1;
  } else if(progressTurn->numCompleted == progressTurn->numTotal) {
    return progressTurn->numTotal - progressTurn->numCompleted;
  } else {
    return progressTurn->numTotal - progressTurn->numCompleted;
  }

}
示例#2
0
static int streamxmit_retransmitRtp(STREAM_RTP_DEST_T *pDest) {
  STREAMXMIT_PKT_HDR_T *pktHdr;
  unsigned int idxRd;
  unsigned int count = 0;
  int lastWasExpired = 0;
  int rc;
  int haveRequestedRetransmission = 0;
  const PKTQUEUE_PKT_T *pQPkt = NULL;
  STREAM_XMIT_QUEUE_T *pAsyncQ = &pDest->asyncQ;
  TIME_VAL tvNow;
  struct timeval tv;
  float kbps;
  char tmp[128];

  tvNow = timer_GetTime();
  TV_FROM_TIMEVAL(tv, tvNow);

  pthread_mutex_lock(&pAsyncQ->mtx);
  idxRd = pAsyncQ->pQ->idxRd;
  //LOG(X_DEBUG("NACK streamxmit_iterate ... idxRd:%d, idxWr:%d / %d"), pAsyncQ->pQ->idxRd, pAsyncQ->pQ->idxWr, pAsyncQ->pQ->cfg.maxPkts);
  while(count++ < pAsyncQ->pQ->cfg.maxPkts) {

    pQPkt = &pAsyncQ->pQ->pkts[idxRd];

    if(!(pQPkt->flags & PKTQUEUE_FLAG_HAVEPKTDATA)) {
      //LOG(X_DEBUG("NACK streamxmit_iterate break at qid[%d]"), idxRd);
      break;
    }
    //LOG(X_DEBUG("NACK streamxmit_iterate check qid[%d] seqno:%d, %lld ms ago"), idxRd, ((STREAMXMIT_PKT_HDR_T *) pQPkt->xtra.pQUserData)->seqNum, (tvNow - ((STREAMXMIT_PKT_HDR_T *) pQPkt->xtra.pQUserData)->tvxmit)/1000);

    lastWasExpired = 0;

    if(!(pktHdr = (STREAMXMIT_PKT_HDR_T *) pQPkt->xtra.pQUserData)) {

      pAsyncQ->pQ->idxRd = idxRd;
      fprintf(stderr, "streamxmit_itertate should never get here... idxRd:%d\n", idxRd);

    } else if(pktHdr->tvXmit + (pAsyncQ->nackHistoryMs * TIME_VAL_MS) < tvNow) {
      //
      // The queue slot RTP sequence number came before the NACK starting sequence number
      // so the current queue content is before the scope of the NACK
      //
      if(pktHdr->doRetransmit > 0) {
        pktHdr->doRetransmit = -1;

        if(pDest->pstreamStats) {
          stream_abr_notifyBitrate(pDest->pstreamStats, &pDest->streamStatsMtx, 
                                   STREAM_ABR_UPDATE_REASON_NACK_AGED, .5f);
        }

      }
      pAsyncQ->pQ->idxRd = idxRd;
      pAsyncQ->pQ->pkts[idxRd].flags = 0;
      lastWasExpired = 1;
      //LOG(X_DEBUG("NACK streamxmit_iterate old here marked to -1 ... idxRd:%d, seqNum:%d"), idxRd, pktHdr->seqNum);

    } else if(pktHdr->doRetransmit > 0 && !pktHdr->rtcp) {

      if(pktHdr->tvLastRetransmit == 0 || 
         pktHdr->tvLastRetransmit + (RTP_RETRANSMIT_INTERVAL_MS * TIME_VAL_MS) < tvNow) {

        //
        // Ensure that the retransmission will not exceed our retransmission bitrate limit
        //
        if(pAsyncQ->retransmissionKbpsMax > 0 &&
          burstmeter_updateCounters(&pAsyncQ->retransmissionMeter, &tv) == 0 &&
          (kbps = (burstmeter_getBitrateBps(&pAsyncQ->retransmissionMeter)/THROUGHPUT_BYTES_IN_KILO_F)) >= pAsyncQ->retransmissionKbpsMax) {

          LOG(X_WARNING("RTP NACK retransmission bitrate %.3f >= %.3f  throttled pt:%d sequence:%d to %s:%d, for original %d ms ago."), 
                     kbps, pAsyncQ->retransmissionKbpsMax, pDest->pRtpMulti->init.pt, pktHdr->seqNum, 
                     FORMAT_NETADDR(pDest->saDstsRtcp, tmp, sizeof(tmp)), ntohs(INET_PORT(pDest->saDstsRtcp)),
                     (tvNow - pktHdr->tvXmit) / TIME_VAL_MS);

          if(pDest->pstreamStats) {
            stream_abr_notifyBitrate(pDest->pstreamStats, &pDest->streamStatsMtx,
                                     STREAM_ABR_UPDATE_REASON_NACK_THROTTLED, .5f);
          }

          pktHdr->doRetransmit = 0;
          pktHdr->tvLastRetransmit = tvNow; 

        } else {

          burstmeter_AddSample(&pAsyncQ->retransmissionMeter, pQPkt->len, &tv);

          //LOG(X_DEBUG("RTP NACK Retransmission bitrate: %.3f %s (%.3f bps)"),  (float) pAsyncQ->retransmissionMeter.meter.rangeMs/1000, burstmeter_printThroughputStr(buf, sizeof(buf), &pAsyncQ->retransmissionMeter), (float) burstmeter_getBitrateBps(&pAsyncQ->retransmissionMeter));

          //
          // Retransmit the RTP packet
          //
          LOG(X_DEBUG("RTP NACK retransmitting pt:%d sequence:%d, len:%d to %s:%d, original sent %d ms ago.  "
                      "Rate: %.3f pkts/s, %.3f b/s"), 
                    pDest->pRtpMulti->init.pt, pktHdr->seqNum, pQPkt->len, 
                    FORMAT_NETADDR(pDest->saDstsRtcp, tmp, sizeof(tmp)), ntohs(INET_PORT(pDest->saDstsRtcp)), 
                    (tvNow - pktHdr->tvXmit) / TIME_VAL_MS,
                    (float) burstmeter_getPacketratePs(&pAsyncQ->retransmissionMeter),
                    (float) burstmeter_getBitrateBps(&pAsyncQ->retransmissionMeter));

          if((rc = srtp_sendto(STREAM_RTP_PNETIOSOCK(*pDest), (void *) pQPkt->pData, pQPkt->len, 0,
                              (const struct sockaddr *) &pDest->saDsts, NULL, SENDTO_PKT_TYPE_RTP, 1)) < 0) {
          
            pktHdr->doRetransmit = -1;
          } else {
            pktHdr->doRetransmit = 0;
          }

          pktHdr->tvLastRetransmit = tvNow; 
          if(pDest->pstreamStats) {
            stream_abr_notifyBitrate(pDest->pstreamStats, &pDest->streamStatsMtx,
                                     STREAM_ABR_UPDATE_REASON_NACK_RETRANSMITTED, .5f);
          }

        }

      } else {
        haveRequestedRetransmission = 1;
      }
   
    }

    if(++idxRd >= pAsyncQ->pQ->cfg.maxPkts) {
      idxRd = 0;
    }
    if(lastWasExpired) {
      pAsyncQ->pQ->idxRd = idxRd;
    } 

  } // end of while...

  pAsyncQ->haveRequestedRetransmission = haveRequestedRetransmission;

  pthread_mutex_unlock(&pAsyncQ->mtx);

  return haveRequestedRetransmission;
}
示例#3
0
int streamxmit_sendto(STREAM_RTP_DEST_T *pDest, const unsigned char *data, unsigned int len, 
                      int rtcp, int keyframe, int drop) {
  int rc = 0;
  NETIO_SOCK_T *pnetsock = NULL;
  const unsigned char *pData = data;
  PKTQ_EXTRADATA_T qXtra;
  STREAMXMIT_PKT_HDR_T pktHdr;
  unsigned char encBuf[PACKETGEN_PKT_UDP_DATA_SZ];

  //
  // If we're using DTLS-SRTP over audio/video mux (on same RTP port) then we need to choose
  // the right socket which has completed the DTLS handshake
  //
  if(rtcp) {
    pnetsock = STREAM_RTCP_PNETIOSOCK(*pDest);
  } else {
    pnetsock = STREAM_RTP_PNETIOSOCK(*pDest);
  }

  //LOG(X_DEBUG("STREAMXMIT_SENDTO len:%d, rtcp:%d, drop:%d, pDest: 0x%x, srtp:0x%x, pSrtpShared: 0x%x, 0x%x, lenK:%d"), len, rtcp, drop, pDest, &pDest->srtps[rtcp ? 1 : 0], pDest->srtps[rtcp ? 1 : 0].pSrtpShared, SRTP_CTXT_PTR(&pDest->srtps[rtcp ? 1 : 0]), SRTP_CTXT_PTR(&pDest->srtps[rtcp ? 1 : 0])->k.lenKey);LOGHEX_DEBUG(data, MIN(16, len));

  if((rc = srtp_dtls_protect(pnetsock, data, len, encBuf, sizeof(encBuf),
                      (const struct sockaddr *) (rtcp ? &pDest->saDstsRtcp : &pDest->saDsts), 
                      pDest->srtps[rtcp ? 1 : 0].pSrtpShared,
                      rtcp ? SENDTO_PKT_TYPE_RTCP : SENDTO_PKT_TYPE_RTP)) < 0) {
    if(rc == -2) {
      // DTLS handshake not complete
      return 0;
    } else {
      return -1;
    }
  } else if(rc > 0) {
    pData = encBuf;
    len = rc;
  }

  //
  // Queue the packet for async sending
  //
  if(pDest->asyncQ.pQ && (pDest->asyncQ.doAsyncXmit || (!rtcp && pDest->asyncQ.doRtcpNack))) {

    memset(&qXtra, 0, sizeof(qXtra));
    memset(&pktHdr, 0, sizeof(pktHdr));
    pktHdr.flags = 0;
    pktHdr.tvCreate = timer_GetTime();
    if(!pDest->asyncQ.doAsyncXmit) {
      pktHdr.tvXmit = pktHdr.tvCreate;
    }
    if(!(pktHdr.rtcp = rtcp)) {
      pktHdr.seqNum = htons(pDest->pRtpMulti->pRtp->sequence_num);
      pktHdr.timeStamp = htonl(pDest->pRtpMulti->pRtp->timeStamp);
      pktHdr.keyframe = keyframe;
    }
    qXtra.pQUserData = &pktHdr;

    pthread_mutex_lock(&pDest->asyncQ.mtx);

    if(!pDest->asyncQ.isCurPktKeyframe && keyframe) {
      pDest->asyncQ.haveLastKeyframeSeqNumStart = 1;
      pDest->asyncQ.lastKeyframeSeqNumStart = pktHdr.seqNum;
      //LOG(X_DEBUG("NACK - GOP start at packet %d"), pktHdr.seqNum);
    }

    if(pktqueue_addpkt(pDest->asyncQ.pQ, pData, len, &qXtra,
       (!pDest->asyncQ.isCurPktKeyframe && keyframe ? 1 : 0)) != PKTQUEUE_RC_OK) {
      pthread_mutex_unlock(&pDest->asyncQ.mtx);
      return -1;
    }
    //LOG(X_DEBUG("NACK q rd:[%d]/%d, wr:%d"), pDest->asyncQ.pQ->idxRd, pDest->asyncQ.pQ->cfg.maxPkts, pDest->asyncQ.pQ->idxWr);
    pDest->asyncQ.isCurPktKeyframe = keyframe;

    pthread_mutex_unlock(&pDest->asyncQ.mtx);
    rc = len;

    //pktqueue_dump(pDest->asyncQ.pQ,  pktqueue_cb_streamxmit_dump_pkthdr);
  } 

  if(!pDest->asyncQ.doAsyncXmit && !drop) {
    if((rc = srtp_sendto(pnetsock, (void *) pData, len, 0, 
                         (const struct sockaddr *) (rtcp ? &pDest->saDstsRtcp : &pDest->saDsts), NULL, 
                         rtcp ? SENDTO_PKT_TYPE_RTCP : SENDTO_PKT_TYPE_RTP, 1)) < 0) {
      return -1;
    }

  } else if(drop) {
    rc = len;
  }

  if(pDest->pstreamStats) {
    stream_stats_addPktSample(pDest->pstreamStats, &pDest->streamStatsMtx, len, !rtcp);
  }

  return rc;
}
示例#4
0
static int do_dtls_handshakes(STREAM_XMIT_NODE_T *pStream, 
                              TIME_VAL tmstart,
                              TIME_VAL *ptmstartRtpHandshakeDone,
                              NET_PROGRESS_T *progRtp, 
                              NET_PROGRESS_T *progRtcp,
                              const DTLS_TIMEOUT_CFG_T *pdtlsTimeouts) {
  int idxDest, idxDestPrior;
  STREAM_RTP_DEST_T *pDest = NULL;
  STREAM_RTP_DEST_T *pDestPrior = NULL;
  STREAM_RTP_MULTI_T *pRtpMulti = NULL;
  STREAM_RTP_MULTI_T *pRtpMultiPrior = NULL;
  int sameRtpSock, sameRtcpSock;
  TIME_VAL tmnow;

  //LOG(X_DEBUG("do_dtls_handshakes"));
  if(progRtp) {
    memset(progRtp, 0, sizeof(NET_PROGRESS_T));
  }
  if(progRtcp) {
    memset(progRtcp, 0, sizeof(NET_PROGRESS_T));
  }

  pRtpMulti = pStream->pRtpMulti;
  while(pRtpMulti) {

    if(g_proc_exit) {
      return -1;
    } else if(*pStream->prunning != STREAMER_STATE_RUNNING) {
      continue; 
    }

    //
    // Check if the RTP socket is pending creation by the capture_socket  thread
    //
    if(progRtp && pRtpMulti->pStreamerCfg->sharedCtxt.state == STREAMER_SHARED_STATE_PENDING_CREATE) {
      progRtp->numTotal++;
      continue;
    }

    for(idxDest = 0; idxDest < pRtpMulti->numDests; idxDest++) {

      if(!(pDest = &pRtpMulti->pdests[idxDest]) || !pDest->isactive) {
        continue;
      }

      sameRtpSock = sameRtcpSock = 0;

      if(pRtpMultiPrior) {
        //
        // Check RTP video/audio multiplexing over the same port
        //
        for(idxDestPrior = 0; idxDestPrior < pRtpMultiPrior->numDests; idxDestPrior++) {

          if(!(pDestPrior = &pRtpMultiPrior->pdests[idxDestPrior]) || !pDestPrior->isactive) {
            continue;
          }

          if(pDestPrior->saDsts.sin_port == pDest->saDsts.sin_port) {
            sameRtpSock = 1;
          }
          if(pDestPrior->saDstsRtcp.sin_port == pDest->saDstsRtcp.sin_port) {
            sameRtcpSock = 1;
          }
        }
      }


      //if(pDest->pRtpMulti->pStreamerCfg->xcode.vid.pip.active) 
      //LOG(X_DEBUG("SAMERTPSOCK:%D, SAMERTCPSOCK:%d"), sameRtpSock, sameRtcpSock);

      if(progRtp && (STREAM_RTP_PNETIOSOCK(*pDest)->flags & NETIO_FLAG_SSL_DTLS) && !sameRtpSock &&
         STREAM_RTP_FD(*pDest) != INVALID_SOCKET) {
        //if(pDest->pRtpMulti->pStreamerCfg->xcode.vid.pip.active) 
        //LOG(X_DEBUG("DO_DTLS_HS RTP pnetsock.state: %d, flags:0x%x"), STREAM_RTP_PNETIOSOCK(*pDest)->ssl.state, STREAM_RTP_PNETIOSOCK(*pDest)->flags);

        do_dtls_handshake(STREAM_RTP_PNETIOSOCK(*pDest), &pDest->saDsts, progRtp);
      }

      if(progRtcp && STREAM_RTP_FD(*pDest) != STREAM_RTCP_FD(*pDest) &&
        (STREAM_RTCP_PNETIOSOCK(*pDest)->flags & NETIO_FLAG_SSL_DTLS) && !sameRtcpSock &&
         STREAM_RTCP_FD(*pDest) != INVALID_SOCKET) {
        //if(pDest->pRtpMulti->pStreamerCfg->xcode.vid.pip.active) 
        //LOG(X_DEBUG("DO_DTLS_HS RCTP pnetsock.state: %d, flags:0x%x"), STREAM_RTCP_PNETIOSOCK(*pDest)->ssl.state, STREAM_RTCP_PNETIOSOCK(*pDest)->flags);

        do_dtls_handshake(STREAM_RTCP_PNETIOSOCK(*pDest), &pDest->saDstsRtcp, progRtcp);
      }

    } // end of for(idxDest..

    pRtpMultiPrior = pRtpMulti;
    pRtpMulti = pRtpMulti->pnext;
  } // end of while(pRtpMulti...

  //LOG(X_DEBUG("streamer_do_dtls_handshake done rtp-numDtls:%d, rtp-numDtlsCompleted:%d, rtcp-numDtls:%d, rtcp-numDtlsCompleted:%d"), progRtp ? progRtp->numTotal : -1, progRtp ? progRtp->numCompleted : -1, progRtcp->numTotal, progRtcp->numCompleted);

  if(!progRtp) {
    return 0;
  } if(progRtp->numError > 0) {
    return -1;
  } else if(progRtp->numCompleted == progRtp->numTotal) {

    if(*ptmstartRtpHandshakeDone == 0) {
      *ptmstartRtpHandshakeDone = timer_GetTime();
    }

    if(progRtcp->numTotal - progRtcp->numCompleted > 0 &&
      ((tmnow = timer_GetTime()) - *ptmstartRtpHandshakeDone) / TIME_VAL_MS < pdtlsTimeouts->handshakeRtcpAdditionalMs) {
      return progRtcp->numTotal - progRtcp->numCompleted;
    } else {
      return 0;
    }

  } else {

    if(((tmnow = timer_GetTime()) - tmstart) / TIME_VAL_MS > pdtlsTimeouts->handshakeRtpTimeoutMs) {
      LOG(X_ERROR("Aborting DTLS RTP handshake(s) after %lld ms.  %d/%d completed"), 
          (tmnow - tmstart) / TIME_VAL_MS, progRtp->numCompleted, progRtp->numTotal);
      return -1;
    } else {
      return progRtp->numTotal - progRtp->numCompleted;
    }

  }

}