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