live555的rtsp rtp over tcp 出流花屏问题

live555的rtsp rtp over tcp 出流花屏问题

windows下用vlc播放 live555出的流会花屏,发现是发送缓冲区满了,live server会丢包

Boolean RTPInterface::sendRTPorRTCPPacketOverTCP(u_int8_t* packet, unsigned packetSize,
						 int socketNum, unsigned char streamChannelId) {
#ifdef DEBUG_SEND
  fprintf(stderr, "sendRTPorRTCPPacketOverTCP: %d bytes over channel %d (socket %d)\n",
	  packetSize, streamChannelId, socketNum); fflush(stderr);
#endif
  // Send a RTP/RTCP packet over TCP, using the encoding defined in RFC 2326, section 10.12:
  //     $<streamChannelId><packetSize><packet>
  // (If the initial "send()" of '$<streamChannelId><packetSize>' succeeds, then we force
  // the subsequent "send()" for the <packet> data to succeed, even if we have to do so with
  // a blocking "send()".)
  do {
    u_int8_t framingHeader[4];
    framingHeader[0] = '$';
    framingHeader[1] = streamChannelId;
    framingHeader[2] = (u_int8_t) ((packetSize&0xFF00)>>8);
    framingHeader[3] = (u_int8_t) (packetSize&0xFF);
    if (!sendDataOverTCP(socketNum, framingHeader, 4, False)) break;

    if (!sendDataOverTCP(socketNum, packet, packetSize, True)) break;
#ifdef DEBUG_SEND
    fprintf(stderr, "sendRTPorRTCPPacketOverTCP: completed\n"); fflush(stderr);
#endif

    return True;
  } while (0);

#ifdef DEBUG_SEND
  fprintf(stderr, "sendRTPorRTCPPacketOverTCP: failed! (errno %d)\n", envir().getErrno()); fflush(stderr);
#endif
  return False;
}

从上面的代码如果第一包发送失败就不会发第二包了,于是vlc的画面就会花掉,这里我们知道live555是非阻塞的

那为什么发送端的发送缓冲区会满呢,抓包发现是windows下的tcp延迟确认机制导致的,
windows下tcp延迟确认机制是默认开启的,这里发送出去的数据一直得不到确认,占着缓冲区,把缓冲区耗尽了。
快速的解决的方法也算简单吧,把第一个send的fasle改为true,那么当异步发送失败时就会变为阻塞发送了!
这样做也不算好吧,因为会阻塞。如果要实现不丢包则需要缓存未发送的数据,还比较麻烦,先就这样改吧,毕竟我已经把live555改为多线程的了:),即时阻塞住也不会影响其他线程的发送哦

下面的函数可以看到在makeSocketBlocking处临时的把发送转为阻塞发送了哈

Boolean RTPInterface::sendDataOverTCP(int socketNum, u_int8_t const* data, unsigned dataSize, Boolean forceSendToSucceed) {
  int sendResult = send(socketNum, (char const*)data, dataSize, 0/*flags*/);
  if (sendResult < (int)dataSize) 
  {
    // The TCP send() failed - at least partially.
    
    unsigned numBytesSentSoFar = sendResult < 0 ? 0 : (unsigned)sendResult;
    fprintf(stderr, "sendResult %d < dataSize %d, forceSendToSucceed %d, getErrno %d\n"
      , sendResult, dataSize, forceSendToSucceed, envir().getErrno());

    if (numBytesSentSoFar > 0 || (forceSendToSucceed && envir().getErrno() == EAGAIN)) 
    {
      // The OS's TCP send buffer has filled up (because the stream's bitrate has exceeded
      // the capacity of the TCP connection!).
      // Force this data write to succeed, by blocking if necessary until it does:
      unsigned numBytesRemainingToSend = dataSize - numBytesSentSoFar;
#ifdef DEBUG_SEND
      fprintf(stderr, "sendDataOverTCP: resending %d-byte send (blocking)\n", numBytesRemainingToSend); fflush(stderr);
#endif
      makeSocketBlocking(socketNum, RTPINTERFACE_BLOCKING_WRITE_TIMEOUT_MS);
      sendResult = send(socketNum, (char const*)(&data[numBytesSentSoFar]), numBytesRemainingToSend, 0/*flags*/);

      fprintf(stderr, "block send %d\n", sendResult);

      if ((unsigned)sendResult != numBytesRemainingToSend) 
      {
        // The blocking "send()" failed, or timed out.  In either case, we assume that the
        // TCP connection has failed (or is 'hanging' indefinitely), and we stop using it
        // (for both RTP and RTP).
        // (If we kept using the socket here, the RTP or RTCP packet write would be in an
        //  incomplete, inconsistent state.)
#ifdef DEBUG_SEND
	      fprintf(stderr, "sendDataOverTCP: blocking send() failed (delivering %d bytes out of %d); closing socket %d\n", sendResult, numBytesRemainingToSend, socketNum); fflush(stderr);
#endif
        removeStreamSocket(socketNum, 0xFF);
        return False;
      }

      makeSocketNonBlocking(socketNum);

      return True;
    }
    else if (sendResult < 0 && envir().getErrno() != EAGAIN) 
    {
      // Because the "send()" call failed, assume that the socket is now unusable, so stop
      // using it (for both RTP and RTCP):
      removeStreamSocket(socketNum, 0xFF);
    }


    return False;
  }

  return True;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值