• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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