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 "HttpMediaDownloader"
16
17 #include "http_media_downloader.h"
18
19 namespace OHOS {
20 namespace Media {
21 namespace Plugin {
22 namespace HttpPlugin {
23 namespace {
24 #ifdef OHOS_LITE
25 constexpr int RING_BUFFER_SIZE = 5 * 48 * 1024;
26 constexpr int WATER_LINE = RING_BUFFER_SIZE / 30; //30 WATER_LINE:8192
27 #else
28 constexpr int RING_BUFFER_SIZE = 5 * 1024 * 1024;
29 constexpr int WATER_LINE = 8192; // WATER_LINE:8192
30 #endif
31 }
32
HttpMediaDownloader()33 HttpMediaDownloader::HttpMediaDownloader() noexcept
34 {
35 buffer_ = std::make_shared<RingBuffer>(RING_BUFFER_SIZE);
36 buffer_->Init();
37
38 downloader_ = std::make_shared<Downloader>("http");
39 }
40
Open(const std::string & url)41 bool HttpMediaDownloader::Open(const std::string& url)
42 {
43 MEDIA_LOG_I("Open download " PUBLIC_LOG_S, url.c_str());
44 auto saveData = [this] (uint8_t*&& data, uint32_t&& len, int64_t&& offset) {
45 return SaveData(std::forward<decltype(data)>(data), std::forward<decltype(len)>(len),
46 std::forward<decltype(offset)>(offset));
47 };
48 FALSE_RETURN_V(statusCallback_ != nullptr, false);
49 auto realStatusCallback = [this] (DownloadStatus&& status, std::shared_ptr<Downloader>& downloader,
50 std::shared_ptr<DownloadRequest>& request) {
51 statusCallback_(status, downloader_, std::forward<decltype(request)>(request));
52 };
53 downloadRequest_ = std::make_shared<DownloadRequest>(url, saveData, realStatusCallback);
54 downloader_->Download(downloadRequest_, -1); // -1
55 downloader_->Start();
56 return true;
57 }
58
Close()59 void HttpMediaDownloader::Close()
60 {
61 buffer_->SetActive(false);
62 downloader_->Stop();
63 }
64
Pause()65 void HttpMediaDownloader::Pause()
66 {
67 bool cleanData = GetSeekable() != Seekable::SEEKABLE;
68 buffer_->SetActive(false, cleanData);
69 downloader_->Pause();
70 }
71
Resume()72 void HttpMediaDownloader::Resume()
73 {
74 buffer_->SetActive(true);
75 downloader_->Resume();
76 }
77
Read(unsigned char * buff,unsigned int wantReadLength,unsigned int & realReadLength,bool & isEos)78 bool HttpMediaDownloader::Read(unsigned char* buff, unsigned int wantReadLength,
79 unsigned int& realReadLength, bool& isEos)
80 {
81 FALSE_RETURN_V(buffer_ != nullptr, false);
82 isEos = false;
83 while (buffer_->GetSize() == 0) {
84 if (downloadRequest_->IsEos()) {
85 MEDIA_LOG_D("HttpMediaDownloader read return because of EOS");
86 isEos = true;
87 realReadLength = 0;
88 return false;
89 }
90 OSAL::SleepFor(5); // 5
91 }
92 realReadLength = buffer_->ReadBuffer(buff, wantReadLength, 2); // wait 2 times
93 MEDIA_LOG_D("Read: wantReadLength " PUBLIC_LOG_D32 ", realReadLength " PUBLIC_LOG_D32 ", isEos "
94 PUBLIC_LOG_D32, wantReadLength, realReadLength, isEos);
95 return true;
96 }
97
Seek(int offset)98 bool HttpMediaDownloader::Seek(int offset)
99 {
100 FALSE_RETURN_V(buffer_ != nullptr, false);
101 MEDIA_LOG_I("Seek: buffer size " PUBLIC_LOG_ZU ", offset " PUBLIC_LOG_D32, buffer_->GetSize(), offset);
102 if (buffer_->Seek(offset)) {
103 return true;
104 }
105 buffer_->Clear(); // First clear buffer, avoid no available buffer then task pause never exit.
106 downloader_->Pause();
107 buffer_->Clear();
108 downloader_->Seek(offset);
109 downloader_->Resume();
110 return true;
111 }
112
GetContentLength() const113 size_t HttpMediaDownloader::GetContentLength() const
114 {
115 return downloadRequest_->GetFileContentLength();
116 }
117
GetDuration() const118 double HttpMediaDownloader::GetDuration() const
119 {
120 return 0;
121 }
122
GetSeekable() const123 Seekable HttpMediaDownloader::GetSeekable() const
124 {
125 return downloadRequest_->IsChunked() ? Seekable::UNSEEKABLE : Seekable::SEEKABLE;
126 }
127
SetCallback(Callback * cb)128 void HttpMediaDownloader::SetCallback(Callback* cb)
129 {
130 callback_ = cb;
131 }
132
SetStatusCallback(StatusCallbackFunc cb)133 void HttpMediaDownloader::SetStatusCallback(StatusCallbackFunc cb)
134 {
135 statusCallback_ = cb;
136 }
137
GetStartedStatus()138 bool HttpMediaDownloader::GetStartedStatus()
139 {
140 return startedPlayStatus_;
141 }
142
SaveData(uint8_t * data,uint32_t len,int64_t offset)143 bool HttpMediaDownloader::SaveData(uint8_t* data, uint32_t len, int64_t offset)
144 {
145 FALSE_RETURN_V(buffer_->WriteBuffer(data, len, offset), false);
146 size_t bufferSize = buffer_->GetSize();
147 double ratio = (static_cast<double>(bufferSize)) / RING_BUFFER_SIZE;
148 if ((bufferSize >= WATER_LINE ||
149 bufferSize >= downloadRequest_->GetFileContentLength() / 2) && !aboveWaterline_) { // 2
150 aboveWaterline_ = true;
151 MEDIA_LOG_I("Send http aboveWaterline event, ringbuffer ratio " PUBLIC_LOG_F, ratio);
152 callback_->OnEvent({PluginEventType::ABOVE_LOW_WATERLINE, {ratio}, "http"});
153 startedPlayStatus_ = true;
154 } else if (bufferSize < WATER_LINE && aboveWaterline_) {
155 aboveWaterline_ = false;
156 MEDIA_LOG_I("Send http belowWaterline event, ringbuffer ratio " PUBLIC_LOG_F, ratio);
157 callback_->OnEvent({PluginEventType::BELOW_LOW_WATERLINE, {ratio}, "http"});
158 }
159 return true;
160 }
161 }
162 }
163 }
164 }