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     std::lock_guard<std::mutex> lock(initSegmentMutex_);
454     for (auto it = initSegments_.begin(); it != initSegments_.end(); ++it) {
455         if ((*it)->streamId_ == currentStreamId) {
456             MEDIA_LOG_I("UpdateInitSegmentState: init streamId:" PUBLIC_LOG_D32 ", contentLen:"
457                 PUBLIC_LOG_ZU ", readIndex:" PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32 ", readState:"
458                 PUBLIC_LOG_D32, currentStreamId, (*it)->content_.length(), (*it)->readIndex_,
459                 (*it)->isDownloadFinish_, (*it)->readState_);
460         }
461         (*it)->readIndex_ = 0;
462         (*it)->readState_ = INIT_SEGMENT_STATE_UNUSE;
463     }
464 }
465 
ReadInitSegment(uint8_t * buff,uint32_t wantReadLength,uint32_t & realReadLength,int32_t currentStreamId)466 bool DashSegmentDownloader::ReadInitSegment(uint8_t *buff, uint32_t wantReadLength, uint32_t &realReadLength,
467                                             int32_t currentStreamId)
468 {
469     std::lock_guard<std::mutex> lock(initSegmentMutex_);
470     std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(currentStreamId);
471     if (initSegment != nullptr && initSegment->readState_ != INIT_SEGMENT_STATE_USED) {
472         unsigned int contentLen = initSegment->content_.length();
473         MEDIA_LOG_I("Read: init streamId:" PUBLIC_LOG_D32 ", contentLen:" PUBLIC_LOG_U32 ", readIndex:"
474             PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32 ", readState:"
475             PUBLIC_LOG_D32, currentStreamId, contentLen, initSegment->readIndex_,
476         initSegment->isDownloadFinish_, initSegment->readState_);
477         if (initSegment->readIndex_ == contentLen && initSegment->isDownloadFinish_) {
478             // init segment read finish
479             initSegment->readState_ = INIT_SEGMENT_STATE_USED;
480             initSegment->readIndex_ = 0;
481             return true;
482         }
483 
484         unsigned int unReadSize = contentLen - initSegment->readIndex_;
485         if (unReadSize > 0) {
486             realReadLength = unReadSize > wantReadLength ? wantReadLength : unReadSize;
487             std::string readStr = initSegment->content_.substr(initSegment->readIndex_);
488             memcpy_s(buff, wantReadLength, readStr.c_str(), realReadLength);
489             initSegment->readIndex_ += realReadLength;
490             if (initSegment->readIndex_ == contentLen && initSegment->isDownloadFinish_) {
491                 // init segment read finish
492                 initSegment->readState_ = INIT_SEGMENT_STATE_USED;
493                 initSegment->readIndex_ = 0;
494             }
495         }
496 
497         MEDIA_LOG_I("after Read: init streamId:" PUBLIC_LOG_D32 ", contentLen:" PUBLIC_LOG_U32 ", readIndex_:"
498             PUBLIC_LOG_D32 ", flag:" PUBLIC_LOG_D32, currentStreamId, contentLen, initSegment->readIndex_,
499             initSegment->isDownloadFinish_);
500         return true;
501     }
502     return false;
503 }
504 
ClearReadSegmentList()505 void DashSegmentDownloader::ClearReadSegmentList()
506 {
507     std::lock_guard<std::mutex> lock(segmentMutex_);
508     for (auto it = segmentList_.begin(); it != segmentList_.end(); ++it) {
509         if (buffer_->GetHead() != 0 && (*it)->isEos_ && buffer_->GetHead() >= (*it)->bufferPosTail_) {
510             MEDIA_LOG_D("Read:streamId:" PUBLIC_LOG_D32 ", erase numberSeq:"
511                 PUBLIC_LOG_D64, (*it)->streamId_, (*it)->numberSeq_);
512             it = segmentList_.erase(it);
513         } else {
514             break;
515         }
516     }
517 }
518 
SetStatusCallback(StatusCallbackFunc statusCallbackFunc)519 void DashSegmentDownloader::SetStatusCallback(StatusCallbackFunc statusCallbackFunc)
520 {
521     statusCallback_ = statusCallbackFunc;
522 }
523 
SetDownloadDoneCallback(SegmentDownloadDoneCbFunc doneCbFunc)524 void DashSegmentDownloader::SetDownloadDoneCallback(SegmentDownloadDoneCbFunc doneCbFunc)
525 {
526     downloadDoneCbFunc_ = doneCbFunc;
527 }
528 
GetRingBufferInitSize(MediaAVCodec::MediaType streamType) const529 size_t DashSegmentDownloader::GetRingBufferInitSize(MediaAVCodec::MediaType streamType) const
530 {
531     size_t ringBufferFixSize = DEFAULT_RING_BUFFER_SIZE;
532     auto ringBufferSizeItem = BUFFER_SIZE_MAP.find(streamType);
533     if (ringBufferSizeItem != BUFFER_SIZE_MAP.end()) {
534         ringBufferFixSize = ringBufferSizeItem->second;
535     }
536 
537     if (streamType == MediaAVCodec::MediaType::MEDIA_TYPE_VID && userDefinedBufferDuration_) {
538         size_t ringBufferSize = expectDuration_ * currentBitrate_;
539         if (ringBufferSize < DEFAULT_RING_BUFFER_SIZE) {
540             MEDIA_LOG_I("Setting buffer size: " PUBLIC_LOG_ZU ", already lower than the min buffer size: "
541                 PUBLIC_LOG_U32 ", setting buffer size: "
542                 PUBLIC_LOG_U32, ringBufferSize, DEFAULT_RING_BUFFER_SIZE, DEFAULT_RING_BUFFER_SIZE);
543             ringBufferSize = DEFAULT_RING_BUFFER_SIZE;
544         } else if (ringBufferSize > ringBufferFixSize) {
545             MEDIA_LOG_I("Setting buffer size: " PUBLIC_LOG_ZU ", already exceed the max buffer size: "
546                 PUBLIC_LOG_ZU ", setting buffer size: "
547                 PUBLIC_LOG_ZU, ringBufferSize, ringBufferFixSize, ringBufferFixSize);
548             ringBufferSize = ringBufferFixSize;
549         }
550         return ringBufferSize;
551     } else {
552         return ringBufferFixSize;
553     }
554 }
555 
SetInitSegment(std::shared_ptr<DashInitSegment> initSegment,bool needUpdateState)556 void DashSegmentDownloader::SetInitSegment(std::shared_ptr<DashInitSegment> initSegment, bool needUpdateState)
557 {
558     if (initSegment == nullptr) {
559         return;
560     }
561 
562     std::lock_guard<std::mutex> lock(initSegmentMutex_);
563     int streamId = initSegment->streamId_;
564     std::shared_ptr<DashInitSegment> dashInitSegment = GetDashInitSegment(streamId);
565     if (dashInitSegment == nullptr) {
566         initSegments_.push_back(initSegment);
567         dashInitSegment = initSegment;
568         needUpdateState = true;
569     }
570 
571     if (!dashInitSegment->isDownloadFinish_) {
572         dashInitSegment->writeState_ = INIT_SEGMENT_STATE_UNUSE;
573     }
574 
575     // seek or first time to set stream init segment should update to UNUSE
576     // read will update state to UNUSE when stream id is changed
577     if (needUpdateState) {
578         dashInitSegment->readState_ = INIT_SEGMENT_STATE_UNUSE;
579     }
580     MEDIA_LOG_I("SetInitSegment:streamId:" PUBLIC_LOG_D32 ", isDownloadFinish_="
581         PUBLIC_LOG_D32 ", readIndex=" PUBLIC_LOG_U32 ", readState_=" PUBLIC_LOG_D32 ", update="
582         PUBLIC_LOG_D32 ", writeState_=" PUBLIC_LOG_D32, streamId, dashInitSegment->isDownloadFinish_,
583         dashInitSegment->readIndex_, dashInitSegment->readState_, needUpdateState, dashInitSegment->writeState_);
584 }
585 
UpdateStreamId(int streamId)586 void DashSegmentDownloader::UpdateStreamId(int streamId)
587 {
588     streamId_ = streamId;
589 }
590 
SetCurrentBitRate(int32_t bitRate)591 void DashSegmentDownloader::SetCurrentBitRate(int32_t bitRate)
592 {
593     if (bitRate <= 0) {
594         realTimeBitBate_ = -1;
595     } else {
596         realTimeBitBate_ = static_cast<int64_t>(bitRate);
597     }
598 }
599 
SetDemuxerState()600 void DashSegmentDownloader::SetDemuxerState()
601 {
602     isFirstFrameArrived_ = true;
603 }
604 
SetAllSegmentFinished()605 void DashSegmentDownloader::SetAllSegmentFinished()
606 {
607     MEDIA_LOG_I("SetAllSegmentFinished streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
608     isAllSegmentFinished_.store(true);
609 }
610 
GetStreamId() const611 int DashSegmentDownloader::GetStreamId() const
612 {
613     return streamId_;
614 }
615 
GetStreamType() const616 MediaAVCodec::MediaType DashSegmentDownloader::GetStreamType() const
617 {
618     return streamType_;
619 }
620 
GetContentLength()621 size_t DashSegmentDownloader::GetContentLength()
622 {
623     if (downloadRequest_ == nullptr || downloadRequest_->IsClosed()) {
624         return 0; // 0
625     }
626     return downloadRequest_->GetFileContentLength();
627 }
628 
GetStartedStatus() const629 bool DashSegmentDownloader::GetStartedStatus() const
630 {
631     return startedPlayStatus_;
632 }
633 
IsSegmentFinish() const634 bool DashSegmentDownloader::IsSegmentFinish() const
635 {
636     if (mediaSegment_ != nullptr && mediaSegment_->isEos_) {
637         return true;
638     }
639 
640     return false;
641 }
642 
CleanAllSegmentBuffer(bool isCleanAll,int64_t & remainLastNumberSeq)643 bool DashSegmentDownloader::CleanAllSegmentBuffer(bool isCleanAll, int64_t& remainLastNumberSeq)
644 {
645     if (isCleanAll) {
646         MEDIA_LOG_I("CleanAllSegmentBuffer clean all");
647         isCleaningBuffer_.store(true);
648         Close(true, true);
649         std::lock_guard<std::mutex> lock(segmentMutex_);
650         isAllSegmentFinished_.store(false);
651         for (const auto &it: segmentList_) {
652             if (it == nullptr || buffer_->GetHead() > it->bufferPosTail_) {
653                 continue;
654             }
655 
656             remainLastNumberSeq = it->numberSeq_;
657             break;
658         }
659 
660         downloader_ = std::make_shared<Downloader>("dashSegment");
661         buffer_->Clear();
662         segmentList_.clear();
663         buffer_->SetActive(true);
664         return true;
665     }
666 
667     return false;
668 }
669 
CleanSegmentBuffer(bool isCleanAll,int64_t & remainLastNumberSeq)670 bool DashSegmentDownloader::CleanSegmentBuffer(bool isCleanAll, int64_t& remainLastNumberSeq)
671 {
672     if (CleanAllSegmentBuffer(isCleanAll, remainLastNumberSeq)) {
673         return true;
674     }
675 
676     size_t clearTail = 0;
677     {
678         std::lock_guard<std::mutex> lock(segmentMutex_);
679         remainLastNumberSeq = -1;
680         uint32_t remainDuration = 0;
681         for (const auto &it: segmentList_) {
682             if (it == nullptr || buffer_->GetHead() > it->bufferPosTail_) {
683                 continue;
684             }
685 
686             remainLastNumberSeq = it->numberSeq_;
687 
688             if (!it->isEos_) {
689                 break;
690             }
691 
692             remainDuration += GetSegmentRemainDuration(it);
693             if (remainDuration >= MIN_RETENTION_DURATION_MS) {
694                 clearTail = it->bufferPosTail_;
695                 break;
696             }
697         }
698 
699         MEDIA_LOG_I("CleanSegmentBuffer:streamId:" PUBLIC_LOG_D32 ", remain numberSeq:"
700             PUBLIC_LOG_D64, streamId_, remainLastNumberSeq);
701     }
702 
703     if (clearTail > 0) {
704         isCleaningBuffer_.store(true);
705         Close(true, false);
706         std::lock_guard<std::mutex> lock(segmentMutex_);
707         isAllSegmentFinished_.store(false);
708         segmentList_.remove_if([&remainLastNumberSeq](std::shared_ptr<DashBufferSegment> bufferSegment) {
709             return (bufferSegment->numberSeq_ > remainLastNumberSeq);
710         });
711 
712         downloader_ = std::make_shared<Downloader>("dashSegment");
713         MEDIA_LOG_I("CleanSegmentBuffer bufferHead:" PUBLIC_LOG_ZU " ,bufferTail:" PUBLIC_LOG_ZU " ,clearTail:"
714             PUBLIC_LOG_ZU, buffer_->GetHead(), buffer_->GetTail(), clearTail);
715         buffer_->SetTail(clearTail);
716         buffer_->SetActive(true);
717         return true;
718     }
719     return false;
720 }
721 
CleanByTimeInternal(int64_t & remainLastNumberSeq,size_t & clearTail,bool & isEnd)722 void DashSegmentDownloader::CleanByTimeInternal(int64_t& remainLastNumberSeq, size_t& clearTail, bool& isEnd)
723 {
724     // residue segment duration
725     uint32_t remainDuration = 0;
726     uint32_t segmentKeepDuration = 1000; // ms
727     uint32_t segmentKeepDelta = 100; // ms
728     for (const auto &it: segmentList_) {
729         if (it == nullptr ||
730             buffer_->GetHead() > it->bufferPosTail_ ||
731             it->bufferPosHead_ >= it->bufferPosTail_) {
732             continue;
733         }
734 
735         remainLastNumberSeq = it->numberSeq_;
736         isEnd = it->isEos_;
737         if (it->contentLength_ == 0 ||
738             it->duration_ == 0) {
739             MEDIA_LOG_I("CleanByTimeInternal: contentLength is:" PUBLIC_LOG_ZU ", duration is:"
740                 PUBLIC_LOG_U32, it->contentLength_, it->duration_);
741             // can not caculate segment content length, just keep one segment
742             clearTail = it->bufferPosTail_;
743             break;
744         }
745 
746         remainDuration = (it->bufferPosTail_ - buffer_->GetHead()) * it->duration_ / it->contentLength_;
747         if (remainDuration < segmentKeepDuration + segmentKeepDelta &&
748             remainDuration + segmentKeepDelta >= segmentKeepDuration) {
749             // find clear buffer position with segment tail position
750             clearTail = it->bufferPosTail_;
751         } else if (remainDuration < segmentKeepDuration) {
752             // get next segment buffer
753             clearTail = it->bufferPosTail_;
754             segmentKeepDuration -= remainDuration;
755             continue;
756         } else {
757             // find clear buffer position
758             uint32_t segmentSize = (segmentKeepDuration * it->contentLength_) / it->duration_;
759             if (clearTail > 0) {
760                 // find clear buffer position in multi segments
761                 clearTail += segmentSize;
762             } else {
763                 // find clear buffer position in one segment
764                 clearTail = buffer_->GetHead() + segmentSize;
765             }
766             it->bufferPosTail_ = clearTail;
767             it->isEos_ = true;
768             isEnd = false;
769         }
770 
771         break;
772     }
773 }
774 
CleanBufferByTime(int64_t & remainLastNumberSeq,bool & isEnd)775 bool DashSegmentDownloader::CleanBufferByTime(int64_t& remainLastNumberSeq, bool& isEnd)
776 {
777     Close(true, false);
778     std::lock_guard<std::mutex> lock(segmentMutex_);
779     remainLastNumberSeq = -1;
780     size_t clearTail = 0;
781     CleanByTimeInternal(remainLastNumberSeq, clearTail, isEnd);
782 
783     if (remainLastNumberSeq == -1 && mediaSegment_ != nullptr) {
784         isEnd = false;
785     }
786 
787     MEDIA_LOG_I("CleanBufferByTime:streamId:" PUBLIC_LOG_D32 ", remain numberSeq:"
788         PUBLIC_LOG_D64 ", isEnd:" PUBLIC_LOG_D32 ", size:" PUBLIC_LOG_ZU, streamId_,
789         remainLastNumberSeq, isEnd, segmentList_.size());
790 
791     if (clearTail > 0) {
792         isCleaningBuffer_.store(true);
793         segmentList_.remove_if([&remainLastNumberSeq](std::shared_ptr<DashBufferSegment> bufferSegment) {
794             return (bufferSegment->numberSeq_ > remainLastNumberSeq);
795         });
796 
797         downloader_ = std::make_shared<Downloader>("dashSegment");
798         MEDIA_LOG_I("CleanBufferByTime bufferHead:" PUBLIC_LOG_ZU " ,bufferTail:" PUBLIC_LOG_ZU " ,clearTail:"
799             PUBLIC_LOG_ZU " ,seq:" PUBLIC_LOG_D64 ",size:" PUBLIC_LOG_ZU, buffer_->GetHead(), buffer_->GetTail(),
800             clearTail, remainLastNumberSeq, segmentList_.size());
801         buffer_->SetTail(clearTail);
802         buffer_->SetActive(true);
803         return true;
804     }
805     return false;
806 }
807 
SeekToTime(const std::shared_ptr<DashSegment> & segment,int32_t & streamId)808 bool DashSegmentDownloader::SeekToTime(const std::shared_ptr<DashSegment> &segment, int32_t& streamId)
809 {
810     std::lock_guard<std::mutex> lock(segmentMutex_);
811     std::shared_ptr<DashBufferSegment> desSegment;
812     auto it = std::find_if(segmentList_.begin(), segmentList_.end(),
813         [&segment](const std::shared_ptr<DashBufferSegment> &item) -> bool {
814             return (item->numberSeq_ - item->startNumberSeq_) == (segment->numberSeq_ - segment->startNumberSeq_);
815         });
816     if (it != segmentList_.end()) {
817         desSegment = *it;
818     }
819 
820     if (desSegment != nullptr && desSegment->bufferPosTail_ > 0) {
821         if (buffer_->SetHead(desSegment->bufferPosHead_)) {
822             // set init segment when seek on buffered, before read first segment demuxer plugin need reboot
823             UpdateInitSegmentState(desSegment->streamId_);
824             streamId = desSegment->streamId_;
825             return true;
826         }
827     }
828     return false;
829 }
830 
SaveData(uint8_t * data,uint32_t len)831 bool DashSegmentDownloader::SaveData(uint8_t* data, uint32_t len)
832 {
833     MEDIA_LOG_D("SaveData:streamId:" PUBLIC_LOG_D32 ", len:" PUBLIC_LOG_D32, streamId_, len);
834     startedPlayStatus_ = true;
835     if (streamType_ == MediaAVCodec::MediaType::MEDIA_TYPE_VID) {
836         OnWriteRingBuffer(len);
837     }
838     {
839         std::lock_guard<std::mutex> lock(initSegmentMutex_);
840         std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(streamId_);
841         if (initSegment != nullptr && initSegment->writeState_ == INIT_SEGMENT_STATE_USING) {
842             MEDIA_LOG_I("SaveData:streamId:" PUBLIC_LOG_D32 ", writeState:"
843                 PUBLIC_LOG_D32, streamId_, initSegment->writeState_);
844             initSegment->content_.append(reinterpret_cast<const char*>(data), len);
845             return true;
846         }
847     }
848 
849     size_t bufferTail = buffer_->GetTail();
850     bool writeRet = buffer_->WriteBuffer(data, len);
851     HandleCachedDuration();
852     SaveDataHandleBuffering();
853     if (!writeRet) {
854         MEDIA_LOG_E("SaveData:error streamId:" PUBLIC_LOG_D32 ", len:" PUBLIC_LOG_D32, streamId_, len);
855         return writeRet;
856     }
857 
858     std::lock_guard<std::mutex> lock(segmentMutex_);
859     for (const auto &mediaSegment: segmentList_) {
860         if (mediaSegment == nullptr || mediaSegment->isEos_) {
861             continue;
862         }
863 
864         if (mediaSegment->bufferPosTail_ == 0) {
865             mediaSegment->bufferPosHead_ = bufferTail;
866         }
867         mediaSegment->bufferPosTail_ = buffer_->GetTail();
868         UpdateBufferSegment(mediaSegment, len);
869         break;
870     }
871     return writeRet;
872 }
873 
UpdateBufferSegment(const std::shared_ptr<DashBufferSegment> & mediaSegment,uint32_t len)874 void DashSegmentDownloader::UpdateBufferSegment(const std::shared_ptr<DashBufferSegment> &mediaSegment, uint32_t len)
875 {
876     if (mediaSegment->contentLength_ == 0 && downloadRequest_ != nullptr) {
877         mediaSegment->contentLength_ = downloadRequest_->GetFileContentLength();
878     }
879 
880     // last packet len is 0 of chunk
881     if (len == 0 || (mediaSegment->contentLength_ > 0 &&
882                      mediaSegment->bufferPosTail_ >= (mediaSegment->bufferPosHead_ + mediaSegment->contentLength_))) {
883         mediaSegment->isEos_ = true;
884         if (mediaSegment->isLast_) {
885             MEDIA_LOG_I("AllSegmentFinish streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
886             isAllSegmentFinished_.store(true);
887         }
888         if (mediaSegment->contentLength_ == 0) {
889             mediaSegment->contentLength_ = mediaSegment->bufferPosTail_ - mediaSegment->bufferPosHead_;
890         }
891         MEDIA_LOG_I("SaveData eos:streamId:" PUBLIC_LOG_D32 ", segmentNum:" PUBLIC_LOG_D64 ", contentLength:"
892             PUBLIC_LOG_ZU ", bufferPosHead:" PUBLIC_LOG_ZU  " ,bufferPosEnd:" PUBLIC_LOG_ZU,
893             mediaSegment->streamId_, mediaSegment->numberSeq_, mediaSegment->contentLength_,
894             mediaSegment->bufferPosHead_, mediaSegment->bufferPosTail_);
895     }
896 }
897 
OnWriteRingBuffer(uint32_t len)898 void DashSegmentDownloader::OnWriteRingBuffer(uint32_t len)
899 {
900     uint32_t writeBits = len * BYTE_TO_BIT;
901     totalBits_ += writeBits;
902     uint64_t now = static_cast<uint64_t>(steadyClock_.ElapsedMilliseconds());
903     if (now > lastCheckTime_ && now - lastCheckTime_ > RECORD_TIME_INTERVAL) {
904         uint64_t curDownloadBits = totalBits_ - lastBits_;
905         if (curDownloadBits >= RECORD_DOWNLOAD_MIN_BIT) {
906             downloadDuringTime_ = now - lastCheckTime_;
907             downloadBits_ += curDownloadBits;
908             totalDownloadDuringTime_ += downloadDuringTime_;
909             double downloadRate = 0;
910             double tmpNumerator = static_cast<double>(curDownloadBits);
911             double tmpDenominator = static_cast<double>(downloadDuringTime_) / SECOND_TO_MILLIONSECOND;
912             if (tmpDenominator > ZERO_THRESHOLD) {
913                 downloadRate = tmpNumerator / tmpDenominator;
914             }
915             size_t remainingBuffer = 0;
916             if (buffer_ != nullptr) {
917                 remainingBuffer = buffer_->GetSize();
918             }
919             MEDIA_LOG_D("Current download speed : " PUBLIC_LOG_D32 " Kbit/s,Current buffer size : " PUBLIC_LOG_U64
920                 " KByte", static_cast<int32_t>(downloadRate / 1024), static_cast<uint64_t>(remainingBuffer / 1024));
921             // Remaining playable time: s
922             uint64_t bufferDuration = 0;
923             if (realTimeBitBate_ > 0) {
924                 bufferDuration =
925                     remainingBuffer * static_cast<uint64_t>(BYTES_TO_BIT) / static_cast<uint64_t>(realTimeBitBate_);
926             } else {
927                 bufferDuration = static_cast<uint64_t>(remainingBuffer * BYTES_TO_BIT) / currentBitrate_;
928             }
929             if (recordData_ != nullptr) {
930                 recordData_->downloadRate = downloadRate;
931                 recordData_->bufferDuring = bufferDuration;
932             }
933         }
934         lastBits_ = totalBits_;
935         lastCheckTime_ = now;
936     }
937 }
938 
GetDownloadSpeed() const939 uint64_t DashSegmentDownloader::GetDownloadSpeed() const
940 {
941     return static_cast<uint64_t>(downloadSpeed_);
942 }
943 
GetIp(std::string & ip)944 void DashSegmentDownloader::GetIp(std::string& ip)
945 {
946     if (downloader_) {
947         downloader_->GetIp(ip);
948     }
949 }
950 
GetDownloadFinishState()951 bool DashSegmentDownloader::GetDownloadFinishState()
952 {
953     std::shared_ptr<DashInitSegment> finishState = GetDashInitSegment(streamId_);
954     if (finishState) {
955         return finishState->isDownloadFinish_;
956     } else {
957         return true;
958     }
959 }
960 
GetDownloadRecordData()961 std::pair<int64_t, int64_t> DashSegmentDownloader::GetDownloadRecordData()
962 {
963     std::pair<int64_t, int64_t> recordData;
964     if (recordData_ != nullptr) {
965         recordData.first = static_cast<int64_t>(recordData_->downloadRate);
966         recordData.second = static_cast<int64_t>(recordData_->bufferDuring);
967     } else {
968         recordData.first = 0;
969         recordData.second = 0;
970     }
971     return recordData;
972 }
973 
GetBufferSize() const974 uint32_t DashSegmentDownloader::GetBufferSize() const
975 {
976     if (buffer_ != nullptr) {
977         return buffer_->GetSize();
978     }
979     return 0;
980 }
981 
GetRingBufferCapacity() const982 uint32_t DashSegmentDownloader::GetRingBufferCapacity() const
983 {
984     return ringBufferCapcity_;
985 }
986 
PutRequestIntoDownloader(unsigned int duration,int64_t startPos,int64_t endPos,const std::string & url)987 void DashSegmentDownloader::PutRequestIntoDownloader(unsigned int duration, int64_t startPos, int64_t endPos,
988                                                      const std::string &url)
989 {
990     auto realStatusCallback = [this](DownloadStatus &&status, std::shared_ptr<Downloader> &downloader,
991         std::shared_ptr<DownloadRequest> &request) {
992             statusCallback_(status, downloader_, std::forward<decltype(request)>(request));
993     };
994     auto downloadDoneCallback = [this](const std::string &url, const std::string &location) {
995         UpdateDownloadFinished(url, location);
996     };
997 
998     bool requestWholeFile = true;
999     if (startPos >= 0 && endPos > 0) {
1000         requestWholeFile = false;
1001     }
1002     RequestInfo requestInfo;
1003     requestInfo.url = url;
1004     requestInfo.timeoutMs = HTTP_TIME_OUT_MS;
1005     downloadRequest_ = std::make_shared<DownloadRequest>(duration, dataSave_,
1006                                                          realStatusCallback, requestInfo, requestWholeFile);
1007     downloadRequest_->SetDownloadDoneCb(downloadDoneCallback);
1008     if (!requestWholeFile && (endPos > startPos)) {
1009         downloadRequest_->SetRangePos(startPos, endPos);
1010     }
1011     MEDIA_LOG_I("PutRequestIntoDownloader:range=" PUBLIC_LOG_D64 "-" PUBLIC_LOG_D64, startPos, endPos);
1012 
1013     isCleaningBuffer_.store(false);
1014     if (downloader_ != nullptr) {
1015         downloader_->Download(downloadRequest_, -1); // -1
1016         downloader_->Start();
1017     }
1018 }
1019 
UpdateDownloadFinished(const std::string & url,const std::string & location)1020 void DashSegmentDownloader::UpdateDownloadFinished(const std::string& url, const std::string& location)
1021 {
1022     MEDIA_LOG_I("UpdateDownloadFinished:streamId:" PUBLIC_LOG_D32, streamId_);
1023     if (totalDownloadDuringTime_ > 0) {
1024         double tmpNumerator = static_cast<double>(downloadBits_);
1025         double tmpDenominator = static_cast<double>(totalDownloadDuringTime_);
1026         double downloadRate = tmpNumerator / tmpDenominator;
1027         downloadSpeed_ = downloadRate * SPEED_MULTI_FACT;
1028     } else {
1029         downloadSpeed_ = 0;
1030     }
1031 
1032     if (UpdateInitSegmentFinish()) {
1033         if (mediaSegment_ != nullptr) {
1034             PutRequestIntoDownloader(mediaSegment_->duration_, mediaSegment_->startRangeValue_,
1035                 mediaSegment_->endRangeValue_, mediaSegment_->url_);
1036             return;
1037         }
1038     }
1039 
1040     if (mediaSegment_ != nullptr) {
1041         if (mediaSegment_->contentLength_ == 0 && downloadRequest_ != nullptr) {
1042             mediaSegment_->contentLength_ = downloadRequest_->GetFileContentLength();
1043         }
1044         if (downloadRequest_ != nullptr) {
1045             size_t fragmentSize = mediaSegment_->contentLength_;
1046             double duration = downloadRequest_->GetDuration();
1047             CalculateBitRate(fragmentSize, duration);
1048             downloadBiteRate_ = downloadRequest_->GetBitRate();
1049         }
1050         mediaSegment_->isEos_ = true;
1051         if (mediaSegment_->isLast_) {
1052             MEDIA_LOG_I("AllSegmentFinish streamId: " PUBLIC_LOG_D32 " download complete", streamId_);
1053             isAllSegmentFinished_.store(true);
1054         }
1055         MEDIA_LOG_I("UpdateDownloadFinished: segmentNum:" PUBLIC_LOG_D64 ", contentLength:" PUBLIC_LOG_ZU
1056             ", isCleaningBuffer:" PUBLIC_LOG_D32 " isLast: " PUBLIC_LOG_D32, mediaSegment_->numberSeq_,
1057             mediaSegment_->contentLength_, isCleaningBuffer_.load(), mediaSegment_->isLast_);
1058     }
1059 
1060     SaveDataHandleBuffering();
1061     if (downloadDoneCbFunc_ && !isCleaningBuffer_.load()) {
1062         downloadDoneCbFunc_(streamId_);
1063     }
1064 }
1065 
UpdateInitSegmentFinish()1066 bool DashSegmentDownloader::UpdateInitSegmentFinish()
1067 {
1068     std::lock_guard<std::mutex> lock(initSegmentMutex_);
1069     std::shared_ptr<DashInitSegment> initSegment = GetDashInitSegment(streamId_);
1070     if (initSegment != nullptr && initSegment->writeState_ == INIT_SEGMENT_STATE_USING) {
1071         MEDIA_LOG_I("UpdateInitSegmentFinish:streamId:" PUBLIC_LOG_D32 ", writeState:"
1072             PUBLIC_LOG_D32, streamId_, initSegment->writeState_);
1073         initSegment->writeState_ = INIT_SEGMENT_STATE_USED;
1074         initSegment->isDownloadFinish_ = true;
1075         return true;
1076     }
1077 
1078     return false;
1079 }
1080 
GetSegmentRemainDuration(const std::shared_ptr<DashBufferSegment> & currentSegment)1081 uint32_t DashSegmentDownloader::GetSegmentRemainDuration(const std::shared_ptr<DashBufferSegment>& currentSegment)
1082 {
1083     if (buffer_->GetHead() > currentSegment->bufferPosHead_) {
1084         return (((currentSegment->bufferPosTail_ - buffer_->GetHead()) * currentSegment->duration_) /
1085             (currentSegment->bufferPosTail_ - currentSegment->bufferPosHead_));
1086     } else {
1087         return currentSegment->duration_;
1088     }
1089 }
1090 
GetDashInitSegment(int32_t streamId)1091 std::shared_ptr<DashInitSegment> DashSegmentDownloader::GetDashInitSegment(int32_t streamId)
1092 {
1093     std::shared_ptr<DashInitSegment> segment = nullptr;
1094     auto it = std::find_if(initSegments_.begin(), initSegments_.end(),
1095         [&streamId](const std::shared_ptr<DashInitSegment> &initSegment) -> bool {
1096             return initSegment != nullptr && initSegment->streamId_ == streamId;
1097         });
1098     if (it != initSegments_.end()) {
1099         segment = *it;
1100     }
1101     return segment;
1102 }
1103 
SetInterruptState(bool isInterruptNeeded)1104 void DashSegmentDownloader::SetInterruptState(bool isInterruptNeeded)
1105 {
1106     if (downloader_ != nullptr) {
1107         downloader_->SetInterruptState(isInterruptNeeded);
1108     }
1109 }
1110 
SetAppUid(int32_t appUid)1111 void DashSegmentDownloader::SetAppUid(int32_t appUid)
1112 {
1113     if (downloader_) {
1114         downloader_->SetAppUid(appUid);
1115     }
1116 }
1117 
GetBufferringStatus() const1118 bool DashSegmentDownloader::GetBufferringStatus() const
1119 {
1120     return isBuffering_.load();
1121 }
1122 
IsAllSegmentFinished() const1123 bool DashSegmentDownloader::IsAllSegmentFinished() const
1124 {
1125     return isAllSegmentFinished_.load();
1126 }
1127 }
1128 }
1129 }
1130 }