• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-2024 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 "DashSegmentDownloader"
16 
17 #include "dash_segment_downloader.h"
18 #include <map>
19 #include <algorithm>
20 #include "network/network_typs.h"
21 #include "dash_mpd_util.h"
22 #include "avcodec_log.h"
23 
24 namespace OHOS {
25 namespace Media {
26 namespace Plugins {
27 namespace HttpPlugin {
28 constexpr uint32_t VID_RING_BUFFER_SIZE = 20 * 1024 * 1024;
29 constexpr uint32_t AUD_RING_BUFFER_SIZE = 2 * 1024 * 1024;
30 constexpr uint32_t SUBTITLE_RING_BUFFER_SIZE = 1 * 1024 * 1024;
31 constexpr uint32_t DEFAULT_RING_BUFFER_SIZE = 5 * 1024 * 1024;
32 constexpr int DEFAULT_WAIT_TIME = 2;
33 constexpr int32_t HTTP_TIME_OUT_MS = 10 * 1000;
34 constexpr uint32_t RECORD_TIME_INTERVAL = 1000;
35 constexpr int32_t RECORD_DOWNLOAD_MIN_BIT = 1000;
36 constexpr uint32_t SPEED_MULTI_FACT = 1000;
37 constexpr uint32_t BYTE_TO_BIT = 8;
38 constexpr int PLAY_WATER_LINE = 5 * 1024;
39 constexpr int64_t BYTES_TO_BIT = 8;
40 constexpr int32_t DEFAULT_VIDEO_WATER_LINE = 512 * 1024;
41 constexpr int32_t DEFAULT_AUDIO_WATER_LINE = 96 * 1024;
42 constexpr float DEFAULT_MIN_CACHE_TIME = 0.3;
43 constexpr float DEFAULT_MAX_CACHE_TIME = 10.0;
44 constexpr uint32_t DURATION_CHANGE_AMOUT_MILLIONSECOND = 500;
45 constexpr int64_t SECOND_TO_MILLISECONDS = 1000;
46 constexpr uint32_t BUFFERING_SLEEP_TIME_MS = 10;
47 constexpr uint32_t BUFFERING_TIME_OUT_MS = 1000;
48 constexpr uint32_t UPDATE_CACHE_STEP = 10;
49 constexpr double ZERO_THRESHOLD = 1e-9;
50 constexpr size_t MAX_BUFFERING_TIME_OUT = 30 * 1000;
51 constexpr size_t DOWNLOADER_RESUME_THRESHOLD = 10 * 1024 * 1024;
52 
53 static const std::map<MediaAVCodec::MediaType, uint32_t> BUFFER_SIZE_MAP = {
54     {MediaAVCodec::MediaType::MEDIA_TYPE_VID, VID_RING_BUFFER_SIZE},
55     {MediaAVCodec::MediaType::MEDIA_TYPE_AUD, AUD_RING_BUFFER_SIZE},
56     {MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE, SUBTITLE_RING_BUFFER_SIZE}};
57 
DashSegmentDownloader(Callback * callback,int streamId,MediaAVCodec::MediaType streamType,uint64_t expectDuration,std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader)58 DashSegmentDownloader::DashSegmentDownloader(Callback *callback, int streamId, MediaAVCodec::MediaType streamType,
59     uint64_t expectDuration, std::shared_ptr<MediaSourceLoaderCombinations> sourceLoader)
60 {
61     callback_ = callback;
62     streamId_ = streamId;
63     streamType_ = streamType;
64     expectDuration_ = expectDuration;
65     if (expectDuration_ > 0) {
66         userDefinedBufferDuration_ = true;
67     }
68     size_t ringBufferSize = GetRingBufferInitSize(streamType_);
69     MEDIA_LOG_I("DashSegmentDownloader streamId:" PUBLIC_LOG_D32 ", ringBufferSize:"
70         PUBLIC_LOG_ZU, streamId, ringBufferSize);
71     ringBufferCapcity_ = ringBufferSize;
72     waterLineAbove_ = PLAY_WATER_LINE;
73     buffer_ = std::make_shared<RingBuffer>(ringBufferSize);
74     buffer_->Init();
75 
76     sourceLoader_ = sourceLoader;
77     downloader_ = std::make_shared<Downloader>("dashSegment", sourceLoader_);
78 
79     dataSave_ =  [this] (uint8_t*&& data, uint32_t&& len, bool&& notBlock) {
80         return SaveData(std::forward<decltype(data)>(data), std::forward<decltype(len)>(len),
81             std::forward<decltype(notBlock)>(notBlock));
82     };
83 
84     downloadRequest_ = nullptr;
85     mediaSegment_ = nullptr;
86     loopInterruptClock_.Reset();
87     recordData_ = std::make_shared<RecordData>();
88 }
89 
~DashSegmentDownloader()90 DashSegmentDownloader::~DashSegmentDownloader() noexcept
91 {
92     if (buffer_ != nullptr) {
93         buffer_->SetActive(false, true);
94     }
95     if (downloader_ != nullptr) {
96         downloader_->Stop(false);
97     }
98     segmentList_.clear();
99 }
100 
Open(const std::shared_ptr<DashSegment> & dashSegment)101 bool DashSegmentDownloader::Open(const std::shared_ptr<DashSegment>& dashSegment)
102 {
103     std::lock_guard<std::mutex> lock(segmentMutex_);
104     steadyClock_.Reset();
105     lastCheckTime_ = 0;
106     downloadDuringTime_ = 0;
107     totalDownloadDuringTime_ = 0;
108     downloadBits_ = 0;
109     totalBits_ = 0;
110     lastBits_ = 0;
111     mediaSegment_ = std::make_shared<DashBufferSegment>(dashSegment);
112     if (mediaSegment_->byteRange_.length() > 0) {
113         DashParseRange(mediaSegment_->byteRange_, mediaSegment_->startRangeValue_, mediaSegment_->endRangeValue_);
114     }
115 
116     if (mediaSegment_->startRangeValue_ >= 0 && mediaSegment_->endRangeValue_ > mediaSegment_->startRangeValue_) {
117         mediaSegment_->contentLength_ = static_cast<size_t>(mediaSegment_->endRangeValue_ -
118                                                             mediaSegment_->startRangeValue_ + 1);
119     }
120     segmentList_.push_back(mediaSegment_);
121     MEDIA_LOG_I("Open enter streamId:" PUBLIC_LOG_D32 " ,seqNum:" PUBLIC_LOG_D64 ", range=" PUBLIC_LOG_D64 "-"
122         PUBLIC_LOG_D64, mediaSegment_->streamId_, mediaSegment_->numberSeq_,
123         mediaSegment_->startRangeValue_, mediaSegment_->endRangeValue_);
124 
125     std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(streamId_);
126     if (initSegment != nullptr && initSegment->writeState_ == INIT_SEGMENT_STATE_UNUSE) {
127         MEDIA_LOG_I("Open streamId:" PUBLIC_LOG_D32 ", writeState:"
128             PUBLIC_LOG_D32, streamId_, initSegment->writeState_);
129         initSegment->writeState_ = INIT_SEGMENT_STATE_USING;
130         if (!initSegment->isDownloadFinish_) {
131             int64_t startPos = initSegment->rangeBegin_;
132             int64_t endPos = initSegment->rangeEnd_;
133             PutRequestIntoDownloader(0, startPos, endPos, initSegment->url_);
134         } else {
135             initSegment->writeState_ = INIT_SEGMENT_STATE_USED;
136             PutRequestIntoDownloader(mediaSegment_->duration_, mediaSegment_->startRangeValue_,
137                                      mediaSegment_->endRangeValue_, mediaSegment_->url_);
138         }
139     } else {
140         PutRequestIntoDownloader(mediaSegment_->duration_, mediaSegment_->startRangeValue_,
141                                  mediaSegment_->endRangeValue_, mediaSegment_->url_);
142     }
143 
144     return true;
145 }
146 
Close(bool isAsync,bool isClean)147 void DashSegmentDownloader::Close(bool isAsync, bool isClean)
148 {
149     MEDIA_LOG_I("Close enter");
150     buffer_->SetActive(false, isClean);
151     downloader_->Stop(isAsync);
152 
153     if (downloadRequest_ != nullptr && !downloadRequest_->IsClosed()) {
154         downloadRequest_->Close();
155     }
156 }
157 
Pause()158 void DashSegmentDownloader::Pause()
159 {
160     MEDIA_LOG_I("Pause enter");
161     buffer_->SetActive(false);
162     downloader_->Pause();
163 }
164 
Resume()165 void DashSegmentDownloader::Resume()
166 {
167     MEDIA_LOG_I("Resume enter");
168     buffer_->SetActive(true);
169     downloader_->Resume();
170 }
171 
Read(uint8_t * buff,ReadDataInfo & readDataInfo,const std::atomic<bool> & isInterruptNeeded)172 DashReadRet DashSegmentDownloader::Read(uint8_t *buff, ReadDataInfo &readDataInfo,
173                                         const std::atomic<bool> &isInterruptNeeded)
174 {
175     FALSE_RETURN_V_MSG(buffer_ != nullptr, DASH_READ_FAILED, "buffer is null");
176     FALSE_RETURN_V_MSG(!isInterruptNeeded.load(), DASH_READ_INTERRUPT, "isInterruptNeeded");
177     int32_t streamId = readDataInfo.streamId_;
178     uint32_t wantReadLength = readDataInfo.wantReadLength_;
179     uint32_t &realReadLength = readDataInfo.realReadLength_;
180     int32_t &realStreamId = readDataInfo.nextStreamId_;
181     FALSE_RETURN_V_MSG(readDataInfo.wantReadLength_ > 0, DASH_READ_FAILED, "wantReadLength_ <= 0");
182 
183     DashReadRet readRet = DASH_READ_OK;
184     if (CheckReadInterrupt(realReadLength, wantReadLength, readRet, isInterruptNeeded)) {
185         return readRet;
186     }
187 
188     std::shared_ptr<DashBufferSegment> currentSegment = GetCurrentSegment();
189     int32_t currentStreamId = streamId;
190     if (currentSegment != nullptr) {
191         currentStreamId = currentSegment->streamId_;
192     }
193     realStreamId = currentStreamId;
194     if (realStreamId != streamId) {
195         MEDIA_LOG_I("Read: changed stream streamId:" PUBLIC_LOG_D32 ", realStreamId:"
196             PUBLIC_LOG_D32, streamId, realStreamId);
197         UpdateInitSegmentState(currentStreamId);
198         return readRet;
199     }
200 
201     if (ReadInitSegment(buff, wantReadLength, realReadLength, currentStreamId)) {
202         return DASH_READ_OK;
203     }
204     bool canWriteTmp = canWrite_.load();
205     uint32_t maxReadLength = GetMaxReadLength(wantReadLength, currentSegment, currentStreamId);
206     realReadLength = buffer_->ReadBuffer(buff, maxReadLength, DEFAULT_WAIT_TIME);
207     size_t bufferSize = buffer_->GetSize();
208     if (downloader_ != nullptr && sourceLoader_ != nullptr && !canWriteTmp && realReadLength > 0
209         && bufferSize < DOWNLOADER_RESUME_THRESHOLD) {
210         downloader_->Resume();
211         MEDIA_LOG_D("Dash downloader resume.");
212     }
213     if (realReadLength == 0) {
214         MEDIA_LOG_W("After read: streamId:" PUBLIC_LOG_D32 " ,bufferHead:" PUBLIC_LOG_ZU ", bufferTail:" PUBLIC_LOG_ZU
215             ", realReadLength:" PUBLIC_LOG_U32, currentStreamId, buffer_->GetHead(), buffer_->GetTail(),
216             realReadLength);
217         return DASH_READ_AGAIN;
218     }
219 
220     MEDIA_LOG_D("After read: streamId:" PUBLIC_LOG_D32 " ,bufferHead:" PUBLIC_LOG_ZU ", bufferTail:" PUBLIC_LOG_ZU
221             ", realReadLength:" PUBLIC_LOG_U32, currentStreamId, buffer_->GetHead(), buffer_->GetTail(),
222             realReadLength);
223     ClearReadSegmentList();
224     return readRet;
225 }
226 
GetMaxReadLength(uint32_t wantReadLength,const std::shared_ptr<DashBufferSegment> & currentSegment,int32_t currentStreamId) const227 uint32_t DashSegmentDownloader::GetMaxReadLength(uint32_t wantReadLength,
228                                                  const std::shared_ptr<DashBufferSegment> &currentSegment,
229                                                  int32_t currentStreamId) const
230 {
231     uint32_t maxReadLength = wantReadLength;
232     if (currentSegment != nullptr) {
233         uint32_t availableSize = currentSegment->bufferPosTail_ - buffer_->GetHead();
234         if (availableSize > 0) {
235             maxReadLength = availableSize;
236         }
237     }
238     maxReadLength = maxReadLength > wantReadLength ? wantReadLength : maxReadLength;
239     MEDIA_LOG_D("Read: streamId:" PUBLIC_LOG_D32 " limit, bufferHead:" PUBLIC_LOG_ZU ", bufferTail:" PUBLIC_LOG_ZU
240         ", maxReadLength:" PUBLIC_LOG_U32, currentStreamId, buffer_->GetHead(), buffer_->GetTail(), maxReadLength);
241     return maxReadLength;
242 }
243 
IsSegmentFinished(uint32_t & realReadLength,DashReadRet & readRet)244 bool DashSegmentDownloader::IsSegmentFinished(uint32_t &realReadLength, DashReadRet &readRet)
245 {
246     if (isAllSegmentFinished_.load()) {
247         readRet = DASH_READ_SEGMENT_DOWNLOAD_FINISH;
248         if (buffer_->GetSize() == 0) {
249             readRet = DASH_READ_END;
250             realReadLength = 0;
251             if (mediaSegment_ != nullptr) {
252                 MEDIA_LOG_I("Read: streamId:" PUBLIC_LOG_D32 " segment "
253                     PUBLIC_LOG_D64 " read Eos", mediaSegment_->streamId_, mediaSegment_->numberSeq_);
254             }
255             DoBufferingEndEvent();
256             return true;
257         }
258     }
259     return false;
260 }
261 
CheckReadInterrupt(uint32_t & realReadLength,uint32_t wantReadLength,DashReadRet & readRet,const std::atomic<bool> & isInterruptNeeded)262 bool DashSegmentDownloader::CheckReadInterrupt(uint32_t &realReadLength, uint32_t wantReadLength, DashReadRet &readRet,
263                                                const std::atomic<bool> &isInterruptNeeded)
264 {
265     if (IsSegmentFinished(realReadLength, readRet)) {
266         return true;
267     }
268 
269     if (HandleBuffering(isInterruptNeeded)) {
270         MEDIA_LOG_E("DashSegmentDownloader read return error again streamId: " PUBLIC_LOG_D32, streamId_);
271         readRet = DASH_READ_AGAIN;
272         return true;
273     }
274 
275     bool arrivedBuffering = streamType_ != MediaAVCodec::MediaType::MEDIA_TYPE_SUBTITLE && isFirstFrameArrived_ &&
276         buffer_->GetSize() < static_cast<size_t>(PLAY_WATER_LINE);
277     if (arrivedBuffering && !isAllSegmentFinished_.load()) {
278         if (HandleCache()) {
279             readRet = DASH_READ_AGAIN;
280             return true;
281         }
282     }
283 
284     if (isInterruptNeeded.load()) {
285         realReadLength = 0;
286         readRet = DASH_READ_INTERRUPT;
287         MEDIA_LOG_I("DashSegmentDownloader interruptNeeded streamId: " PUBLIC_LOG_D32, streamId_);
288         return true;
289     }
290     return false;
291 }
292 
HandleBuffering(const std::atomic<bool> & isInterruptNeeded)293 bool DashSegmentDownloader::HandleBuffering(const std::atomic<bool> &isInterruptNeeded)
294 {
295     if (!isBuffering_.load()) {
296         return false;
297     }
298 
299     MEDIA_LOG_I("HandleBuffering begin streamId: " PUBLIC_LOG_D32, streamId_);
300     int32_t sleepTime = 0;
301     while (!isInterruptNeeded.load()) {
302         if (!isBuffering_.load()) {
303             break;
304         }
305 
306         if (isAllSegmentFinished_.load()) {
307             DoBufferingEndEvent();
308             break;
309         }
310         OSAL::SleepFor(BUFFERING_SLEEP_TIME_MS);
311         sleepTime += BUFFERING_SLEEP_TIME_MS;
312         if (sleepTime > BUFFERING_TIME_OUT_MS) {
313             break;
314         }
315     }
316     MEDIA_LOG_I("HandleBuffering end streamId: " PUBLIC_LOG_D32 " isBuffering: "
317         PUBLIC_LOG_D32, streamId_, isBuffering_.load());
318     return isBuffering_.load();
319 }
320 
SaveDataHandleBuffering()321 void DashSegmentDownloader::SaveDataHandleBuffering()
322 {
323     if (IsNeedBufferForPlaying() || !isBuffering_.load()) {
324         return;
325     }
326     UpdateCachedPercent(BufferingInfoType::BUFFERING_PERCENT);
327     if (buffer_->GetSize() >= waterLineAbove_ || isAllSegmentFinished_.load()) {
328         DoBufferingEndEvent();
329     }
330 }
331 
DoBufferingEndEvent()332 void DashSegmentDownloader::DoBufferingEndEvent()
333 {
334     if (isBuffering_.exchange(false)) {
335         MEDIA_LOG_I("DoBufferingEndEvent OnEvent streamId: " PUBLIC_LOG_D32 " cacheData buffering end", streamId_);
336         UpdateCachedPercent(BufferingInfoType::BUFFERING_END);
337     }
338 }
339 
HandleCache()340 bool DashSegmentDownloader::HandleCache()
341 {
342     waterLineAbove_ = static_cast<size_t>(GetWaterLineAbove());
343     if (!isBuffering_.exchange(true)) {
344         MEDIA_LOG_I("HandleCache OnEvent streamId: " PUBLIC_LOG_D32 " start buffering, waterLineAbove:"
345             PUBLIC_LOG_U32, streamId_, waterLineAbove_);
346         UpdateCachedPercent(BufferingInfoType::BUFFERING_START);
347         return true;
348     }
349     return false;
350 }
351 
GetWaterLineAbove()352 int32_t DashSegmentDownloader::GetWaterLineAbove()
353 {
354     int32_t waterLineAbove = streamType_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID ? DEFAULT_VIDEO_WATER_LINE :
355         DEFAULT_AUDIO_WATER_LINE;
356     if (downloadRequest_ != nullptr && realTimeBitBate_ > 0) {
357         MEDIA_LOG_I("GetWaterLineAbove streamId: " PUBLIC_LOG_D32 " realTimeBitBate: "
358             PUBLIC_LOG_D64 " downloadBiteRate: " PUBLIC_LOG_U32, streamId_, realTimeBitBate_, downloadBiteRate_);
359         if (downloadBiteRate_ == 0) {
360             MEDIA_LOG_I("GetWaterLineAbove streamId: " PUBLIC_LOG_D32 " use default waterLineAbove: "
361                 PUBLIC_LOG_D32, streamId_, waterLineAbove);
362             return waterLineAbove;
363         }
364 
365         if (realTimeBitBate_ > static_cast<int64_t>(downloadBiteRate_)) {
366             waterLineAbove = static_cast<int32_t>(DEFAULT_MAX_CACHE_TIME * realTimeBitBate_ / BYTES_TO_BIT);
367         } else {
368             waterLineAbove = static_cast<int32_t>(DEFAULT_MIN_CACHE_TIME * realTimeBitBate_ / BYTES_TO_BIT);
369         }
370         int32_t maxWaterLineAbove = static_cast<int32_t>(ringBufferCapcity_ / 2);
371         waterLineAbove = waterLineAbove > maxWaterLineAbove ? maxWaterLineAbove : waterLineAbove;
372         int32_t minWaterLineAbove = 2 * PLAY_WATER_LINE;
373         waterLineAbove = waterLineAbove < minWaterLineAbove ? minWaterLineAbove : waterLineAbove;
374     }
375     MEDIA_LOG_I("GetWaterLineAbove streamId: " PUBLIC_LOG_D32 " waterLineAbove: "
376         PUBLIC_LOG_D32, streamId_, waterLineAbove);
377     return waterLineAbove;
378 }
379 
CalculateBitRate(size_t fragmentSize,double duration)380 void DashSegmentDownloader::CalculateBitRate(size_t fragmentSize, double duration)
381 {
382     if (fragmentSize == 0 || duration == 0) {
383         return;
384     }
385 
386     realTimeBitBate_ = static_cast<int64_t>(fragmentSize * BYTES_TO_BIT * SECOND_TO_MILLISECONDS) / duration;
387     MEDIA_LOG_I("CalculateBitRate streamId: " PUBLIC_LOG_D32 " realTimeBitBate: "
388         PUBLIC_LOG_D64, streamId_, realTimeBitBate_);
389 }
390 
HandleCachedDuration()391 void DashSegmentDownloader::HandleCachedDuration()
392 {
393     auto tmpBitRate = realTimeBitBate_;
394     if (tmpBitRate <= 0) {
395         return;
396     }
397 
398     uint64_t cachedDuration = static_cast<uint64_t>((static_cast<int64_t>(buffer_->GetSize()) *
399         BYTES_TO_BIT * SECOND_TO_MILLISECONDS) / tmpBitRate);
400     if ((cachedDuration > lastDurationRecord_ &&
401          cachedDuration - lastDurationRecord_ > DURATION_CHANGE_AMOUT_MILLIONSECOND) ||
402         (lastDurationRecord_ > cachedDuration &&
403          lastDurationRecord_ - cachedDuration > DURATION_CHANGE_AMOUT_MILLIONSECOND)) {
404         if (callback_ != nullptr) {
405             MEDIA_LOG_D("HandleCachedDuration OnEvent streamId: " PUBLIC_LOG_D32 " cachedDuration: "
406                 PUBLIC_LOG_U64, streamId_, cachedDuration);
407             callback_->OnEvent({PluginEventType::CACHED_DURATION, {cachedDuration}, "buffering_duration"});
408         }
409         lastDurationRecord_ = cachedDuration;
410     }
411 }
412 
GetCachedPercent()413 uint32_t DashSegmentDownloader::GetCachedPercent()
414 {
415     if (waterLineAbove_ == 0) {
416         return 0;
417     }
418 
419     uint32_t bufferSize = static_cast<uint32_t>(buffer_->GetSize());
420     return (bufferSize >= waterLineAbove_) ? BUFFERING_PERCENT_FULL : bufferSize * BUFFERING_PERCENT_FULL /
421         waterLineAbove_;
422 }
423 
UpdateCachedPercent(BufferingInfoType infoType)424 void DashSegmentDownloader::UpdateCachedPercent(BufferingInfoType infoType)
425 {
426     if (waterLineAbove_ == 0 || bufferingCbFunc_ == nullptr) {
427         MEDIA_LOG_W("OnEvent streamId: " PUBLIC_LOG_D32 " UpdateCachedPercent error", streamId_);
428         return;
429     }
430 
431     if (infoType == BufferingInfoType::BUFFERING_START || infoType == BufferingInfoType::BUFFERING_END) {
432         lastCachedSize_ = 0;
433         bufferingCbFunc_(streamId_, infoType);
434         return;
435     }
436     if (infoType != BufferingInfoType::BUFFERING_PERCENT) {
437         return;
438     }
439 
440     uint32_t bufferSize = static_cast<uint32_t>(buffer_->GetSize());
441     if (bufferSize < lastCachedSize_) {
442         return;
443     }
444     uint32_t deltaSize = bufferSize - lastCachedSize_;
445     if ((deltaSize * BUFFERING_PERCENT_FULL / waterLineAbove_) >= UPDATE_CACHE_STEP) {
446         bufferingCbFunc_(streamId_, infoType);
447         lastCachedSize_ = bufferSize;
448     }
449 }
450 
GetCurrentSegment()451 std::shared_ptr<DashBufferSegment> DashSegmentDownloader::GetCurrentSegment()
452 {
453     std::shared_ptr<DashBufferSegment> currentSegment;
454     {
455         std::lock_guard<std::mutex> lock(segmentMutex_);
456         auto it = std::find_if(segmentList_.begin(), segmentList_.end(),
457             [this](const std::shared_ptr<DashBufferSegment> &item) -> bool {
458                 return buffer_->GetHead() >= item->bufferPosHead_ && buffer_->GetHead() < item->bufferPosTail_;
459             });
460         if (it != segmentList_.end()) {
461             currentSegment = *it;
462         }
463     }
464     return currentSegment;
465 }
466 
UpdateInitSegmentState(int32_t currentStreamId)467 void DashSegmentDownloader::UpdateInitSegmentState(int32_t currentStreamId)
468 {
469     std::lock_guard<std::mutex> lock(initSegmentMutex_);
470     for (auto it = initSegments_.begin(); it != initSegments_.end(); ++it) {
471         if ((*it)->streamId_ == currentStreamId) {
472             MEDIA_LOG_I("UpdateInitSegmentState: init streamId:" PUBLIC_LOG_D32 ", contentLen:"
473                 PUBLIC_LOG_ZU ", readIndex:" PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32 ", readState:"
474                 PUBLIC_LOG_D32, currentStreamId, (*it)->content_.length(), (*it)->readIndex_,
475                 (*it)->isDownloadFinish_, (*it)->readState_);
476         }
477         (*it)->readIndex_ = 0;
478         (*it)->readState_ = INIT_SEGMENT_STATE_UNUSE;
479     }
480 }
481 
ReadInitSegment(uint8_t * buff,uint32_t wantReadLength,uint32_t & realReadLength,int32_t currentStreamId)482 bool DashSegmentDownloader::ReadInitSegment(uint8_t *buff, uint32_t wantReadLength, uint32_t &realReadLength,
483                                             int32_t currentStreamId)
484 {
485     std::lock_guard<std::mutex> lock(initSegmentMutex_);
486     std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(currentStreamId);
487     if (initSegment != nullptr && initSegment->readState_ != INIT_SEGMENT_STATE_USED) {
488         unsigned int contentLen = initSegment->content_.length();
489         MEDIA_LOG_I("Read: init streamId:" PUBLIC_LOG_D32 ", contentLen:" PUBLIC_LOG_U32 ", readIndex:"
490             PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32 ", readState:"
491             PUBLIC_LOG_D32, currentStreamId, contentLen, initSegment->readIndex_,
492         initSegment->isDownloadFinish_, initSegment->readState_);
493         if (initSegment->readIndex_ == contentLen && initSegment->isDownloadFinish_) {
494             // init segment read finish
495             initSegment->readState_ = INIT_SEGMENT_STATE_USED;
496             initSegment->readIndex_ = 0;
497             return true;
498         }
499 
500         unsigned int unReadSize = contentLen - initSegment->readIndex_;
501         if (unReadSize > 0) {
502             realReadLength = unReadSize > wantReadLength ? wantReadLength : unReadSize;
503             std::string readStr = initSegment->content_.substr(initSegment->readIndex_);
504             CHECK_AND_RETURN_RET_LOG(wantReadLength <= VID_RING_BUFFER_SIZE * BYTE_TO_BIT, 1, "too large");
505             CHECK_AND_RETURN_RET_LOG(realReadLength <= VID_RING_BUFFER_SIZE * BYTE_TO_BIT, 1, "too large");
506             memcpy_s(buff, wantReadLength, readStr.c_str(), realReadLength);
507             initSegment->readIndex_ += realReadLength;
508             if (initSegment->readIndex_ == contentLen && initSegment->isDownloadFinish_) {
509                 // init segment read finish
510                 initSegment->readState_ = INIT_SEGMENT_STATE_USED;
511                 initSegment->readIndex_ = 0;
512             }
513         }
514 
515         MEDIA_LOG_I("after Read: init streamId:" PUBLIC_LOG_D32 ", contentLen:" PUBLIC_LOG_U32 ", readIndex_:"
516             PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32, currentStreamId, contentLen, initSegment->readIndex_,
517             initSegment->isDownloadFinish_);
518         return true;
519     }
520     return false;
521 }
522 
ClearReadSegmentList()523 void DashSegmentDownloader::ClearReadSegmentList()
524 {
525     std::lock_guard<std::mutex> lock(segmentMutex_);
526     for (auto it = segmentList_.begin(); it != segmentList_.end(); ++it) {
527         if (buffer_->GetHead() != 0 && (*it)->isEos_ && buffer_->GetHead() >= (*it)->bufferPosTail_) {
528             MEDIA_LOG_D("Read:streamId:" PUBLIC_LOG_D32 ", erase numberSeq:"
529                 PUBLIC_LOG_D64, (*it)->streamId_, (*it)->numberSeq_);
530             it = segmentList_.erase(it);
531         } else {
532             break;
533         }
534     }
535 }
536 
SetStatusCallback(StatusCallbackFunc statusCallbackFunc)537 void DashSegmentDownloader::SetStatusCallback(StatusCallbackFunc statusCallbackFunc)
538 {
539     statusCallback_ = statusCallbackFunc;
540 }
541 
SetDownloadDoneCallback(SegmentDownloadDoneCbFunc doneCbFunc)542 void DashSegmentDownloader::SetDownloadDoneCallback(SegmentDownloadDoneCbFunc doneCbFunc)
543 {
544     downloadDoneCbFunc_ = doneCbFunc;
545 }
546 
SetSegmentBufferingCallback(SegmentBufferingCbFunc bufferingCbFunc)547 void DashSegmentDownloader::SetSegmentBufferingCallback(SegmentBufferingCbFunc bufferingCbFunc)
548 {
549     bufferingCbFunc_ = bufferingCbFunc;
550 }
551 
GetRingBufferInitSize(MediaAVCodec::MediaType streamType) const552 size_t DashSegmentDownloader::GetRingBufferInitSize(MediaAVCodec::MediaType streamType) const
553 {
554     size_t ringBufferFixSize = DEFAULT_RING_BUFFER_SIZE;
555     auto ringBufferSizeItem = BUFFER_SIZE_MAP.find(streamType);
556     if (ringBufferSizeItem != BUFFER_SIZE_MAP.end()) {
557         ringBufferFixSize = ringBufferSizeItem->second;
558     }
559 
560     if (streamType == MediaAVCodec::MediaType::MEDIA_TYPE_VID && userDefinedBufferDuration_) {
561         size_t ringBufferSize = expectDuration_ * currentBitrate_;
562         if (ringBufferSize < DEFAULT_RING_BUFFER_SIZE) {
563             MEDIA_LOG_I("Setting buffer size: " PUBLIC_LOG_ZU ", already lower than the min buffer size: "
564                 PUBLIC_LOG_U32 ", setting buffer size: "
565                 PUBLIC_LOG_U32, ringBufferSize, DEFAULT_RING_BUFFER_SIZE, DEFAULT_RING_BUFFER_SIZE);
566             ringBufferSize = DEFAULT_RING_BUFFER_SIZE;
567         } else if (ringBufferSize > ringBufferFixSize) {
568             MEDIA_LOG_I("Setting buffer size: " PUBLIC_LOG_ZU ", already exceed the max buffer size: "
569                 PUBLIC_LOG_ZU ", setting buffer size: "
570                 PUBLIC_LOG_ZU, ringBufferSize, ringBufferFixSize, ringBufferFixSize);
571             ringBufferSize = ringBufferFixSize;
572         }
573         return ringBufferSize;
574     } else {
575         return ringBufferFixSize;
576     }
577 }
578 
SetInitSegment(std::shared_ptr<DashInitSegment> initSegment,bool needUpdateState)579 void DashSegmentDownloader::SetInitSegment(std::shared_ptr<DashInitSegment> initSegment, bool needUpdateState)
580 {
581     if (initSegment == nullptr) {
582         return;
583     }
584 
585     std::lock_guard<std::mutex> lock(initSegmentMutex_);
586     int streamId = initSegment->streamId_;
587     std::shared_ptr<DashInitSegment> dashInitSegment = GetDashInitSegment(streamId);
588     if (dashInitSegment == nullptr) {
589         initSegments_.push_back(initSegment);
590         dashInitSegment = initSegment;
591         needUpdateState = true;
592     }
593 
594     if (!dashInitSegment->isDownloadFinish_) {
595         dashInitSegment->writeState_ = INIT_SEGMENT_STATE_UNUSE;
596     }
597 
598     // seek or first time to set stream init segment should update to UNUSE
599     // read will update state to UNUSE when stream id is changed
600     if (needUpdateState) {
601         dashInitSegment->readState_ = INIT_SEGMENT_STATE_UNUSE;
602     }
603     MEDIA_LOG_I("SetInitSegment:streamId:" PUBLIC_LOG_D32 ", isDownloadFinish_="
604         PUBLIC_LOG_D32 ", readIndex=" PUBLIC_LOG_U32 ", readState_=" PUBLIC_LOG_D32 ", update="
605         PUBLIC_LOG_D32 ", writeState_=" PUBLIC_LOG_D32, streamId, dashInitSegment->isDownloadFinish_,
606         dashInitSegment->readIndex_, dashInitSegment->readState_, needUpdateState, dashInitSegment->writeState_);
607 }
608 
UpdateStreamId(int streamId)609 void DashSegmentDownloader::UpdateStreamId(int streamId)
610 {
611     streamId_ = streamId;
612 }
613 
SetCurrentBitRate(int32_t bitRate)614 void DashSegmentDownloader::SetCurrentBitRate(int32_t bitRate)
615 {
616     if (bitRate <= 0) {
617         realTimeBitBate_ = -1;
618     } else {
619         realTimeBitBate_ = static_cast<int64_t>(bitRate);
620     }
621 }
622 
SetDemuxerState()623 void DashSegmentDownloader::SetDemuxerState()
624 {
625     isFirstFrameArrived_ = true;
626 }
627 
SetAllSegmentFinished()628 void DashSegmentDownloader::SetAllSegmentFinished()
629 {
630     MEDIA_LOG_I("SetAllSegmentFinished streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
631     isAllSegmentFinished_.store(true);
632 }
633 
GetStreamId() const634 int DashSegmentDownloader::GetStreamId() const
635 {
636     return streamId_;
637 }
638 
GetStreamType() const639 MediaAVCodec::MediaType DashSegmentDownloader::GetStreamType() const
640 {
641     return streamType_;
642 }
643 
GetContentLength()644 size_t DashSegmentDownloader::GetContentLength()
645 {
646     if (downloadRequest_ == nullptr || downloadRequest_->IsClosed()) {
647         return 0; // 0
648     }
649     return downloadRequest_->GetFileContentLength();
650 }
651 
GetStartedStatus() const652 bool DashSegmentDownloader::GetStartedStatus() const
653 {
654     return startedPlayStatus_;
655 }
656 
IsSegmentFinish() const657 bool DashSegmentDownloader::IsSegmentFinish() const
658 {
659     if (mediaSegment_ != nullptr && mediaSegment_->isEos_) {
660         return true;
661     }
662 
663     return false;
664 }
665 
CleanAllSegmentBuffer(bool isCleanAll,int64_t & remainLastNumberSeq)666 bool DashSegmentDownloader::CleanAllSegmentBuffer(bool isCleanAll, int64_t& remainLastNumberSeq)
667 {
668     if (isCleanAll) {
669         MEDIA_LOG_I("CleanAllSegmentBuffer clean all");
670         isCleaningBuffer_.store(true);
671         Close(false, true);
672         std::lock_guard<std::mutex> lock(segmentMutex_);
673         isAllSegmentFinished_.store(false);
674         for (const auto &it: segmentList_) {
675             if (it == nullptr || buffer_->GetHead() > it->bufferPosTail_) {
676                 continue;
677             }
678 
679             remainLastNumberSeq = it->numberSeq_;
680             break;
681         }
682 
683         downloader_ = std::make_shared<Downloader>("dashSegment", sourceLoader_);
684         buffer_->Clear();
685         segmentList_.clear();
686         buffer_->SetActive(true);
687         return true;
688     }
689 
690     return false;
691 }
692 
CleanSegmentBuffer(bool isCleanAll,int64_t & remainLastNumberSeq)693 bool DashSegmentDownloader::CleanSegmentBuffer(bool isCleanAll, int64_t& remainLastNumberSeq)
694 {
695     if (CleanAllSegmentBuffer(isCleanAll, remainLastNumberSeq)) {
696         return true;
697     }
698 
699     size_t clearTail = 0;
700     {
701         std::lock_guard<std::mutex> lock(segmentMutex_);
702         remainLastNumberSeq = -1;
703         uint32_t remainDuration = 0;
704         for (const auto &it: segmentList_) {
705             if (it == nullptr || (buffer_->GetHead() > it->bufferPosTail_ && it->bufferPosTail_ > 0)) {
706                 continue;
707             }
708 
709             remainLastNumberSeq = it->numberSeq_;
710 
711             if (!it->isEos_) {
712                 break;
713             }
714 
715             remainDuration += GetSegmentRemainDuration(it);
716             if (remainDuration >= MIN_RETENTION_DURATION_MS) {
717                 clearTail = it->bufferPosTail_;
718                 break;
719             }
720         }
721 
722         MEDIA_LOG_I("CleanSegmentBuffer:streamId:" PUBLIC_LOG_D32 ", remain numberSeq:"
723             PUBLIC_LOG_D64, streamId_, remainLastNumberSeq);
724     }
725 
726     if (clearTail > 0) {
727         isCleaningBuffer_.store(true);
728         Close(false, false);
729         std::lock_guard<std::mutex> lock(segmentMutex_);
730         isAllSegmentFinished_.store(false);
731         segmentList_.remove_if([&remainLastNumberSeq](std::shared_ptr<DashBufferSegment> bufferSegment) {
732             return (bufferSegment->numberSeq_ > remainLastNumberSeq);
733         });
734 
735         downloader_ = std::make_shared<Downloader>("dashSegment", sourceLoader_);
736         MEDIA_LOG_I("CleanSegmentBuffer bufferHead:" PUBLIC_LOG_ZU " ,bufferTail:" PUBLIC_LOG_ZU " ,clearTail:"
737             PUBLIC_LOG_ZU, buffer_->GetHead(), buffer_->GetTail(), clearTail);
738         buffer_->SetTail(clearTail);
739         buffer_->SetActive(true);
740         return true;
741     }
742     return false;
743 }
744 
CleanByTimeInternal(int64_t & remainLastNumberSeq,size_t & clearTail,bool & isEnd)745 void DashSegmentDownloader::CleanByTimeInternal(int64_t& remainLastNumberSeq, size_t& clearTail, bool& isEnd)
746 {
747     // residue segment duration
748     uint32_t remainDuration = 0;
749     uint32_t segmentKeepDuration = 1000; // ms
750     uint32_t segmentKeepDelta = 100; // ms
751     for (const auto &it: segmentList_) {
752         if (it == nullptr ||
753             buffer_->GetHead() > it->bufferPosTail_ ||
754             it->bufferPosHead_ >= it->bufferPosTail_) {
755             continue;
756         }
757 
758         remainLastNumberSeq = it->numberSeq_;
759         isEnd = it->isEos_;
760         if (it->contentLength_ == 0 ||
761             it->duration_ == 0) {
762             MEDIA_LOG_I("CleanByTimeInternal: contentLength is:" PUBLIC_LOG_ZU ", duration is:"
763                 PUBLIC_LOG_U32, it->contentLength_, it->duration_);
764             // can not caculate segment content length, just keep one segment
765             clearTail = it->bufferPosTail_;
766             break;
767         }
768 
769         remainDuration = (it->bufferPosTail_ - buffer_->GetHead()) * it->duration_ / it->contentLength_;
770         if (remainDuration < segmentKeepDuration + segmentKeepDelta &&
771             remainDuration + segmentKeepDelta >= segmentKeepDuration) {
772             // find clear buffer position with segment tail position
773             clearTail = it->bufferPosTail_;
774         } else if (remainDuration < segmentKeepDuration) {
775             // get next segment buffer
776             clearTail = it->bufferPosTail_;
777             segmentKeepDuration -= remainDuration;
778             continue;
779         } else {
780             // find clear buffer position
781             uint32_t segmentSize = (segmentKeepDuration * it->contentLength_) / it->duration_;
782             if (clearTail > 0) {
783                 // find clear buffer position in multi segments
784                 clearTail += segmentSize;
785             } else {
786                 // find clear buffer position in one segment
787                 clearTail = buffer_->GetHead() + segmentSize;
788             }
789             it->bufferPosTail_ = clearTail;
790             it->isEos_ = true;
791             isEnd = false;
792         }
793 
794         break;
795     }
796 }
797 
CleanBufferByTime(int64_t & remainLastNumberSeq,bool & isEnd)798 bool DashSegmentDownloader::CleanBufferByTime(int64_t& remainLastNumberSeq, bool& isEnd)
799 {
800     Close(false, false);
801     std::lock_guard<std::mutex> lock(segmentMutex_);
802     remainLastNumberSeq = -1;
803     size_t clearTail = 0;
804     CleanByTimeInternal(remainLastNumberSeq, clearTail, isEnd);
805 
806     if (remainLastNumberSeq == -1 && mediaSegment_ != nullptr) {
807         isEnd = false;
808     }
809 
810     MEDIA_LOG_I("CleanBufferByTime:streamId:" PUBLIC_LOG_D32 ", remain numberSeq:"
811         PUBLIC_LOG_D64 ", isEnd:" PUBLIC_LOG_D32 ", size:" PUBLIC_LOG_ZU, streamId_,
812         remainLastNumberSeq, isEnd, segmentList_.size());
813 
814     if (clearTail > 0) {
815         isCleaningBuffer_.store(true);
816         segmentList_.remove_if([&remainLastNumberSeq](std::shared_ptr<DashBufferSegment> bufferSegment) {
817             return (bufferSegment->numberSeq_ > remainLastNumberSeq);
818         });
819 
820         downloader_ = std::make_shared<Downloader>("dashSegment", sourceLoader_);
821         MEDIA_LOG_I("CleanBufferByTime bufferHead:" PUBLIC_LOG_ZU " ,bufferTail:" PUBLIC_LOG_ZU " ,clearTail:"
822             PUBLIC_LOG_ZU " ,seq:" PUBLIC_LOG_D64 ",size:" PUBLIC_LOG_ZU, buffer_->GetHead(), buffer_->GetTail(),
823             clearTail, remainLastNumberSeq, segmentList_.size());
824         buffer_->SetTail(clearTail);
825         buffer_->SetActive(true);
826         return true;
827     }
828     return false;
829 }
830 
SeekToTime(const std::shared_ptr<DashSegment> & segment,int32_t & streamId)831 bool DashSegmentDownloader::SeekToTime(const std::shared_ptr<DashSegment> &segment, int32_t& streamId)
832 {
833     std::lock_guard<std::mutex> lock(segmentMutex_);
834     std::shared_ptr<DashBufferSegment> desSegment;
835     auto it = std::find_if(segmentList_.begin(), segmentList_.end(),
836         [&segment](const std::shared_ptr<DashBufferSegment> &item) -> bool {
837             return (item->numberSeq_ - item->startNumberSeq_) == (segment->numberSeq_ - segment->startNumberSeq_);
838         });
839     if (it != segmentList_.end()) {
840         desSegment = *it;
841     }
842 
843     if (desSegment != nullptr && desSegment->bufferPosTail_ > 0) {
844         if (buffer_->SetHead(desSegment->bufferPosHead_)) {
845             // set init segment when seek on buffered, before read first segment demuxer plugin need reboot
846             UpdateInitSegmentState(desSegment->streamId_);
847             streamId = desSegment->streamId_;
848             return true;
849         }
850     }
851     return false;
852 }
853 
SaveData(uint8_t * data,uint32_t len,bool notBlock)854 uint32_t DashSegmentDownloader::SaveData(uint8_t* data, uint32_t len, bool notBlock)
855 {
856     MEDIA_LOG_D("SaveData:streamId:" PUBLIC_LOG_D32 ", len:" PUBLIC_LOG_D32, streamId_, len);
857     size_t freeSize = buffer_->GetFreeSize();
858     startedPlayStatus_ = true;
859     if (notBlock && len >= freeSize) {
860         MEDIA_LOG_D("SaveData buffer not enough, freeSize " PUBLIC_LOG_ZU ", len:" PUBLIC_LOG_U32, freeSize, len);
861         canWrite_.store(false);
862         if (freeSize == 0) {
863             return 0;
864         }
865         len = freeSize;
866     }
867     if (notBlock && len < freeSize) {
868         canWrite_.store(true);
869     }
870     if (streamType_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
871         OnWriteRingBuffer(len);
872     }
873     {
874         std::lock_guard<std::mutex> lock(initSegmentMutex_);
875         std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(streamId_);
876         if (initSegment != nullptr && initSegment->writeState_ == INIT_SEGMENT_STATE_USING) {
877             MEDIA_LOG_I("SaveData:streamId:" PUBLIC_LOG_D32 ", writeState:"
878                 PUBLIC_LOG_D32, streamId_, initSegment->writeState_);
879             initSegment->content_.append(reinterpret_cast<const char*>(data), len);
880             return len;
881         }
882     }
883 
884     size_t bufferTail = buffer_->GetTail();
885     bool writeRet = buffer_->WriteBuffer(data, len);
886     HandleCachedDuration();
887     SaveDataHandleBuffering();
888     if (!writeRet) {
889         MEDIA_LOG_E("SaveData:error streamId:" PUBLIC_LOG_D32 ", len:" PUBLIC_LOG_D32, streamId_, len);
890         return 0;
891     }
892     UpdateMediaSegments(bufferTail, len);
893     return len;
894 }
895 
UpdateMediaSegments(size_t bufferTail,uint32_t len)896 void DashSegmentDownloader::UpdateMediaSegments(size_t bufferTail, uint32_t len)
897 {
898     std::lock_guard<std::mutex> lock(segmentMutex_);
899     int64_t loopStartTime = loopInterruptClock_.ElapsedSeconds();
900     for (const auto &mediaSegment: segmentList_) {
901         CheckLoopTimeout(loopStartTime);
902         if (mediaSegment == nullptr || mediaSegment->isEos_) {
903             continue;
904         }
905 
906         if (mediaSegment->bufferPosTail_ == 0) {
907             mediaSegment->bufferPosHead_ = bufferTail;
908         }
909         mediaSegment->bufferPosTail_ = buffer_->GetTail();
910         UpdateBufferSegment(mediaSegment, len);
911         break;
912     }
913 }
914 
UpdateBufferSegment(const std::shared_ptr<DashBufferSegment> & mediaSegment,uint32_t len)915 void DashSegmentDownloader::UpdateBufferSegment(const std::shared_ptr<DashBufferSegment> &mediaSegment, uint32_t len)
916 {
917     if (mediaSegment->contentLength_ == 0 && downloadRequest_ != nullptr) {
918         mediaSegment->contentLength_ = downloadRequest_->GetFileContentLength();
919     }
920 
921     // last packet len is 0 of chunk
922     if (len == 0 || (mediaSegment->contentLength_ > 0 &&
923                      mediaSegment->bufferPosTail_ >= (mediaSegment->bufferPosHead_ + mediaSegment->contentLength_))) {
924         mediaSegment->isEos_ = true;
925         if (mediaSegment->isLast_) {
926             MEDIA_LOG_I("AllSegmentFinish streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
927             isAllSegmentFinished_.store(true);
928         }
929         if (mediaSegment->contentLength_ == 0) {
930             mediaSegment->contentLength_ = mediaSegment->bufferPosTail_ - mediaSegment->bufferPosHead_;
931         }
932         MEDIA_LOG_I("SaveData eos:streamId:" PUBLIC_LOG_D32 ", segmentNum:" PUBLIC_LOG_D64 ", contentLength:"
933             PUBLIC_LOG_ZU ", bufferPosHead:" PUBLIC_LOG_ZU  " ,bufferPosEnd:" PUBLIC_LOG_ZU,
934             mediaSegment->streamId_, mediaSegment->numberSeq_, mediaSegment->contentLength_,
935             mediaSegment->bufferPosHead_, mediaSegment->bufferPosTail_);
936     }
937 }
938 
OnWriteRingBuffer(uint32_t len)939 void DashSegmentDownloader::OnWriteRingBuffer(uint32_t len)
940 {
941     uint32_t writeBits = len * BYTE_TO_BIT;
942     totalBits_ += writeBits;
943     uint64_t now = static_cast<uint64_t>(steadyClock_.ElapsedMilliseconds());
944     if (now > lastCheckTime_ && now - lastCheckTime_ > RECORD_TIME_INTERVAL) {
945         uint64_t curDownloadBits = totalBits_ - lastBits_;
946         if (curDownloadBits >= RECORD_DOWNLOAD_MIN_BIT) {
947             downloadDuringTime_ = now - lastCheckTime_;
948             downloadBits_ += curDownloadBits;
949             totalDownloadDuringTime_ += downloadDuringTime_;
950             double downloadRate = 0;
951             double tmpNumerator = static_cast<double>(curDownloadBits);
952             double tmpDenominator = static_cast<double>(downloadDuringTime_) / SECOND_TO_MILLISECONDS;
953             if (tmpDenominator > ZERO_THRESHOLD) {
954                 downloadRate = tmpNumerator / tmpDenominator;
955             }
956             size_t remainingBuffer = 0;
957             if (buffer_ != nullptr) {
958                 remainingBuffer = buffer_->GetSize();
959             }
960             MEDIA_LOG_D("Current download speed : " PUBLIC_LOG_D32 " Kbit/s,Current buffer size : " PUBLIC_LOG_U64
961                 " KByte", static_cast<int32_t>(downloadRate / 1024), static_cast<uint64_t>(remainingBuffer / 1024));
962             // Remaining playable time: s
963             uint64_t bufferDuration = 0;
964             if (realTimeBitBate_ > 0) {
965                 bufferDuration =
966                     remainingBuffer * static_cast<uint64_t>(BYTES_TO_BIT) / static_cast<uint64_t>(realTimeBitBate_);
967             } else {
968                 bufferDuration = static_cast<uint64_t>(remainingBuffer * BYTES_TO_BIT) / currentBitrate_;
969             }
970             if (recordData_ != nullptr) {
971                 recordData_->downloadRate = downloadRate;
972                 recordData_->bufferDuring = bufferDuration;
973             }
974         }
975         lastBits_ = totalBits_;
976         lastCheckTime_ = now;
977     }
978 }
979 
GetDownloadSpeed() const980 uint64_t DashSegmentDownloader::GetDownloadSpeed() const
981 {
982     return static_cast<uint64_t>(downloadSpeed_);
983 }
984 
GetIp(std::string & ip)985 void DashSegmentDownloader::GetIp(std::string& ip)
986 {
987     if (downloader_) {
988         downloader_->GetIp(ip);
989     }
990 }
991 
GetDownloadFinishState()992 bool DashSegmentDownloader::GetDownloadFinishState()
993 {
994     std::shared_ptr<DashInitSegment> finishState = GetDashInitSegment(streamId_);
995     if (finishState) {
996         return finishState->isDownloadFinish_;
997     } else {
998         return true;
999     }
1000 }
1001 
GetDownloadRecordData()1002 std::pair<int64_t, int64_t> DashSegmentDownloader::GetDownloadRecordData()
1003 {
1004     std::pair<int64_t, int64_t> recordData;
1005     if (recordData_ != nullptr) {
1006         recordData.first = static_cast<int64_t>(recordData_->downloadRate);
1007         recordData.second = static_cast<int64_t>(recordData_->bufferDuring);
1008     } else {
1009         recordData.first = 0;
1010         recordData.second = 0;
1011     }
1012     return recordData;
1013 }
1014 
GetBufferSize() const1015 uint32_t DashSegmentDownloader::GetBufferSize() const
1016 {
1017     if (buffer_ != nullptr) {
1018         return buffer_->GetSize();
1019     }
1020     return 0;
1021 }
1022 
GetRingBufferCapacity() const1023 uint32_t DashSegmentDownloader::GetRingBufferCapacity() const
1024 {
1025     return ringBufferCapcity_;
1026 }
1027 
PutRequestIntoDownloader(unsigned int duration,int64_t startPos,int64_t endPos,const std::string & url)1028 void DashSegmentDownloader::PutRequestIntoDownloader(unsigned int duration, int64_t startPos, int64_t endPos,
1029                                                      const std::string &url)
1030 {
1031     auto realStatusCallback = [this](DownloadStatus &&status, std::shared_ptr<Downloader> &downloader,
1032         std::shared_ptr<DownloadRequest> &request) {
1033             statusCallback_(status, downloader_, std::forward<decltype(request)>(request));
1034     };
1035     auto downloadDoneCallback = [this](const std::string &url, const std::string &location) {
1036         UpdateDownloadFinished(url, location);
1037     };
1038 
1039     bool requestWholeFile = true;
1040     if (startPos >= 0 && endPos > 0) {
1041         requestWholeFile = false;
1042     }
1043     RequestInfo requestInfo;
1044     requestInfo.url = url;
1045     requestInfo.timeoutMs = HTTP_TIME_OUT_MS;
1046     downloadRequest_ = std::make_shared<DownloadRequest>(duration, dataSave_,
1047                                                          realStatusCallback, requestInfo, requestWholeFile);
1048     downloadRequest_->SetDownloadDoneCb(downloadDoneCallback);
1049     downloadRequest_->SetRequestProtocolType(RequestProtocolType::DASH);
1050     if (!requestWholeFile && (endPos > startPos)) {
1051         downloadRequest_->SetRangePos(startPos, endPos);
1052     }
1053     MEDIA_LOG_I("PutRequestIntoDownloader:range=" PUBLIC_LOG_D64 "-" PUBLIC_LOG_D64, startPos, endPos);
1054 
1055     isCleaningBuffer_.store(false);
1056     if (downloader_ != nullptr) {
1057         downloader_->Download(downloadRequest_, -1); // -1
1058         downloader_->Start();
1059     }
1060 }
1061 
UpdateDownloadFinished(const std::string & url,const std::string & location)1062 void DashSegmentDownloader::UpdateDownloadFinished(const std::string& url, const std::string& location)
1063 {
1064     MEDIA_LOG_I("UpdateDownloadFinished:streamId:" PUBLIC_LOG_D32, streamId_);
1065     if (totalDownloadDuringTime_ > 0) {
1066         double tmpNumerator = static_cast<double>(downloadBits_);
1067         double tmpDenominator = static_cast<double>(totalDownloadDuringTime_);
1068         double downloadRate = tmpNumerator / tmpDenominator;
1069         downloadSpeed_ = downloadRate * SPEED_MULTI_FACT;
1070     } else {
1071         downloadSpeed_ = 0;
1072     }
1073 
1074     if (UpdateInitSegmentFinish()) {
1075         if (mediaSegment_ != nullptr) {
1076             PutRequestIntoDownloader(mediaSegment_->duration_, mediaSegment_->startRangeValue_,
1077                 mediaSegment_->endRangeValue_, mediaSegment_->url_);
1078             return;
1079         }
1080     }
1081 
1082     if (mediaSegment_ != nullptr) {
1083         if (mediaSegment_->contentLength_ == 0 && downloadRequest_ != nullptr) {
1084             mediaSegment_->contentLength_ = downloadRequest_->GetFileContentLength();
1085         }
1086         if (downloadRequest_ != nullptr) {
1087             size_t fragmentSize = mediaSegment_->contentLength_;
1088             double duration = downloadRequest_->GetDuration();
1089             CalculateBitRate(fragmentSize, duration);
1090             downloadBiteRate_ = downloadRequest_->GetBitRate();
1091         }
1092         mediaSegment_->isEos_ = true;
1093         if (mediaSegment_->isLast_) {
1094             MEDIA_LOG_I("AllSegmentFinish streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
1095             isAllSegmentFinished_.store(true);
1096         }
1097         MEDIA_LOG_I("UpdateDownloadFinished: segmentNum:" PUBLIC_LOG_D64 ", contentLength:" PUBLIC_LOG_ZU
1098             ", isCleaningBuffer:" PUBLIC_LOG_D32 " isLast: " PUBLIC_LOG_D32, mediaSegment_->numberSeq_,
1099             mediaSegment_->contentLength_, isCleaningBuffer_.load(), mediaSegment_->isLast_);
1100     }
1101 
1102     SaveDataHandleBuffering();
1103     if (downloadDoneCbFunc_ && !isCleaningBuffer_.load()) {
1104         downloadDoneCbFunc_(streamId_);
1105     }
1106 }
1107 
UpdateInitSegmentFinish()1108 bool DashSegmentDownloader::UpdateInitSegmentFinish()
1109 {
1110     std::lock_guard<std::mutex> lock(initSegmentMutex_);
1111     std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(streamId_);
1112     if (initSegment != nullptr && initSegment->writeState_ == INIT_SEGMENT_STATE_USING) {
1113         MEDIA_LOG_I("UpdateInitSegmentFinish:streamId:" PUBLIC_LOG_D32 ", writeState:"
1114             PUBLIC_LOG_D32, streamId_, initSegment->writeState_);
1115         initSegment->writeState_ = INIT_SEGMENT_STATE_USED;
1116         initSegment->isDownloadFinish_ = true;
1117         return true;
1118     }
1119 
1120     return false;
1121 }
1122 
GetSegmentRemainDuration(const std::shared_ptr<DashBufferSegment> & currentSegment)1123 uint32_t DashSegmentDownloader::GetSegmentRemainDuration(const std::shared_ptr<DashBufferSegment>& currentSegment)
1124 {
1125     if (buffer_->GetHead() > currentSegment->bufferPosHead_) {
1126         return (((currentSegment->bufferPosTail_ - buffer_->GetHead()) * currentSegment->duration_) /
1127             (currentSegment->bufferPosTail_ - currentSegment->bufferPosHead_));
1128     } else {
1129         return currentSegment->duration_;
1130     }
1131 }
1132 
GetDashInitSegment(int32_t streamId)1133 std::shared_ptr<DashInitSegment> DashSegmentDownloader::GetDashInitSegment(int32_t streamId)
1134 {
1135     std::shared_ptr<DashInitSegment> segment = nullptr;
1136     auto it = std::find_if(initSegments_.begin(), initSegments_.end(),
1137         [&streamId](const std::shared_ptr<DashInitSegment> &initSegment) -> bool {
1138             return initSegment != nullptr && initSegment->streamId_ == streamId;
1139         });
1140     if (it != initSegments_.end()) {
1141         segment = *it;
1142     }
1143     return segment;
1144 }
1145 
SetInterruptState(bool isInterruptNeeded)1146 void DashSegmentDownloader::SetInterruptState(bool isInterruptNeeded)
1147 {
1148     FALSE_RETURN(downloader_ != nullptr && buffer_ != nullptr);
1149     downloader_->SetInterruptState(isInterruptNeeded);
1150     if (isInterruptNeeded) {
1151         buffer_->SetActive(false);
1152     }
1153 }
1154 
SetAppUid(int32_t appUid)1155 void DashSegmentDownloader::SetAppUid(int32_t appUid)
1156 {
1157     if (downloader_) {
1158         downloader_->SetAppUid(appUid);
1159     }
1160 }
1161 
GetBufferringStatus() const1162 bool DashSegmentDownloader::GetBufferringStatus() const
1163 {
1164     return isBuffering_.load();
1165 }
1166 
IsAllSegmentFinished() const1167 bool DashSegmentDownloader::IsAllSegmentFinished() const
1168 {
1169     return isAllSegmentFinished_.load();
1170 }
1171 
SetDurationForPlaying(double duration)1172 void DashSegmentDownloader::SetDurationForPlaying(double duration)
1173 {
1174     if (duration > 0 && streamType_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
1175         bufferDurationForPlaying_ = duration;
1176         MEDIA_LOG_I("Dash buffer duration for playing : " PUBLIC_LOG ".3f", bufferDurationForPlaying_);
1177     }
1178 }
1179 
IsNeedBufferForPlaying()1180 bool DashSegmentDownloader::IsNeedBufferForPlaying()
1181 {
1182     if (bufferDurationForPlaying_ <= 0 || !isDemuxerInitSuccess_.load() || !isBuffering_.load()) {
1183         return false;
1184     }
1185     if (GetBufferingTimeOut() && callback_) {
1186         callback_->OnEvent({PluginEventType::CLIENT_ERROR, {NetworkClientErrorCode::ERROR_TIME_OUT},
1187                             "buffer for playing"});
1188         isBuffering_.store(false);
1189         isDemuxerInitSuccess_.store(false);
1190         bufferingTime_ = 0;
1191         return false;
1192     }
1193     if (GetBufferSize() >= waterlineForPlaying_ || isAllSegmentFinished_.load()) {
1194         MEDIA_LOG_I("Dash buffer duration for playing is enough, buffersize: " PUBLIC_LOG_U32 " waterLineAbove: "
1195                     PUBLIC_LOG_U64, GetBufferSize(), waterlineForPlaying_);
1196         isBuffering_.store(false);
1197         isDemuxerInitSuccess_.store(false);
1198         bufferingTime_ = 0;
1199         return false;
1200     }
1201     return true;
1202 }
1203 
NotifyInitSuccess()1204 void DashSegmentDownloader::NotifyInitSuccess()
1205 {
1206     if (streamType_ != MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
1207         return;
1208     }
1209     MEDIA_LOG_I("Dash NotifyInitSuccess in");
1210     isDemuxerInitSuccess_.store(true);
1211     if (bufferDurationForPlaying_ <= 0 || realTimeBitBate_ <= 0) {
1212         return;
1213     }
1214     waterlineForPlaying_ = static_cast<uint64_t>(static_cast<double>(realTimeBitBate_) /
1215         static_cast<double>(BYTES_TO_BIT) * bufferDurationForPlaying_);
1216     isBuffering_.store(true);
1217     bufferingTime_ = static_cast<size_t>(steadyClock_.ElapsedMilliseconds());
1218 }
1219 
GetBufferingTimeOut()1220 bool DashSegmentDownloader::GetBufferingTimeOut()
1221 {
1222     if (bufferingTime_ == 0) {
1223         return false;
1224     } else {
1225         size_t now = static_cast<size_t>(steadyClock_.ElapsedMilliseconds());
1226         return now >= bufferingTime_ ? now - bufferingTime_ >= MAX_BUFFERING_TIME_OUT : false;
1227     }
1228 }
1229 
CheckLoopTimeout(int64_t startLoopTime)1230 bool DashSegmentDownloader::CheckLoopTimeout(int64_t startLoopTime)
1231 {
1232     int64_t now = loopInterruptClock_.ElapsedSeconds();
1233     int64_t loopDuration = now > startLoopTime ? now - startLoopTime : 0;
1234     bool isLoopTimeOut = loopDuration > LOOP_TIMEOUT ? true : false;
1235     if (isLoopTimeOut) {
1236         MEDIA_LOG_E("loop timeout");
1237     }
1238     return isLoopTimeOut;
1239 }
1240 
StopBufferring(bool isAppBackground)1241 Status DashSegmentDownloader::StopBufferring(bool isAppBackground)
1242 {
1243     MEDIA_LOG_I("DashSegmentDownloader:StopBufferring enter");
1244     FALSE_RETURN_V(buffer_ != nullptr && downloader_ != nullptr, Status::ERROR_NULL_POINTER);
1245     downloader_->SetAppState(isAppBackground);
1246     if (isAppBackground) {
1247         buffer_->SetActive(false, false);
1248     } else {
1249         buffer_->SetActive(true, false);
1250     }
1251     downloader_->StopBufferring();
1252     return Status::OK;
1253 }
1254 }
1255 }
1256 }
1257 }