• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2022 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 "HlsMediaDownloader"
16 
17 #include "hls_media_downloader.h"
18 #include "hls_playlist_downloader.h"
19 #include "securec.h"
20 
21 namespace OHOS {
22 namespace Media {
23 namespace Plugin {
24 namespace HttpPlugin {
25 namespace {
26 constexpr int RING_BUFFER_SIZE = 5 * 48 * 1024;
27 }
28 
29 // Description:
30 //   hls manifest, m3u8 --- content get from m3u8 url, we get play list from the content
31 //   fragment --- one item in play list, download media data according to the fragment address.
HlsMediaDownloader()32 HlsMediaDownloader::HlsMediaDownloader() noexcept
33 {
34     buffer_ = std::make_shared<RingBuffer>(RING_BUFFER_SIZE);
35     buffer_->Init();
36 
37     downloader_ = std::make_shared<Downloader>("hlsMedia");
38     downloadTask_ = std::make_shared<OSAL::Task>(std::string("FragmentDownload"));
39     downloadTask_->RegisterHandler([this] { FragmentDownloadLoop(); });
40 
41     playList_ = std::make_shared<BlockingQueue<std::string>>("PlayList", 50); // 50
42 
43     dataSave_ =  [this] (uint8_t*&& data, uint32_t&& len) {
44         return SaveData(std::forward<decltype(data)>(data), std::forward<decltype(len)>(len));
45     };
46 
47     playListDownloader_ = std::make_shared<HlsPlayListDownloader>();
48     playListDownloader_->SetPlayListCallback(this);
49 }
50 
FragmentDownloadLoop()51 void HlsMediaDownloader::FragmentDownloadLoop()
52 {
53     std::string url = playList_->Pop();
54     if (url.empty()) { // when monitor pause, playList_ set active false, it's empty
55         OSAL::SleepFor(10); // 10
56         return;
57     }
58     if (!fragmentDownloadStart[url]) {
59         fragmentDownloadStart[url] = true;
60         auto realStatusCallback = [this] (DownloadStatus&& status, std::shared_ptr<Downloader>& downloader,
61                                           std::shared_ptr<DownloadRequest>& request) {
62             statusCallback_(status, downloader_, std::forward<decltype(request)>(request));
63         };
64         // TO DO: If the fragment file is too large, should not requestWholeFile.
65         downloadRequest_ = std::make_shared<DownloadRequest>(url, dataSave_, realStatusCallback, true);
66         downloader_->Download(downloadRequest_, -1); // -1
67         downloader_->Start();
68     }
69 }
70 
Open(const std::string & url)71 bool HlsMediaDownloader::Open(const std::string& url)
72 {
73     playListDownloader_->Open(url);
74     downloadTask_->Start();
75     return true;
76 }
77 
Close(bool isAsync)78 void HlsMediaDownloader::Close(bool isAsync)
79 {
80     buffer_->SetActive(false);
81     playList_->SetActive(false);
82     downloadTask_->Stop();
83     playListDownloader_->Close();
84     downloader_->Stop();
85 }
86 
Pause()87 void HlsMediaDownloader::Pause()
88 {
89     bool cleanData = GetSeekable() != Seekable::SEEKABLE;
90     buffer_->SetActive(false, cleanData);
91     playList_->SetActive(false, cleanData);
92     playListDownloader_->Pause();
93     downloadTask_->Pause();
94     downloader_->Pause();
95 }
96 
Resume()97 void HlsMediaDownloader::Resume()
98 {
99     buffer_->SetActive(true);
100     playList_->SetActive(true);
101     playListDownloader_->Resume();
102     downloadTask_->Start();
103     downloader_->Resume();
104 }
105 
Read(unsigned char * buff,unsigned int wantReadLength,unsigned int & realReadLength,bool & isEos)106 bool HlsMediaDownloader::Read(unsigned char* buff, unsigned int wantReadLength,
107                               unsigned int& realReadLength, bool& isEos)
108 {
109     FALSE_RETURN_V(buffer_ != nullptr, false);
110     realReadLength = buffer_->ReadBuffer(buff, wantReadLength, 2); // wait 2 times
111     MEDIA_LOG_D("Read: wantReadLength " PUBLIC_LOG_D32 ", realReadLength " PUBLIC_LOG_D32 ", isEos "
112                 PUBLIC_LOG_D32, wantReadLength, realReadLength, isEos);
113     return true;
114 }
115 
Seek(int offset)116 bool HlsMediaDownloader::Seek(int offset)
117 {
118     FALSE_RETURN_V(buffer_ != nullptr, false);
119     MEDIA_LOG_I("Seek: buffer size " PUBLIC_LOG_ZU ", offset " PUBLIC_LOG_D32, buffer_->GetSize(), offset);
120     if (buffer_->Seek(offset)) {
121         return true;
122     }
123     buffer_->Clear(); // First clear buffer, avoid no available buffer then task pause never exit.
124     downloader_->Pause();
125     buffer_->Clear();
126     downloader_->Seek(offset);
127     downloader_->Start();
128     return true;
129 }
130 
GetContentLength() const131 size_t HlsMediaDownloader::GetContentLength() const
132 {
133     return 0;
134 }
135 
GetDuration() const136 double HlsMediaDownloader::GetDuration() const
137 {
138     return playListDownloader_->GetDuration();
139 }
140 
GetSeekable() const141 Seekable HlsMediaDownloader::GetSeekable() const
142 {
143     return playListDownloader_->GetSeekable();
144 }
145 
SetCallback(Callback * cb)146 void HlsMediaDownloader::SetCallback(Callback* cb)
147 {
148     callback_ = cb;
149 }
150 
OnPlayListChanged(const std::vector<std::string> & playList)151 void HlsMediaDownloader::OnPlayListChanged(const std::vector<std::string>& playList)
152 {
153     for (auto& fragment : playList) {
154         playList_->Push(fragment);
155     }
156 }
157 
GetStartedStatus()158 bool HlsMediaDownloader::GetStartedStatus()
159 {
160     return playListDownloader_->GetPlayListDownloadStatus() && startedPlayStatus_;
161 }
162 
SaveData(uint8_t * data,uint32_t len)163 bool HlsMediaDownloader::SaveData(uint8_t* data, uint32_t len)
164 {
165     startedPlayStatus_ = true;
166     return buffer_->WriteBuffer(data, len);
167 }
168 
SetStatusCallback(StatusCallbackFunc cb)169 void HlsMediaDownloader::SetStatusCallback(StatusCallbackFunc cb)
170 {
171     statusCallback_ = cb;
172     playListDownloader_->SetStatusCallback(cb);
173 }
174 }
175 }
176 }
177 }