}
timeout_time.tv_sec -= REQUEST_READ_TIMEOUT_SEC;
while (!clients_ordered_by_connect_time.empty()) {
- pair<timespec, int> &connect_time_and_fd = clients_ordered_by_connect_time.front();
+ const pair<timespec, int> &connect_time_and_fd = clients_ordered_by_connect_time.front();
// See if we have reached the end of clients to process.
if (is_earlier(timeout_time, connect_time_and_fd.first)) {
// If this client doesn't exist anymore, just ignore it
// (it was deleted earlier).
- std::map<int, Client>::iterator client_it = clients.find(connect_time_and_fd.second);
+ map<int, Client>::iterator client_it = clients.find(connect_time_and_fd.second);
if (client_it == clients.end()) {
clients_ordered_by_connect_time.pop();
continue;
}
}
-int Server::lookup_stream_by_url(const std::string &url) const
+int Server::lookup_stream_by_url(const string &url) const
{
map<string, int>::const_iterator url_it = url_map.find(url);
if (url_it == url_map.end()) {
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)) {
- client->stream_pos = std::min<size_t>(
+ // Start sending from the beginning of the backlog.
+ client->stream_pos = min<size_t>(
stream->bytes_received - stream->backlog_size,
0);
client->state = Client::SENDING_DATA;
- } else {
+ goto sending_data;
+ } 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<size_t>::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;
+ }
}
- stream->put_client_to_sleep(client);
- return;
+ // Fall through.
}
case Client::WAITING_FOR_KEYFRAME: {
Stream *stream = client->stream;
// 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);
// Fall through.
}
case Client::SENDING_DATA: {
+sending_data:
skip_lost_data(client);
Stream *stream = client->stream;