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