1 /* 2 * Copyright (c) 2022-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef HISTREAMER_DOWNLOADER_H 17 #define HISTREAMER_DOWNLOADER_H 18 19 #include <functional> 20 #include <memory> 21 #include <string> 22 #include "network_client.h" 23 #include "osal/thread/task.h" 24 #include "blocking_queue.h" 25 #include "osal/utils/util.h" 26 27 namespace OHOS { 28 namespace Media { 29 namespace Plugin { 30 namespace HttpPlugin { 31 enum struct DownloadStatus { 32 PARTTAL_DOWNLOAD, 33 }; 34 35 struct HeaderInfo { 36 char contentType[32]; // 32 chars 37 size_t fileContentLen {0}; 38 long contentLen {0}; 39 bool isChunked {false}; 40 UpdateHeaderInfo41 void Update(const HeaderInfo* info) 42 { 43 (void)memcpy_s(contentType, sizeof(contentType), info->contentType, sizeof(contentType)); 44 fileContentLen = info->fileContentLen; 45 contentLen = info->contentLen; 46 isChunked = info->isChunked; 47 } 48 GetFileContentLengthHeaderInfo49 size_t GetFileContentLength() const 50 { 51 while (fileContentLen == 0 && !isChunked) { 52 OSAL::SleepFor(10); // 10, wait for fileContentLen updated 53 } 54 return fileContentLen; 55 } 56 }; 57 58 // uint8_t* : the data should save 59 // uint32_t : length 60 using DataSaveFunc = std::function<bool(uint8_t*, uint32_t, int64_t)>; 61 class Downloader; 62 class DownloadRequest; 63 using StatusCallbackFunc = std::function<void(DownloadStatus, std::shared_ptr<Downloader>&, 64 std::shared_ptr<DownloadRequest>&)>; 65 66 class DownloadRequest { 67 public: 68 DownloadRequest(const std::string& url, DataSaveFunc saveData, StatusCallbackFunc statusCallback, 69 bool requestWholeFile = false); 70 size_t GetFileContentLength() const; 71 void SaveHeader(const HeaderInfo* header); 72 bool IsChunked() const; 73 bool IsEos() const; 74 int GetRetryTimes(); 75 NetworkClientErrorCode GetClientError(); 76 NetworkServerErrorCode GetServerError(); IsSame(const std::shared_ptr<DownloadRequest> & other)77 bool IsSame(const std::shared_ptr<DownloadRequest>& other) 78 { 79 return url_ == other->url_ && startPos_ == other->startPos_; 80 } GetUrl()81 std::string GetUrl() 82 { 83 return url_; 84 } 85 86 private: 87 void WaitHeaderUpdated() const; 88 89 std::string url_; 90 DataSaveFunc saveData_; 91 StatusCallbackFunc statusCallback_; 92 93 HeaderInfo headerInfo_; 94 95 bool isHeaderUpdated {false}; 96 bool isEos_ {false}; // file download finished 97 int64_t startPos_; 98 bool isDownloading_; 99 bool requestWholeFile_ {false}; 100 int requestSize_; 101 int retryTimes_ {0}; 102 NetworkClientErrorCode clientError_ {NetworkClientErrorCode::ERROR_OK}; 103 NetworkServerErrorCode serverError_ {0}; 104 105 friend class Downloader; 106 }; 107 108 class Downloader { 109 public: 110 explicit Downloader(std::string name) noexcept; 111 ~Downloader() = default; 112 113 bool Download(const std::shared_ptr<DownloadRequest>& request, int32_t waitMs); 114 void Start(); 115 void Pause(); 116 void Resume(); 117 void Stop(); 118 bool Seek(int64_t offset); 119 bool Retry(const std::shared_ptr<DownloadRequest>& request); 120 private: 121 bool BeginDownload(); 122 123 void HttpDownloadLoop(); 124 static size_t RxBodyData(void* buffer, size_t size, size_t nitems, void* userParam); 125 static size_t RxHeaderData(void* buffer, size_t size, size_t nitems, void* userParam); 126 127 std::string name_; 128 std::shared_ptr<NetworkClient> client_; 129 std::shared_ptr<OSAL::Task> task_; 130 std::shared_ptr<BlockingQueue<std::shared_ptr<DownloadRequest>>> requestQue_; 131 132 std::shared_ptr<DownloadRequest> currentRequest_; 133 bool shouldStartNextRequest {false}; 134 }; 135 } 136 } 137 } 138 } 139 #endif