From a0c0f0bd551155270b11ac23c7f1c526a20a44b9 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 5 Aug 2021 10:22:41 +0200 Subject: Youtube: attempt to auto-detect throttling and restart download --- src/plugins/youtube/YoutubeMediaProxy.cpp | 57 ++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 4 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/youtube/YoutubeMediaProxy.cpp b/src/plugins/youtube/YoutubeMediaProxy.cpp index 6642b86..ed38981 100644 --- a/src/plugins/youtube/YoutubeMediaProxy.cpp +++ b/src/plugins/youtube/YoutubeMediaProxy.cpp @@ -19,6 +19,8 @@ namespace QuickMedia { static const int MAX_BUFFER_SIZE = 65536; static const int RANGE = 524287; + static const int64_t THROTTLED_DOWNLOAD_LIMIT_KB = 80; // TODO: What about people with really slow internet? What if the video player cache is not working and download is stuck, leading to false download speed calculation? + static const int64_t THROTTLED_DURATION_SECS = 3; static const char download_error_response_msg[] = "HTTP/1.1 500 Internal Server Error\r\n" "Content-Length: 0\r\n\r\n"; @@ -73,6 +75,10 @@ namespace QuickMedia { return true; } + YoutubeStaticMediaProxy::YoutubeStaticMediaProxy(ThrottleHandler throttle_handler) : throttle_handler(std::move(throttle_handler)) { + + } + YoutubeStaticMediaProxy::~YoutubeStaticMediaProxy() { stop(); } @@ -193,6 +199,8 @@ namespace QuickMedia { void YoutubeStaticMediaProxy::on_client_disconnect() { client_request_buffer.clear(); client_request_finished = false; + download_started = false; + throttle_started = false; if(client_fd != -1) { close(client_fd); @@ -248,6 +256,8 @@ namespace QuickMedia { if(header_end != std::string::npos) { client_request_buffer.erase(header_end + 4); client_request_finished = true; + download_started = false; + throttle_started = false; int new_start_range = header_extract_start_range(client_request_buffer); //fprintf(stderr, "got new range from client: %d\n", new_start_range); @@ -284,7 +294,7 @@ namespace QuickMedia { if(client_disconnected) { wait_program(downloader_read_program.pid); } else { - if(wait_program_non_blocking(downloader_read_program.pid, &program_status) == 0) + if(wait_program_non_blocking(downloader_read_program.pid, &program_status) == 0 && program_status == 0) return Error::OK; } downloader_read_program.pid = -1; @@ -444,6 +454,45 @@ namespace QuickMedia { Error err = update_download_program_status(false, -1, true); if(err != Error::OK) return err; + } else { + if(!download_started) { + total_downloaded_bytes = 0; + download_started = true; + throttle_started = false; + + struct timespec tp; + clock_gettime(CLOCK_BOOTTIME, &tp); + download_start_time = tp.tv_sec; + } + total_downloaded_bytes += downloader_num_read_bytes; + } + } + + if(download_started) { + struct timespec tp; + clock_gettime(CLOCK_BOOTTIME, &tp); + + int64_t time_elapsed = tp.tv_sec - download_start_time; + int64_t download_speed_kb_sec = 0; + if(time_elapsed > 0) + download_speed_kb_sec = (total_downloaded_bytes / time_elapsed) / 1024; + + if(download_speed_kb_sec < THROTTLED_DOWNLOAD_LIMIT_KB) { + if(throttle_started) { + if(tp.tv_sec - throttle_start_time >= THROTTLED_DURATION_SECS && !throttle_callback_called) { + total_downloaded_bytes = 0; + download_started = false; + throttle_started = false; + throttle_callback_called = true; + if(throttle_handler) + throttle_handler(); + } + } else { + throttle_started = true; + throttle_start_time = tp.tv_sec; + } + } else { + throttle_started = false; } } @@ -587,7 +636,7 @@ namespace QuickMedia { YoutubeMediaProxy::Error YoutubeLiveStreamMediaProxy::update_download_program_status() { int program_status = 0; - if(wait_program_non_blocking(downloader_read_program.pid, &program_status) == 0) + if(wait_program_non_blocking(downloader_read_program.pid, &program_status) == 0 && program_status == 0) return Error::OK; downloader_read_program.pid = -1; @@ -688,13 +737,13 @@ namespace QuickMedia { std::string sequence_num = header_extract_value(download_header, "x-sequence-num"); fprintf(stderr, "server sequence num: |%s|\n", sequence_num.c_str()); if(sequence_num.empty()) - fprintf(stderr, "YoutubeLiveStreamMediaProxy::handle_download: missing sequence num from server\n"); + fprintf(stderr, "YoutubeLiveStreamMediaProxy::update: missing sequence num from server\n"); else livestream_sequence_num = strtoll(sequence_num.c_str(), nullptr, 10); } } else { if(download_header.size() > MAX_BUFFER_SIZE) { - fprintf(stderr, "YoutubeLiveStreamMediaProxy::handle_download: buffer is full (malicious server?)\n"); + fprintf(stderr, "YoutubeLiveStreamMediaProxy::update: buffer is full (malicious server?)\n"); if(downloader_read_program.pid != -1) { kill(downloader_read_program.pid, SIGTERM); wait_program(downloader_read_program.pid); -- cgit v1.2.3