aboutsummaryrefslogtreecommitdiff
path: root/plugins/youtube/YoutubeMediaProxy.hpp
blob: cc797a962f7027025d4b60fc8c1117294de2e0dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#pragma once

#include "../../include/Program.hpp"
#include <string>
#include <functional>

// TODO: Sync sequence for video and audio (for live stream).

namespace QuickMedia {
    using ThrottleHandler = std::function<void()>;

    class YoutubeMediaProxy {
    public:
        enum Error {
            OK,
            ERROR
        };

        virtual ~YoutubeMediaProxy() = default;

        virtual bool start(const std::string &youtube_media_url, int64_t content_length) = 0;
        // This should be the last call. Do not call |start| after this. TODO: Allow restarting with |start| after |stop| is called.
        virtual void stop() = 0;
        virtual Error update() = 0;
        virtual bool get_address(std::string &address) = 0;

        bool start_download(const std::string &media_url, ReadProgram &read_program, int64_t range_start, bool include_header, bool is_livestream = false, int livestream_sequence = -1);
    private:
        int rn = 0;
        int rbuf = 0;
    };

    class YoutubeStaticMediaProxy : public YoutubeMediaProxy {
    public:
        YoutubeStaticMediaProxy(ThrottleHandler throttle_handler = nullptr);
        YoutubeStaticMediaProxy(YoutubeStaticMediaProxy&) = delete;
        YoutubeStaticMediaProxy&operator=(YoutubeStaticMediaProxy&) = delete;
        ~YoutubeStaticMediaProxy();

        bool start(const std::string &youtube_media_url, int64_t content_length) override;
        void stop() override;
        Error update() override;
        bool get_address(std::string &address) override;
    private:
        void on_client_disconnect();
        Error read_client_data();
        void clear_download_state();
        // If |new_range_start| is not -1 then the start range is set to that
        Error update_download_program_status(bool client_disconnected, int64_t new_range_start = -1, bool restart_download = false);
        Error continue_send(const char *buffer_start, size_t total_bytes_to_write, int &buffer_offset);
        Error handle_download();
        // Returns the client fd or -1
        int accept_client();
    private:
        int socket_fd = -1;
        int port = 0;
        int client_fd = -1;
        std::string youtube_media_url;
        int64_t content_length = 0;
        ReadProgram downloader_read_program;
        int download_read_buffer_offset = 0;
        ssize_t downloader_num_read_bytes = 0;
        int64_t download_range_start = 0;
        int64_t current_download_range = 0;
        std::string download_header;
        bool download_header_finished = false;
        bool download_header_sent = false;
        bool download_header_remaining_sent = false;
        int download_header_written_offset = 0;
        int download_header_offset_to_end_of_header = 0;
        time_t download_start_time = 0;
        time_t throttle_start_time = 0;
        int64_t total_downloaded_bytes = 0;
        bool download_started = false;
        bool throttle_started = false;
        bool throttle_callback_called = false;
        ThrottleHandler throttle_handler = nullptr;
        bool client_request_finished = false;
        std::string client_request_buffer;
        char download_read_buffer[16384];
    };

    // TODO: Add throttle detection for live streams
    class YoutubeLiveStreamMediaProxy : public YoutubeMediaProxy {
    public:
        YoutubeLiveStreamMediaProxy() = default;
        YoutubeLiveStreamMediaProxy(YoutubeLiveStreamMediaProxy&) = delete;
        YoutubeLiveStreamMediaProxy&operator=(YoutubeLiveStreamMediaProxy&) = delete;
        ~YoutubeLiveStreamMediaProxy();

        bool start(const std::string &youtube_media_url, int64_t content_length) override;
        void stop() override;
        Error update() override;
        bool get_address(std::string &address) override;
    private:
        Error update_download_program_status();
        Error continue_send(const char *buffer_start, size_t total_bytes_to_write, int &buffer_offset);
    private:
        ReadProgram downloader_read_program;
        std::string youtube_media_url;
        int fd[2];
        int64_t livestream_sequence_num = -1;
        std::string download_header;
        bool download_header_finished = false;
        bool download_header_remaining_sent = false;
        int download_header_written_offset = 0;
        int download_read_buffer_offset = 0;
        ssize_t downloader_num_read_bytes = 0;
        char download_read_buffer[16384];
    };
}