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