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