• 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 = 5;
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(bool isAsync)84 void DownloadMonitor::Close(bool isAsync)
85 {
86     retryTasks_.clear();
87     task_->Stop();
88     downloader_->Close(isAsync);
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     {
107         OSAL::ScopedLock lock(taskMutex_);
108         retryTasks_.clear();
109     }
110     return downloader_->Seek(offset);
111 }
112 
GetContentLength() const113 size_t DownloadMonitor::GetContentLength() const
114 {
115     return downloader_->GetContentLength();
116 }
117 
GetDuration() const118 double DownloadMonitor::GetDuration() const
119 {
120     return downloader_->GetDuration();
121 }
122 
GetSeekable() const123 Seekable DownloadMonitor::GetSeekable() const
124 {
125     return downloader_->GetSeekable();
126 }
127 
SetCallback(Callback * cb)128 void DownloadMonitor::SetCallback(Callback* cb)
129 {
130     callback_ = cb;
131     downloader_->SetCallback(cb);
132 }
133 
SetStatusCallback(StatusCallbackFunc cb)134 void DownloadMonitor::SetStatusCallback(StatusCallbackFunc cb)
135 {
136 }
137 
GetStartedStatus()138 bool DownloadMonitor::GetStartedStatus()
139 {
140     return downloader_->GetStartedStatus();
141 }
142 
NeedRetry(const std::shared_ptr<DownloadRequest> & request)143 bool DownloadMonitor::NeedRetry(const std::shared_ptr<DownloadRequest>& request)
144 {
145     auto clientError = request->GetClientError();
146     auto serverError = request->GetServerError();
147     auto retryTimes = request->GetRetryTimes();
148     MEDIA_LOG_I("NeedRetry: clientError = " PUBLIC_LOG_D32 ", serverError = " PUBLIC_LOG_D32
149         ", retryTimes = " PUBLIC_LOG_D32 ",", clientError, serverError, retryTimes);
150     if ((clientError != NetworkClientErrorCode::ERROR_OK && clientError != NetworkClientErrorCode::ERROR_NOT_RETRY)
151         || serverError != 0) {
152         if (retryTimes > RETRY_TIMES_TO_REPORT_ERROR) { // Report error to upper layer
153             if (clientError != NetworkClientErrorCode::ERROR_OK && callback_ != nullptr) {
154                 MEDIA_LOG_I("Send http client error, code " PUBLIC_LOG_D32, static_cast<int32_t>(clientError));
155                 callback_->OnEvent({PluginEventType::CLIENT_ERROR, {clientError}, "http"});
156             }
157             if (serverError != 0 && callback_ != nullptr) {
158                 MEDIA_LOG_I("Send http server error, code " PUBLIC_LOG_D32, serverError);
159                 callback_->OnEvent({PluginEventType::SERVER_ERROR, {serverError}, "http"});
160             }
161             task_->StopAsync();
162             // The current thread is the downloader thread, Therefore, the thread must be stopped asynchronously.
163             downloader_->Close(true);
164             return false;
165         }
166         return true;
167     }
168     return false;
169 }
170 
OnDownloadStatus(std::shared_ptr<Downloader> & downloader,std::shared_ptr<DownloadRequest> & request)171 void DownloadMonitor::OnDownloadStatus(std::shared_ptr<Downloader>& downloader,
172                                        std::shared_ptr<DownloadRequest>& request)
173 {
174     FALSE_RETURN_MSG(downloader != nullptr, "downloader is null, url is " PUBLIC_LOG_S, request->GetUrl().c_str());
175     if (NeedRetry(request)) {
176         OSAL::ScopedLock lock(taskMutex_);
177         bool exists = CppExt::AnyOf(retryTasks_.begin(), retryTasks_.end(), [&](const RetryRequest& item) {
178             return item.request->IsSame(request);
179         });
180         if (!exists) {
181             RetryRequest retryRequest {request, [downloader, request] { downloader->Retry(request); }};
182             retryTasks_.emplace_back(std::move(retryRequest));
183         }
184     }
185 }
186 }
187 }
188 }
189 }