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 HST_LOG_TAG "FileFdSourcePlugin"
17
18 #include <cerrno>
19 #include <cstring>
20 #include <regex>
21 #include <memory>
22 #ifdef WIN32
23 #include <fcntl.h>
24 #else
25 #include <sys/types.h>
26 #include <unistd.h>
27 #endif
28 #include <sys/ioctl.h>
29 #include <sys/stat.h>
30 #include "common/log.h"
31 #include "osal/filesystem/file_system.h"
32 #include "file_fd_source_plugin.h"
33 #include "common/media_core.h"
34
35 namespace {
36 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_SYSTEM_PLAYER, "FileFdSourcePlugin" };
37 }
38
39 namespace OHOS {
40 namespace Media {
41 namespace Plugins {
42 namespace FileFdSource {
43 namespace {
44 constexpr int32_t FDPOS = 2;
45 constexpr int32_t READ_TIME = 3;
46 constexpr size_t CACHE_SIZE = 40 * 1024 * 1024;
47 constexpr size_t PER_CACHE_SIZE = 48 * 10 * 1024;;
48 constexpr size_t WATER_LINE_BELOW_DEFAULT = 5 * 1024;
49 constexpr int32_t TEN_MILLISECOUNDS = 10 * 1000;
50 constexpr int32_t ONE_SECONDS = 1 * 1000 * 1000;
51 constexpr int32_t CACHE_TIME_DEFAULT = 5;
52 constexpr int32_t SEEK_TIME_LOWER = 20;
53 constexpr int32_t SEEK_TIME_UPPER = 1000;
54 constexpr int32_t RECORD_TIME_INTERVAL = 1 * 1000;
55 constexpr int32_t MILLISECOUND_TO_SECOND = 1 * 1000;
56 constexpr int32_t RETRY_TIMES = 3;
57 constexpr int32_t TO_BYTE = 8;
58 constexpr int32_t PERCENT_100 = 100;
59 constexpr int32_t MAX_RANK = 100;
60 constexpr int32_t READ_RETRY = 2;
61 constexpr float CACHE_LEVEL_1 = 0.3;
62
63 constexpr unsigned int HMDFS_IOC = 0xf2;
64 #define IOCTL_CLOUD 2
65 #define HMDFS_IOC_HAS_CACHE _IOW(HMDFS_IOC, 6, struct HmdfsHasCache)
66 #define HMDFS_IOC_GET_LOCATION _IOR(HMDFS_IOC, 7, __u32)
67 #define HMDFS_IOC_CANCEL_READ _IO(HMDFS_IOC, 8)
68 #define HMDFS_IOC_RESTORE_READ _IO(HMDFS_IOC, 9)
69
GetFileSize(int32_t fd)70 uint64_t GetFileSize(int32_t fd)
71 {
72 uint64_t fileSize = 0;
73 struct stat s {};
74 int ret = fstat(fd, &s);
75 if (ret == 0) {
76 fileSize = static_cast<uint64_t>(s.st_size);
77 FALSE_RETURN_V_MSG_E(fileSize != 0, fileSize, "fileSize 0, fstat ret 0");
78 return fileSize;
79 } else {
80 MEDIA_LOG_W("GetFileSize error ret " PUBLIC_LOG_D32 ", errno " PUBLIC_LOG_D32, ret, errno);
81 }
82 return fileSize;
83 }
isNumber(const std::string & str)84 bool isNumber(const std::string& str)
85 {
86 return str.find_first_not_of("0123456789") == std::string::npos;
87 }
88 }
FileFdSourceRegister(const std::shared_ptr<Register> & reg)89 Status FileFdSourceRegister(const std::shared_ptr<Register>& reg)
90 {
91 MEDIA_LOG_I("fileSourceRegister is started");
92 SourcePluginDef definition;
93 definition.name = "FileFdSource";
94 definition.description = "File Fd source";
95 definition.rank = MAX_RANK; // 100: max rank
96 Capability capability;
97 capability.AppendFixedKey<std::vector<ProtocolType>>(Tag::MEDIA_PROTOCOL_TYPE, {ProtocolType::FD});
98 definition.AddInCaps(capability);
99 auto func = [](const std::string& name) -> std::shared_ptr<SourcePlugin> {
100 return std::make_shared<FileFdSourcePlugin>(name);
101 };
102 definition.SetCreator(func);
103 return reg->AddPlugin(definition);
104 }
105
__anon93482eec0402null106 PLUGIN_DEFINITION(FileFdSource, LicenseType::APACHE_V2, FileFdSourceRegister, [] {});
107
FileFdSourcePlugin(std::string name)108 FileFdSourcePlugin::FileFdSourcePlugin(std::string name)
109 : SourcePlugin(std::move(name))
110 {
111 }
112
~FileFdSourcePlugin()113 FileFdSourcePlugin::~FileFdSourcePlugin()
114 {
115 MEDIA_LOG_I("~FileFdSourcePlugin in.");
116 steadyClock_.Reset();
117 SetInterruptState(true);
118 MEDIA_LOG_I("~FileFdSourcePlugin isInterrupted_ " PUBLIC_LOG_D32, isInterrupted_.load());
119 FALSE_RETURN_MSG(downloadTask_ != nullptr, "~FileFdSourcePlugin out.");
120 downloadTask_->Stop();
121 MEDIA_LOG_I("~FileFdSourcePlugin out.");
122 }
123
SetCallback(Callback * cb)124 Status FileFdSourcePlugin::SetCallback(Callback* cb)
125 {
126 MEDIA_LOG_D("SetCallback in " PUBLIC_LOG_D32, cb != nullptr);
127 callback_ = cb;
128 return Status::OK;
129 }
130
SetSource(std::shared_ptr<MediaSource> source)131 Status FileFdSourcePlugin::SetSource(std::shared_ptr<MediaSource> source)
132 {
133 MEDIA_LOG_I("SetSource in. %{private}s", source->GetSourceUri().c_str());
134 auto err = ParseUriInfo(source->GetSourceUri());
135 if (err != Status::OK) {
136 MEDIA_LOG_E("Parse file name from uri fail, uri %{private}s", source->GetSourceUri().c_str());
137 return err;
138 }
139 CheckFileType();
140 if (isCloudFile_ && isEnableFdCache_) {
141 ringBuffer_ = std::make_shared<RingBuffer>(CACHE_SIZE);
142 FALSE_RETURN_V_MSG_E(!(ringBuffer_ == nullptr || !ringBuffer_->Init()),
143 Status::ERROR_NO_MEMORY, "memory is not enough ringBuffer_");
144 downloadTask_ = std::make_shared<Task>(std::string("downloadTaskFD"));
145 FALSE_RETURN_V_MSG_E(downloadTask_ != nullptr, Status::ERROR_NO_MEMORY, "memory is not enough");
146 downloadTask_->RegisterJob([this] {
147 CacheDataLoop();
148 return 0;
149 });
150 downloadTask_->Start();
151 steadyClock_.Reset();
152 }
153 return Status::OK;
154 }
155
Read(std::shared_ptr<Buffer> & buffer,uint64_t offset,size_t expectedLen)156 Status FileFdSourcePlugin::Read(std::shared_ptr<Buffer>& buffer, uint64_t offset, size_t expectedLen)
157 {
158 return Read(0, buffer, offset, expectedLen);
159 }
160
Read(int32_t streamId,std::shared_ptr<Buffer> & buffer,uint64_t offset,size_t expectedLen)161 Status FileFdSourcePlugin::Read(int32_t streamId, std::shared_ptr<Buffer>& buffer, uint64_t offset, size_t expectedLen)
162 {
163 FALSE_RETURN_V_MSG_E(fd_ != -1, Status::ERROR_WRONG_STATE, "no valid fd");
164 if (isCloudFile_) {
165 return ReadOnlineFile(0, buffer, offset, expectedLen);
166 } else {
167 return ReadOfflineFile(0, buffer, offset, expectedLen);
168 }
169 }
170
ReadOfflineFile(int32_t streamId,std::shared_ptr<Buffer> & buffer,uint64_t offset,size_t expectedLen)171 Status FileFdSourcePlugin::ReadOfflineFile(int32_t streamId, std::shared_ptr<Buffer>& buffer,
172 uint64_t offset, size_t expectedLen)
173 {
174 std::shared_ptr<Memory> bufData = GetBufferPtr(buffer, expectedLen);
175 FALSE_RETURN_V_MSG_E(bufData != nullptr, Status::ERROR_NO_MEMORY, "memory is not enough");
176 expectedLen = std::min(static_cast<size_t>(GetLastSize(position_)), expectedLen);
177 expectedLen = std::min(bufData->GetCapacity(), expectedLen);
178 MEDIA_LOG_D("ReadLocal buffer pos: " PUBLIC_LOG_U64 " , len:" PUBLIC_LOG_ZU, position_.load(), expectedLen);
179
180 auto size = read(fd_, bufData->GetWritableAddr(expectedLen), expectedLen);
181 if (size <= 0) {
182 HandleReadResult(expectedLen, size);
183 MEDIA_LOG_D("ReadLocal END_OF_STREAM");
184 return Status::END_OF_STREAM;
185 }
186 bufData->UpdateDataSize(size);
187 position_ += static_cast<uint64_t>(size);
188 if (buffer->GetMemory() != nullptr) {
189 MEDIA_LOG_D("ReadLocal position_ " PUBLIC_LOG_U64 ", readSize " PUBLIC_LOG_ZU,
190 position_.load(), buffer->GetMemory()->GetSize());
191 }
192 return Status::OK;
193 }
194
ReadOnlineFile(int32_t streamId,std::shared_ptr<Buffer> & buffer,uint64_t offset,size_t expectedLen)195 Status FileFdSourcePlugin::ReadOnlineFile(int32_t streamId, std::shared_ptr<Buffer>& buffer,
196 uint64_t offset, size_t expectedLen)
197 {
198 if (isBuffering_) {
199 if (HandleBuffering()) {
200 FALSE_RETURN_V_MSG_E(!isInterrupted_, Status::OK, "please not retry read, isInterrupted true");
201 FALSE_RETURN_V_MSG_E(isReadBlocking_, Status::OK, "please not retry read, isReadBlocking false");
202 MEDIA_LOG_I("is buffering, return error again.");
203 return Status::ERROR_AGAIN;
204 }
205 }
206
207 std::shared_ptr<Memory> bufData = GetBufferPtr(buffer, expectedLen);
208 FALSE_RETURN_V_MSG_E(bufData != nullptr, Status::ERROR_NO_MEMORY, "memory is not enough");
209 expectedLen = std::min(static_cast<size_t>(GetLastSize(position_)), expectedLen);
210 expectedLen = std::min(bufData->GetCapacity(), expectedLen);
211
212 // ringbuffer 0 after seek in 20ms, don't notify buffering
213 curReadTime_ = steadyClock2_.ElapsedMilliseconds();
214 if (isReadFrame_ && !HasCacheData(expectedLen, offset) && ringBuffer_->GetSize() < WATER_LINE_BELOW_DEFAULT &&
215 (GetLastSize(position_) > static_cast<int64_t>(WATER_LINE_BELOW_DEFAULT))) {
216 MEDIA_LOG_I("ringBuffer.size() " PUBLIC_LOG_ZU " curReadTime_ " PUBLIC_LOG_D64
217 " lastReadTime_ " PUBLIC_LOG_D64, ringBuffer_->GetSize(), curReadTime_, lastReadTime_);
218 CheckReadTime();
219 FALSE_RETURN_V_MSG_E(!isInterrupted_, Status::OK, "please not retry read, isInterrupted true");
220 FALSE_RETURN_V_MSG_E(isReadBlocking_, Status::OK, "please not retry read, isReadBlocking false");
221 return Status::ERROR_AGAIN;
222 }
223
224 size_t size = ringBuffer_->ReadBuffer(bufData->GetWritableAddr(expectedLen), expectedLen, READ_RETRY);
225 if (size == 0) {
226 MEDIA_LOG_I("read size 0,fd " PUBLIC_LOG_D32 ",offset " PUBLIC_LOG_D64 ", size:" PUBLIC_LOG_U64 ", pos:"
227 PUBLIC_LOG_U64 ",readBlock:" PUBLIC_LOG_D32, fd_, offset, size_, position_.load(), isReadBlocking_.load());
228 FALSE_RETURN_V_MSG_E(GetLastSize(position_) != 0, Status::END_OF_STREAM, "ReadCloud END_OF_STREAM");
229 bufData->UpdateDataSize(0);
230 return Status::OK;
231 }
232 bufData->UpdateDataSize(size);
233 int64_t ct = steadyClock2_.ElapsedMilliseconds() - curReadTime_;
234 if (ct > READ_TIME) {
235 MEDIA_LOG_I("ReadCloud buffer position " PUBLIC_LOG_U64 ", expectedLen " PUBLIC_LOG_ZU
236 " costTime: " PUBLIC_LOG_U64, position_.load(), expectedLen, ct);
237 }
238 position_ += static_cast<uint64_t>(size);
239 MEDIA_LOG_D("ringBuffer.size() " PUBLIC_LOG_ZU, ringBuffer_->GetSize());
240 return Status::OK;
241 }
242
SeekTo(uint64_t offset)243 Status FileFdSourcePlugin::SeekTo(uint64_t offset)
244 {
245 FALSE_RETURN_V_MSG_E(fd_ != -1 && seekable_ == Seekable::SEEKABLE,
246 Status::ERROR_WRONG_STATE, "no valid fd or no seekable.");
247
248 MEDIA_LOG_I("SeekTo offset: " PUBLIC_LOG_U64, offset);
249 if (isCloudFile_) {
250 return SeekToOnlineFile(offset);
251 } else {
252 return SeekToOfflineFile(offset);
253 }
254 }
255
SeekToOfflineFile(uint64_t offset)256 Status FileFdSourcePlugin::SeekToOfflineFile(uint64_t offset)
257 {
258 int32_t ret = lseek(fd_, offset + static_cast<uint64_t>(offset_), SEEK_SET);
259 if (ret == -1) {
260 MEDIA_LOG_E("SeekLocal failed, fd " PUBLIC_LOG_D32 ", offset " PUBLIC_LOG_U64 ", errStr "
261 PUBLIC_LOG_S, fd_, offset, strerror(errno));
262 return Status::ERROR_UNKNOWN;
263 }
264 position_ = offset + static_cast<uint64_t>(offset_);
265 MEDIA_LOG_D("SeekLocal end ret " PUBLIC_LOG_D32 ", position_ " PUBLIC_LOG_U64, ret, position_.load());
266 return Status::OK;
267 }
268
SeekToOnlineFile(uint64_t offset)269 Status FileFdSourcePlugin::SeekToOnlineFile(uint64_t offset)
270 {
271 FALSE_RETURN_V_MSG_E(ringBuffer_ != nullptr, Status::ERROR_WRONG_STATE, "SeekCloud ringBuffer_ is nullptr");
272 MEDIA_LOG_D("SeekCloud,ringBuffer.size: " PUBLIC_LOG_ZU ",offset " PUBLIC_LOG_U64, ringBuffer_->GetSize(), offset);
273 if (ringBuffer_->Seek(offset)) {
274 position_ = offset + static_cast<uint64_t>(offset_);
275 MEDIA_LOG_I("SeekCloud ringBuffer_ seek hit, offset " PUBLIC_LOG_U64, offset);
276 return Status::OK;
277 }
278 // First clear buffer, avoid no available buffer then task pause never exit.
279 ringBuffer_->SetActive(false);
280 inSeek_ = true;
281 if (downloadTask_ != nullptr) {
282 downloadTask_->Pause();
283 inSeek_ = false;
284 }
285 ringBuffer_->Clear();
286 ringBuffer_->SetMediaOffset(offset);
287 ringBuffer_->SetActive(true);
288
289 int32_t ret = lseek(fd_, offset + static_cast<uint64_t>(offset_), SEEK_SET);
290 if (ret == -1) {
291 MEDIA_LOG_E("SeekCloud failed, fd_ " PUBLIC_LOG_D32 ", offset " PUBLIC_LOG_U64 ", errStr "
292 PUBLIC_LOG_S, fd_, offset, strerror(errno));
293 return Status::ERROR_UNKNOWN;
294 }
295 position_ = offset + static_cast<uint64_t>(offset_);
296 cachePosition_ = position_.load();
297
298 MEDIA_LOG_D("SeekCloud end, fd_ " PUBLIC_LOG_D32 ", size_ " PUBLIC_LOG_U64 ", offset_ " PUBLIC_LOG_D64
299 ", position_ " PUBLIC_LOG_U64, fd_, size_, offset_, position_.load());
300 if (downloadTask_ != nullptr) {
301 downloadTask_->Start();
302 }
303 return Status::OK;
304 }
305
ParseUriInfo(const std::string & uri)306 Status FileFdSourcePlugin::ParseUriInfo(const std::string& uri)
307 {
308 if (uri.empty()) {
309 MEDIA_LOG_E("uri is empty");
310 return Status::ERROR_INVALID_PARAMETER;
311 }
312 std::smatch fdUriMatch;
313 FALSE_RETURN_V_MSG_E(std::regex_match(uri, fdUriMatch, std::regex("^fd://(.*)\\?offset=(.*)&size=(.*)")) ||
314 std::regex_match(uri, fdUriMatch, std::regex("^fd://(.*)")),
315 Status::ERROR_INVALID_PARAMETER, "Invalid fd uri format");
316 FALSE_RETURN_V_MSG_E(fdUriMatch.size() >= FDPOS && isNumber(fdUriMatch[1].str()),
317 Status::ERROR_INVALID_PARAMETER, "Invalid fd uri format");
318 fd_ = std::stoi(fdUriMatch[1].str()); // 1: sub match fd subscript
319 FALSE_RETURN_V_MSG_E(fd_ != -1 && FileSystem::IsRegularFile(fd_),
320 Status::ERROR_INVALID_PARAMETER, "Invalid fd: " PUBLIC_LOG_D32, fd_);
321 fileSize_ = GetFileSize(fd_);
322 if (fdUriMatch.size() == 4) { // 4:4 sub match
323 offset_ = std::stoll(fdUriMatch[2].str()); // 2: sub match offset subscript
324 if (static_cast<uint64_t>(offset_) > fileSize_) {
325 offset_ = fileSize_;
326 }
327 size_ = static_cast<uint64_t>(std::stoll(fdUriMatch[3].str())); // 3: sub match size subscript
328 uint64_t remainingSize = fileSize_ - offset_;
329 if (size_ > remainingSize) {
330 size_ = remainingSize;
331 }
332 } else {
333 size_ = fileSize_;
334 offset_ = 0;
335 }
336 position_ = offset_;
337 seekable_ = FileSystem::IsSeekable(fd_) ? Seekable::SEEKABLE : Seekable::UNSEEKABLE;
338 if (seekable_ == Seekable::SEEKABLE) {
339 NOK_LOG(SeekTo(0));
340 }
341 MEDIA_LOG_I("Fd: " PUBLIC_LOG_D32 ", offset: " PUBLIC_LOG_D64 ", size: " PUBLIC_LOG_U64, fd_, offset_, size_);
342 return Status::OK;
343 }
344
CacheDataLoop()345 void FileFdSourcePlugin::CacheDataLoop()
346 {
347 if (isInterrupted_) {
348 MEDIA_LOG_E("CacheData break");
349 usleep(TEN_MILLISECOUNDS);
350 return;
351 }
352
353 int64_t curTime = steadyClock_.ElapsedMilliseconds();
354 GetCurrentSpeed(curTime);
355
356 size_t bufferSize = std::min(PER_CACHE_SIZE, static_cast<size_t>(GetLastSize(cachePosition_.load())));
357 if (bufferSize < 0) {
358 MEDIA_LOG_E("CacheData memory is not enough bufferSize " PUBLIC_LOG_ZU, bufferSize);
359 usleep(TEN_MILLISECOUNDS);
360 return;
361 }
362
363 char* cacheBuffer = new char[bufferSize];
364 if (cacheBuffer == nullptr) {
365 MEDIA_LOG_E("CacheData memory is not enough bufferSize " PUBLIC_LOG_ZU, bufferSize);
366 usleep(TEN_MILLISECOUNDS);
367 return;
368 }
369 int size = read(fd_, cacheBuffer, bufferSize);
370 if (size <= 0) {
371 DeleteCacheBuffer(cacheBuffer, bufferSize);
372 HandleReadResult(bufferSize, size);
373 return;
374 }
375 MEDIA_LOG_D("Cache fd: " PUBLIC_LOG_D32 "cachePos_ " PUBLIC_LOG_U64 " ringBuffer_.size() " PUBLIC_LOG_ZU
376 ", size_ " PUBLIC_LOG_U64, fd_, cachePosition_.load(), ringBuffer_->GetSize(), size_);
377 while (!ringBuffer_->WriteBuffer(cacheBuffer, size)) {
378 MEDIA_LOG_I("CacheData ringbuffer write failed");
379 if (inSeek_ || isInterrupted_) {
380 DeleteCacheBuffer(cacheBuffer, bufferSize);
381 return;
382 }
383 usleep(TEN_MILLISECOUNDS);
384 }
385 cachePosition_ += static_cast<uint64_t>(size);
386 downloadSize_ += static_cast<uint64_t>(size);
387
388 int64_t ct = steadyClock2_.ElapsedMilliseconds() - curTime;
389 if (ct > READ_TIME) {
390 MEDIA_LOG_I("Cache fd: " PUBLIC_LOG_D32 "cachePos:" PUBLIC_LOG_U64 ",ringBuffer.size() " PUBLIC_LOG_ZU ", size "
391 PUBLIC_LOG_U64 " cTime: " PUBLIC_LOG_U64, fd_, cachePosition_.load(), ringBuffer_->GetSize(), size_, ct);
392 }
393
394 DeleteCacheBuffer(cacheBuffer, bufferSize);
395
396 if (isBuffering_ && (static_cast<int64_t>(ringBuffer_->GetSize()) > waterLineAbove_ ||
397 GetLastSize(cachePosition_.load()) == 0)) {
398 NotifyBufferingEnd();
399 }
400 }
401
HasCacheData(size_t bufferSize,uint64_t offset)402 bool FileFdSourcePlugin::HasCacheData(size_t bufferSize, uint64_t offset)
403 {
404 HmdfsHasCache ioctlData;
405 ioctlData.offset = static_cast<int64_t>(offset);
406 ioctlData.readSize = static_cast<int64_t>(bufferSize);
407 int32_t ioResult = ioctl(fd_, HMDFS_IOC_HAS_CACHE, &ioctlData); // 0在 -1不在
408 // ioctl has cache
409 if (ioResult == 0) {
410 return true;
411 } else {
412 MEDIA_LOG_I("ioctl has no cache with errno " PUBLIC_LOG_D32, errno);
413 }
414 return false;
415 }
416
Stop()417 Status FileFdSourcePlugin::Stop()
418 {
419 MEDIA_LOG_I("Stop enter.");
420 isInterrupted_ = true;
421 MEDIA_LOG_I("Stop isInterrupted_ " PUBLIC_LOG_D32, isInterrupted_.load());
422 FALSE_RETURN_V(downloadTask_ != nullptr, Status::OK);
423 downloadTask_->StopAsync();
424 return Status::OK;
425 }
426
Reset()427 Status FileFdSourcePlugin::Reset()
428 {
429 MEDIA_LOG_I("Reset enter.");
430 isInterrupted_ = true;
431 MEDIA_LOG_I("Reset isInterrupted_ " PUBLIC_LOG_D32, isInterrupted_.load());
432 FALSE_RETURN_V(downloadTask_ != nullptr, Status::OK);
433 downloadTask_->StopAsync();
434 return Status::OK;
435 }
436
PauseDownloadTask(bool isAsync)437 void FileFdSourcePlugin::PauseDownloadTask(bool isAsync)
438 {
439 FALSE_RETURN(downloadTask_ != nullptr);
440 if (isAsync) {
441 downloadTask_->PauseAsync();
442 } else {
443 downloadTask_->Pause();
444 }
445 }
446
HandleBuffering()447 bool FileFdSourcePlugin::HandleBuffering()
448 {
449 MEDIA_LOG_I("HandleBuffering in.");
450 int32_t sleepTime = 0;
451 // return error again 1 time 1s, avoid ffmpeg error
452 while (sleepTime < ONE_SECONDS && !isInterrupted_ && isReadBlocking_) {
453 NotifyBufferingPercent();
454 if (!isBuffering_) {
455 break;
456 }
457 MEDIA_LOG_I("isBuffering.");
458 usleep(TEN_MILLISECOUNDS);
459 sleepTime += TEN_MILLISECOUNDS;
460 }
461 MEDIA_LOG_I("HandleBuffering out.");
462 return isBuffering_;
463 }
464
HandleReadResult(size_t bufferSize,int size)465 void FileFdSourcePlugin::HandleReadResult(size_t bufferSize, int size)
466 {
467 MEDIA_LOG_I("HandleReadResult size " PUBLIC_LOG_D32 ", fd " PUBLIC_LOG_D32 ", cachePosition_" PUBLIC_LOG_U64
468 ", position_ " PUBLIC_LOG_U64 ", bufferSize " PUBLIC_LOG_ZU ", size_ " PUBLIC_LOG_U64 ", offset_ "
469 PUBLIC_LOG_D64, size, fd_, cachePosition_.load(), position_.load(), bufferSize, size_, offset_);
470 if (size < 0) {
471 // errno EIO 5
472 MEDIA_LOG_E("read fail, errno " PUBLIC_LOG_D32, errno);
473
474 // read fail with errno, retry 3 * 10ms
475 retryTimes_++;
476 if (retryTimes_ >= RETRY_TIMES) {
477 NotifyReadFail();
478 SetInterruptState(true);
479 }
480 usleep(TEN_MILLISECOUNDS);
481 } else {
482 cachePosition_ = 0;
483 PauseDownloadTask(false);
484 }
485 }
486
NotifyBufferingStart()487 void FileFdSourcePlugin::NotifyBufferingStart()
488 {
489 MEDIA_LOG_I("NotifyBufferingStart, ringBuffer.size() " PUBLIC_LOG_ZU
490 ", waterLineAbove_ " PUBLIC_LOG_U64, ringBuffer_->GetSize(), waterLineAbove_);
491 isBuffering_ = true;
492 if (callback_ != nullptr && !isInterrupted_) {
493 MEDIA_LOG_I("Read OnEvent BUFFERING_START.");
494 callback_->OnEvent({PluginEventType::BUFFERING_START, {BufferingInfoType::BUFFERING_START}, "start"});
495 } else {
496 MEDIA_LOG_E("BUFFERING_START callback_ is nullptr or isInterrupted_ is true");
497 }
498 }
499
NotifyBufferingPercent()500 void FileFdSourcePlugin::NotifyBufferingPercent()
501 {
502 if (waterLineAbove_ != 0) {
503 int64_t bp = static_cast<float>(ringBuffer_->GetSize()) / waterLineAbove_ * PERCENT_100;
504 bp = bp > PERCENT_100 ? PERCENT_100 : bp;
505 if (isBuffering_ && callback_ != nullptr && !isInterrupted_) {
506 MEDIA_LOG_I("NotifyBufferingPercent, ringBuffer.size() " PUBLIC_LOG_ZU ", waterLineAbove_ " PUBLIC_LOG_U64
507 ", PERCENT " PUBLIC_LOG_D32, ringBuffer_->GetSize(), waterLineAbove_, static_cast<int32_t>(bp));
508 callback_->OnEvent({PluginEventType::EVENT_BUFFER_PROGRESS,
509 {BufferingInfoType::BUFFERING_PERCENT}, std::to_string(bp)});
510 } else {
511 MEDIA_LOG_E("EVENT_BUFFER_PROGRESS callback_ is nullptr or isInterrupted_ \
512 is true or isBuffering_ is false");
513 }
514 }
515 }
516
NotifyBufferingEnd()517 void FileFdSourcePlugin::NotifyBufferingEnd()
518 {
519 NotifyBufferingPercent();
520 MEDIA_LOG_I("NotifyBufferingEnd, ringBuffer.size() " PUBLIC_LOG_ZU
521 ", waterLineAbove_ " PUBLIC_LOG_U64, ringBuffer_->GetSize(), waterLineAbove_);
522 isBuffering_ = false;
523 lastReadTime_ = 0;
524 if (callback_ != nullptr && !isInterrupted_) {
525 MEDIA_LOG_I("NotifyBufferingEnd success .");
526 callback_->OnEvent({PluginEventType::BUFFERING_END, {BufferingInfoType::BUFFERING_END}, "end"});
527 } else {
528 MEDIA_LOG_E("BUFFERING_END callback_ is nullptr or isInterrupted_ is true");
529 }
530 }
531
NotifyReadFail()532 void FileFdSourcePlugin::NotifyReadFail()
533 {
534 MEDIA_LOG_I("NotifyReadFail in.");
535 if (callback_ != nullptr && !isInterrupted_) {
536 MEDIA_LOG_I("Read OnEvent read fail");
537 callback_->OnEvent({PluginEventType::CLIENT_ERROR, {NetworkClientErrorCode::ERROR_TIME_OUT}, "read"});
538 } else {
539 MEDIA_LOG_E("CLIENT_ERROR callback_ is nullptr or isInterrupted_ is true");
540 }
541 }
542
SetDemuxerState(int32_t streamId)543 void FileFdSourcePlugin::SetDemuxerState(int32_t streamId)
544 {
545 MEDIA_LOG_I("SetDemuxerState");
546 isReadFrame_ = true;
547 }
548
SetCurrentBitRate(int32_t bitRate,int32_t streamID)549 Status FileFdSourcePlugin::SetCurrentBitRate(int32_t bitRate, int32_t streamID)
550 {
551 currentBitRate_ = bitRate / TO_BYTE; // 8b
552 MEDIA_LOG_I("currentBitRate: " PUBLIC_LOG_D32, currentBitRate_);
553 // default cache 0.3s
554 waterLineAbove_ = CACHE_LEVEL_1 * currentBitRate_;
555 return Status::OK;
556 }
557
SetBundleName(const std::string & bundleName)558 void FileFdSourcePlugin::SetBundleName(const std::string& bundleName)
559 {
560 MEDIA_LOG_I("SetBundleName bundleName: " PUBLIC_LOG_S, bundleName.c_str());
561 }
562
SetReadBlockingFlag(bool isAllowed)563 Status FileFdSourcePlugin::SetReadBlockingFlag(bool isAllowed)
564 {
565 MEDIA_LOG_I("SetReadBlockingFlag entered, IsReadBlockingAllowed %{public}d", isAllowed);
566 if (ringBuffer_) {
567 ringBuffer_->SetReadBlocking(isAllowed);
568 }
569 isReadBlocking_ = isAllowed;
570 return Status::OK;
571 }
572
SetInterruptState(bool isInterruptNeeded)573 void FileFdSourcePlugin::SetInterruptState(bool isInterruptNeeded)
574 {
575 MEDIA_LOG_I("SetInterruptState isInterrupted_" PUBLIC_LOG_D32, isInterruptNeeded);
576 isInterrupted_ = isInterruptNeeded;
577 if (ringBuffer_ != nullptr) {
578 if (isInterrupted_) {
579 ringBuffer_->SetActive(false);
580 } else {
581 ringBuffer_->SetActive(true);
582 }
583 }
584
585 if (isInterrupted_ && isCloudFile_) {
586 if (downloadTask_ != nullptr) {
587 downloadTask_->StopAsync();
588 }
589 int ret = ioctl(fd_, HMDFS_IOC_CANCEL_READ);
590 MEDIA_LOG_I("ioctl break read, fd %{public}d, ret %{public}d, errno %{public}d", fd_, ret, errno);
591 }
592 }
593
GetSize(uint64_t & size)594 Status FileFdSourcePlugin::GetSize(uint64_t& size)
595 {
596 size = size_;
597 return Status::OK;
598 }
599
GetSeekable()600 Seekable FileFdSourcePlugin::GetSeekable()
601 {
602 MEDIA_LOG_D("GetSeekable in");
603 return seekable_;
604 }
605
CheckFileType()606 void FileFdSourcePlugin::CheckFileType()
607 {
608 int loc; // 1本地,2云端
609 int ioResult = ioctl(fd_, HMDFS_IOC_GET_LOCATION, &loc);
610 MEDIA_LOG_I("SetSource ioctl loc, ret " PUBLIC_LOG_D32 ", loc " PUBLIC_LOG_D32 ", errno"
611 PUBLIC_LOG_D32, ioResult, loc, errno);
612
613 if (!isEnableFdCache_) {
614 isCloudFile_ = false;
615 return;
616 }
617
618 if (ioResult == 0) {
619 if (loc == IOCTL_CLOUD) {
620 isCloudFile_ = true;
621 MEDIA_LOG_I("ioctl file is cloud");
622 int ret = ioctl(fd_, HMDFS_IOC_RESTORE_READ);
623 MEDIA_LOG_I("ioctl restore fd, fd %{public}d, ret %{public}d, errno %{public}d", fd_, ret, errno);
624 return;
625 } else {
626 isCloudFile_ = false;
627 MEDIA_LOG_I("ioctl file is local");
628 }
629 } else {
630 isCloudFile_ = false;
631 MEDIA_LOG_I("ioctl get file type");
632 }
633 }
634
GetBufferPtr(std::shared_ptr<Buffer> & buffer,size_t expectedLen)635 std::shared_ptr<Memory> FileFdSourcePlugin::GetBufferPtr(std::shared_ptr<Buffer>& buffer, size_t expectedLen)
636 {
637 if (!buffer) {
638 buffer = std::make_shared<Buffer>();
639 }
640 std::shared_ptr<Memory> bufData;
641 if (buffer->IsEmpty()) {
642 bufData = buffer->AllocMemory(nullptr, expectedLen);
643 } else {
644 bufData = buffer->GetMemory();
645 }
646 return bufData;
647 }
648
GetLastSize(uint64_t position)649 int64_t FileFdSourcePlugin::GetLastSize(uint64_t position)
650 {
651 int64_t ret = static_cast<int64_t>(size_) + offset_ - static_cast<int64_t>(position);
652 if (ret < 0) {
653 MEDIA_LOG_E("GetLastSize error, fd_ " PUBLIC_LOG_D32 ", offset_ " PUBLIC_LOG_D64 ", size_ "
654 PUBLIC_LOG_U64 ", position " PUBLIC_LOG_U64, fd_, offset_, size_, position);
655 }
656 return ret;
657 }
658
GetCurrentSpeed(int64_t curTime)659 void FileFdSourcePlugin::GetCurrentSpeed(int64_t curTime)
660 {
661 if ((curTime - lastCheckTime_) > RECORD_TIME_INTERVAL) {
662 MEDIA_LOG_I("CacheDataLoop curTime_: " PUBLIC_LOG_U64 " lastCheckTime_: "
663 PUBLIC_LOG_U64 " downloadSize_: " PUBLIC_LOG_U64, curTime, lastCheckTime_, downloadSize_);
664 float duration = static_cast<double>(curTime - lastCheckTime_) / MILLISECOUND_TO_SECOND;
665 avgDownloadSpeed_ = downloadSize_ / duration; //b/s
666 MEDIA_LOG_I("downloadDuration: " PUBLIC_LOG_F "avgDownloadSpeed_: " PUBLIC_LOG_F,
667 duration, avgDownloadSpeed_);
668 downloadSize_ = 0;
669 lastCheckTime_ = curTime;
670 FALSE_RETURN(currentBitRate_ > 0);
671 UpdateWaterLineAbove();
672 }
673 }
674
UpdateWaterLineAbove()675 void FileFdSourcePlugin::UpdateWaterLineAbove()
676 {
677 FALSE_RETURN_MSG(currentBitRate_ > 0, "currentBitRate_ <= 0");
678 float cacheTime = GetCacheTime(avgDownloadSpeed_ / currentBitRate_);
679 MEDIA_LOG_I("cacheTime: " PUBLIC_LOG_F "avgDownloadSpeed_: " PUBLIC_LOG_F
680 "currentBitRate: " PUBLIC_LOG_D32, cacheTime, avgDownloadSpeed_, currentBitRate_);
681 waterLineAbove_ = cacheTime * currentBitRate_ > GetLastSize(cachePosition_.load()) ?
682 GetLastSize(cachePosition_.load()) : cacheTime * currentBitRate_;
683 MEDIA_LOG_I("waterLineAbove_: " PUBLIC_LOG_U64, waterLineAbove_);
684 }
685
GetCacheTime(float num)686 float FileFdSourcePlugin::GetCacheTime(float num)
687 {
688 MEDIA_LOG_I("GetCacheTime with num: " PUBLIC_LOG_F, num);
689 if (num < 0) {
690 return CACHE_LEVEL_1;
691 }
692 if (num > 0 && num < 0.5) { // (0, 0.5)
693 return CACHE_TIME_DEFAULT;
694 } else if (num >= 0.5 && num < 1) { //[0.5, 1)
695 return CACHE_TIME_DEFAULT;
696 } else if (num >= 1) { //[1, 2)
697 return CACHE_LEVEL_1;
698 }
699 return CACHE_TIME_DEFAULT;
700 }
701
DeleteCacheBuffer(char * buffer,size_t bufferSize)702 void FileFdSourcePlugin::DeleteCacheBuffer(char* buffer, size_t bufferSize)
703 {
704 if (buffer != nullptr && bufferSize > 0) {
705 delete[] buffer;
706 }
707 }
708
CheckReadTime()709 void FileFdSourcePlugin::CheckReadTime()
710 {
711 if (IsValidTime(curReadTime_, lastReadTime_)) {
712 NotifyBufferingStart();
713 lastReadTime_ = 0;
714 } else {
715 if (lastReadTime_ == 0) {
716 lastReadTime_ = curReadTime_;
717 }
718 }
719 }
720
IsValidTime(int64_t curTime,int64_t lastTime)721 bool FileFdSourcePlugin::IsValidTime(int64_t curTime, int64_t lastTime)
722 {
723 return lastReadTime_ != 0 && curReadTime_ - lastReadTime_ < SEEK_TIME_UPPER &&
724 curReadTime_ - lastReadTime_ > SEEK_TIME_LOWER;
725 }
726
SetEnableOnlineFdCache(bool isEnableFdCache)727 void FileFdSourcePlugin::SetEnableOnlineFdCache(bool isEnableFdCache)
728 {
729 isEnableFdCache_ = isEnableFdCache;
730 }
731 } // namespace FileFdSource
732 } // namespace Plugin
733 } // namespace Media
734 } // namespace OHOS