• 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     }
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