• 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 #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 constexpr int REQUEST_OFTEN_ERROR_CODE = 500;
46 constexpr int SLEEP_TEN_MICRO_SEC = 10; // 10ms
47 constexpr int APP_OPEN_RETRY_TIMES = 10;
48 constexpr int32_t REDIRECT_CODE = 302;
49 constexpr uint32_t MAX_LOOP_TIMES = 100;
50 }
51 
DownloadRequest(const std::string & url,DataSaveFunc saveData,StatusCallbackFunc statusCallback,bool requestWholeFile)52 DownloadRequest::DownloadRequest(const std::string& url, DataSaveFunc saveData, StatusCallbackFunc statusCallback,
53                                  bool requestWholeFile)
54     : url_(url), saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)),
55     requestWholeFile_(requestWholeFile)
56 {
57     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
58     headerInfo_.fileContentLen = 0;
59     headerInfo_.contentLen = 0;
60 }
61 
DownloadRequest(const std::string & url,double duration,DataSaveFunc saveData,StatusCallbackFunc statusCallback,bool requestWholeFile)62 DownloadRequest::DownloadRequest(const std::string& url,
63                                  double duration,
64                                  DataSaveFunc saveData,
65                                  StatusCallbackFunc statusCallback,
66                                  bool requestWholeFile)
67     : url_(url), duration_(duration), saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)),
68     requestWholeFile_(requestWholeFile)
69 {
70     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
71     headerInfo_.fileContentLen = 0;
72     headerInfo_.contentLen = 0;
73 }
74 
DownloadRequest(DataSaveFunc saveData,StatusCallbackFunc statusCallback,RequestInfo requestInfo,bool requestWholeFile)75 DownloadRequest::DownloadRequest(DataSaveFunc saveData, StatusCallbackFunc statusCallback, RequestInfo requestInfo,
76                                  bool requestWholeFile)
77     : saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)), requestInfo_(requestInfo),
78     requestWholeFile_(requestWholeFile)
79 {
80     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
81     headerInfo_.fileContentLen = 0;
82     headerInfo_.contentLen = 0;
83     url_ = requestInfo.url;
84     httpHeader_ = requestInfo.httpHeader;
85 }
86 
DownloadRequest(double duration,DataSaveFunc saveData,StatusCallbackFunc statusCallback,RequestInfo requestInfo,bool requestWholeFile)87 DownloadRequest::DownloadRequest(double duration,
88                                  DataSaveFunc saveData,
89                                  StatusCallbackFunc statusCallback,
90                                  RequestInfo requestInfo,
91                                  bool requestWholeFile)
92     : duration_(duration), saveData_(std::move(saveData)), statusCallback_(std::move(statusCallback)),
93     requestInfo_(requestInfo), requestWholeFile_(requestWholeFile)
94 {
95     (void)memset_s(&headerInfo_, sizeof(HeaderInfo), 0x00, sizeof(HeaderInfo));
96     headerInfo_.fileContentLen = 0;
97     headerInfo_.contentLen = 0;
98     url_ = requestInfo.url;
99     httpHeader_ = requestInfo.httpHeader;
100 }
101 
GetFileContentLength() const102 size_t DownloadRequest::GetFileContentLength() const
103 {
104     WaitHeaderUpdated();
105     return headerInfo_.GetFileContentLength();
106 }
107 
GetFileContentLengthNoWait() const108 size_t DownloadRequest::GetFileContentLengthNoWait() const
109 {
110     return headerInfo_.fileContentLen;
111 }
112 
SaveHeader(const HeaderInfo * header)113 void DownloadRequest::SaveHeader(const HeaderInfo* header)
114 {
115     MediaAVCodec::AVCodecTrace trace("DownloadRequest::SaveHeader");
116     headerInfo_.Update(header);
117     isHeaderUpdated_ = true;
118 }
119 
IsChunked(bool isInterruptNeeded)120 Seekable DownloadRequest::IsChunked(bool isInterruptNeeded)
121 {
122     isInterruptNeeded_ = isInterruptNeeded;
123     WaitHeaderUpdated();
124     if (isInterruptNeeded) {
125         MEDIA_LOG_I("Canceled");
126         return Seekable::INVALID;
127     }
128     if (headerInfo_.isChunked) {
129         return GetFileContentLength() == LIVE_CONTENT_LENGTH ? Seekable::SEEKABLE : Seekable::UNSEEKABLE;
130     } else {
131         return Seekable::SEEKABLE;
132     }
133 };
134 
IsEos() const135 bool DownloadRequest::IsEos() const
136 {
137     return isEos_;
138 }
139 
GetRetryTimes() const140 int DownloadRequest::GetRetryTimes() const
141 {
142     return retryTimes_;
143 }
144 
GetClientError() const145 int32_t DownloadRequest::GetClientError() const
146 {
147     return clientError_;
148 }
149 
GetServerError() const150 int32_t DownloadRequest::GetServerError() const
151 {
152     return serverError_;
153 }
154 
IsClosed() const155 bool DownloadRequest::IsClosed() const
156 {
157     return headerInfo_.isClosed;
158 }
159 
Close()160 void DownloadRequest::Close()
161 {
162     headerInfo_.isClosed = true;
163 }
164 
WaitHeaderUpdated() const165 void DownloadRequest::WaitHeaderUpdated() const
166 {
167     isHeaderUpdating_ = true;
168     MediaAVCodec::AVCodecTrace trace("DownloadRequest::WaitHeaderUpdated");
169     // Wait Header(fileContentLen etc.) updated
170     while (!isHeaderUpdated_ && times_ < RETRY_TIMES && !isInterruptNeeded_ && !headerInfo_.isClosed) {
171         Task::SleepInTask(SLEEP_TIME);
172         times_++;
173     }
174     MEDIA_LOG_D("isHeaderUpdated_ " PUBLIC_LOG_D32 ", times " PUBLIC_LOG_ZU ", isClosed " PUBLIC_LOG_D32,
175         isHeaderUpdated_.load(), times_.load(), headerInfo_.isClosed.load());
176     isHeaderUpdating_ = false;
177 }
178 
GetDuration() const179 double DownloadRequest::GetDuration() const
180 {
181     return duration_;
182 }
183 
SetStartTimePos(int64_t startTimePos)184 void DownloadRequest::SetStartTimePos(int64_t startTimePos)
185 {
186     startTimePos_ = startTimePos;
187     if (startTimePos_ > 0) {
188         shouldSaveData_ = false;
189     }
190 }
191 
SetRangePos(int64_t startPos,int64_t endPos)192 void DownloadRequest::SetRangePos(int64_t startPos, int64_t endPos)
193 {
194     startPos_ = startPos;
195     endPos_ = endPos;
196 }
197 
SetDownloadDoneCb(DownloadDoneCbFunc downloadDoneCallback)198 void DownloadRequest::SetDownloadDoneCb(DownloadDoneCbFunc downloadDoneCallback)
199 {
200     downloadDoneCallback_ = downloadDoneCallback;
201 }
202 
GetNowTime()203 int64_t DownloadRequest::GetNowTime()
204 {
205     return std::chrono::duration_cast<std::chrono::milliseconds>
206            (std::chrono::system_clock::now().time_since_epoch()).count();
207 }
208 
GetBitRate() const209 uint32_t DownloadRequest::GetBitRate() const
210 {
211     if ((downloadDoneTime_ == 0) || (downloadStartTime_ == 0) || (realRecvContentLen_ == 0)) {
212         return 0;
213     }
214     int64_t timeGap = downloadDoneTime_ - downloadStartTime_;
215     if (timeGap == 0) {
216         return 0;
217     }
218     uint32_t bitRate = static_cast<uint32_t>(realRecvContentLen_ * 1000 *
219                         1 * 8 / timeGap); // 1000:ms to sec 1:weight 8:byte to bit
220     return bitRate;
221 }
222 
IsChunkedVod() const223 bool DownloadRequest::IsChunkedVod() const
224 {
225     return headerInfo_.isChunked && headerInfo_.GetFileContentLength() == LIVE_CONTENT_LENGTH;
226 }
227 
IsM3u8Request() const228 bool DownloadRequest::IsM3u8Request() const
229 {
230     return protocolType_ == RequestProtocolType::HLS;
231 }
232 
SetRequestProtocolType(RequestProtocolType protocolType)233 void DownloadRequest::SetRequestProtocolType(RequestProtocolType protocolType)
234 {
235     protocolType_ = protocolType;
236 }
237 
IsServerAcceptRange() const238 bool DownloadRequest::IsServerAcceptRange() const
239 {
240     if (headerInfo_.isChunked) {
241         return false;
242     }
243     return headerInfo_.isServerAcceptRange;
244 }
245 
~DownloadRequest()246 DownloadRequest::~DownloadRequest()
247 {
248     MEDIA_LOG_D("~DownloadRequest dtor in.");
249     int sleepTmpTime = 0;
250     while (isHeaderUpdating_.load() && sleepTmpTime < RETRY_TIMES) {
251         Task::SleepInTask(SLEEP_TIME);
252         sleepTmpTime++;
253     }
254 }
255 
GetLocation(std::string & location) const256 void DownloadRequest::GetLocation(std::string& location) const
257 {
258     location = location_;
259 }
260 
Downloader(const std::string & name)261 Downloader::Downloader(const std::string& name) noexcept : name_(std::move(name))
262 {
263     shouldStartNextRequest = true;
264 
265     client_ = NetworkClient::GetInstance(&RxHeaderData, &RxBodyData, this);
266     DonwloaderInit(name);
267 }
268 
DonwloaderInit(const std::string & name)269 void Downloader::DonwloaderInit(const std::string& name)
270 {
271     client_->Init();
272     requestQue_ = std::make_shared<BlockingQueue<std::shared_ptr<DownloadRequest>>>(name_ + "RequestQue",
273         REQUEST_QUEUE_SIZE);
274     task_ = std::make_shared<Task>(std::string("OS_" + name_ + "Downloader"));
275     task_->RegisterJob([this] {
276         {
277             AutoLock lk(loopPauseMutex_);
278             if (loopStatus_ == LoopStatus::PAUSE) {
279                 MEDIA_LOG_I("0x%{public}06" PRIXPTR " loopStatus PAUSE to START", FAKE_POINTER(this));
280             }
281             loopStatus_ = LoopStatus::START;
282         }
283         HttpDownloadLoop();
284         NotifyLoopPause();
285         return 0;
286     });
287     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Downloader ctor", FAKE_POINTER(this));
288 }
289 
Downloader(const std::string & name,std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader)290 Downloader::Downloader(const std::string& name, std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader) noexcept
291 {
292     name_ = name;
293     shouldStartNextRequest = true;
294     if (sourceLoader != nullptr) {
295         isNotBlock_ = true;
296         sourceLoader_ = sourceLoader;
297         client_ = NetworkClient::GetAppInstance(&RxHeaderData, &RxBodyData, this);
298         client_->SetLoader(sourceLoader->loader_);
299         MEDIA_LOG_I("0x%{public}06" PRIXPTR "Get app instance success", FAKE_POINTER(this));
300     } else {
301         MEDIA_LOG_I("0x%{public}06" PRIXPTR "Get libcurl instance success", FAKE_POINTER(this));
302         client_ = NetworkClient::GetInstance(&RxHeaderData, &RxBodyData, this);
303     }
304     DonwloaderInit(name);
305 }
306 
~Downloader()307 Downloader::~Downloader()
308 {
309     isDestructor_ = true;
310     MEDIA_LOG_I("~Downloader In");
311     {
312         AutoLock lock(closeMutex_);
313         if (sourceLoader_ != nullptr) {
314             sourceLoader_->Close(uuid_);
315             sourceLoader_ = nullptr;
316         }
317     }
318     Stop(false);
319     if (task_ != nullptr) {
320         task_ = nullptr;
321     }
322     if (client_ != nullptr) {
323         client_->Deinit();
324         client_ = nullptr;
325     }
326     MEDIA_LOG_I("0x%{public}06" PRIXPTR " ~Downloader dtor", FAKE_POINTER(this));
327 }
328 
Download(const std::shared_ptr<DownloadRequest> & request,int32_t waitMs)329 bool Downloader::Download(const std::shared_ptr<DownloadRequest>& request, int32_t waitMs)
330 {
331     MEDIA_LOG_I("In");
332     if (isInterruptNeeded_) {
333         request->isInterruptNeeded_ = true;
334     }
335     requestQue_->SetActive(true);
336     if (waitMs == -1) { // wait until push success
337         requestQue_->Push(request);
338         return true;
339     }
340     return requestQue_->Push(request, static_cast<int>(waitMs));
341 }
342 
GetContentType()343 std::string Downloader::GetContentType()
344 {
345     if (isDestructor_) {
346         MEDIA_LOG_E("Get " PUBLIC_LOG_S " content type failed, uuid " PUBLIC_LOG_D64, name_.c_str(), uuid_);
347         return contentType_;
348     }
349     FALSE_RETURN_V_NOLOG(!isContentTypeUpdated_, contentType_);
350     AutoLock lock(sleepMutex_);
351     MEDIA_LOG_I("GetContentType wait begin ");
352     sleepCond_.WaitFor(lock, SLEEP_TIME * RETRY_TIMES, [this]() {
353         return isInterruptNeeded_.load() || isContentTypeUpdated_;
354     });
355     MEDIA_LOG_I("ContentType: %{public}s", contentType_.c_str());
356     return contentType_;
357 }
358 
Start()359 void Downloader::Start()
360 {
361     MediaAVCodec::AVCodecTrace trace("Downloader::Start");
362     MEDIA_LOG_I("start Begin");
363     requestQue_->SetActive(true);
364     task_->Start();
365     MEDIA_LOG_I("start End");
366 }
367 
ReStart()368 void Downloader::ReStart()
369 {
370     MEDIA_LOG_I("Downloader::ReStart");
371     shouldStartNextRequest = true;
372 }
373 
Pause(bool isAsync)374 void Downloader::Pause(bool isAsync)
375 {
376     MediaAVCodec::AVCodecTrace trace("Downloader::Pause");
377     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Pause Begin", FAKE_POINTER(this));
378     requestQue_->SetActive(false, false);
379     if (client_ != nullptr) {
380         isClientClose_ = true;
381         client_->Close(isAsync);
382     }
383     PauseLoop(true);
384     if (!isAsync) {
385         WaitLoopPause();
386     }
387     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Pause End", FAKE_POINTER(this));
388 }
389 
Cancel()390 void Downloader::Cancel()
391 {
392     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Cancel Begin", FAKE_POINTER(this));
393     if (currentRequest_ != nullptr && currentRequest_->retryTimes_ > 0) {
394         currentRequest_->retryTimes_ = 0;
395     }
396     requestQue_->SetActive(false, true);
397     shouldStartNextRequest = true;
398     if (client_ != nullptr) {
399         client_->Close(false);
400     }
401     PauseLoop(true);
402     WaitLoopPause();
403     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Cancel End", FAKE_POINTER(this));
404 }
405 
406 
Resume()407 void Downloader::Resume()
408 {
409     MediaAVCodec::AVCodecTrace trace("Downloader::Resume");
410     FALSE_RETURN_MSG(!isDestructor_ && !isInterruptNeeded_, "not Resume. is Destructor or InterruptNeeded");
411     {
412         AutoLock lock(operatorMutex_);
413         MEDIA_LOG_I("resume Begin");
414         if (isClientClose_ && client_ != nullptr && currentRequest_ != nullptr) {
415             isClientClose_ = false;
416             client_->Open(currentRequest_->url_, currentRequest_->httpHeader_, currentRequest_->requestInfo_.timeoutMs);
417         }
418         requestQue_->SetActive(true);
419         if (currentRequest_ != nullptr) {
420             currentRequest_->isEos_ = false;
421 
422             int64_t fileLength = static_cast<int64_t>(currentRequest_->GetFileContentLength());
423             if (currentRequest_->startPos_ + currentRequest_->requestSize_ > fileLength) {
424                 int correctRequestSize = fileLength - currentRequest_->startPos_;
425                 MEDIA_LOG_E("resume error startPos = " PUBLIC_LOG_D64 ", requestSize = " PUBLIC_LOG_D32
426                     ", fileLength = " PUBLIC_LOG_D64 ", correct requestSize = " PUBLIC_LOG_D32,
427                     currentRequest_->startPos_, currentRequest_->requestSize_, fileLength, correctRequestSize);
428                 if (currentRequest_->startPos_ < fileLength) {
429                     currentRequest_->requestSize_ = correctRequestSize;
430                 }
431             }
432         }
433     }
434     Start();
435     MEDIA_LOG_I("resume End");
436 }
437 
Stop(bool isAsync)438 void Downloader::Stop(bool isAsync)
439 {
440     MediaAVCodec::AVCodecTrace trace("Downloader::Stop");
441     MEDIA_LOG_I("Stop Begin");
442     isDestructor_ = true;
443     if (requestQue_ != nullptr) {
444         requestQue_->SetActive(false);
445     }
446     if (currentRequest_ != nullptr) {
447         currentRequest_->isInterruptNeeded_ = true;
448         currentRequest_->Close();
449     }
450     if (client_ != nullptr) {
451         client_->Close(isAsync);
452         if (!isAsync) {
453             client_->Deinit();
454         }
455     }
456     shouldStartNextRequest = true;
457     if (task_ != nullptr) {
458         if (isAsync) {
459             task_->StopAsync();
460         } else {
461             task_->Stop();
462         }
463     }
464     MEDIA_LOG_I("Stop End");
465 }
466 
Seek(int64_t offset)467 bool Downloader::Seek(int64_t offset)
468 {
469     MediaAVCodec::AVCodecTrace trace("Downloader::Seek, offset: " + std::to_string(offset));
470     FALSE_RETURN_V_MSG(!isDestructor_ && !isInterruptNeeded_, false, "Seek fail, is Destructor or InterruptNeeded");
471     AutoLock lock(operatorMutex_);
472     FALSE_RETURN_V_MSG(currentRequest_ != nullptr, false, "Seek fail, currentRequest nullptr");
473     size_t contentLength = currentRequest_->GetFileContentLength();
474     MEDIA_LOG_I("Seek Begin, offset = " PUBLIC_LOG_D64 ", contentLength = " PUBLIC_LOG_ZU, offset, contentLength);
475     if (offset >= 0 && offset < static_cast<int64_t>(contentLength)) {
476         currentRequest_->startPos_ = offset;
477     }
478     size_t temp = currentRequest_->GetFileContentLength() - static_cast<size_t>(currentRequest_->startPos_);
479     currentRequest_->requestSize_ = static_cast<int>(std::min(temp, static_cast<size_t>(PER_REQUEST_SIZE)));
480     if (downloadRequestSize_ > 0) {
481         currentRequest_->requestSize_ = std::min(currentRequest_->requestSize_,
482             static_cast<int>(downloadRequestSize_));
483         downloadRequestSize_ = 0;
484     }
485     currentRequest_->isEos_ = false;
486     shouldStartNextRequest = false; // Reuse last request when seek
487     if (currentRequest_->retryTimes_ > 0) {
488         currentRequest_->retryTimes_ = 0;
489     }
490     return true;
491 }
492 
SetRequestSize(size_t downloadRequestSize)493 void Downloader::SetRequestSize(size_t downloadRequestSize)
494 {
495     downloadRequestSize_ = downloadRequestSize;
496 }
497 
GetIp(std::string & ip)498 void Downloader::GetIp(std::string &ip)
499 {
500     if (client_ != nullptr) {
501         client_->GetIp(ip);
502     }
503 }
504 
505 // Pause download thread before use currentRequest_
Retry(const std::shared_ptr<DownloadRequest> & request)506 bool Downloader::Retry(const std::shared_ptr<DownloadRequest>& request)
507 {
508     FALSE_RETURN_V_MSG(client_ != nullptr && !isDestructor_ && !isInterruptNeeded_, false,
509         "not Retry, client null or isDestructor or isInterruptNeeded");
510     if (isAppBackground_) {
511         Pause(true);
512         MEDIA_LOG_I("Retry avoid, forground to background.");
513         return true;
514     }
515     {
516         AutoLock lock(operatorMutex_);
517         MEDIA_LOG_I("0x%{public}06" PRIXPTR " Retry Begin", FAKE_POINTER(this));
518         FALSE_RETURN_V(client_ != nullptr && !shouldStartNextRequest && !isDestructor_ && !isInterruptNeeded_, false);
519         requestQue_->SetActive(false, false);
520     }
521     PauseLoop(true);
522     WaitLoopPause();
523     {
524         AutoLock lock(operatorMutex_);
525         FALSE_RETURN_V(client_ != nullptr && !shouldStartNextRequest && !isDestructor_ && !isInterruptNeeded_, false);
526         client_->Close(false);
527         if (currentRequest_ != nullptr) {
528             if (currentRequest_->IsSame(request) && !shouldStartNextRequest) {
529                 currentRequest_->retryTimes_++;
530                 currentRequest_->retryOnGoing_ = true;
531                 currentRequest_->dropedDataLen_ = 0;
532             }
533             client_->Open(currentRequest_->url_, currentRequest_->httpHeader_, currentRequest_->requestInfo_.timeoutMs);
534             requestQue_->SetActive(true);
535             currentRequest_->isEos_ = false;
536             if (currentRequest_->endPos_ > 0 && currentRequest_->startPos_ >= 0 &&
537                 currentRequest_->endPos_ >= currentRequest_->startPos_) {
538                 currentRequest_->requestSize_ = currentRequest_->endPos_ - currentRequest_->startPos_ + 1;
539             }
540         }
541     }
542     task_->Start();
543     MEDIA_LOG_I("Do retry.");
544     return true;
545 }
546 
GetSystemParam(const std::string & key)547 std::string GetSystemParam(const std::string &key)
548 {
549     char value[MAX_LEN] = {0};
550     int32_t ret = GetParameter(key.c_str(), "", value, MAX_LEN);
551     if (ret < 0) {
552         return "";
553     }
554     return std::string(value);
555 }
556 
GetUserAgent()557 std::string GetUserAgent()
558 {
559     std::string displayVersion = GetSystemParam(DISPLAYVERSION);
560     std::string userAgent = " AVPlayerLib " + displayVersion;
561     return userAgent;
562 }
563 
BeginDownload()564 bool Downloader::BeginDownload()
565 {
566     MEDIA_LOG_I("BeginDownload %{public}s", name_.c_str());
567     std::string url = currentRequest_->url_;
568     std::map<std::string, std::string> httpHeader = currentRequest_->httpHeader_;
569 
570     if (currentRequest_->httpHeader_.count(USER_AGENT) <= 0) {
571         currentRequest_->httpHeader_[USER_AGENT] = GetUserAgent();
572         httpHeader[USER_AGENT] = GetUserAgent();
573         MEDIA_LOG_I("Set default UA.");
574     }
575 
576     int32_t timeoutMs = currentRequest_->requestInfo_.timeoutMs;
577     FALSE_RETURN_V(!url.empty(), false);
578     if (client_) {
579         client_->Open(url, httpHeader, timeoutMs);
580     }
581 
582     if (currentRequest_->endPos_ <= 0) {
583         currentRequest_->startPos_ = 0;
584         currentRequest_->requestSize_ = FIRST_REQUEST_SIZE;
585     } else {
586         int64_t temp = currentRequest_->endPos_ - currentRequest_->startPos_ + 1;
587         currentRequest_->requestSize_ = static_cast<int>(std::min(temp, static_cast<int64_t>(PER_REQUEST_SIZE)));
588     }
589     currentRequest_->isEos_ = false;
590     currentRequest_->retryTimes_ = 0;
591     currentRequest_->downloadStartTime_ = currentRequest_->GetNowTime();
592     MEDIA_LOG_I("End");
593     return true;
594 }
595 
HttpDownloadLoop()596 void Downloader::HttpDownloadLoop()
597 {
598     AutoLock lock(operatorMutex_);
599     MEDIA_LOGI_LIMIT(LOOP_LOG_FEQUENCE, "Downloader loop shouldStartNextRequest %{public}d",
600         shouldStartNextRequest.load());
601     if (shouldStartNextRequest) {
602         std::shared_ptr<DownloadRequest> tempRequest = requestQue_->Pop(1000); // 1000ms timeout limit.
603         if (!tempRequest) {
604             MEDIA_LOG_W("HttpDownloadLoop tempRequest is null.");
605             noTaskLoopTimes_++;
606             if (noTaskLoopTimes_ >= LOOP_TIMES) {
607                 PauseLoop(true);
608             }
609             return;
610         }
611         noTaskLoopTimes_ = 0;
612         currentRequest_ = tempRequest;
613         if (isInterruptNeeded_) {
614             currentRequest_->isInterruptNeeded_ = true;
615         }
616         BeginDownload();
617         shouldStartNextRequest = currentRequest_->IsClosed();
618     }
619     if (currentRequest_ == nullptr || client_ == nullptr) {
620         MEDIA_LOG_I("currentRequest_ %{public}d client_ %{public}d nullptr",
621                     currentRequest_ != nullptr, client_ != nullptr);
622         PauseLoop(true);
623         return;
624     }
625     RequestData();
626     return;
627 }
628 
OpenAppUri()629 void Downloader::OpenAppUri()
630 {
631     {
632         AutoLock lock(closeMutex_);
633         if (currentRequest_ != nullptr) {
634             appPreviousRequestUrl_ = currentRequest_->GetUrl();
635         }
636         if (sourceLoader_ != nullptr && currentRequest_ != nullptr) {
637             if (uuid_ != 0) {
638                 sourceLoader_->Close(uuid_);
639                 MEDIA_LOG_D("0x%{public}06" PRIXPTR "LoaderCombinations Close uuid " PUBLIC_LOG_D64,
640                     FAKE_POINTER(this), uuid_);
641             }
642 
643             int64_t uuid = 0;
644             for (int i = 0; i < APP_OPEN_RETRY_TIMES; i++) {
645                 uuid = sourceLoader_->Open(appPreviousRequestUrl_, currentRequest_->GetHttpHeader(), client_);
646                 if (uuid > 0) {
647                     break;
648                 }
649                 MEDIA_LOG_D("0x%{public}06" PRIXPTR "Open retry " PUBLIC_LOG_D64 " retryTimes: " PUBLIC_LOG_D32,
650                 FAKE_POINTER(this), uuid, i);
651             }
652             MEDIA_LOG_I("0x%{public}06" PRIXPTR "LoaderCombinations Open uuid " PUBLIC_LOG_D64,
653                 FAKE_POINTER(this), uuid);
654             if (uuid != 0) {
655                 client_->SetUuid(uuid);
656                 uuid_ = uuid;
657             } else {
658                 MEDIA_LOG_E("0x%{public}06" PRIXPTR "Open faild, uuid " PUBLIC_LOG_D64,
659                 FAKE_POINTER(this), uuid);
660                 std::shared_ptr<Downloader> unused;
661                 currentRequest_->statusCallback_(DownloadStatus::PARTTAL_DOWNLOAD, unused, currentRequest_);
662             }
663         }
664     }
665 }
666 
HandleRedirect(Status & ret)667 void Downloader::HandleRedirect(Status& ret)
668 {
669     if (!currentRequest_->location_.empty() && !currentRequest_->haveRedirectRetry_.load()) {
670         currentRequest_->clientError_ = 0;
671         currentRequest_->serverError_ = REDIRECT_CODE;
672         ret = Status::ERROR_SERVER;
673         currentRequest_->url_ = currentRequest_->location_;
674         currentRequest_->haveRedirectRetry_.store(true);
675         currentRequest_->headerInfo_.contentLen = 0;
676     }
677 }
678 
HandleResponseCb(int32_t clientCode,int32_t serverCode,Status & ret)679 void Downloader::HandleResponseCb(int32_t clientCode, int32_t serverCode, Status& ret)
680 {
681     currentRequest_->clientError_ = clientCode;
682     currentRequest_->serverError_ = serverCode;
683 
684     HandleRedirect(ret);
685 
686     if (isDestructor_) {
687         return;
688     }
689     if (currentRequest_->preRequestSize_ == FIRST_REQUEST_SIZE && !currentRequest_->isFirstRangeRequestReady_
690         && currentRequest_->serverError_ == SERVER_RANGE_ERROR_CODE) {
691         MEDIA_LOG_I("first request is above filesize, need retry.");
692         currentRequest_->startPos_ = 0;
693         currentRequest_->requestSize_ = MIN_REQUEST_SIZE;
694         currentRequest_->isHeaderUpdated_ = false;
695         currentRequest_->isFirstRangeRequestReady_ = true;
696         currentRequest_->headerInfo_.fileContentLen = 0;
697         return;
698     }
699     if (ret == Status::OK) {
700         HandleRetOK();
701     } else {
702         PauseLoop(true);
703         MEDIA_LOG_E("Client request data failed. ret = " PUBLIC_LOG_D32 ", clientCode = " PUBLIC_LOG_D32
704             ", request queue size: " PUBLIC_LOG_U64, static_cast<int32_t>(ret),
705             static_cast<int32_t>(clientCode), static_cast<int64_t>(requestQue_->Size()));
706         HandleRetErrorCode();
707         std::shared_ptr<Downloader> unused;
708         currentRequest_->statusCallback_(DownloadStatus::PARTTAL_DOWNLOAD, unused, currentRequest_);
709     }
710 }
711 
RequestData()712 void Downloader::RequestData()
713 {
714     MediaAVCodec::AVCodecTrace trace("Downloader::HttpDownloadLoop, startPos: "
715         + std::to_string(currentRequest_->startPos_) + ", reqSize: " + std::to_string(currentRequest_->requestSize_));
716     int64_t startPos = currentRequest_->startPos_;
717     if (currentRequest_->requestWholeFile_ && currentRequest_->shouldSaveData_) {
718         startPos = -1;
719     }
720     RequestInfo sourceInfo;
721     sourceInfo.url = currentRequest_->url_;
722     sourceInfo.httpHeader = currentRequest_->httpHeader_;
723     sourceInfo.timeoutMs = currentRequest_->requestInfo_.timeoutMs;
724 
725     if ((currentRequest_->protocolType_ == RequestProtocolType::HTTP && uuid_ == 0) ||
726         currentRequest_->protocolType_ == RequestProtocolType::HLS ||
727         currentRequest_->protocolType_ == RequestProtocolType::DASH) {
728         OpenAppUri();
729     }
730 
731     auto handleResponseCb = [this](int32_t clientCode, int32_t serverCode, Status ret) {
732         HandleResponseCb(clientCode, serverCode, ret);
733     };
734     MEDIA_LOG_I("0x%{public}06" PRIXPTR " RequestData enter.", FAKE_POINTER(this));
735     int len = currentRequest_->requestSize_;
736     if (currentRequest_->requestWholeFile_) {
737         len = 0;
738     }
739     client_->RequestData(startPos, len, sourceInfo, handleResponseCb);
740     MEDIA_LOG_I("0x%{public}06" PRIXPTR " RequestData end.", FAKE_POINTER(this));
741 }
742 
HandleRetErrorCode()743 void Downloader::HandleRetErrorCode()
744 {
745     if (currentRequest_ && currentRequest_->serverError_ == REQUEST_OFTEN_ERROR_CODE) {
746         int sleepTime = 0;
747         while (!isInterruptNeeded_ && sleepTime <= 1000) { // 1000:sleep 1s
748             Task::SleepInTask(SLEEP_TEN_MICRO_SEC);
749             sleepTime += SLEEP_TEN_MICRO_SEC;
750         }
751     }
752 }
HandlePlayingFinish()753 void Downloader::HandlePlayingFinish()
754 {
755     if (requestQue_->Empty()) {
756         PauseLoop(true);
757     }
758     shouldStartNextRequest = true;
759     if (currentRequest_->downloadDoneCallback_ && !isDestructor_) {
760         currentRequest_->downloadDoneTime_ = currentRequest_->GetNowTime();
761         currentRequest_->downloadDoneCallback_(currentRequest_->GetUrl(), currentRequest_->location_);
762         currentRequest_->isFirstRangeRequestReady_ = false;
763     }
764 }
765 
HandleRetOK()766 void Downloader::HandleRetOK()
767 {
768     if (currentRequest_->retryTimes_ > 0) {
769         currentRequest_->retryTimes_ = 0;
770     }
771     if (currentRequest_->headerInfo_.isChunked && requestQue_->Empty()) {
772         currentRequest_->isEos_ = true;
773         PauseLoop(true);
774         return;
775     }
776 
777     int64_t remaining = 0;
778     if (currentRequest_->endPos_ <= 0) {
779         remaining = static_cast<int64_t>(currentRequest_->headerInfo_.fileContentLen) -
780                     currentRequest_->startPos_;
781     } else {
782         remaining = currentRequest_->endPos_ - currentRequest_->startPos_ + 1;
783     }
784     if (currentRequest_->headerInfo_.fileContentLen > 0 && remaining <= 0) { // Check whether the playback ends.
785         MEDIA_LOG_I("http transfer reach end, startPos_ " PUBLIC_LOG_D64, currentRequest_->startPos_);
786         currentRequest_->isEos_ = true;
787         HandlePlayingFinish();
788         return;
789     }
790     if (currentRequest_->headerInfo_.fileContentLen == 0 && remaining <= 0) {
791         currentRequest_->isEos_ = true;
792         currentRequest_->Close();
793         HandlePlayingFinish();
794         return;
795     }
796     if (remaining < PER_REQUEST_SIZE) {
797         currentRequest_->requestSize_ = remaining;
798     } else {
799         currentRequest_->requestSize_ = PER_REQUEST_SIZE;
800     }
801 }
802 
UpdateHeaderInfo(Downloader * mediaDownloader)803 void Downloader::UpdateHeaderInfo(Downloader* mediaDownloader)
804 {
805     if (mediaDownloader->currentRequest_->isHeaderUpdated_) {
806         return;
807     }
808     MEDIA_LOG_I("UpdateHeaderInfo enter.");
809     HeaderInfo* info = &(mediaDownloader->currentRequest_->headerInfo_);
810     if (info->contentLen > 0 && info->contentLen < LIVE_CONTENT_LENGTH) {
811         info->isChunked = false;
812     }
813     if (info->contentLen <= 0 && !mediaDownloader->currentRequest_->IsM3u8Request()) {
814         info->isChunked = true;
815     }
816     if (info->fileContentLen > 0 && info->isChunked && !mediaDownloader->currentRequest_->IsM3u8Request()) {
817         info->isChunked = false;
818     }
819     mediaDownloader->currentRequest_->SaveHeader(info);
820     if (!mediaDownloader->isContentTypeUpdated_) {
821         {
822             AutoLock lock(mediaDownloader->sleepMutex_);
823             mediaDownloader->isContentTypeUpdated_ = true;
824             mediaDownloader->contentType_ = info->contentType;
825         }
826         mediaDownloader->sleepCond_.NotifyOne();
827     }
828 }
829 
IsDropDataRetryRequest(Downloader * mediaDownloader)830 bool Downloader::IsDropDataRetryRequest(Downloader* mediaDownloader)
831 {
832     bool isWholeFileRetry = mediaDownloader->currentRequest_->requestWholeFile_ &&
833                             mediaDownloader->currentRequest_->shouldSaveData_ &&
834                             mediaDownloader->currentRequest_->retryOnGoing_;
835     if (!isWholeFileRetry) {
836         return false;
837     }
838     if (mediaDownloader->currentRequest_->startPos_ > 0) {
839         return true;
840     } else {
841         mediaDownloader->currentRequest_->retryOnGoing_ = false;
842         return false;
843     }
844 }
845 
DropRetryData(void * buffer,size_t dataLen,Downloader * mediaDownloader)846 size_t Downloader::DropRetryData(void* buffer, size_t dataLen, Downloader* mediaDownloader)
847 {
848     auto currentRequest_ = mediaDownloader->currentRequest_;
849     int64_t needDropLen = currentRequest_->startPos_ - currentRequest_->dropedDataLen_;
850     int64_t writeOffSet = -1;
851     if (needDropLen > 0) {
852         writeOffSet = needDropLen >= static_cast<int64_t>(dataLen) ? 0 : needDropLen; // 0:drop all
853     }
854     bool dropRet = false;
855     uint32_t writeLen = 0;
856     if (writeOffSet > 0) {
857         int64_t secondParam = static_cast<int64_t>(dataLen) - writeOffSet;
858         if (secondParam < 0) {
859             secondParam = 0;
860         }
861         writeLen = currentRequest_->saveData_(static_cast<uint8_t *>(buffer) + writeOffSet,
862             static_cast<uint32_t>(secondParam), mediaDownloader->isNotBlock_);
863         dropRet = writeLen == secondParam;
864         currentRequest_->dropedDataLen_ = currentRequest_->dropedDataLen_ + writeOffSet;
865         MEDIA_LOG_D("DropRetryData: last drop, droped len " PUBLIC_LOG_D64 ", startPos_ " PUBLIC_LOG_D64,
866                     currentRequest_->dropedDataLen_, currentRequest_->startPos_);
867     } else if (writeOffSet == 0) {
868         currentRequest_->dropedDataLen_ += static_cast<int64_t>(dataLen);
869         dropRet = true;
870         MEDIA_LOG_D("DropRetryData: drop, droped len " PUBLIC_LOG_D64 ", startPos_ " PUBLIC_LOG_D64,
871                     currentRequest_->dropedDataLen_, currentRequest_->startPos_);
872     } else {
873         MEDIA_LOG_E("drop data error");
874     }
875     if (dropRet && currentRequest_->startPos_ == currentRequest_->dropedDataLen_) {
876         currentRequest_->retryOnGoing_ = false;
877         currentRequest_->dropedDataLen_ = 0;
878         if (writeOffSet > 0) {
879             currentRequest_->startPos_ += static_cast<int64_t>(dataLen) - writeOffSet;
880         }
881         MEDIA_LOG_I("drop data finished, startPos_ " PUBLIC_LOG_D64, currentRequest_->startPos_);
882     }
883     if (!dropRet && mediaDownloader->sourceLoader_ != nullptr) {
884         mediaDownloader->currentRequest_->startPos_ += static_cast<int64_t>(writeLen);
885         mediaDownloader->PauseLoop(true);
886         mediaDownloader->currentRequest_->retryOnGoing_ = true;
887         mediaDownloader->currentRequest_->dropedDataLen_ = 0;
888     }
889     return dropRet ? dataLen : 0; // 0:save data failed or drop error
890 }
891 
UpdateCurRequest(Downloader * mediaDownloader,HeaderInfo * header)892 void Downloader::UpdateCurRequest(Downloader* mediaDownloader, HeaderInfo* header)
893 {
894     int64_t hstTime = 0;
895     Sec2HstTime(mediaDownloader->currentRequest_->GetDuration(), hstTime);
896     int64_t startTimePos = mediaDownloader->currentRequest_->startTimePos_;
897     int64_t contenLen = static_cast<int64_t>(header->fileContentLen);
898     int64_t startPos = 0;
899     if (hstTime != 0) {
900         startPos = contenLen * startTimePos / (HstTime2Ns(hstTime));
901     }
902     mediaDownloader->currentRequest_->startPos_ = startPos;
903     mediaDownloader->currentRequest_->shouldSaveData_ = true;
904     mediaDownloader->currentRequest_->requestWholeFile_ = false;
905     mediaDownloader->currentRequest_->requestSize_ = PER_REQUEST_SIZE;
906     mediaDownloader->currentRequest_->startTimePos_ = 0;
907 }
908 
HandleFileContentLen(HeaderInfo * header)909 void Downloader::HandleFileContentLen(HeaderInfo* header)
910 {
911     if (header->fileContentLen == 0) {
912         if (header->contentLen > 0) {
913             MEDIA_LOG_W("Unsupported range, use content length as content file length, contentLen: " PUBLIC_LOG_D32,
914                 static_cast<int32_t>(header->contentLen));
915             header->fileContentLen = static_cast<size_t>(header->contentLen);
916         } else {
917             MEDIA_LOG_D("fileContentLen and contentLen are both zero.");
918         }
919     }
920 }
921 
UpdateRequestSize(Downloader * mediaDownloader)922 void Downloader::UpdateRequestSize(Downloader* mediaDownloader)
923 {
924     int64_t remaining = 0;
925     if (mediaDownloader->currentRequest_->endPos_ <= 0) {
926         remaining = static_cast<int64_t>(mediaDownloader->currentRequest_->headerInfo_.fileContentLen) -
927                     mediaDownloader->currentRequest_->startPos_;
928     } else {
929         remaining = mediaDownloader->currentRequest_->endPos_ - mediaDownloader->currentRequest_->startPos_ + 1;
930     }
931 
932     mediaDownloader->currentRequest_->preRequestSize_ = mediaDownloader->currentRequest_->requestSize_;
933     mediaDownloader->currentRequest_->requestSize_ = remaining < PER_REQUEST_SIZE ? remaining : PER_REQUEST_SIZE;
934 }
935 
RxBodyData(void * buffer,size_t size,size_t nitems,void * userParam)936 size_t Downloader::RxBodyData(void* buffer, size_t size, size_t nitems, void* userParam)
937 {
938     auto mediaDownloader = static_cast<Downloader *>(userParam);
939     size_t dataLen = size * nitems;
940     int64_t curLen = mediaDownloader->currentRequest_->realRecvContentLen_;
941     int64_t realRecvContentLen = static_cast<int64_t>(dataLen) + curLen;
942 
943     if (!mediaDownloader->currentRequest_->location_.empty() &&
944         !mediaDownloader->currentRequest_->haveRedirectRetry_.load()) {
945         MEDIA_LOG_W("Receive location, need retry.");
946         return 0;
947     }
948 
949     UpdateHeaderInfo(mediaDownloader);
950     MediaAVCodec::AVCodecTrace trace("Downloader::RxBodyData, dataLen: " + std::to_string(dataLen)
951         + ", realRecvContentLen: " + std::to_string(realRecvContentLen));
952     mediaDownloader->currentRequest_->realRecvContentLen_ = realRecvContentLen;
953 
954     if (IsDropDataRetryRequest(mediaDownloader) && !mediaDownloader->currentRequest_->IsIndexM3u8Request()) {
955         return DropRetryData(buffer, dataLen, mediaDownloader);
956     }
957     HeaderInfo* header = &(mediaDownloader->currentRequest_->headerInfo_);
958     if (!mediaDownloader->currentRequest_->shouldSaveData_) {
959         UpdateCurRequest(mediaDownloader, header);
960         return dataLen;
961     }
962     HandleFileContentLen(header);
963     if (!mediaDownloader->currentRequest_->isDownloading_) {
964         mediaDownloader->currentRequest_->isDownloading_ = true;
965     }
966     uint32_t writeLen = mediaDownloader->currentRequest_->saveData_(static_cast<uint8_t *>(buffer),
967         static_cast<uint32_t>(dataLen), mediaDownloader->isNotBlock_);
968     MEDIA_LOGI_LIMIT(DOWNLOAD_LOG_FEQUENCE, "RxBodyData: dataLen " PUBLIC_LOG_ZU ", startPos_ " PUBLIC_LOG_D64, dataLen,
969                      mediaDownloader->currentRequest_->startPos_);
970     mediaDownloader->currentRequest_->startPos_ = mediaDownloader->currentRequest_->startPos_ +
971                                                   static_cast<int64_t>(writeLen);
972     UpdateRequestSize(mediaDownloader);
973 
974     if (writeLen != dataLen) {
975         if (mediaDownloader->sourceLoader_ != nullptr) {
976             mediaDownloader->PauseLoop(true);
977             mediaDownloader->currentRequest_->retryOnGoing_ = true;
978             mediaDownloader->currentRequest_->dropedDataLen_ = 0;
979         }
980         MEDIA_LOG_W("Save data failed.");
981         return 0; // save data failed, make perform finished.
982     }
983 
984     mediaDownloader->currentRequest_->isDownloading_ = false;
985     return dataLen;
986 }
987 
988 namespace {
StringTrim(char * str)989 char* StringTrim(char* str)
990 {
991     if (str == nullptr) {
992         return nullptr;
993     }
994     char* p = str;
995     char* p1 = p + strlen(str) - 1;
996 
997     while (*p && isspace(static_cast<int>(*p))) {
998         p++;
999     }
1000     while (p1 > p && isspace(static_cast<int>(*p1))) {
1001         *p1-- = 0;
1002     }
1003     return p;
1004 }
1005 }
1006 
HandleContentRange(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)1007 bool Downloader::HandleContentRange(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
1008 {
1009     if (!strncmp(key, "content-range", strlen("content-range"))) {
1010         char* token = strtok_s(nullptr, ":", &next);
1011         FALSE_RETURN_V(token != nullptr, false);
1012         char* strRange = StringTrim(token);
1013         size_t start;
1014         size_t end;
1015         size_t fileLen;
1016         FALSE_LOG_MSG(sscanf_s(strRange, "bytes %lu-%lu/%lu", &start, &end, &fileLen) != -1,
1017             "sscanf get range failed");
1018         if (info->fileContentLen > 0 && info->fileContentLen != fileLen) {
1019             MEDIA_LOG_E("FileContentLen doesn't equal to fileLen");
1020         }
1021         if (info->fileContentLen == 0) {
1022             info->fileContentLen = fileLen;
1023         }
1024     }
1025     return true;
1026 }
1027 
HandleContentType(HeaderInfo * info,char * key,char * next,size_t headerSize,Downloader * mediaDownloader)1028 bool Downloader::HandleContentType(HeaderInfo* info, char* key, char* next, size_t headerSize,
1029                                    Downloader* mediaDownloader)
1030 {
1031     if (!strncmp(key, "content-type", strlen("content-type"))) {
1032         char* token = strtok_s(nullptr, ":", &next);
1033         FALSE_RETURN_V(token != nullptr, false);
1034         char* type = StringTrim(token);
1035         std::string headStr = (std::string)token;
1036         MEDIA_LOG_I("content-type: " PUBLIC_LOG_S, headStr.c_str());
1037         NZERO_LOG(memcpy_s(info->contentType, sizeof(info->contentType), type, strlen(type)));
1038     }
1039     return true;
1040 }
1041 
HandleContentEncode(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)1042 bool Downloader::HandleContentEncode(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
1043 {
1044     if (!strncmp(key, "content-encode", strlen("content-encode"))) {
1045         char* token = strtok_s(nullptr, ":", &next);
1046         FALSE_RETURN_V(token != nullptr, false);
1047         std::string headStr = (std::string)token;
1048         MEDIA_LOG_I("content-encode: " PUBLIC_LOG_S, headStr.c_str());
1049     }
1050     return true;
1051 }
1052 
HandleContentLength(HeaderInfo * info,char * key,char * next,Downloader * mediaDownloader)1053 bool Downloader::HandleContentLength(HeaderInfo* info, char* key, char* next, Downloader* mediaDownloader)
1054 {
1055     FALSE_RETURN_V(key != nullptr, false);
1056     if (!strncmp(key, "content-length", strlen("content-length"))) {
1057         FALSE_RETURN_V(next != nullptr, false);
1058         char* token = strtok_s(nullptr, ":", &next);
1059         FALSE_RETURN_V(token != nullptr, false);
1060         if (info != nullptr && mediaDownloader != nullptr) {
1061             info->contentLen = atol(StringTrim(token));
1062             MEDIA_LOG_I("content-length: " PUBLIC_LOG_D32, static_cast<int32_t>(info->contentLen));
1063             if (info->contentLen <= 0 && !mediaDownloader->currentRequest_->IsM3u8Request()) {
1064                 info->isChunked = true;
1065             }
1066         }
1067     }
1068     return true;
1069 }
1070 
1071 // Check if this server supports range download. (HTTP)
HandleRange(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)1072 bool Downloader::HandleRange(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
1073 {
1074     if (!strncmp(key, "accept-ranges", strlen("accept-ranges"))) {
1075         char* token = strtok_s(nullptr, ":", &next);
1076         FALSE_RETURN_V(token != nullptr, false);
1077         if (!strncmp(StringTrim(token), "bytes", strlen("bytes"))) {
1078             info->isServerAcceptRange = true;
1079             MEDIA_LOG_I("accept-ranges: bytes");
1080         }
1081     }
1082     if (!strncmp(key, "content-range", strlen("content-range"))) {
1083         char* token = strtok_s(nullptr, ":", &next);
1084         FALSE_RETURN_V(token != nullptr, false);
1085         std::string headStr = (std::string)token;
1086         if (headStr.find("bytes") != std::string::npos) {
1087             info->isServerAcceptRange = true;
1088             MEDIA_LOG_I("content-range: " PUBLIC_LOG_S, headStr.c_str());
1089         }
1090     }
1091     return true;
1092 }
1093 
ToLower(char * str)1094 void Downloader::ToLower(char* str)
1095 {
1096     FALSE_RETURN(str != nullptr);
1097     for (int i = 0; str[i] != '\0'; ++i) {
1098         if (i > MAX_LOOP_TIMES) {
1099             break;
1100         }
1101         if (str[i] >= 'A' && str[i] <= 'Z') {
1102             str[i] = tolower(static_cast<unsigned char>(str[i]));
1103         }
1104     }
1105 }
1106 
RxHeaderData(void * buffer,size_t size,size_t nitems,void * userParam)1107 size_t Downloader::RxHeaderData(void* buffer, size_t size, size_t nitems, void* userParam)
1108 {
1109     MediaAVCodec::AVCodecTrace trace("Downloader::RxHeaderData");
1110     auto mediaDownloader = static_cast<Downloader *>(userParam);
1111     HeaderInfo* info = &(mediaDownloader->currentRequest_->headerInfo_);
1112     if (mediaDownloader->currentRequest_->isHeaderUpdated_) {
1113         return size * nitems;
1114     }
1115     char* next = nullptr;
1116     char* key = strtok_s(reinterpret_cast<char*>(buffer), ":", &next);
1117     FALSE_RETURN_V(key != nullptr, size * nitems);
1118     ToLower(key);
1119 
1120     if (!strncmp(key, "transfer-encoding", strlen("transfer-encoding"))) {
1121         char* token = strtok_s(nullptr, ":", &next);
1122         FALSE_RETURN_V(token != nullptr, size * nitems);
1123         if (!strncmp(StringTrim(token), "chunked", strlen("chunked")) &&
1124             !mediaDownloader->currentRequest_->IsM3u8Request()) {
1125             info->isChunked = true;
1126             if (static_cast<int32_t>(mediaDownloader->currentRequest_->url_.find(".flv") == std::string::npos)) {
1127                 info->contentLen = LIVE_CONTENT_LENGTH;
1128             } else {
1129                 info->contentLen = 0;
1130             }
1131             std::string headStr = (std::string)token;
1132             MEDIA_LOG_I("transfer-encoding: " PUBLIC_LOG_S, headStr.c_str());
1133         }
1134     }
1135     if (!strncmp(key, "location", strlen("location"))) {
1136         FALSE_RETURN_V(next != nullptr, size * nitems);
1137         char* headTrim = StringTrim(next);
1138         MEDIA_LOG_I("redirect: " PUBLIC_LOG_S, headTrim);
1139         mediaDownloader->currentRequest_->location_ = headTrim;
1140     }
1141 
1142     if (!HandleContentRange(info, key, next, size, nitems) ||
1143         !HandleContentType(info, key, next, size * nitems, mediaDownloader) ||
1144         !HandleContentEncode(info, key, next, size, nitems) ||
1145         !HandleContentLength(info, key, next, mediaDownloader) ||
1146         !HandleRange(info, key, next, size, nitems)) {
1147         return size * nitems;
1148     }
1149 
1150     return size * nitems;
1151 }
1152 
PauseLoop(bool isAsync)1153 void Downloader::PauseLoop(bool isAsync)
1154 {
1155     if (task_ == nullptr) {
1156         return;
1157     }
1158     if (isAsync) {
1159         task_->PauseAsync();
1160     } else {
1161         task_->Pause();
1162     }
1163 }
1164 
SetAppUid(int32_t appUid)1165 void Downloader::SetAppUid(int32_t appUid)
1166 {
1167     if (client_) {
1168         client_->SetAppUid(appUid);
1169     }
1170 }
1171 
GetCurrentRequest()1172 const std::shared_ptr<DownloadRequest>& Downloader::GetCurrentRequest()
1173 {
1174     return currentRequest_;
1175 }
1176 
SetInterruptState(bool isInterruptNeeded)1177 void Downloader::SetInterruptState(bool isInterruptNeeded)
1178 {
1179     MEDIA_LOG_I("0x%{public}06" PRIXPTR " Downloader SetInterruptState %{public}d",
1180         FAKE_POINTER(this), isInterruptNeeded);
1181     {
1182         AutoLock lk(loopPauseMutex_);
1183         AutoLock lock(sleepMutex_);
1184         isInterruptNeeded_ = isInterruptNeeded;
1185     }
1186     if (currentRequest_ != nullptr) {
1187         currentRequest_->isInterruptNeeded_ = isInterruptNeeded;
1188     }
1189     if (isInterruptNeeded) {
1190         MEDIA_LOG_I("SetInterruptState, Notify.");
1191         sleepCond_.NotifyOne();
1192     }
1193     if (sourceLoader_ != nullptr) {
1194         client_->Close(false);
1195     }
1196     NotifyLoopPause();
1197 }
1198 
NotifyLoopPause()1199 void Downloader::NotifyLoopPause()
1200 {
1201     AutoLock lk(loopPauseMutex_);
1202     if (loopStatus_ == LoopStatus::PAUSE || isInterruptNeeded_) {
1203         MEDIA_LOG_I("0x%{public}06" PRIXPTR " Downloader NotifyLoopPause", FAKE_POINTER(this));
1204         loopStatus_ = LoopStatus::IDLE;
1205         loopPauseCond_.NotifyAll();
1206     } else {
1207         loopStatus_ = LoopStatus::IDLE;
1208         MEDIA_LOG_I("Downloader not NotifyLoopPause loopStatus %{public}d isInterruptNeeded %{public}d",
1209             loopStatus_.load(), isInterruptNeeded_.load());
1210     }
1211 }
1212 
WaitLoopPause()1213 void Downloader::WaitLoopPause()
1214 {
1215     AutoLock lk(loopPauseMutex_);
1216     if (loopStatus_ == LoopStatus::IDLE) {
1217         MEDIA_LOG_I("0x%{public}06" PRIXPTR "Downloader not WaitLoopPause loopStatus is idle", FAKE_POINTER(this));
1218         return;
1219     }
1220     MEDIA_LOG_I("0x%{public}06" PRIXPTR "Downloader WaitLoopPause task loopStatus_ %{public}d",
1221         FAKE_POINTER(this), loopStatus_.load());
1222     loopStatus_ = LoopStatus::PAUSE;
1223     loopPauseCond_.Wait(lk, [this]() {
1224         MEDIA_LOG_I("0x%{public}06" PRIXPTR " WaitLoopPause wake loopStatus %{public}d",
1225             FAKE_POINTER(this), loopStatus_.load());
1226         return loopStatus_ != LoopStatus::PAUSE || isInterruptNeeded_;
1227     });
1228 }
1229 
SetAppState(bool isAppBackground)1230 void Downloader::SetAppState(bool isAppBackground)
1231 {
1232     isAppBackground_ = isAppBackground;
1233 }
1234 
StopBufferring()1235 void Downloader::StopBufferring()
1236 {
1237     MediaAVCodec::AVCodecTrace trace("Downloader::StopBufferring");
1238     FALSE_RETURN_MSG(task_ != nullptr && currentRequest_ != nullptr, "task or request is null");
1239     if (isAppBackground_) {
1240         FALSE_RETURN_NOLOG(client_ != nullptr);
1241         MEDIA_LOG_I("StopBufferring: is task not running.");
1242         client_->Close(false);
1243         client_->Deinit();
1244         {
1245             AutoLock lk(operatorMutex_);
1246             client_ = nullptr;
1247         }
1248     } else {
1249         {
1250             AutoLock lk(operatorMutex_);
1251             if (client_ == nullptr) {
1252                 MEDIA_LOG_I("StopBufferring: restart task.");
1253                 client_ = NetworkClient::GetInstance(&RxHeaderData, &RxBodyData, this);
1254                 client_->Init();
1255                 client_->Open(currentRequest_->url_, currentRequest_->httpHeader_,
1256                     currentRequest_->requestInfo_.timeoutMs);
1257                 if (currentRequest_->startPos_ > 0 && currentRequest_->protocolType_ != RequestProtocolType::HTTP) {
1258                     currentRequest_->retryOnGoing_ = true;
1259                     currentRequest_->dropedDataLen_ = 0;
1260                 }
1261                 MEDIA_LOG_I("StopBufferring: begin pos " PUBLIC_LOG_U64, currentRequest_->startPos_);
1262             }
1263         }
1264         Start();
1265     }
1266 }
1267 }
1268 }
1269 }
1270 }
1271