• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     }
GetHttpHeader()114     const std::map<std::string, std::string>& GetHttpHeader() const
115     {
116         return httpHeader_;
117     }
SetUrl(const std::string & url)118     void SetUrl(const std::string& url)
119     {
120         url_ = url;
121     }
SetIsAuthRequest(bool isAuthRequest)122     void SetIsAuthRequest(bool isAuthRequest)
123     {
124         isAuthRequest_ = isAuthRequest;
125     }
IsAuthRequest()126     bool IsAuthRequest() const
127     {
128         return isAuthRequest_;
129     }
SetIsIndexM3u8Request(bool isIndexM3u8Request)130     void SetIsIndexM3u8Request(bool isIndexM3u8Request)
131     {
132         isIndexM3u8Request_ = isIndexM3u8Request;
133     }
IsIndexM3u8Request()134     bool IsIndexM3u8Request() const
135     {
136         return isIndexM3u8Request_;
137     }
138     bool IsClosed() const;
139     void Close();
140     double GetDuration() const;
141     void SetStartTimePos(int64_t startTimePos);
142     void SetRangePos(int64_t startPos, int64_t endPos);
143     void SetDownloadDoneCb(DownloadDoneCbFunc downloadDoneCallback);
144     int64_t GetNowTime();
145     uint32_t GetBitRate() const;
146     bool IsChunkedVod() const;
147     bool IsM3u8Request() const;
148     bool IsServerAcceptRange() const;
149     void GetLocation(std::string& location) const;
150     void SetRequestProtocolType(RequestProtocolType protocolType);
151     void SetIsM3u8Request(bool isM3u8Request);
152     std::atomic<bool> isHeaderUpdated_ {false};
153     std::atomic<bool> haveRedirectRetry_ {false};
154 private:
155     void WaitHeaderUpdated() const;
156     std::string url_;
157     double duration_ {0.0};
158     DataSaveFunc saveData_;
159     StatusCallbackFunc statusCallback_;
160     DownloadDoneCbFunc downloadDoneCallback_;
161     mutable std::atomic<bool> isHeaderUpdating_ {false};
162     HeaderInfo headerInfo_;
163     std::map<std::string, std::string> httpHeader_;
164     RequestInfo requestInfo_ {};
165     bool isEos_ {false}; // file download finished
166     int64_t startPos_ {0};
167     int64_t endPos_ {-1};
168     int64_t startTimePos_ {0};
169     bool isDownloading_ {false};
170     bool requestWholeFile_ {false};
171     int requestSize_ {0};
172     int preRequestSize_ {0};
173     int retryTimes_ {0};
174     int32_t clientError_ {0};
175     int32_t serverError_ {0};
176     bool shouldSaveData_ {true};
177     int64_t downloadStartTime_ {0};
178     int64_t downloadDoneTime_ {0};
179     int64_t realRecvContentLen_ {0};
180     friend class Downloader;
181     std::string location_;
182     mutable std::atomic<size_t> times_ {0};
183     std::atomic<bool> isInterruptNeeded_{false};
184     std::atomic<bool> retryOnGoing_ {false};
185     int64_t dropedDataLen_ {0};
186     std::atomic<bool> isFirstRangeRequestReady_ {false};
187     bool isM3u8Request_ {false};
188     bool isIndexM3u8Request_ {false};
189     bool isAuthRequest_ {false};
190     RequestProtocolType protocolType_ {RequestProtocolType::HTTP};
191 };
192 
193 class Downloader {
194 public:
195     explicit Downloader(const std::string& name) noexcept;
196     explicit Downloader(const std::string& name, std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader) noexcept;
197     virtual ~Downloader();
198 
199     bool Download(const std::shared_ptr<DownloadRequest>& request, int32_t waitMs);
200     void Start();
201     void Pause(bool isAsync = false);
202     void Resume();
203     void Stop(bool isAsync = false);
204     bool Seek(int64_t offset);
205     void Cancel();
206     bool Retry(const std::shared_ptr<DownloadRequest>& request);
207     void SetRequestSize(size_t downloadRequestSize);
208     void GetIp(std::string &ip);
209     void SetAppUid(int32_t appUid);
210     const std::shared_ptr<DownloadRequest>& GetCurrentRequest();
211     void SetInterruptState(bool isInterruptNeeded);
212     void SetAppState(bool isAppBackground);
213     void StopBufferring();
214     std::string GetContentType();
215     void ReStart();
216 
217 private:
218     bool BeginDownload();
219     void HttpDownloadLoop();
220     void RequestData();
221     void HandlePlayingFinish();
222     void HandleRetOK();
223     void HandleResponseCb(int32_t clientCode, int32_t serverCode, Status& ret);
224     static size_t RxBodyData(void* buffer, size_t size, size_t nitems, void* userParam);
225     static size_t RxHeaderData(void* buffer, size_t size, size_t nitems, void* userParam);
226     static bool HandleContentRange(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems);
227     static bool HandleContentType(HeaderInfo* info, char* key, char* next, size_t headerSize,
228                                   Downloader* mediaDownloader);
229     static bool HandleContentEncode(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems);
230     static bool HandleContentLength(HeaderInfo* info, char* key, char* next, Downloader* mediaDownloader);
231     static bool HandleRange(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems);
232     static void UpdateHeaderInfo(Downloader* mediaDownloader);
233     static size_t DropRetryData(void* buffer, size_t dataLen, Downloader* mediaDownloader);
234     static bool IsDropDataRetryRequest(Downloader* mediaDownloader);
235     static void UpdateCurRequest(Downloader* mediaDownloader, HeaderInfo* header);
236     static void HandleFileContentLen(HeaderInfo* header);
237     static void UpdateRequestSize(Downloader* mediaDownloader);
238     static void ToLower(char* str);
239     void PauseLoop(bool isAsync = false);
240     void WaitLoopPause();
241     void NotifyLoopPause();
242     void HandleRetErrorCode();
243     void DonwloaderInit(const std::string& name);
244     void OpenAppUri();
245     void HandleRedirect(Status& ret);
246 
247     std::string name_;
248     std::shared_ptr<NetworkClient> client_;
249     std::shared_ptr<BlockingQueue<std::shared_ptr<DownloadRequest>>> requestQue_;
250     FairMutex operatorMutex_{};
251     std::shared_ptr<DownloadRequest> currentRequest_;
252     std::atomic<bool> shouldStartNextRequest {false};
253     int32_t noTaskLoopTimes_ {0};
254     size_t downloadRequestSize_ {0};
255     std::shared_ptr<Task> task_;
256     std::atomic<bool> isDestructor_ {false};
257     std::atomic<bool> isClientClose_ {false};
258     std::atomic<bool> isInterruptNeeded_{false};
259 
260     enum struct LoopStatus {
261         IDLE,
262         START,
263         PAUSE,
264     };
265     std::atomic<LoopStatus> loopStatus_ {LoopStatus::IDLE};
266     FairMutex loopPauseMutex_ {};
267     ConditionVariable loopPauseCond_;
268     std::atomic<bool> isAppBackground_ {false};
269 
270     int64_t uuid_ {0};
271     FairMutex closeMutex_ {};
272     std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader_;
273     std::shared_ptr<IMediaSourceLoadingRequest> loadingReques_;
274     bool isNotBlock_ {false};
275     std::string appPreviousRequestUrl_ {};
276     std::string contentType_;
277     bool isContentTypeUpdated_{false};
278     ConditionVariable sleepCond_;
279     FairMutex sleepMutex_;
280 };
281 }
282 }
283 }
284 }
285 #endif