1 /* 2 * Copyright (c) 2024-2024 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 "osal/task/task.h" 23 #include "osal/task/mutex.h" 24 #include "osal/task/condition_variable.h" 25 #include "osal/task/blocking_queue.h" 26 #include "osal/utils/util.h" 27 #include "network/network_client.h" 28 #include "network/network_typs.h" 29 #include <chrono> 30 #include "securec.h" 31 #include "common/media_source.h" 32 #include "media_source_loading_request.h" 33 34 namespace OHOS { 35 namespace Media { 36 namespace Plugins { 37 namespace HttpPlugin { 38 39 enum struct DownloadStatus { 40 PARTTAL_DOWNLOAD, 41 }; 42 43 struct HeaderInfo { 44 char contentType[32]; // 32 chars 45 size_t fileContentLen {0}; 46 mutable size_t retryTimes {0}; 47 const static size_t maxRetryTimes {100}; 48 const static int sleepTime {10}; 49 long contentLen {0}; 50 bool isChunked {false}; 51 std::atomic<bool> isClosed {false}; 52 bool isServerAcceptRange {false}; 53 UpdateHeaderInfo54 void Update(const HeaderInfo* info) 55 { 56 NZERO_LOG(memcpy_s(contentType, sizeof(contentType), info->contentType, sizeof(contentType))); 57 fileContentLen = info->fileContentLen; 58 contentLen = info->contentLen; 59 isChunked = info->isChunked; 60 } 61 GetFileContentLengthHeaderInfo62 size_t GetFileContentLength() const 63 { 64 while (fileContentLen == 0 && !isChunked && !isClosed && retryTimes < maxRetryTimes) { 65 OSAL::SleepFor(sleepTime); // 10, wait for fileContentLen updated 66 retryTimes++; 67 } 68 return fileContentLen; 69 } 70 }; 71 72 // uint8_t* : the data should save 73 // uint32_t : length 74 using DataSaveFunc = std::function<uint32_t(uint8_t*, uint32_t, bool)>; 75 class Downloader; 76 class DownloadRequest; 77 using StatusCallbackFunc = std::function<void(DownloadStatus, std::shared_ptr<Downloader>&, 78 std::shared_ptr<DownloadRequest>&)>; 79 using DownloadDoneCbFunc = std::function<void(const std::string&, const std::string&)>; 80 81 enum class RequestProtocolType : int32_t { 82 HTTP = 0, 83 HLS = 1, 84 DASH = 2, 85 }; 86 87 class DownloadRequest { 88 public: 89 DownloadRequest(const std::string& url, DataSaveFunc saveData, StatusCallbackFunc statusCallback, 90 bool requestWholeFile = false); 91 DownloadRequest(const std::string& url, double duration, DataSaveFunc saveData, StatusCallbackFunc statusCallback, 92 bool requestWholeFile = false); 93 DownloadRequest(DataSaveFunc saveData, StatusCallbackFunc statusCallback, RequestInfo requestInfo, 94 bool requestWholeFile = false); 95 DownloadRequest(double duration, DataSaveFunc saveData, StatusCallbackFunc statusCallback, RequestInfo requestInfo, 96 bool requestWholeFile = false); 97 ~DownloadRequest(); 98 size_t GetFileContentLength() const; 99 size_t GetFileContentLengthNoWait() const; 100 void SaveHeader(const HeaderInfo* header); 101 Seekable IsChunked(bool isInterruptNeeded); 102 bool IsEos() const; 103 int GetRetryTimes() const; 104 int32_t GetClientError() const; 105 int32_t GetServerError() const; IsSame(const std::shared_ptr<DownloadRequest> & other)106 bool IsSame(const std::shared_ptr<DownloadRequest>& other) const 107 { 108 return url_ == other->url_ && startPos_ == other->startPos_; 109 } GetUrl()110 const std::string GetUrl() const 111 { 112 return url_; 113 } SetIsAuthRequest(bool isAuthRequest)114 void SetIsAuthRequest(bool isAuthRequest) 115 { 116 isAuthRequest_ = isAuthRequest; 117 } IsAuthRequest()118 bool IsAuthRequest() const 119 { 120 return isAuthRequest_; 121 } GetHttpHeader()122 const std::map<std::string, std::string>& GetHttpHeader() const 123 { 124 return httpHeader_; 125 } SetIsIndexM3u8Request(bool isIndexM3u8Request)126 void SetIsIndexM3u8Request(bool isIndexM3u8Request) 127 { 128 isIndexM3u8Request_ = isIndexM3u8Request; 129 } IsIndexM3u8Request()130 bool IsIndexM3u8Request() const 131 { 132 return isIndexM3u8Request_; 133 } 134 bool IsClosed() const; 135 void Close(); 136 double GetDuration() const; 137 void SetStartTimePos(int64_t startTimePos); 138 void SetRangePos(int64_t startPos, int64_t endPos); 139 void SetDownloadDoneCb(DownloadDoneCbFunc downloadDoneCallback); 140 int64_t GetNowTime(); 141 uint32_t GetBitRate() const; 142 bool IsChunkedVod() const; 143 bool IsM3u8Request() const; 144 bool IsServerAcceptRange() const; 145 void GetLocation(std::string& location) const; 146 void SetRequestProtocolType(RequestProtocolType protocolType); 147 void SetIsM3u8Request(bool isM3u8Request); 148 std::atomic<bool> isHeaderUpdated_ {false}; 149 private: 150 void WaitHeaderUpdated() const; 151 std::string url_; 152 double duration_ {0.0}; 153 DataSaveFunc saveData_; 154 StatusCallbackFunc statusCallback_; 155 DownloadDoneCbFunc downloadDoneCallback_; 156 mutable std::atomic<bool> isHeaderUpdating_ {false}; 157 HeaderInfo headerInfo_; 158 std::map<std::string, std::string> httpHeader_; 159 RequestInfo requestInfo_ {}; 160 bool isEos_ {false}; // file download finished 161 int64_t startPos_ {0}; 162 int64_t endPos_ {-1}; 163 int64_t startTimePos_ {0}; 164 bool isDownloading_ {false}; 165 bool requestWholeFile_ {false}; 166 int requestSize_ {0}; 167 int retryTimes_ {0}; 168 int32_t clientError_ {0}; 169 int32_t serverError_ {0}; 170 bool shouldSaveData_ {true}; 171 int64_t downloadStartTime_ {0}; 172 int64_t downloadDoneTime_ {0}; 173 int64_t realRecvContentLen_ {0}; 174 friend class Downloader; 175 std::string location_; 176 mutable std::atomic<size_t> times_ {0}; 177 std::atomic<bool> isInterruptNeeded_{false}; 178 std::atomic<bool> retryOnGoing_ {false}; 179 int64_t dropedDataLen_ {0}; 180 std::atomic<bool> isFirstRangeRequestReady_ {false}; 181 bool isM3u8Request_ {false}; 182 bool isIndexM3u8Request_ {false}; 183 bool isAuthRequest_ {false}; 184 RequestProtocolType protocolType_ {RequestProtocolType::HTTP}; 185 }; 186 187 class Downloader { 188 public: 189 explicit Downloader(const std::string& name) noexcept; 190 explicit Downloader(const std::string& name, std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader) noexcept; 191 virtual ~Downloader(); 192 193 bool Download(const std::shared_ptr<DownloadRequest>& request, int32_t waitMs); 194 void Start(); 195 void Pause(bool isAsync = false); 196 void Resume(); 197 void Stop(bool isAsync = false); 198 bool Seek(int64_t offset); 199 void Cancel(); 200 bool Retry(const std::shared_ptr<DownloadRequest>& request); 201 void SetRequestSize(size_t downloadRequestSize); 202 void GetIp(std::string &ip); 203 void SetAppUid(int32_t appUid); 204 const std::shared_ptr<DownloadRequest>& GetCurrentRequest(); 205 void SetInterruptState(bool isInterruptNeeded); 206 void SetAppState(bool isAppBackground); 207 void StopBufferring(); 208 209 private: 210 bool BeginDownload(); 211 void HttpDownloadLoop(); 212 void RequestData(); 213 void HandlePlayingFinish(); 214 void HandleRetOK(); 215 static size_t RxBodyData(void* buffer, size_t size, size_t nitems, void* userParam); 216 static size_t RxHeaderData(void* buffer, size_t size, size_t nitems, void* userParam); 217 static bool HandleContentRange(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems); 218 static bool HandleContentType(HeaderInfo* info, char* key, char* next, size_t headerSize, 219 Downloader* mediaDownloader); 220 static bool HandleContentEncode(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems); 221 static bool HandleContentLength(HeaderInfo* info, char* key, char* next, Downloader* mediaDownloader); 222 static bool HandleRange(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems); 223 static void UpdateHeaderInfo(Downloader* mediaDownloader); 224 static size_t DropRetryData(void* buffer, size_t dataLen, Downloader* mediaDownloader); 225 static bool IsDropDataRetryRequest(Downloader* mediaDownloader); 226 static void UpdateCurRequest(Downloader* mediaDownloader, HeaderInfo* header); 227 static void HandleFileContentLen(HeaderInfo* header); 228 void PauseLoop(bool isAsync = false); 229 void WaitLoopPause(); 230 void NotifyLoopPause(); 231 void HandleRetErrorCode(); 232 void DonwloaderInit(const std::string& name); 233 void OpenAppUri(); 234 235 std::string name_; 236 std::shared_ptr<NetworkClient> client_; 237 std::shared_ptr<BlockingQueue<std::shared_ptr<DownloadRequest>>> requestQue_; 238 FairMutex operatorMutex_{}; 239 std::shared_ptr<DownloadRequest> currentRequest_; 240 std::atomic<bool> shouldStartNextRequest {false}; 241 int32_t noTaskLoopTimes_ {0}; 242 size_t downloadRequestSize_ {0}; 243 std::shared_ptr<Task> task_; 244 std::atomic<bool> isDestructor_ {false}; 245 std::atomic<bool> isClientClose_ {false}; 246 std::atomic<bool> isInterruptNeeded_{false}; 247 248 enum struct LoopStatus { 249 IDLE, 250 START, 251 PAUSE, 252 }; 253 std::atomic<LoopStatus> loopStatus_ {LoopStatus::IDLE}; 254 FairMutex loopPauseMutex_ {}; 255 ConditionVariable loopPauseCond_; 256 std::atomic<bool> isAppBackground_ {false}; 257 258 int64_t uuid_ {0}; 259 FairMutex closeMutex_ {}; 260 std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader_; 261 std::shared_ptr<IMediaSourceLoadingRequest> loadingReques_; 262 bool isNotBlock_ {false}; 263 std::string appPreviousRequestUrl_ {}; 264 }; 265 } 266 } 267 } 268 } 269 #endif