1 /*
2 * Copyright (c) 2021-2021 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 "HttpLiteSourcePlugin"
16 #include "http_lite_source_plugin.h"
17 #include "foundation/log.h"
18 #include "foundation/osal/utils/util.h"
19
20 namespace OHOS {
21 namespace Media {
22 namespace Plugin {
23 namespace HttpLitePlugin {
24 namespace {
25 constexpr int DEFAULT_BUFFER_SIZE = 200 * 1024;
26 constexpr int DEFAULT_HTTP_PRORITY = 32;
27 constexpr int8_t RANK_MAX = 100;
28 }
29
HttpSourcePluginCreater(const std::string & name)30 std::shared_ptr<SourcePlugin> HttpSourcePluginCreater(const std::string &name)
31 {
32 return std::make_shared<HttpSourcePlugin>(name);
33 }
34
HttpSourceRegister(std::shared_ptr<Register> reg)35 const Status HttpSourceRegister(std::shared_ptr<Register> reg)
36 {
37 SourcePluginDef definition;
38 definition.name = "HttpLiteSource";
39 definition.description = "Http lite source";
40 definition.rank = RANK_MAX;
41 definition.protocol.emplace_back(ProtocolType::HTTP);
42 definition.protocol.emplace_back(ProtocolType::HTTPS);
43 definition.protocol.emplace_back(ProtocolType::HLS);
44 definition.creator = HttpSourcePluginCreater;
45 return reg->AddPlugin(definition);
46 }
__anona3910c420202null47 PLUGIN_DEFINITION(HttpLiteSource, LicenseType::APACHE_V2, HttpSourceRegister, [] {});
48
Alloc(size_t size)49 void* HttpSourceAllocator::Alloc(size_t size)
50 {
51 if (size == 0) {
52 return nullptr;
53 }
54 return reinterpret_cast<void*>(new (std::nothrow) uint8_t[size]); // NOLINT: cast
55 }
56
Free(void * ptr)57 void HttpSourceAllocator::Free(void* ptr) // NOLINT: void*
58 {
59 if (ptr != nullptr) {
60 delete[]static_cast<uint8_t*>(ptr);
61 }
62 }
63
HttpSourcePlugin(const std::string & name)64 HttpSourcePlugin::HttpSourcePlugin(const std::string& name) noexcept
65 : SourcePlugin(std::move(name)),
66 url_(""),
67 certFile_(""),
68 needExit_(false),
69 isStream_(false),
70 bufferSize_(DEFAULT_BUFFER_SIZE),
71 position_(0),
72 waterline_(0),
73 fileSize_(0),
74 httpHandle_(nullptr),
75 mAllocator_(nullptr),
76 httpMutex_()
77 {
78 MEDIA_LOG_I("HttpSourcePlugin IN");
79 }
80
~HttpSourcePlugin()81 HttpSourcePlugin::~HttpSourcePlugin()
82 {
83 MEDIA_LOG_I("~HttpSourcePlugin IN");
84 }
85
Init()86 Status HttpSourcePlugin::Init()
87 {
88 OSAL::ScopedLock lock(httpMutex_);
89 MEDIA_LOG_D("Init IN");
90 httpHandle_ = std::make_shared<HttpLiteManager>();
91 if (httpHandle_ == nullptr) {
92 MEDIA_LOG_E("httpHandle_ create error");
93 return Status::ERROR_UNKNOWN;
94 }
95 mAllocator_ = std::make_shared<HttpSourceAllocator>();
96 if (mAllocator_ == nullptr) {
97 MEDIA_LOG_E("mAllocator_ create error");
98 return Status::ERROR_UNKNOWN;
99 }
100 MEDIA_LOG_D("Init OUT");
101 return Status::OK;
102 }
103
Deinit()104 Status HttpSourcePlugin::Deinit()
105 {
106 OSAL::ScopedLock lock(httpMutex_);
107 MEDIA_LOG_D("IN");
108 CloseUri();
109 return Status::OK;
110 }
111
Prepare()112 Status HttpSourcePlugin::Prepare()
113 {
114 OSAL::ScopedLock lock(httpMutex_);
115 MEDIA_LOG_D("IN");
116 return Status::OK;
117 }
118
Reset()119 Status HttpSourcePlugin::Reset()
120 {
121 needExit_ = true;
122 {
123 OSAL::ScopedLock lock(httpMutex_);
124 needExit_ = false;
125 MEDIA_LOG_D("IN");
126 CloseUri();
127 return Status::OK;
128 }
129 }
130
Stop()131 Status HttpSourcePlugin::Stop()
132 {
133 needExit_ = true;
134 {
135 MEDIA_LOG_D("IN");
136 OSAL::ScopedLock lock(httpMutex_);
137 needExit_ = false;
138 if (httpHandle_ != nullptr) {
139 httpHandle_->HttpClose();
140 httpHandle_ = nullptr;
141 }
142 MEDIA_LOG_D("OUT");
143 return Status::ERROR_UNKNOWN;
144 }
145 }
146
GetParameter(Tag tag,ValueType & value)147 Status HttpSourcePlugin::GetParameter(Tag tag, ValueType &value)
148 {
149 OSAL::ScopedLock lock(httpMutex_);
150 MEDIA_LOG_D("IN");
151 switch (tag) {
152 case Tag::BUFFERING_SIZE:
153 value = bufferSize_;
154 return Status::OK;
155 case Tag::WATERLINE_HIGH:
156 value = waterline_;
157 return Status::OK;
158 default:
159 return Status::ERROR_INVALID_PARAMETER;
160 }
161 }
162
SetParameter(Tag tag,const ValueType & value)163 Status HttpSourcePlugin::SetParameter(Tag tag, const ValueType &value)
164 {
165 OSAL::ScopedLock lock(httpMutex_);
166 MEDIA_LOG_D("IN");
167 switch (tag) {
168 case Tag::BUFFERING_SIZE:
169 bufferSize_ = AnyCast<uint32_t>(value);
170 return Status::OK;
171 case Tag::WATERLINE_HIGH:
172 waterline_ = AnyCast<uint32_t>(value);
173 return Status::OK;
174 default:
175 return Status::ERROR_INVALID_PARAMETER;
176 }
177 }
178
SetCallback(Callback * cb)179 Status HttpSourcePlugin::SetCallback(Callback* cb)
180 {
181 MEDIA_LOG_D("IN");
182 callback_ = cb;
183 return Status::OK;
184 }
185
SetSource(std::shared_ptr<MediaSource> source)186 Status HttpSourcePlugin::SetSource(std::shared_ptr<MediaSource> source)
187 {
188 OSAL::ScopedLock lock(httpMutex_);
189 MEDIA_LOG_D("SetSource IN");
190 if (httpHandle_ == nullptr) {
191 MEDIA_LOG_E("httpHandle_ null error");
192 return Status::ERROR_UNKNOWN;
193 }
194 auto uri = source->GetSourceUri();
195 MEDIA_LOG_D(PUBLIC_LOG_S, uri.c_str());
196 Status ret = OpenUri(uri);
197 if (ret != Status::OK) {
198 MEDIA_LOG_E("OpenUri error");
199 return ret;
200 }
201 MEDIA_LOG_D("OpenUri success");
202 unsigned int downloadPos = 0;
203 httpHandle_->GetHttpBufferRange(&position_, &downloadPos);
204 MEDIA_LOG_D("position_ " PUBLIC_LOG_U32 "downloadPos " PUBLIC_LOG_U32, position_, downloadPos);
205 int8_t retryTimes = 0;
206 while (!needExit_ && position_ == downloadPos && retryTimes < 60) { // 60
207 OHOS::Media::OSAL::SleepFor(200); // 200
208 httpHandle_->GetHttpBufferRange(&position_, &downloadPos);
209 retryTimes++;
210 }
211 MEDIA_LOG_D("position_ " PUBLIC_LOG_U32 "downloadPos " PUBLIC_LOG_U32, position_, downloadPos);
212 if (position_ == downloadPos) {
213 MEDIA_LOG_D("position_ == downloadPos");
214 httpHandle_->HttpClose();
215 return Status::ERROR_UNKNOWN;
216 }
217 isStream_ = httpHandle_->IsStreaming();
218 waterline_ = 20; // 20
219 httpHandle_->SetWaterline(waterline_, 0);
220 fileSize_ = isStream_ ? 0 : httpHandle_->GetContentLength();
221 MEDIA_LOG_D("SetSource OUT fileSize_ " PUBLIC_LOG_ZU, fileSize_);
222 return Status::OK;
223 }
224
GetAllocator()225 std::shared_ptr<Allocator> HttpSourcePlugin::GetAllocator()
226 {
227 MEDIA_LOG_D("GetAllocator IN");
228 return mAllocator_;
229 }
230
OnError(int httpError,int localError,void * param,int supportRetry)231 void HttpSourcePlugin::OnError(int httpError, int localError, void *param, int supportRetry)
232 {
233 MEDIA_LOG_D("httpError " PUBLIC_LOG_D32 " localError " PUBLIC_LOG_D32, httpError, localError);
234 auto plugin = reinterpret_cast<HttpSourcePlugin *>(param);
235 if (plugin == nullptr) {
236 return;
237 }
238 plugin->needExit_ = true;
239 plugin->OnHttpEvent(param, httpError, localError);
240 }
241
OnHttpEvent(void * priv,int errorType,int32_t errorCode)242 Status HttpSourcePlugin::OnHttpEvent(void *priv, int errorType, int32_t errorCode)
243 {
244 if (priv == nullptr) {
245 MEDIA_LOG_D("priv null error");
246 return Status::ERROR_UNKNOWN;
247 }
248 auto plugin = reinterpret_cast<HttpSourcePlugin *>(priv);
249 plugin->callback_->OnEvent(
250 PluginEvent{PluginEventType::OTHER_ERROR, errorCode, "http lite error"});
251 return Status::OK;
252 }
253
Read(std::shared_ptr<Buffer> & buffer,size_t expectedLen)254 Status HttpSourcePlugin::Read(std::shared_ptr<Buffer> &buffer, size_t expectedLen)
255 {
256 MEDIA_LOG_D("Read in");
257 if (httpHandle_ == nullptr) {
258 MEDIA_LOG_D("Read error");
259 return Status::ERROR_INVALID_PARAMETER;
260 }
261 if (buffer == nullptr) {
262 buffer = std::make_shared<Buffer>();
263 }
264
265 OSAL::ScopedLock lock(httpMutex_);
266 std::shared_ptr<Memory> bufData;
267
268 if (buffer->IsEmpty()) {
269 bufData = buffer->AllocMemory(GetAllocator(), expectedLen);
270 } else {
271 bufData = buffer->GetMemory();
272 }
273 unsigned int read = 0;
274 unsigned int write = 0;
275 unsigned int realReadSize = 0;
276 int isEos = -1;
277 int retryReadTimes = 0;
278
279 httpHandle_->GetHttpBufferRange(&read, &write);
280
281 MEDIA_LOG_D("read pos " PUBLIC_LOG_U32 " write pos " PUBLIC_LOG_U32 " expectedLen " PUBLIC_LOG_ZU,
282 read, write, expectedLen);
283
284 do {
285 MEDIA_LOG_D("bufData->GetCapacity() " PUBLIC_LOG_ZU, bufData->GetCapacity());
286 httpHandle_->HttpRead(bufData->GetWritableAddr(expectedLen), expectedLen, realReadSize, isEos);
287 if (realReadSize == 0 && retryReadTimes <= 200) { // 200
288 OSAL::SleepFor(10); // 10
289 retryReadTimes++;
290 continue;
291 }
292 break;
293 } while (true);
294 bufData->UpdateDataSize(realReadSize);
295 httpHandle_->GetHttpBufferRange(&position_, &write);
296 MEDIA_LOG_D("position_ : " PUBLIC_LOG_U32 ", readSize = " PUBLIC_LOG_ZU ", isEos " PUBLIC_LOG_D32,
297 position_, bufData->GetSize(), isEos);
298 return Status::OK;
299 }
300
GetSize(uint64_t & size)301 Status HttpSourcePlugin::GetSize(uint64_t& size)
302 {
303 OSAL::ScopedLock lock(httpMutex_);
304 MEDIA_LOG_D("IN");
305 size = fileSize_;
306 return Status::OK;
307 }
308
GetSeekable()309 Seekable HttpSourcePlugin::GetSeekable()
310 {
311 OSAL::ScopedLock lock(httpMutex_);
312 MEDIA_LOG_D("IN");
313 return !isStream_ ? Seekable::SEEKABLE : Seekable::UNSEEKABLE;
314 }
315
SeekTo(uint64_t offset)316 Status HttpSourcePlugin::SeekTo(uint64_t offset)
317 {
318 OSAL::ScopedLock lock(httpMutex_);
319 unsigned int readPos = 0;
320 unsigned int writePos = 0;
321 if ((httpHandle_ == nullptr) || (isStream_) || (position_ == offset) || (offset > fileSize_)) {
322 MEDIA_LOG_E("Invalid operation");
323 return Status::ERROR_INVALID_PARAMETER;
324 }
325 if (!httpHandle_->HttpSeek(offset)) {
326 MEDIA_LOG_E("seek to position_ " PUBLIC_LOG_U32 " failed", position_);
327 return Status::ERROR_UNKNOWN;
328 }
329 position_ = static_cast<unsigned int>(offset);
330 httpHandle_->GetHttpBufferRange(&readPos, &writePos);
331 MEDIA_LOG_D("offset = " PUBLIC_LOG_U32 " , after SeekTo readPos = " PUBLIC_LOG_U32 ", writePos = " PUBLIC_LOG_U32,
332 static_cast<uint32_t>(offset), readPos, writePos);
333 MEDIA_LOG_D("seek to position_ " PUBLIC_LOG_U32 " success", position_);
334 return Status::OK;
335 }
336
OpenUri(std::string & url)337 Status HttpSourcePlugin::OpenUri(std::string &url)
338 {
339 MEDIA_LOG_I("OpenUri IN");
340 if (httpHandle_ == nullptr) {
341 return Status::ERROR_UNIMPLEMENTED;
342 }
343 httpHandle_->HttpClose();
344 HttpLiteAttr httpAttr;
345 httpAttr.certFile = certFile_;
346 httpAttr.priority = DEFAULT_HTTP_PRORITY;
347 httpAttr.bufferSize = bufferSize_;
348 httpAttr.pluginHandle = this;
349 httpAttr.callbackFunc = OnError;
350 httpAttr.notVerifyCert = true;
351 return httpHandle_->HttpOpen(url, httpAttr) ? Status::OK : Status::ERROR_UNKNOWN;
352 }
353
CloseUri()354 void HttpSourcePlugin::CloseUri()
355 {
356 if (httpHandle_ != nullptr) {
357 MEDIA_LOG_D("close uri");
358 httpHandle_->HttpClose();
359 httpHandle_ = nullptr;
360 }
361 }
362 } // namespace HttpLitePlugin
363 } // namespace Plugin
364 } // namespace Media
365 } // namespace OHOS