bool cBackgroundWriterI::Flush(int TimeoutMs)
{
  uint64_t WaitEnd = cTimeMs::Now();

  // wait for ring buffer to drain
  if (TimeoutMs > 0) {
    WaitEnd += (uint64_t)TimeoutMs;

    while (cTimeMs::Now() < WaitEnd &&
           Running() &&
           m_RingBuffer.Available() > 0)
      cCondWait::SleepMs(3);
  }

  int Available = m_RingBuffer.Available();
  if (m_IsSocket && Available <= 0) {
    // flush corked data too
    Cork();
  }

  return Available <= 0;
}
Beispiel #2
0
void CPulseAEStream::Resume()
{
  if (m_Initialized)
    m_Paused = Cork(false);
}
Beispiel #3
0
void CPulseAEStream::Pause()
{
  if (m_Initialized)
    m_Paused = Cork(true);
}
void cTcpWriter::Action(void)
{
  uint64_t NextHeaderPos = 0;
  uint64_t GetPos        = 0;
  cPoller  Poller (m_fd, true);
  bool     CorkReq = false;

  while (Running()) {

    if (!Poller.Poll(100))
      continue;

    if (CorkReq && m_RingBuffer.Available() <= 0) {
      // Force TCP packet to avoid delaying control messages
      Cork();
      CorkReq = false;
    }

    uint64_t StartPos;
    int      Count = 0;
    int      n;
    uchar   *Data = m_RingBuffer.Get(Count);

    if (!Data || Count <= 0)
      continue;

    Lock(); // uint64_t m_DiscardStart can not be read atomically (IA32)
    StartPos = m_DiscardEnd;
    Unlock();

    // Next frame ?
    if (NextHeaderPos == GetPos) {

      // Discard data ?
      if (StartPos > GetPos) {
        // we're at frame boundary
        // drop only data packets, not control messages
        stream_tcp_header_t *header = (stream_tcp_header_t*)Data;
        if (eStreamId(header->stream) == sidVdr) {
          Count = min(Count, (int)(StartPos - GetPos));

          // size of next (complete) packet.
          // drop only one packet at time.
          int pkt_len = ntohl(header->len) + sizeof(stream_tcp_header_t);
          if (Count >= pkt_len) {
            // drop only complete packets.
            // some packets are not dropped (packets overlapping end of ringbuffer)
            Count = pkt_len;

            m_RingBuffer.Del(Count);
            GetPos += Count;
            NextHeaderPos = GetPos;

            CorkReq = true; // force sending last frame

            continue;
          }
        }
      }

      // Next frame

      if (Count < (int)sizeof(stream_tcp_header_t))
        LOGMSG("cBackgroundWriter @NextHeaderPos: Count < header size !");

      // limit single write to size of next (complete) packet.
      // (we need to track packet boundaries)
      stream_tcp_header_t *header = (stream_tcp_header_t*)Data;
      int pkt_len = ntohl(header->len) + sizeof(stream_tcp_header_t);
      if (Count > pkt_len)
        Count = pkt_len;
      // next packet start position in stream
      NextHeaderPos = GetPos + pkt_len;

      // check for control message
      if (eStreamId(header->stream) == sidControl)
        CorkReq = true;

    } else {
      // end of prev frame
      Count = min(Count, (int)(NextHeaderPos-GetPos));
    }

    errno = 0;
    n = write(m_fd, Data, Count);

    if (n <= 0) {

      if (n == 0) {
        LOGERR("cBackgroundWriter: Client disconnected data stream ?");
        break;
      }

      if (errno == EINTR || errno == EWOULDBLOCK)
        continue;

      LOGERR("cBackgroundWriter: TCP write error");
      break;
    }

    GetPos += n;
    m_RingBuffer.Del(n);
  }

  m_RingBuffer.Clear();
}