From: Steinar H. Gunderson Date: Thu, 23 Jul 2015 16:31:06 +0000 (+0200) Subject: Allow prebuffer to happen by playing data from the backlog. X-Git-Tag: 1.2.0~4 X-Git-Url: https://git.sesse.net/?p=cubemap;a=commitdiff_plain;h=150a9636b58ac912ed4d46e6d8379beb5632f2f8 Allow prebuffer to happen by playing data from the backlog. This won't reduce the latency (although it shouldn't increase it either, unless you have extreme bitrate changes), but it should give a picture on screen much sooner, hopefully getting rid of the “what's going on, why is nothing starting” feeling. --- diff --git a/server.cpp b/server.cpp index 14162f5..e99dbea 100644 --- a/server.cpp +++ b/server.cpp @@ -469,20 +469,43 @@ sending_header_or_error_again: return; } - // Start sending from the first keyframe we get. In other - // words, we won't send any of the backlog, but we'll start - // sending immediately as we get the next keyframe block. - // This is postcondition #3. Stream *stream = client->stream; if (client->stream_pos == size_t(-2)) { + // Start sending from the beginning of the backlog. client->stream_pos = std::min( stream->bytes_received - stream->backlog_size, 0); client->state = Client::SENDING_DATA; goto sending_data; - } else { + } else if (stream->prebuffering_bytes == 0) { + // Start sending from the first keyframe we get. In other + // words, we won't send any of the backlog, but we'll start + // sending immediately as we get the next keyframe block. + // Note that this is functionally identical to the next if branch, + // except that we save a binary search. client->stream_pos = stream->bytes_received; client->state = Client::WAITING_FOR_KEYFRAME; + } else { + // We're not going to send anything to the client before we have + // N bytes. However, this wait might be boring; we can just as well + // use it to send older data if we have it. We use lower_bound() + // so that we are conservative and never add extra latency over just + // waiting (assuming CBR or nearly so); otherwise, we could want e.g. + // 100 kB prebuffer but end up sending a 10 MB GOP. + deque::const_iterator starting_point_it = + lower_bound(stream->suitable_starting_points.begin(), + stream->suitable_starting_points.end(), + stream->bytes_received - stream->prebuffering_bytes); + if (starting_point_it == stream->suitable_starting_points.end()) { + // None found. Just put us at the end, and then wait for the + // first keyframe to appear. + client->stream_pos = stream->bytes_received; + client->state = Client::WAITING_FOR_KEYFRAME; + } else { + client->stream_pos = *starting_point_it; + client->state = Client::PREBUFFERING; + goto prebuffering; + } } // Fall through. } @@ -501,6 +524,7 @@ sending_header_or_error_again: // Fall through. } case Client::PREBUFFERING: { +prebuffering: Stream *stream = client->stream; size_t bytes_to_send = stream->bytes_received - client->stream_pos; assert(bytes_to_send <= stream->backlog_size);