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 int32_t DownloadRequest::GetClientError() const
141 {
142 return clientError_;
143 }
144
GetServerError() const145 int32_t 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 if (currentRequest_->endPos_ > 0 && currentRequest_->startPos_ >= 0 &&
450 currentRequest_->endPos_ >= currentRequest_->startPos_) {
451 currentRequest_->requestSize_ = currentRequest_->endPos_ - currentRequest_->startPos_ + 1;
452 }
453 }
454 }
455 task_->Start();
456 return true;
457 }
458
GetSystemParam(const std::string & key)459 std::string GetSystemParam(const std::string &key)
460 {
461 char value[MAX_LEN] = {0};
462 int32_t ret = GetParameter(key.c_str(), "", value, MAX_LEN);
463 if (ret < 0) {
464 return "";
465 }
466 return std::string(value);
467 }
468
GetUserAgent()469 std::string GetUserAgent()
470 {
471 std::string displayVersion = GetSystemParam(DISPLAYVERSION);
472 std::string userAgent = " AVPlayerLib " + displayVersion;
473 return userAgent;
474 }
475
BeginDownload()476 bool Downloader::BeginDownload()
477 {
478 MEDIA_LOG_I("BeginDownload");
479 std::string url = currentRequest_->url_;
480 std::map<std::string, std::string> httpHeader = currentRequest_->httpHeader_;
481
482 if (currentRequest_->httpHeader_.count(USER_AGENT) <= 0) {
483 currentRequest_->httpHeader_[USER_AGENT] = GetUserAgent();
484 httpHeader[USER_AGENT] = GetUserAgent();
485 MEDIA_LOG_I("Set default UA.");
486 }
487
488 int32_t timeoutMs = currentRequest_->requestInfo_.timeoutMs;
489 FALSE_RETURN_V(!url.empty(), false);
490 if (client_) {
491 client_->Open(url, httpHeader, timeoutMs);
492 }
493
494 if (currentRequest_->endPos_ <= 0) {
495 currentRequest_->startPos_ = 0;
496 currentRequest_->requestSize_ = FIRST_REQUEST_SIZE;
497 } else {
498 int64_t temp = currentRequest_->endPos_ - currentRequest_->startPos_ + 1;
499 currentRequest_->requestSize_ = static_cast<int>(std::min(temp, static_cast<int64_t>(PER_REQUEST_SIZE)));
500 }
501 currentRequest_->isEos_ = false;
502 currentRequest_->retryTimes_ = 0;
503 currentRequest_->downloadStartTime_ = currentRequest_->GetNowTime();
504 MEDIA_LOG_I("End");
505 return true;
506 }
507
HttpDownloadLoop()508 void Downloader::HttpDownloadLoop()
509 {
510 AutoLock lock(operatorMutex_);
511 MEDIA_LOGI_LIMIT(LOOP_LOG_FEQUENCE, "Downloader loop shouldStartNextRequest %{public}d",
512 shouldStartNextRequest.load());
513 if (shouldStartNextRequest) {
514 std::shared_ptr<DownloadRequest> tempRequest = requestQue_->Pop(1000); // 1000ms timeout limit.
515 if (!tempRequest) {
516 MEDIA_LOG_W("HttpDownloadLoop tempRequest is null.");
517 noTaskLoopTimes_++;
518 if (noTaskLoopTimes_ >= LOOP_TIMES) {
519 PauseLoop(true);
520 }
521 return;
522 }
523 noTaskLoopTimes_ = 0;
524 currentRequest_ = tempRequest;
525 BeginDownload();
526 shouldStartNextRequest = currentRequest_->IsClosed();
527 }
528 if (currentRequest_ == nullptr || client_ == nullptr) {
529 MEDIA_LOG_I("currentRequest_ %{public}d client_ %{public}d nullptr",
530 currentRequest_ != nullptr, client_ != nullptr);
531 PauseLoop(true);
532 return;
533 }
534 RequestData();
535 return;
536 }
537
RequestData()538 void Downloader::RequestData()
539 {
540 MediaAVCodec::AVCodecTrace trace("Downloader::HttpDownloadLoop, startPos: "
541 + std::to_string(currentRequest_->startPos_) + ", reqSize: " + std::to_string(currentRequest_->requestSize_));
542 int64_t startPos = currentRequest_->startPos_;
543 if (currentRequest_->requestWholeFile_ && currentRequest_->shouldSaveData_) {
544 startPos = -1;
545 }
546 RequestInfo sourceInfo;
547 sourceInfo.url = currentRequest_->url_;
548 sourceInfo.httpHeader = currentRequest_->httpHeader_;
549 sourceInfo.timeoutMs = currentRequest_->requestInfo_.timeoutMs;
550
551 auto handleResponseCb = [this](int32_t clientCode, int32_t serverCode, Status ret) {
552 currentRequest_->clientError_ = clientCode;
553 currentRequest_->serverError_ = serverCode;
554 if (isDestructor_) {
555 return;
556 }
557
558 if (currentRequest_->requestSize_ == FIRST_REQUEST_SIZE && !currentRequest_->isFirstRangeRequestReady_
559 && currentRequest_->serverError_ == SERVER_RANGE_ERROR_CODE) {
560 MEDIA_LOG_I("first request is above filesize, need retry.");
561 currentRequest_->startPos_ = 0;
562 currentRequest_->requestSize_ = MIN_REQUEST_SIZE;
563 currentRequest_->isHeaderUpdated = false;
564 currentRequest_->isFirstRangeRequestReady_ = true;
565 currentRequest_->headerInfo_.fileContentLen = 0;
566 return;
567 }
568 if (ret == Status::OK) {
569 HandleRetOK();
570 } else {
571 PauseLoop(true);
572 MEDIA_LOG_E("Client request data failed. ret = " PUBLIC_LOG_D32 ", clientCode = " PUBLIC_LOG_D32
573 ",request queue size: " PUBLIC_LOG_U64,
574 static_cast<int32_t>(ret), static_cast<int32_t>(clientCode),
575 static_cast<int64_t>(requestQue_->Size()));
576 std::shared_ptr<Downloader> unused;
577 currentRequest_->statusCallback_(DownloadStatus::PARTTAL_DOWNLOAD, unused, currentRequest_);
578 }
579 };
580 MEDIA_LOG_I("0x%{public}06" PRIXPTR " RequestData enter.", FAKE_POINTER(this));
581 client_->RequestData(startPos, currentRequest_->requestSize_, sourceInfo, handleResponseCb);
582 MEDIA_LOG_I("0x%{public}06" PRIXPTR " RequestData end.", FAKE_POINTER(this));
583 }
584
HandlePlayingFinish()585 void Downloader::HandlePlayingFinish()
586 {
587 if (requestQue_->Empty()) {
588 PauseLoop(true);
589 }
590 shouldStartNextRequest = true;
591 if (currentRequest_->downloadDoneCallback_ && !isDestructor_) {
592 currentRequest_->downloadDoneTime_ = currentRequest_->GetNowTime();
593 currentRequest_->downloadDoneCallback_(currentRequest_->GetUrl(), currentRequest_->location_);
594 currentRequest_->isFirstRangeRequestReady_ = false;
595 }
596 }
597
HandleRetOK()598 void Downloader::HandleRetOK()
599 {
600 if (currentRequest_->retryTimes_ > 0) {
601 currentRequest_->retryTimes_ = 0;
602 }
603 if (currentRequest_->headerInfo_.isChunked && requestQue_->Empty()) {
604 currentRequest_->isEos_ = true;
605 PauseLoop(true);
606 return;
607 }
608
609 int64_t remaining = 0;
610 if (currentRequest_->endPos_ <= 0) {
611 remaining = static_cast<int64_t>(currentRequest_->headerInfo_.fileContentLen) -
612 currentRequest_->startPos_;
613 } else {
614 remaining = currentRequest_->endPos_ - currentRequest_->startPos_ + 1;
615 }
616 if (currentRequest_->headerInfo_.fileContentLen > 0 && remaining <= 0) { // Check whether the playback ends.
617 MEDIA_LOG_I("http transfer reach end, startPos_ " PUBLIC_LOG_D64, currentRequest_->startPos_);
618 currentRequest_->isEos_ = true;
619 HandlePlayingFinish();
620 return;
621 }
622 if (currentRequest_->headerInfo_.fileContentLen == 0 && remaining <= 0) {
623 currentRequest_->isEos_ = true;
624 currentRequest_->Close();
625 HandlePlayingFinish();
626 return;
627 }
628 if (remaining < PER_REQUEST_SIZE) {
629 currentRequest_->requestSize_ = remaining;
630 } else {
631 currentRequest_->requestSize_ = PER_REQUEST_SIZE;
632 }
633 }
634
UpdateHeaderInfo(Downloader * mediaDownloader)635 void Downloader::UpdateHeaderInfo(Downloader* mediaDownloader)
636 {
637 if (mediaDownloader->currentRequest_->isHeaderUpdated) {
638 return;
639 }
640 MEDIA_LOG_I("UpdateHeaderInfo enter.");
641 HeaderInfo* info = &(mediaDownloader->currentRequest_->headerInfo_);
642 if (info->contentLen > 0 && info->contentLen < LIVE_CONTENT_LENGTH) {
643 info->isChunked = false;
644 }
645 if (info->contentLen <= 0 && !mediaDownloader->currentRequest_->IsM3u8Request()) {
646 info->isChunked = true;
647 }
648 if (info->fileContentLen > 0 && info->isChunked && !mediaDownloader->currentRequest_->IsM3u8Request()) {
649 info->isChunked = false;
650 }
651 mediaDownloader->currentRequest_->SaveHeader(info);
652 }
653
IsDropDataRetryRequest(Downloader * mediaDownloader)654 bool Downloader::IsDropDataRetryRequest(Downloader* mediaDownloader)
655 {
656 bool isWholeFileRetry = mediaDownloader->currentRequest_->requestWholeFile_ &&
657 mediaDownloader->currentRequest_->shouldSaveData_ &&
658 mediaDownloader->currentRequest_->retryOnGoing_;
659 if (!isWholeFileRetry) {
660 return false;
661 }
662 if (mediaDownloader->currentRequest_->startPos_ > 0) {
663 return true;
664 } else {
665 mediaDownloader->currentRequest_->retryOnGoing_ = false;
666 return false;
667 }
668 }
669
DropRetryData(void * buffer,size_t dataLen,Downloader * mediaDownloader)670 size_t Downloader::DropRetryData(void* buffer, size_t dataLen, Downloader* mediaDownloader)
671 {
672 auto currentRequest_ = mediaDownloader->currentRequest_;
673 int64_t needDropLen = currentRequest_->startPos_ - currentRequest_->dropedDataLen_;
674 int64_t writeOffSet = -1;
675 if (needDropLen > 0) {
676 writeOffSet = needDropLen >= static_cast<int64_t>(dataLen) ? 0 : needDropLen; // 0:drop all
677 }
678 bool dropRet = false;
679 if (writeOffSet > 0) {
680 int64_t secondParam = static_cast<int64_t>(dataLen) - writeOffSet;
681 if (secondParam < 0) {
682 secondParam = 0;
683 }
684 dropRet = currentRequest_->saveData_(static_cast<uint8_t *>(buffer) + writeOffSet,
685 static_cast<uint32_t>(secondParam));
686 currentRequest_->dropedDataLen_ = currentRequest_->dropedDataLen_ + writeOffSet;
687 MEDIA_LOG_D("DropRetryData: last drop, droped len " PUBLIC_LOG_D64 ", startPos_ " PUBLIC_LOG_D64,
688 currentRequest_->dropedDataLen_, currentRequest_->startPos_);
689 } else if (writeOffSet == 0) {
690 currentRequest_->dropedDataLen_ = currentRequest_->dropedDataLen_ +
691 static_cast<int64_t>(dataLen);
692 dropRet = true;
693 MEDIA_LOG_D("DropRetryData: drop, droped len " PUBLIC_LOG_D64 ", startPos_ " PUBLIC_LOG_D64,
694 currentRequest_->dropedDataLen_, currentRequest_->startPos_);
695 } else {
696 MEDIA_LOG_E("drop data error");
697 }
698 if (dropRet && currentRequest_->startPos_ == currentRequest_->dropedDataLen_) {
699 currentRequest_->retryOnGoing_ = false;
700 currentRequest_->dropedDataLen_ = 0;
701 if (writeOffSet > 0) {
702 currentRequest_->startPos_ = currentRequest_->startPos_ +
703 static_cast<int64_t>(dataLen) - writeOffSet;
704 }
705 MEDIA_LOG_I("drop data finished, startPos_ " PUBLIC_LOG_D64, currentRequest_->startPos_);
706 }
707 return dropRet ? dataLen : 0; // 0:save data failed or drop error
708 }
709
UpdateCurRequest(Downloader * mediaDownloader,HeaderInfo * header)710 void Downloader::UpdateCurRequest(Downloader* mediaDownloader, HeaderInfo* header)
711 {
712 int64_t hstTime = 0;
713 Sec2HstTime(mediaDownloader->currentRequest_->GetDuration(), hstTime);
714 int64_t startTimePos = mediaDownloader->currentRequest_->startTimePos_;
715 int64_t contenLen = static_cast<int64_t>(header->fileContentLen);
716 int64_t startPos = 0;
717 if (hstTime != 0) {
718 startPos = contenLen * startTimePos / (HstTime2Ns(hstTime));
719 }
720 mediaDownloader->currentRequest_->startPos_ = startPos;
721 mediaDownloader->currentRequest_->shouldSaveData_ = true;
722 mediaDownloader->currentRequest_->requestWholeFile_ = false;
723 mediaDownloader->currentRequest_->requestSize_ = PER_REQUEST_SIZE;
724 mediaDownloader->currentRequest_->startTimePos_ = 0;
725 }
726
RxBodyData(void * buffer,size_t size,size_t nitems,void * userParam)727 size_t Downloader::RxBodyData(void* buffer, size_t size, size_t nitems, void* userParam)
728 {
729 auto mediaDownloader = static_cast<Downloader *>(userParam);
730 size_t dataLen = size * nitems;
731 int64_t curLen = mediaDownloader->currentRequest_->realRecvContentLen_;
732 int64_t realRecvContentLen = static_cast<int64_t>(dataLen) + curLen;
733 UpdateHeaderInfo(mediaDownloader);
734 MediaAVCodec::AVCodecTrace trace("Downloader::RxBodyData, dataLen: " + std::to_string(dataLen)
735 + ", realRecvContentLen: " + std::to_string(realRecvContentLen));
736 if (mediaDownloader->currentRequest_->IsClosed()) {
737 return 0;
738 }
739 if (IsDropDataRetryRequest(mediaDownloader)) {
740 return DropRetryData(buffer, dataLen, mediaDownloader);
741 }
742 HeaderInfo* header = &(mediaDownloader->currentRequest_->headerInfo_);
743 if (!mediaDownloader->currentRequest_->shouldSaveData_) {
744 UpdateCurRequest(mediaDownloader, header);
745 return dataLen;
746 }
747 if (header->fileContentLen == 0) {
748 if (header->contentLen > 0) {
749 MEDIA_LOG_W("Unsupported range, use content length as content file length");
750 header->fileContentLen = header->contentLen;
751 } else {
752 MEDIA_LOG_D("fileContentLen and contentLen are both zero.");
753 }
754 }
755 if (!mediaDownloader->currentRequest_->isDownloading_) {
756 mediaDownloader->currentRequest_->isDownloading_ = true;
757 }
758 if (!mediaDownloader->currentRequest_->saveData_(static_cast<uint8_t *>(buffer), static_cast<uint32_t>(dataLen))) {
759 MEDIA_LOG_W("Save data failed.");
760 return 0; // save data failed, make perform finished.
761 }
762 mediaDownloader->currentRequest_->realRecvContentLen_ = realRecvContentLen;
763 mediaDownloader->currentRequest_->isDownloading_ = false;
764 MEDIA_LOGI_LIMIT(DOWNLOAD_LOG_FEQUENCE, "RxBodyData: dataLen " PUBLIC_LOG_ZU ", startPos_ " PUBLIC_LOG_D64, dataLen,
765 mediaDownloader->currentRequest_->startPos_);
766 mediaDownloader->currentRequest_->startPos_ = mediaDownloader->currentRequest_->startPos_ + dataLen;
767 return dataLen;
768 }
769
770 namespace {
StringTrim(char * str)771 char* StringTrim(char* str)
772 {
773 if (str == nullptr) {
774 return nullptr;
775 }
776 char* p = str;
777 char* p1 = p + strlen(str) - 1;
778
779 while (*p && isspace(static_cast<int>(*p))) {
780 p++;
781 }
782 while (p1 > p && isspace(static_cast<int>(*p1))) {
783 *p1-- = 0;
784 }
785 return p;
786 }
787 }
788
HandleContentRange(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)789 bool Downloader::HandleContentRange(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
790 {
791 if (!strncmp(key, "content-range", strlen("content-range"))) {
792 char* token = strtok_s(nullptr, ":", &next);
793 FALSE_RETURN_V(token != nullptr, false);
794 char* strRange = StringTrim(token);
795 size_t start;
796 size_t end;
797 size_t fileLen;
798 FALSE_LOG_MSG(sscanf_s(strRange, "bytes %lu-%lu/%lu", &start, &end, &fileLen) != -1,
799 "sscanf get range failed");
800 if (info->fileContentLen > 0 && info->fileContentLen != fileLen) {
801 MEDIA_LOG_E("FileContentLen doesn't equal to fileLen");
802 }
803 if (info->fileContentLen == 0) {
804 info->fileContentLen = fileLen;
805 }
806 }
807 return true;
808 }
809
HandleContentType(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)810 bool Downloader::HandleContentType(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
811 {
812 if (!strncmp(key, "content-type", strlen("content-type"))) {
813 char* token = strtok_s(nullptr, ":", &next);
814 FALSE_RETURN_V(token != nullptr, false);
815 char* type = StringTrim(token);
816 std::string tokenStr = (std::string)token;
817 MEDIA_LOG_I("content-type: " PUBLIC_LOG_S, tokenStr.c_str());
818 NZERO_LOG(memcpy_s(info->contentType, sizeof(info->contentType), type, strlen(type)));
819 }
820 return true;
821 }
822
HandleContentEncode(HeaderInfo * info,char * key,char * next,size_t size,size_t nitems)823 bool Downloader::HandleContentEncode(HeaderInfo* info, char* key, char* next, size_t size, size_t nitems)
824 {
825 if (!strncmp(key, "content-encode", strlen("content-encode"))) {
826 char* token = strtok_s(nullptr, ":", &next);
827 FALSE_RETURN_V(token != nullptr, false);
828 std::string tokenStr = (std::string)token;
829 MEDIA_LOG_I("content-encode: " PUBLIC_LOG_S, tokenStr.c_str());
830 }
831 return true;
832 }
833
HandleContentLength(HeaderInfo * info,char * key,char * next,Downloader * mediaDownloader)834 bool Downloader::HandleContentLength(HeaderInfo* info, char* key, char* next, Downloader* mediaDownloader)
835 {
836 FALSE_RETURN_V(key != nullptr, false);
837 if (!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 char* token = strtok_s(nullptr, ":", &next);
856 FALSE_RETURN_V(token != nullptr, false);
857 if (!strncmp(StringTrim(token), "bytes", strlen("bytes"))) {
858 info->isServerAcceptRange = true;
859 MEDIA_LOG_I("accept-ranges: bytes");
860 }
861 }
862 if (!strncmp(key, "content-range", strlen("content-range"))) {
863 char* token = strtok_s(nullptr, ":", &next);
864 FALSE_RETURN_V(token != nullptr, false);
865 std::string tokenStr = (std::string)token;
866 std::transform(tokenStr.begin(), tokenStr.end(), tokenStr.begin(), ::tolower);
867 if (tokenStr.find("bytes") != std::string::npos) {
868 info->isServerAcceptRange = true;
869 MEDIA_LOG_I("content-range: " PUBLIC_LOG_S, tokenStr.c_str());
870 }
871 }
872 return true;
873 }
874
RxHeaderData(void * buffer,size_t size,size_t nitems,void * userParam)875 size_t Downloader::RxHeaderData(void* buffer, size_t size, size_t nitems, void* userParam)
876 {
877 MediaAVCodec::AVCodecTrace trace("Downloader::RxHeaderData");
878 auto mediaDownloader = reinterpret_cast<Downloader *>(userParam);
879 HeaderInfo* info = &(mediaDownloader->currentRequest_->headerInfo_);
880 if (mediaDownloader->currentRequest_->isHeaderUpdated) {
881 return size * nitems;
882 }
883 char* next = nullptr;
884 char* key = strtok_s(reinterpret_cast<char*>(buffer), ":", &next);
885 FALSE_RETURN_V(key != nullptr, size * nitems);
886 std::string keyStr = (std::string)key;
887 std::transform(keyStr.begin(), keyStr.end(), keyStr.begin(), ::tolower);
888 key = const_cast<char*>(keyStr.c_str());
889 if (!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 FALSE_RETURN_V(next != nullptr, size * nitems);
906 char* location = StringTrim(next);
907 mediaDownloader->currentRequest_->location_ = location;
908 }
909
910 if (!HandleContentRange(info, key, next, size, nitems) || !HandleContentType(info, key, next, size, nitems) ||
911 !HandleContentEncode(info, key, next, size, nitems) ||
912 !HandleContentLength(info, key, next, mediaDownloader) ||
913 !HandleRange(info, key, next, size, nitems)) {
914 return size * nitems;
915 }
916
917 return size * nitems;
918 }
919
PauseLoop(bool isAsync)920 void Downloader::PauseLoop(bool isAsync)
921 {
922 if (task_ == nullptr) {
923 return;
924 }
925 if (isAsync) {
926 task_->PauseAsync();
927 } else {
928 task_->Pause();
929 }
930 }
931
SetAppUid(int32_t appUid)932 void Downloader::SetAppUid(int32_t appUid)
933 {
934 if (client_) {
935 client_->SetAppUid(appUid);
936 }
937 }
938
GetCurrentRequest()939 const std::shared_ptr<DownloadRequest>& Downloader::GetCurrentRequest()
940 {
941 return currentRequest_;
942 }
943
SetInterruptState(bool isInterruptNeeded)944 void Downloader::SetInterruptState(bool isInterruptNeeded)
945 {
946 MEDIA_LOG_I("0x%{public}06" PRIXPTR " Downloader SetInterruptState %{public}d",
947 FAKE_POINTER(this), isInterruptNeeded);
948 isInterruptNeeded_ = isInterruptNeeded;
949 if (currentRequest_ != nullptr) {
950 currentRequest_->isInterruptNeeded_ = isInterruptNeeded;
951 }
952 NotifyLoopPause();
953 }
954
NotifyLoopPause()955 void Downloader::NotifyLoopPause()
956 {
957 AutoLock lk(loopPauseMutex_);
958 if (loopStatus_ == LoopStatus::PAUSE || isInterruptNeeded_) {
959 MEDIA_LOG_I("0x%{public}06" PRIXPTR " Downloader NotifyLoopPause", FAKE_POINTER(this));
960 loopStatus_ = LoopStatus::IDLE;
961 loopPauseCond_.NotifyAll();
962 } else {
963 loopStatus_ = LoopStatus::IDLE;
964 MEDIA_LOG_I("Downloader not NotifyLoopPause loopStatus %{public}d isInterruptNeeded %{public}d",
965 loopStatus_.load(), isInterruptNeeded_.load());
966 }
967 }
968
WaitLoopPause()969 void Downloader::WaitLoopPause()
970 {
971 AutoLock lk(loopPauseMutex_);
972 if (loopStatus_ == LoopStatus::IDLE) {
973 MEDIA_LOG_I("0x%{public}06" PRIXPTR "Downloader not WaitLoopPause loopStatus is idle", FAKE_POINTER(this));
974 return;
975 }
976 MEDIA_LOG_I("0x%{public}06" PRIXPTR "Downloader WaitLoopPause task loopStatus_ %{public}d",
977 FAKE_POINTER(this), loopStatus_.load());
978 loopStatus_ = LoopStatus::PAUSE;
979 loopPauseCond_.Wait(lk, [this]() {
980 MEDIA_LOG_I("0x%{public}06" PRIXPTR " WaitLoopPause wake loopStatus %{public}d",
981 FAKE_POINTER(this), loopStatus_.load());
982 return loopStatus_ != LoopStatus::PAUSE || isInterruptNeeded_;
983 });
984 }
985
986 }
987 }
988 }
989 }
990