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