• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2022 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 #define HST_LOG_TAG "DownloadMonitor"
16 
17 #include "download_monitor.h"
18 #include "foundation/cpp_ext/algorithm_ext.h"
19 
20 namespace OHOS {
21 namespace Media {
22 namespace Plugin {
23 namespace HttpPlugin {
24 namespace {
25     constexpr int RETRY_TIMES_TO_REPORT_ERROR = 10;
26 }
DownloadMonitor(std::shared_ptr<MediaDownloader> downloader)27 DownloadMonitor::DownloadMonitor(std::shared_ptr<MediaDownloader> downloader) noexcept
28     : downloader_(std::move(downloader))
29 {
30     auto statusCallback = [this] (DownloadStatus&& status, std::shared_ptr<Downloader>& downloader,
31         std::shared_ptr<DownloadRequest>& request) {
32         OnDownloadStatus(std::forward<decltype(downloader)>(downloader), std::forward<decltype(request)>(request));
33     };
34     downloader_->SetStatusCallback(statusCallback);
35     task_ = std::make_shared<OSAL::Task>(std::string("HttpMonitor"));
36     task_->RegisterHandler([this] { HttpMonitorLoop(); });
37     task_->Start();
38 }
39 
HttpMonitorLoop()40 void DownloadMonitor::HttpMonitorLoop()
41 {
42     if (isPlaying_) {
43         time_t nowTime;
44         time(&nowTime);
45         if ((lastReadTime_ != 0) && (nowTime - lastReadTime_ >= 60)) {  // 60
46             MEDIA_LOG_D("HttpMonitorLoop : too long without reading data, paused");
47             Pause();
48         }
49     }
50     RetryRequest task;
51     {
52         OSAL::ScopedLock lock(taskMutex_);
53         if (!retryTasks_.empty()) {
54             task = retryTasks_.front();
55             retryTasks_.pop_front();
56         }
57     }
58     if (task.request && task.function) {
59         task.function();
60     }
61     OSAL::SleepFor(50); // 50
62 }
63 
Open(const std::string & url)64 bool DownloadMonitor::Open(const std::string& url)
65 {
66     isPlaying_ = true;
67     retryTasks_.clear();
68     return downloader_->Open(url);
69 }
70 
Pause()71 void DownloadMonitor::Pause()
72 {
73     downloader_->Pause();
74     isPlaying_ = false;
75     lastReadTime_ = 0;
76 }
77 
Resume()78 void DownloadMonitor::Resume()
79 {
80     downloader_->Resume();
81     isPlaying_ = true;
82 }
83 
Close()84 void DownloadMonitor::Close()
85 {
86     retryTasks_.clear();
87     task_->Stop();
88     downloader_->Close();
89     isPlaying_ = false;
90 }
91 
Read(unsigned char * buff,unsigned int wantReadLength,unsigned int & realReadLength,bool & isEos)92 bool DownloadMonitor::Read(unsigned char *buff, unsigned int wantReadLength,
93                            unsigned int &realReadLength, bool &isEos)
94 {
95     if (!isPlaying_) {
96         Resume();
97     }
98     bool ret = downloader_->Read(buff, wantReadLength, realReadLength, isEos);
99     time(&lastReadTime_);
100     return ret;
101 }
102 
Seek(int offset)103 bool DownloadMonitor::Seek(int offset)
104 {
105     isPlaying_ = true;
106     retryTasks_.clear();
107     return downloader_->Seek(offset);
108 }
109 
GetContentLength() const110 size_t DownloadMonitor::GetContentLength() const
111 {
112     return downloader_->GetContentLength();
113 }
114 
GetDuration() const115 double DownloadMonitor::GetDuration() const
116 {
117     return downloader_->GetDuration();
118 }
119 
GetSeekable() const120 Seekable DownloadMonitor::GetSeekable() const
121 {
122     return downloader_->GetSeekable();
123 }
124 
SetCallback(Callback * cb)125 void DownloadMonitor::SetCallback(Callback* cb)
126 {
127     callback_ = cb;
128     downloader_->SetCallback(cb);
129 }
130 
SetStatusCallback(StatusCallbackFunc cb)131 void DownloadMonitor::SetStatusCallback(StatusCallbackFunc cb)
132 {
133 }
134 
GetStartedStatus()135 bool DownloadMonitor::GetStartedStatus()
136 {
137     return downloader_->GetStartedStatus();
138 }
139 
NeedRetry(const std::shared_ptr<DownloadRequest> & request)140 bool DownloadMonitor::NeedRetry(const std::shared_ptr<DownloadRequest>& request)
141 {
142     auto clientError = request->GetClientError();
143     auto serverError = request->GetServerError();
144     auto retryTimes = request->GetRetryTimes();
145     if ((clientError != NetworkClientErrorCode::ERROR_OK && clientError != NetworkClientErrorCode::ERROR_NOT_RETRY)
146         || serverError != 0) {
147         MEDIA_LOG_I("NeedRetry: clientError = " PUBLIC_LOG_D32 ", serverError = " PUBLIC_LOG_D32
148             ", retryTimes = " PUBLIC_LOG_D32, clientError, serverError, retryTimes);
149         if (retryTimes > RETRY_TIMES_TO_REPORT_ERROR) { // Report error to upper layer
150             if (clientError != NetworkClientErrorCode::ERROR_OK) {
151                 MEDIA_LOG_I("Send http client error, code " PUBLIC_LOG_D32, static_cast<int32_t>(clientError));
152                 callback_->OnEvent({PluginEventType::CLIENT_ERROR, {clientError}, "http"});
153             }
154             if (serverError != 0) {
155                 MEDIA_LOG_I("Send http server error, code " PUBLIC_LOG_D32, serverError);
156                 callback_->OnEvent({PluginEventType::SERVER_ERROR, {serverError}, "http"});
157             }
158             if (!downloader_->GetStartedStatus()) {
159                 task_->Stop();
160                 downloader_->Close();
161                 return false;
162             }
163         }
164         return true;
165     }
166     return false;
167 }
168 
OnDownloadStatus(std::shared_ptr<Downloader> & downloader,std::shared_ptr<DownloadRequest> & request)169 void DownloadMonitor::OnDownloadStatus(std::shared_ptr<Downloader>& downloader,
170                                        std::shared_ptr<DownloadRequest>& request)
171 {
172     FALSE_RETURN_MSG(downloader != nullptr, "downloader is null, url is " PUBLIC_LOG_S, request->GetUrl().c_str());
173     if (NeedRetry(request)) {
174         OSAL::ScopedLock lock(taskMutex_);
175         bool exists = CppExt::AnyOf(retryTasks_.begin(), retryTasks_.end(), [&](const RetryRequest& item) {
176             return item.request->IsSame(request);
177         });
178         if (!exists) {
179             RetryRequest retryRequest {request, [downloader, request] { downloader->Retry(request); }};
180             retryTasks_.emplace_back(std::move(retryRequest));
181         }
182     }
183 }
184 }
185 }
186 }
187 }