• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2023 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 #define MEDIA_PLUGIN
17 #define HST_LOG_TAG "Downloader"
18 
19 #include "avcodec_trace.h"
20 #include "downloader.h"
21 #include "osal/utils/steady_clock.h"
22 #include "securec.h"
23 #include "plugin/plugin_time.h"
24 #include "syspara/parameter.h"
25 
26 namespace OHOS {
27 namespace Media {
28 namespace Plugins {
29 namespace HttpPlugin {
30 namespace {
31 constexpr int PER_REQUEST_SIZE = 48 * 1024 * 10;
32 constexpr unsigned int SLEEP_TIME = 5;    // Sleep 5ms
33 constexpr size_t RETRY_TIMES = 6000;  // Retry 6000 times
34 constexpr size_t REQUEST_QUEUE_SIZE = 50;
35 constexpr long LIVE_CONTENT_LENGTH = 2147483646;
36 constexpr int32_t DOWNLOAD_LOG_FEQUENCE = 10;
37 constexpr int32_t LOOP_TIMES = 5;
38 constexpr int32_t MAX_LEN = 128;
39 const std::string USER_AGENT = "User-Agent";
40 const std::string DISPLAYVERSION = "const.product.software.version";
41 constexpr int FIRST_REQUEST_SIZE = 8 * 1024;
42 constexpr int MIN_REQUEST_SIZE = 2;
43 constexpr int SERVER_RANGE_ERROR_CODE = 416;
44 constexpr int32_t LOOP_LOG_FEQUENCE = 50;
45 }
46 
DownloadRequest(const std::string & url,DataSaveFunc saveData,StatusCallbackFunc statusCallback,bool requestWholeFile)47 DownloadRequest::DownloadRequest(const std::string& url, DataSaveFunc saveData, StatusCallbackFunc statusCallback,
48                                  bool requestWholeFile)
49     : url_(url), saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)),
50     requestWholeFile_(requestWholeFile)
51 {
52     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
53     headerInfo_.fileContentLen = 0;
54     headerInfo_.contentLen = 0;
55 }
56 
DownloadRequest(const std::string & url,double duration,DataSaveFunc saveData,StatusCallbackFunc statusCallback,bool requestWholeFile)57 DownloadRequest::DownloadRequest(const std::string& url,
58                                  double duration,
59                                  DataSaveFunc saveData,
60                                  StatusCallbackFunc statusCallback,
61                                  bool requestWholeFile)
62     : url_(url), duration_(duration), saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)),
63     requestWholeFile_(requestWholeFile)
64 {
65     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
66     headerInfo_.fileContentLen = 0;
67     headerInfo_.contentLen = 0;
68 }
69 
DownloadRequest(DataSaveFunc saveData,StatusCallbackFunc statusCallback,RequestInfo requestInfo,bool requestWholeFile)70 DownloadRequest::DownloadRequest(DataSaveFunc saveData, StatusCallbackFunc statusCallback, RequestInfo requestInfo,
71                                  bool requestWholeFile)
72     : saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)), requestInfo_(requestInfo),
73     requestWholeFile_(requestWholeFile)
74 {
75     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
76     headerInfo_.fileContentLen = 0;
77     headerInfo_.contentLen = 0;
78     url_ = requestInfo.url;
79     httpHeader_ = requestInfo.httpHeader;
80 }
81 
DownloadRequest(double duration,DataSaveFunc saveData,StatusCallbackFunc statusCallback,RequestInfo requestInfo,bool requestWholeFile)82 DownloadRequest::DownloadRequest(double duration,
83                                  DataSaveFunc saveData,
84                                  StatusCallbackFunc statusCallback,
85                                  RequestInfo requestInfo,
86                                  bool requestWholeFile)
87     : duration_(duration), saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)),
88     requestInfo_(requestInfo), requestWholeFile_(requestWholeFile)
89 {
90     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
91     headerInfo_.fileContentLen = 0;
92     headerInfo_.contentLen = 0;
93     url_ = requestInfo.url;
94     httpHeader_ = requestInfo.httpHeader;
95 }
96 
GetFileContentLength() const97 size_t DownloadRequest::GetFileContentLength() const
98 {
99     WaitHeaderUpdated();
100     return headerInfo_.GetFileContentLength();
101 }
102 
GetFileContentLengthNoWait() const103 size_t DownloadRequest::GetFileContentLengthNoWait() const
104 {
105     return headerInfo_.fileContentLen;
106 }
107 
SaveHeader(const HeaderInfo * header)108 void DownloadRequest::SaveHeader(const HeaderInfo* header)
109 {
110     MediaAVCodec::AVCodecTrace trace("DownloadRequest::SaveHeader");
111     headerInfo_.Update(header);
112     isHeaderUpdated = true;
113 }
114 
IsChunked(bool isInterruptNeeded)115 Seekable DownloadRequest::IsChunked(bool isInterruptNeeded)
116 {
117     isInterruptNeeded_ = isInterruptNeeded;
118     WaitHeaderUpdated();
119     if (isInterruptNeeded) {
120         MEDIA_LOG_I("Canceled");
121         return Seekable::INVALID;
122     }
123     if (headerInfo_.isChunked) {
124         return GetFileContentLength() == LIVE_CONTENT_LENGTH ? Seekable::SEEKABLE : Seekable::UNSEEKABLE;
125     } else {
126         return Seekable::SEEKABLE;
127     }
128 };
129 
IsEos() const130 bool DownloadRequest::IsEos() const
131 {
132     return isEos_;
133 }
134 
GetRetryTimes() const135 int DownloadRequest::GetRetryTimes() const
136 {
137     return retryTimes_;
138 }
139 
GetClientError() const140 NetworkClientErrorCode DownloadRequest::GetClientError() const
141 {
142     return clientError_;
143 }
144 
GetServerError() const145 NetworkServerErrorCode DownloadRequest::GetServerError() const
146 {
147     return serverError_;
148 }
149 
IsClosed() const150 bool DownloadRequest::IsClosed() const
151 {
152     return headerInfo_.isClosed;
153 }
154 
Close()155 void DownloadRequest::Close()
156 {
157     headerInfo_.isClosed = true;
158 }
159 
WaitHeaderUpdated() const160 void DownloadRequest::WaitHeaderUpdated() const
161 {
162     MediaAVCodec::AVCodecTrace trace("DownloadRequest::WaitHeaderUpdated");
163 
164     // Wait Header(fileContentLen etc.) updated
165     while (!isHeaderUpdated && times_ < RETRY_TIMES && !isInterruptNeeded_ && !headerInfo_.isClosed) {
166         Task::SleepInTask(SLEEP_TIME);
167         times_++;
168     }
169     uint32_t headerIsClosed = static_cast<uint32_t>(headerInfo_.isClosed.load());
170     MEDIA_LOG_D("isHeaderUpdated " PUBLIC_LOG_D32 ", times " PUBLIC_LOG_ZU ", isClosed " PUBLIC_LOG_D32,
171         isHeaderUpdated, times_, headerIsClosed);
172 }
173 
GetDuration() const174 double DownloadRequest::GetDuration() const
175 {
176     return duration_;
177 }
178 
SetStartTimePos(int64_t startTimePos)179 void DownloadRequest::SetStartTimePos(int64_t startTimePos)
180 {
181     startTimePos_ = startTimePos;
182     if (startTimePos_ > 0) {
183         shouldSaveData_ = false;
184     }
185 }
186 
SetRangePos(int64_t startPos,int64_t endPos)187 void DownloadRequest::SetRangePos(int64_t startPos, int64_t endPos)
188 {
189     startPos_ = startPos;
190     endPos_ = endPos;
191 }
192 
SetDownloadDoneCb(DownloadDoneCbFunc downloadDoneCallback)193 void DownloadRequest::SetDownloadDoneCb(DownloadDoneCbFunc downloadDoneCallback)
194 {
195     downloadDoneCallback_ = downloadDoneCallback;
196 }
197 
GetNowTime()198 int64_t DownloadRequest::GetNowTime()
199 {
200     return std::chrono::duration_cast<std::chrono::milliseconds>
201            (std::chrono::system_clock::now().time_since_epoch()).count();
202 }
203 
GetBitRate() const204 uint32_t DownloadRequest::GetBitRate() const
205 {
206     if ((downloadDoneTime_ == 0) || (downloadStartTime_ == 0) || (realRecvContentLen_ == 0)) {
207         return 0;
208     }
209     int64_t timeGap = downloadDoneTime_ - downloadStartTime_;
210     if (timeGap == 0) {
211         return 0;
212     }
213     uint32_t bitRate = static_cast<uint32_t>(realRecvContentLen_ * 1000 *
214                         1 * 8 / timeGap); // 1000:ms to sec 1:weight 8:byte to bit
215     return bitRate;
216 }
217 
IsChunkedVod() const218 bool DownloadRequest::IsChunkedVod() const
219 {
220     return headerInfo_.isChunked && headerInfo_.GetFileContentLength() == LIVE_CONTENT_LENGTH;
221 }
222 
IsM3u8Request() const223 bool DownloadRequest::IsM3u8Request() const
224 {
225     return isM3u8Request_;
226 }
227 
SetIsM3u8Request(bool isM3u8Request)228 void DownloadRequest::SetIsM3u8Request(bool isM3u8Request)
229 {
230     isM3u8Request_ = isM3u8Request;
231 }
232 
IsServerAcceptRange() const233 bool DownloadRequest::IsServerAcceptRange() const
234 {
235     if (headerInfo_.isChunked) {
236         return false;
237     }
238     return headerInfo_.isServerAcceptRange;
239 }
240 
GetLocation(std::string & location) const241 void DownloadRequest::GetLocation(std::string& location) const
242 {
243     location = location_;
244 }
245 
Downloader(const std::string & name)246 Downloader::Downloader(const std::string& name) noexcept : name_(std::move(name))
247 {
248     shouldStartNextRequest = true;
249 
250     client_ = NetworkClient::GetInstance(&RxHeaderData, &RxBodyData, this);
251     client_->Init();
252     requestQue_ = std::make_shared<BlockingQueue<std::shared_ptr<DownloadRequest>>>(name_ + "RequestQue",
253         REQUEST_QUEUE_SIZE);
254     task_ = std::make_shared<Task>(std::string("OS_" + name_ + "Downloader"));
255     task_->RegisterJob([this] {
256         {
257             AutoLock lk(loopPauseMutex_);
258             loopStatus_ = LoopStatus::START;
259         }
260         HttpDownloadLoop();
261         NotifyLoopPause();
262         return 0;
263     });
264     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Downloader ctor", FAKE_POINTER(this));
265 }
266 
~Downloader()267 Downloader::~Downloader()
268 {
269     isDestructor_ = true;
270     MEDIA_LOG_I("~Downloader In");
271     Stop(false);
272     if (task_ != nullptr) {
273         task_ = nullptr;
274     }
275     if (client_ != nullptr) {
276         client_->Deinit();
277         client_ = nullptr;
278     }
279     MEDIA_LOG_I("0x%{public}06" PRIXPTR " ~Downloader dtor", FAKE_POINTER(this));
280 }
281 
Download(const std::shared_ptr<DownloadRequest> & request,int32_t waitMs)282 bool Downloader::Download(const std::shared_ptr<DownloadRequest>& request, int32_t waitMs)
283 {
284     MEDIA_LOG_I("In");
285     if (isInterruptNeeded_) {
286         request->isInterruptNeeded_ = true;
287     }
288     requestQue_->SetActive(true);
289     if (waitMs == -1) { // wait until push success
290         requestQue_->Push(request);
291         return true;
292     }
293     return requestQue_->Push(request, static_cast<int>(waitMs));
294 }
295 
Start()296 void Downloader::Start()
297 {
298     MediaAVCodec::AVCodecTrace trace("Downloader::Start");
299     MEDIA_LOG_I("start Begin");
300     requestQue_->SetActive(true);
301     task_->Start();
302     MEDIA_LOG_I("start End");
303 }
304 
Pause(bool isAsync)305 void Downloader::Pause(bool isAsync)
306 {
307     MediaAVCodec::AVCodecTrace trace("Downloader::Pause");
308     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Pause Begin", FAKE_POINTER(this));
309     requestQue_->SetActive(false, false);
310     if (client_ != nullptr) {
311         isClientClose_ = true;
312         client_->Close(isAsync);
313     }
314     PauseLoop(true);
315     if (!isAsync) {
316         WaitLoopPause();
317     }
318     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Pause End", FAKE_POINTER(this));
319 }
320 
Cancel()321 void Downloader::Cancel()
322 {
323     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Cancel Begin", FAKE_POINTER(this));
324     requestQue_->SetActive(false, true);
325     shouldStartNextRequest = true;
326     if (client_ != nullptr) {
327         client_->Close(false);
328     }
329     PauseLoop(true);
330     WaitLoopPause();
331     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Cancel End", FAKE_POINTER(this));
332 }
333 
334 
Resume()335 void Downloader::Resume()
336 {
337     MediaAVCodec::AVCodecTrace trace("Downloader::Resume");
338     FALSE_RETURN_MSG(!isDestructor_ && !isInterruptNeeded_, "not Resume. is Destructor or InterruptNeeded");
339     {
340         AutoLock lock(operatorMutex_);
341         MEDIA_LOG_I("resume Begin");
342         if (isClientClose_ && client_ != nullptr && currentRequest_ != nullptr) {
343             isClientClose_ = false;
344             client_->Open(currentRequest_->url_, currentRequest_->httpHeader_, currentRequest_->requestInfo_.timeoutMs);
345         }
346         requestQue_->SetActive(true);
347         if (currentRequest_ != nullptr) {
348             currentRequest_->isEos_ = false;
349         }
350     }
351     Start();
352     MEDIA_LOG_I("resume End");
353 }
354 
Stop(bool isAsync)355 void Downloader::Stop(bool isAsync)
356 {
357     MediaAVCodec::AVCodecTrace trace("Downloader::Stop");
358     MEDIA_LOG_I("Stop Begin");
359     isDestructor_ = true;
360     if (requestQue_ != nullptr) {
361         requestQue_->SetActive(false);
362     }
363     if (currentRequest_ != nullptr) {
364         currentRequest_->isInterruptNeeded_ = true;
365         currentRequest_->Close();
366     }
367     if (client_ != nullptr) {
368         client_->Close(isAsync);
369         if (!isAsync) {
370             client_->Deinit();
371         }
372     }
373     shouldStartNextRequest = true;
374     if (task_ != nullptr) {
375         if (isAsync) {
376             task_->StopAsync();
377         } else {
378             task_->Stop();
379         }
380     }
381     MEDIA_LOG_I("Stop End");
382 }
383 
Seek(int64_t offset)384 bool Downloader::Seek(int64_t offset)
385 {
386     MediaAVCodec::AVCodecTrace trace("Downloader::Seek, offset: " + std::to_string(offset));
387     FALSE_RETURN_V_MSG(!isDestructor_ && !isInterruptNeeded_, false, "not Seek. is Destructor or InterruptNeeded");
388     AutoLock lock(operatorMutex_);
389     FALSE_RETURN_V(currentRequest_ != nullptr, false);
390     size_t contentLength = currentRequest_->GetFileContentLength();
391     MEDIA_LOG_I("Seek Begin, offset = " PUBLIC_LOG_D64 ", contentLength = " PUBLIC_LOG_ZU, offset, contentLength);
392     if (offset >= 0 && offset < static_cast<int64_t>(contentLength)) {
393         currentRequest_->startPos_ = offset;
394     }
395     size_t temp = currentRequest_->GetFileContentLength() - static_cast<size_t>(currentRequest_->startPos_);
396     currentRequest_->requestSize_ = static_cast<int>(std::min(temp, static_cast<size_t>(PER_REQUEST_SIZE)));
397     if (downloadRequestSize_ > 0) {
398         currentRequest_->requestSize_ = std::min(currentRequest_->requestSize_,
399             static_cast<int>(downloadRequestSize_));
400         downloadRequestSize_ = 0;
401     }
402     currentRequest_->isEos_ = false;
403     shouldStartNextRequest = false; // Reuse last request when seek
404     if (currentRequest_->retryTimes_ > 0) {
405         currentRequest_->retryTimes_ = 0;
406     }
407     return true;
408 }
409 
SetRequestSize(size_t downloadRequestSize)410 void Downloader::SetRequestSize(size_t downloadRequestSize)
411 {
412     downloadRequestSize_ = downloadRequestSize;
413 }
414 
GetIp(std::string & ip)415 void Downloader::GetIp(std::string &ip)
416 {
417     if (client_ != nullptr) {
418         client_->GetIp(ip);
419     }
420 }
421 
422 // Pause download thread before use currentRequest_
Retry(const std::shared_ptr<DownloadRequest> & request)423 bool Downloader::Retry(const std::shared_ptr<DownloadRequest>& request)
424 {
425     FALSE_RETURN_V_MSG(client_ != nullptr && !isDestructor_ && !isInterruptNeeded_, false,
426         "not Retry, client null or isDestructor or isInterruptNeeded");
427     {
428         AutoLock lock(operatorMutex_);
429         MEDIA_LOG_I("0x%{public}06" PRIXPTR " Retry Begin", FAKE_POINTER(this));
430         FALSE_RETURN_V(client_ != nullptr && !shouldStartNextRequest && !isDestructor_ && !isInterruptNeeded_, false);
431         requestQue_->SetActive(false, false);
432     }
433     PauseLoop(true);
434     WaitLoopPause();
435     {
436         AutoLock lock(operatorMutex_);
437         FALSE_RETURN_V(client_ != nullptr && !shouldStartNextRequest && !isDestructor_ && !isInterruptNeeded_, false);
438         client_->Close(false);
439         if (currentRequest_ != nullptr) {
440             if (currentRequest_->IsSame(request) && !shouldStartNextRequest) {
441                 currentRequest_->retryTimes_++;
442                 currentRequest_->retryOnGoing_ = true;
443                 currentRequest_->dropedDataLen_ = 0;
444                 MEDIA_LOG_D("Do retry.");
445             }
446             client_->Open(currentRequest_->url_, currentRequest_->httpHeader_, currentRequest_->requestInfo_.timeoutMs);
447             requestQue_->SetActive(true);
448             currentRequest_->isEos_ = false;
449         }
450     }
451     task_->Start();
452     return true;
453 }
454 
GetSystemParam(const std::string & key)455 std::string GetSystemParam(const std::string &key)
456 {
457     char value[MAX_LEN] = {0};
458     int32_t ret = GetParameter(key.c_str(), "", value, MAX_LEN);
459     if (ret < 0) {
460         return "";
461     }
462     return std::string(value);
463 }
464 
GetUserAgent()465 std::string GetUserAgent()
466 {
467     std::string displayVersion = GetSystemParam(DISPLAYVERSION);
468     std::string userAgent = " AVPlayerLib " + displayVersion;
469     return userAgent;
470 }
471 
BeginDownload()472 bool Downloader::BeginDownload()
473 {
474     MEDIA_LOG_I("BeginDownload");
475     std::string url = currentRequest_->url_;
476     std::map<std::string, std::string> httpHeader = currentRequest_->httpHeader_;
477 
478     if (currentRequest_->httpHeader_.count(USER_AGENT) <= 0) {
479         currentRequest_->httpHeader_[USER_AGENT] = GetUserAgent();
480         httpHeader[USER_AGENT] = GetUserAgent();
481         MEDIA_LOG_I("Set default UA.");
482     }
483 
484     int32_t timeoutMs = currentRequest_->requestInfo_.timeoutMs;
485     FALSE_RETURN_V(!url.empty(), false);
486     if (client_) {
487         client_->Open(url, httpHeader, timeoutMs);
488     }
489 
490     if (currentRequest_->endPos_ <= 0) {
491         currentRequest_->startPos_ = 0;
492         currentRequest_->requestSize_ = FIRST_REQUEST_SIZE;
493     } else {
494         int64_t temp = currentRequest_->endPos_ - currentRequest_->startPos_ + 1;
495         currentRequest_->requestSize_ = static_cast<int>(std::min(temp, static_cast<int64_t>(PER_REQUEST_SIZE)));
496     }
497     currentRequest_->isEos_ = false;
498     currentRequest_->retryTimes_ = 0;
499     currentRequest_->downloadStartTime_ = currentRequest_->GetNowTime();
500     MEDIA_LOG_I("End");
501     return true;
502 }
503 
HttpDownloadLoop()504 void Downloader::HttpDownloadLoop()
505 {
506     AutoLock lock(operatorMutex_);
507     MEDIA_LOGI_LIMIT(LOOP_LOG_FEQUENCE, "Downloader loop shouldStartNextRequest %{public}d",
508         shouldStartNextRequest.load());
509     if (shouldStartNextRequest) {
510         std::shared_ptr<DownloadRequest> tempRequest = requestQue_->Pop(1000); // 1000ms timeout limit.
511         if (!tempRequest) {
512             MEDIA_LOG_W("HttpDownloadLoop tempRequest is null.");
513             noTaskLoopTimes_++;
514             if (noTaskLoopTimes_ >= LOOP_TIMES) {
515                 PauseLoop(true);
516             }
517             return;
518         }
519         noTaskLoopTimes_ = 0;
520         currentRequest_ = tempRequest;
521         BeginDownload();
522         shouldStartNextRequest = currentRequest_->IsClosed();
523     }
524     if (currentRequest_ == nullptr || client_ == nullptr) {
525         MEDIA_LOG_I("currentRequest_ %{public}d client_ %{public}d nullptr",
526                     currentRequest_ != nullptr, client_ != nullptr);
527         PauseLoop(true);
528         return;
529     }
530     RequestData();
531     return;
532 }
533 
RequestData()534 void Downloader::RequestData()
535 {
536     MediaAVCodec::AVCodecTrace trace("Downloader::HttpDownloadLoop, startPos: "
537         + std::to_string(currentRequest_->startPos_) + ", reqSize: " + std::to_string(currentRequest_->requestSize_));
538     int64_t startPos = currentRequest_->startPos_;
539     if (currentRequest_->requestWholeFile_ && currentRequest_->shouldSaveData_) {
540         startPos = -1;
541     }
542     RequestInfo sourceInfo;
543     sourceInfo.url = currentRequest_->url_;
544     sourceInfo.httpHeader = currentRequest_->httpHeader_;
545     sourceInfo.timeoutMs = currentRequest_->requestInfo_.timeoutMs;
546 
547     auto handleResponseCb = [this](NetworkClientErrorCode clientCode, NetworkServerErrorCode serverCode,
548                                    Status ret) {
549         currentRequest_->clientError_ = clientCode;
550         currentRequest_->serverError_ = serverCode;
551         if (isDestructor_) {
552             return;
553         }
554 
555         if (currentRequest_->requestSize_ == FIRST_REQUEST_SIZE && !currentRequest_->isFirstRangeRequestReady_
556             && currentRequest_->serverError_ == SERVER_RANGE_ERROR_CODE) {
557             MEDIA_LOG_I("first request is above filesize, need retry.");
558             currentRequest_->startPos_ = 0;
559             currentRequest_->requestSize_ = MIN_REQUEST_SIZE;
560             currentRequest_->isHeaderUpdated = false;
561             currentRequest_->isFirstRangeRequestReady_ = true;
562             currentRequest_->headerInfo_.fileContentLen = 0;
563             return;
564         }
565         if (ret == Status::OK) {
566             HandleRetOK();
567         } else {
568             PauseLoop(true);
569             MEDIA_LOG_E("Client request data failed. ret = " PUBLIC_LOG_D32 ", clientCode = " PUBLIC_LOG_D32
570                 ",request queue size: " PUBLIC_LOG_U64,
571                 static_cast<int32_t>(ret), static_cast<int32_t>(clientCode),
572                 static_cast<int64_t>(requestQue_->Size()));
573             std::shared_ptr<Downloader> unused;
574             currentRequest_->statusCallback_(DownloadStatus::PARTTAL_DOWNLOAD, unused, currentRequest_);
575         }
576     };
577     MEDIA_LOG_I("0x%{public}06" PRIXPTR " RequestData enter.", FAKE_POINTER(this));
578     client_->RequestData(startPos, currentRequest_->requestSize_, sourceInfo, handleResponseCb);
579     MEDIA_LOG_I("0x%{public}06" PRIXPTR " RequestData end.", FAKE_POINTER(this));
580 }
581 
HandlePlayingFinish()582 void Downloader::HandlePlayingFinish()
583 {
584     if (requestQue_->Empty()) {
585         PauseLoop(true);
586     }
587     shouldStartNextRequest = true;
588     if (currentRequest_->downloadDoneCallback_ && !isDestructor_) {
589         currentRequest_->downloadDoneTime_ = currentRequest_->GetNowTime();
590         currentRequest_->downloadDoneCallback_(currentRequest_->GetUrl(), currentRequest_->location_);
591         currentRequest_->isFirstRangeRequestReady_ = false;
592     }
593 }
594 
HandleRetOK()595 void Downloader::HandleRetOK()
596 {
597     if (currentRequest_->retryTimes_ > 0) {
598         currentRequest_->retryTimes_ = 0;
599     }
600     if (currentRequest_->headerInfo_.isChunked && requestQue_->Empty()) {
601         currentRequest_->isEos_ = true;
602         PauseLoop(true);
603         return;
604     }
605 
606     int64_t remaining = 0;
607     if (currentRequest_->endPos_ <= 0) {
608         remaining = static_cast<int64_t>(currentRequest_->headerInfo_.fileContentLen) -
609                     currentRequest_->startPos_;
610     } else {
611         remaining = currentRequest_->endPos_ - currentRequest_->startPos_ + 1;
612     }
613     if (currentRequest_->headerInfo_.fileContentLen > 0 && remaining <= 0) { // Check whether the playback ends.
614         MEDIA_LOG_I("http transfer reach end, startPos_ " PUBLIC_LOG_D64, currentRequest_->startPos_);
615         currentRequest_->isEos_ = true;
616         HandlePlayingFinish();
617         return;
618     }
619     if (currentRequest_->headerInfo_.fileContentLen == 0 && remaining <= 0) {
620         currentRequest_->isEos_ = true;
621         currentRequest_->Close();
622         HandlePlayingFinish();
623         return;
624     }
625     if (remaining < PER_REQUEST_SIZE) {
626         currentRequest_->requestSize_ = remaining;
627     } else {
628         currentRequest_->requestSize_ = PER_REQUEST_SIZE;
629     }
630 }
631 
UpdateHeaderInfo(Downloader * mediaDownloader)632 void Downloader::UpdateHeaderInfo(Downloader* mediaDownloader)
633 {
634     if (mediaDownloader->currentRequest_->isHeaderUpdated) {
635         return;
636     }
637     MEDIA_LOG_I("UpdateHeaderInfo enter.");
638     HeaderInfo* info = &(mediaDownloader->currentRequest_->headerInfo_);
639     if (info->contentLen > 0 && info->contentLen < LIVE_CONTENT_LENGTH) {
640         info->isChunked = false;
641     }
642     if (info->contentLen <= 0 && !mediaDownloader->currentRequest_->IsM3u8Request()) {
643         info->isChunked = true;
644     }
645     if (info->fileContentLen > 0 && info->isChunked && !mediaDownloader->currentRequest_->IsM3u8Request()) {
646         info->isChunked = false;
647     }
648     mediaDownloader->currentRequest_->SaveHeader(info);
649 }
650 
IsDropDataRetryRequest(Downloader * mediaDownloader)651 bool Downloader::IsDropDataRetryRequest(Downloader* mediaDownloader)
652 {
653     bool isWholeFileRetry = mediaDownloader->currentRequest_->requestWholeFile_ &&
654                             mediaDownloader->currentRequest_->shouldSaveData_ &&
655                             mediaDownloader->currentRequest_->retryOnGoing_;
656     if (!isWholeFileRetry) {
657         return false;
658     }
659     if (mediaDownloader->currentRequest_->startPos_ > 0) {
660         return true;
661     } else {
662         mediaDownloader->currentRequest_->retryOnGoing_ = false;
663         return false;
664     }
665 }
666 
DropRetryData(void * buffer,size_t dataLen,Downloader * mediaDownloader)667 size_t Downloader::DropRetryData(void* buffer, size_t dataLen, Downloader* mediaDownloader)
668 {
669     auto currentRequest_ = mediaDownloader->currentRequest_;
670     int64_t needDropLen = currentRequest_->startPos_ - currentRequest_->dropedDataLen_;
671     int64_t writeOffSet = -1;
672     if (needDropLen > 0) {
673         writeOffSet = needDropLen >= static_cast<int64_t>(dataLen) ? 0 : needDropLen; // 0:drop all
674     }
675     bool dropRet = false;
676     if (writeOffSet > 0) {
677         int64_t secondParam = static_cast<int64_t>(dataLen) - writeOffSet;
678         if (secondParam < 0) {
679             secondParam = 0;
680         }
681         dropRet = currentRequest_->saveData_(static_cast<uint8_t *>(buffer) + writeOffSet,
682                                              static_cast<uint32_t>(secondParam));
683         currentRequest_->dropedDataLen_ = currentRequest_->dropedDataLen_ + writeOffSet;
684         MEDIA_LOG_D("DropRetryData: last drop, droped len " PUBLIC_LOG_D64 ", startPos_ " PUBLIC_LOG_D64,
685                     currentRequest_->dropedDataLen_, currentRequest_->startPos_);
686     } else if (writeOffSet == 0) {
687         currentRequest_->dropedDataLen_ = currentRequest_->dropedDataLen_ +
688                                             static_cast<int64_t>(dataLen);
689         dropRet = true;
690         MEDIA_LOG_D("DropRetryData: drop, droped len " PUBLIC_LOG_D64 ", startPos_ " PUBLIC_LOG_D64,
691                     currentRequest_->dropedDataLen_, currentRequest_->startPos_);
692     } else {
693         MEDIA_LOG_E("drop data error");
694     }
695     if (dropRet && currentRequest_->startPos_ == currentRequest_->dropedDataLen_) {
696         currentRequest_->retryOnGoing_ = false;
697         currentRequest_->dropedDataLen_ = 0;
698         if (writeOffSet > 0) {
699             currentRequest_->startPos_ = currentRequest_->startPos_ +
700                                          static_cast<int64_t>(dataLen) - writeOffSet;
701         }
702         MEDIA_LOG_I("drop data finished, startPos_ " PUBLIC_LOG_D64, currentRequest_->startPos_);
703     }
704     return dropRet ? dataLen : 0; // 0:save data failed or drop error
705 }
706 
UpdateCurRequest(Downloader * mediaDownloader,HeaderInfo * header)707 void Downloader::UpdateCurRequest(Downloader* mediaDownloader, HeaderInfo* header)
708 {
709     int64_t hstTime = 0;
710     Sec2HstTime(mediaDownloader->currentRequest_->GetDuration(), hstTime);
711     int64_t startTimePos = mediaDownloader->currentRequest_->startTimePos_;
712     int64_t contenLen = static_cast<int64_t>(header->fileContentLen);
713     int64_t startPos = 0;
714     if (hstTime != 0) {
715         startPos = contenLen * startTimePos / (HstTime2Ns(hstTime));
716     }
717     mediaDownloader->currentRequest_->startPos_ = startPos;
718     mediaDownloader->currentRequest_->shouldSaveData_ = true;
719     mediaDownloader->currentRequest_->requestWholeFile_ = false;
720     mediaDownloader->currentRequest_->requestSize_ = PER_REQUEST_SIZE;
721     mediaDownloader->currentRequest_->startTimePos_ = 0;
722 }
723 
RxBodyData(void * buffer,size_t size,size_t nitems,void * userParam)724 size_t Downloader::RxBodyData(void* buffer, size_t size, size_t nitems, void* userParam)
725 {
726     auto mediaDownloader = static_cast<Downloader *>(userParam);
727     size_t dataLen = size * nitems;
728     int64_t curLen = mediaDownloader->currentRequest_->realRecvContentLen_;
729     int64_t realRecvContentLen = static_cast<int64_t>(dataLen) + curLen;
730     UpdateHeaderInfo(mediaDownloader);
731     MediaAVCodec::AVCodecTrace trace("Downloader::RxBodyData, dataLen: " + std::to_string(dataLen)
732         + ", realRecvContentLen: " + std::to_string(realRecvContentLen));
733     if (mediaDownloader->currentRequest_->IsClosed()) {
734         return 0;
735     }
736     if (IsDropDataRetryRequest(mediaDownloader)) {
737         return DropRetryData(buffer, dataLen, mediaDownloader);
738     }
739     HeaderInfo* header = &(mediaDownloader->currentRequest_->headerInfo_);
740     if (!mediaDownloader->currentRequest_->shouldSaveData_) {
741         UpdateCurRequest(mediaDownloader, header);
742         return dataLen;
743     }
744     if (header->fileContentLen == 0) {
745         if (header->contentLen > 0) {
746             MEDIA_LOG_W("Unsupported range, use content length as content file length");
747             header->fileContentLen = header->contentLen;
748         } else {
749             MEDIA_LOG_D("fileContentLen and contentLen are both zero.");
750         }
751     }
752     if (!mediaDownloader->currentRequest_->isDownloading_) {
753         mediaDownloader->currentRequest_->isDownloading_ = true;
754     }
755     if (!mediaDownloader->currentRequest_->saveData_(static_cast<uint8_t *>(buffer), static_cast<uint32_t>(dataLen))) {
756         MEDIA_LOG_W("Save data failed.");
757         return 0; // save data failed, make perform finished.
758     }
759     mediaDownloader->currentRequest_->realRecvContentLen_ = realRecvContentLen;
760     mediaDownloader->currentRequest_->isDownloading_ = false;
761     MEDIA_LOGI_LIMIT(DOWNLOAD_LOG_FEQUENCE, "RxBodyData: dataLen " PUBLIC_LOG_ZU ", startPos_ " PUBLIC_LOG_D64, dataLen,
762                      mediaDownloader->currentRequest_->startPos_);
763     mediaDownloader->currentRequest_->startPos_ = mediaDownloader->currentRequest_->startPos_ + dataLen;
764     return dataLen;
765 }
766 
767 namespace {
StringTrim(char * str)768 char* StringTrim(char* str)
769 {
770     if (str == nullptr) {
771         return nullptr;
772     }
773     char* p = str;
774     char* p1 = p + strlen(str) - 1;
775 
776     while (*p && isspace(static_cast<int>(*p))) {
777         p++;
778     }
779     while (p1 > p && isspace(static_cast<int>(*p1))) {
780         *p1-- = 0;
781     }
782     return p;
783 }
784 }
785 
HandleContentRange(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)786 bool Downloader::HandleContentRange(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
787 {
788     if (!strncmp(key, "Content-Range", strlen("Content-Range")) ||
789         !strncmp(key, "content-range", strlen("content-range"))) {
790         char* token = strtok_s(nullptr, ":", &next);
791         FALSE_RETURN_V(token != nullptr, false);
792         char* strRange = StringTrim(token);
793         size_t start;
794         size_t end;
795         size_t fileLen;
796         FALSE_LOG_MSG(sscanf_s(strRange, "bytes %lu-%lu/%lu", &start, &end, &fileLen) != -1,
797             "sscanf get range failed");
798         if (info->fileContentLen > 0 && info->fileContentLen != fileLen) {
799             MEDIA_LOG_E("FileContentLen doesn't equal to fileLen");
800         }
801         if (info->fileContentLen == 0) {
802             info->fileContentLen = fileLen;
803         }
804     }
805     return true;
806 }
807 
HandleContentType(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)808 bool Downloader::HandleContentType(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
809 {
810     if (!strncmp(key, "Content-Type", strlen("Content-Type"))) {
811         char* token = strtok_s(nullptr, ":", &next);
812         FALSE_RETURN_V(token != nullptr, false);
813         char* type = StringTrim(token);
814         std::string tokenStr = (std::string)token;
815         MEDIA_LOG_I("Content-Type: " PUBLIC_LOG_S, tokenStr.c_str());
816         NZERO_LOG(memcpy_s(info->contentType, sizeof(info->contentType), type, strlen(type)));
817     }
818     return true;
819 }
820 
HandleContentEncode(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)821 bool Downloader::HandleContentEncode(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
822 {
823     if (!strncmp(key, "Content-Encode", strlen("Content-Encode")) ||
824         !strncmp(key, "content-encode", strlen("content-encode"))) {
825         char* token = strtok_s(nullptr, ":", &next);
826         FALSE_RETURN_V(token != nullptr, false);
827         std::string tokenStr = (std::string)token;
828         MEDIA_LOG_I("Content-Encode: " PUBLIC_LOG_S, tokenStr.c_str());
829     }
830     return true;
831 }
832 
HandleContentLength(HeaderInfo * info,char * key,char * next,Downloader * mediaDownloader)833 bool Downloader::HandleContentLength(HeaderInfo* info, char* key, char* next, Downloader* mediaDownloader)
834 {
835     FALSE_RETURN_V(key != nullptr, false);
836     if (!strncmp(key, "Content-Length", strlen("Content-Length")) ||
837         !strncmp(key, "content-length", strlen("content-length"))) {
838         FALSE_RETURN_V(next != nullptr, false);
839         char* token = strtok_s(nullptr, ":", &next);
840         FALSE_RETURN_V(token != nullptr, false);
841         if (info != nullptr && mediaDownloader != nullptr) {
842             info->contentLen = atol(StringTrim(token));
843             if (info->contentLen <= 0 && !mediaDownloader->currentRequest_->IsM3u8Request()) {
844                 info->isChunked = true;
845             }
846         }
847     }
848     return true;
849 }
850 
851 // Check if this server supports range download. (HTTP)
HandleRange(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)852 bool Downloader::HandleRange(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
853 {
854     if (!strncmp(key, "Accept-Ranges", strlen("Accept-Ranges")) ||
855         !strncmp(key, "accept-ranges", strlen("accept-ranges"))) {
856         char* token = strtok_s(nullptr, ":", &next);
857         FALSE_RETURN_V(token != nullptr, false);
858         if (!strncmp(StringTrim(token), "bytes", strlen("bytes"))) {
859             info->isServerAcceptRange = true;
860             MEDIA_LOG_I("Accept-Ranges: bytes");
861         }
862     }
863     if (!strncmp(key, "Content-Range", strlen("Content-Range")) ||
864         !strncmp(key, "content-range", strlen("content-range"))) {
865         char* token = strtok_s(nullptr, ":", &next);
866         FALSE_RETURN_V(token != nullptr, false);
867         std::string tokenStr = (std::string)token;
868         if (tokenStr.find("bytes") != std::string::npos) {
869             info->isServerAcceptRange = true;
870             MEDIA_LOG_I("Content-Range: " PUBLIC_LOG_S, tokenStr.c_str());
871         }
872     }
873     return true;
874 }
875 
RxHeaderData(void * buffer,size_t size,size_t nitems,void * userParam)876 size_t Downloader::RxHeaderData(void* buffer, size_t size, size_t nitems, void* userParam)
877 {
878     MediaAVCodec::AVCodecTrace trace("Downloader::RxHeaderData");
879     auto mediaDownloader = reinterpret_cast<Downloader *>(userParam);
880     HeaderInfo* info = &(mediaDownloader->currentRequest_->headerInfo_);
881     if (mediaDownloader->currentRequest_->isHeaderUpdated) {
882         return size * nitems;
883     }
884     char* next = nullptr;
885     char* key = strtok_s(reinterpret_cast<char*>(buffer), ":", &next);
886     FALSE_RETURN_V(key != nullptr, size * nitems);
887 
888     if (!strncmp(key, "Transfer-Encoding", strlen("Transfer-Encoding")) ||
889         !strncmp(key, "transfer-encoding", strlen("transfer-encoding"))) {
890         char* token = strtok_s(nullptr, ":", &next);
891         FALSE_RETURN_V(token != nullptr, size * nitems);
892         if (!strncmp(StringTrim(token), "chunked", strlen("chunked")) &&
893             !mediaDownloader->currentRequest_->IsM3u8Request()) {
894             info->isChunked = true;
895             if (static_cast<int32_t>(mediaDownloader->currentRequest_->url_.find(".flv") == std::string::npos)) {
896                 info->contentLen = LIVE_CONTENT_LENGTH;
897             } else {
898                 info->contentLen = 0;
899             }
900             std::string tokenStr = (std::string)token;
901             MEDIA_LOG_I("Transfer-Encoding: " PUBLIC_LOG_S, tokenStr.c_str());
902         }
903     }
904     if (!strncmp(key, "Location", strlen("Location")) ||
905         !strncmp(key, "location", strlen("location"))) {
906         FALSE_RETURN_V(next != nullptr, size * nitems);
907         char* location = StringTrim(next);
908         mediaDownloader->currentRequest_->location_ = location;
909     }
910 
911     if (!HandleContentRange(info, key, next, size, nitems) || !HandleContentType(info, key, next, size, nitems) ||
912         !HandleContentEncode(info, key, next, size, nitems) ||
913         !HandleContentLength(info, key, next, mediaDownloader) ||
914         !HandleRange(info, key, next, size, nitems)) {
915         return size * nitems;
916     }
917 
918     return size * nitems;
919 }
920 
PauseLoop(bool isAsync)921 void Downloader::PauseLoop(bool isAsync)
922 {
923     if (task_ == nullptr) {
924         return;
925     }
926     if (isAsync) {
927         task_->PauseAsync();
928     } else {
929         task_->Pause();
930     }
931 }
932 
SetAppUid(int32_t appUid)933 void Downloader::SetAppUid(int32_t appUid)
934 {
935     if (client_) {
936         client_->SetAppUid(appUid);
937     }
938 }
939 
GetCurrentRequest()940 const std::shared_ptr<DownloadRequest>& Downloader::GetCurrentRequest()
941 {
942     return currentRequest_;
943 }
944 
SetInterruptState(bool isInterruptNeeded)945 void Downloader::SetInterruptState(bool isInterruptNeeded)
946 {
947     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Downloader SetInterruptState %{public}d",
948         FAKE_POINTER(this), isInterruptNeeded);
949     isInterruptNeeded_ = isInterruptNeeded;
950     if (currentRequest_ != nullptr) {
951         currentRequest_->isInterruptNeeded_ = isInterruptNeeded;
952     }
953     NotifyLoopPause();
954 }
955 
NotifyLoopPause()956 void Downloader::NotifyLoopPause()
957 {
958     AutoLock lk(loopPauseMutex_);
959     if (loopStatus_ == LoopStatus::PAUSE || isInterruptNeeded_) {
960         MEDIA_LOG_I("0x%{public}06" PRIXPTR " Downloader NotifyLoopPause", FAKE_POINTER(this));
961         loopStatus_ = LoopStatus::IDLE;
962         loopPauseCond_.NotifyAll();
963     } else {
964         loopStatus_ = LoopStatus::IDLE;
965         MEDIA_LOG_I("Downloader not NotifyLoopPause loopStatus %{public}d isInterruptNeeded %{public}d",
966             loopStatus_.load(), isInterruptNeeded_.load());
967     }
968 }
969 
WaitLoopPause()970 void Downloader::WaitLoopPause()
971 {
972     AutoLock lk(loopPauseMutex_);
973     if (loopStatus_ == LoopStatus::IDLE) {
974         MEDIA_LOG_I("0x%{public}06" PRIXPTR "Downloader not WaitLoopPause loopStatus is idle", FAKE_POINTER(this));
975         return;
976     }
977     MEDIA_LOG_I("0x%{public}06" PRIXPTR "Downloader WaitLoopPause task loopStatus_ %{public}d",
978         FAKE_POINTER(this), loopStatus_.load());
979     loopStatus_ = LoopStatus::PAUSE;
980     loopPauseCond_.Wait(lk, [this]() {
981         MEDIA_LOG_I("0x%{public}06" PRIXPTR " WaitLoopPause wake loopStatus %{public}d",
982             FAKE_POINTER(this), loopStatus_.load());
983         return loopStatus_ != LoopStatus::PAUSE || isInterruptNeeded_;
984     });
985 }
986 
987 }
988 }
989 }
990 }
991