1 /*
2 * Copyright (c) 2025 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
16 #define HST_LOG_TAG "AppClient"
17
18 #include <fstream>
19 #include <algorithm>
20 #include <fcntl.h>
21 #include <map>
22 #include "app_client.h"
23 #include "avcodec_trace.h"
24 #include "osal/task/task.h"
25
26
27 namespace OHOS {
28 namespace Media {
29 namespace Plugins {
30 namespace HttpPlugin {
31 namespace {
32 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_SYSTEM_PLAYER, "HiStreamer" };
33 constexpr size_t MAX_MAP_SIZE = 100;
34 constexpr int DROP_APP_DATA = -2;
35 constexpr int64_t DEFAULT_CURRENT_OFFSET = -2;
36 constexpr int BUFFER_FULL = -3;
37 constexpr int RETRY_SLEEP_TIME = 500; // ms
38 constexpr int FINISHLOADING_SLEEP_TIME = 10; // ms
39 }
40
AppClient(RxHeader headCallback,RxBody bodyCallback,void * userParam)41 AppClient::AppClient(RxHeader headCallback, RxBody bodyCallback, void *userParam)
42 : rxHeader_(headCallback), rxBody_(bodyCallback), userParam_(userParam)
43 {
44 rxHeader_ = headCallback;
45 rxBody_ = bodyCallback;
46 userParam_ = userParam;
47 MEDIA_LOG_I("0x%{public}06" PRIXPTR " AppClient create", FAKE_POINTER(this));
48 }
49
~AppClient()50 AppClient::~AppClient()
51 {
52 }
53
MapToString(std::map<std::string,std::string> httpHeader)54 void AppClient::MapToString(std::map<std::string, std::string> httpHeader)
55 {
56 std::string headerStr = "";
57 if (httpHeader.size() > MAX_MAP_SIZE) { // The length of map exceeds the limit
58 rxHeader_(nullptr, 0, 0, userParam_);
59 return;
60 }
61 std::map<std::string, std::string> httpHeaderTmp = httpHeader;
62 for (std::map<std::string, std::string>::iterator iter = httpHeaderTmp.begin();
63 iter != httpHeaderTmp.end(); iter++) {
64 headerStr = iter->first + " : " + iter->second;
65 char* headerTmp = (char*)headerStr.c_str();
66 MEDIA_LOG_D("0x%{public}06" PRIXPTR " AppClient header: " PUBLIC_LOG_S,
67 FAKE_POINTER(this), (char*)headerStr.c_str());
68 void* buffer = reinterpret_cast<void*>(headerTmp);
69 rxHeader_(buffer, 1, 1, userParam_);
70 }
71 }
72
Init()73 Status AppClient::Init()
74 {
75 return Status::OK;
76 }
77
Open(const std::string & url,const std::map<std::string,std::string> & httpHeader,int32_t timeoutMs)78 Status AppClient::Open(const std::string& url, const std::map<std::string, std::string>& httpHeader,
79 int32_t timeoutMs)
80 {
81 (void)url;
82 (void)httpHeader;
83 (void)timeoutMs;
84 return Status::OK;
85 }
86
RequestData(long startPos,int len,const RequestInfo & requestInfo,HandleResponseCbFunc completedCb)87 Status AppClient::RequestData(long startPos, int len, const RequestInfo& requestInfo,
88 HandleResponseCbFunc completedCb)
89 {
90 MediaAVCodec::AVCodecTrace trace("AppClient RequestData, startPos: " +
91 std::to_string(startPos) + ", len: " + std::to_string(len));
92 (void)requestInfo;
93 MEDIA_LOG_I("0x%{public}06" PRIXPTR "AppClient RequestData in, startPos: "
94 PUBLIC_LOG_D32 " len: " PUBLIC_LOG_D32, FAKE_POINTER(this), static_cast<int>(startPos), len);
95
96 startPos_ = startPos;
97 if (startPos == -1) {
98 len = -1;
99 startPos = 0;
100 }
101 len_ = len;
102 startPos_ = startPos;
103 curOffset_ = static_cast<int64_t>(startPos);
104 dataInFlight_ = len;
105
106 int32_t clientCode = 0;
107 int32_t serverCode = 0;
108 LoadingRequestError requestState;
109 {
110 AutoLock lock(mutex_);
111 isResponseCompleted_.store(false);
112 int32_t res = sourceLoader_->Read(uuid_, static_cast<int64_t>(startPos), static_cast<int64_t>(len));
113 FALSE_LOG_MSG(res == 0, "sourceLoader read fail.");
114
115 responseCondition_.Wait(lock, [this] {
116 return isResponseCompleted_.load();
117 });
118 requestState = requestState_;
119 }
120 clientCode = static_cast<int32_t>(requestState) * (-1);
121
122 Status ret = Status::OK;
123 if (requestState_ == LoadingRequestError::LOADING_ERROR_SUCCESS) {
124 MEDIA_LOG_I("0x%{public}06" PRIXPTR "AppClient RequestData success", FAKE_POINTER(this));
125 completedCb(clientCode, serverCode, ret);
126 } else {
127 MEDIA_LOG_I("0x%{public}06" PRIXPTR "AppClient RequestData fail, clientCode: " PUBLIC_LOG_D32
128 " requestState_: " PUBLIC_LOG_D32, FAKE_POINTER(this), clientCode, requestState_);
129
130 Task::SleepInTask(RETRY_SLEEP_TIME);
131 ret = Status::ERROR_CLIENT;
132 completedCb(clientCode, serverCode, ret);
133 }
134 requestState_ = LoadingRequestError::LOADING_ERROR_SUCCESS;
135 return Status::OK;
136 }
137
Close(bool isAsync)138 Status AppClient::Close(bool isAsync)
139 {
140 (void)isAsync;
141 NotifyResponseDataEnd(LoadingRequestError::LOADING_ERROR_SUCCESS);
142 MEDIA_LOG_I("0x%{public}06" PRIXPTR "AppClient Close.", FAKE_POINTER(this));
143 return Status::OK;
144 }
145
Deinit()146 Status AppClient::Deinit()
147 {
148 return Status::OK;
149 }
150
GetIp(std::string & ip)151 Status AppClient::GetIp(std::string &ip)
152 {
153 (void)ip;
154 return Status::OK;
155 }
156
SetAppUid(int32_t appUid)157 void AppClient::SetAppUid(int32_t appUid)
158 {
159 }
160
GetAppInstance(RxHeader headCallback,RxBody bodyCallback,void * userParam)161 std::shared_ptr<NetworkClient> NetworkClient::GetAppInstance(RxHeader headCallback,
162 RxBody bodyCallback, void *userParam)
163 {
164 return std::make_shared<AppClient>(headCallback, bodyCallback, userParam);
165 }
166
SetLoader(std::shared_ptr<IMediaSourceLoader> sourceLoader)167 void AppClient::SetLoader(std::shared_ptr<IMediaSourceLoader> sourceLoader)
168 {
169 sourceLoader_ = sourceLoader;
170 }
171
RespondHeader(int64_t uuid,const std::map<std::string,std::string> & httpHeader,std::string redirectUrl)172 int32_t AppClient::RespondHeader(int64_t uuid, const std::map<std::string, std::string>& httpHeader,
173 std::string redirectUrl)
174 {
175 MediaAVCodec::AVCodecTrace trace("AppClient RespondHeader, uuid: " + std::to_string(uuid));
176 FALSE_LOG_MSG(uuid > 0, "sourceLoader read fail.");
177 std::map<std::string, std::string> httpHeaderTmp = httpHeader;
178 if (!redirectUrl.empty()) {
179 httpHeaderTmp.emplace("location", redirectUrl);
180 }
181 MapToString(httpHeaderTmp);
182 return 0;
183 }
184
NotifyResponseDataEnd(LoadingRequestError state)185 void AppClient::NotifyResponseDataEnd(LoadingRequestError state)
186 {
187 {
188 AutoLock lock(mutex_);
189 requestState_ = state;
190 isResponseCompleted_.store(true);
191 responseCondition_.NotifyOne();
192 if (state == LoadingRequestError::LOADING_ERROR_SUCCESS) {
193 curOffset_ = DEFAULT_CURRENT_OFFSET;
194 }
195 }
196 MEDIA_LOG_D("0x%{public}06" PRIXPTR "AppClient NotifyResponseDataEnd state: " PUBLIC_LOG_D32,
197 FAKE_POINTER(this), static_cast<int32_t>(state));
198 }
199
RespondData(int64_t uuid,int64_t offset,const std::shared_ptr<AVSharedMemory> memory)200 int32_t AppClient::RespondData(int64_t uuid, int64_t offset, const std::shared_ptr<AVSharedMemory> memory)
201 {
202 FALSE_RETURN_V(memory != nullptr, 0);
203 if (uuid != uuid_) {
204 MEDIA_LOG_E("0x%{public}06" PRIXPTR " AppClient respondData uuid invalid, uuid: " PUBLIC_LOG_D64,
205 FAKE_POINTER(this), uuid);
206 NotifyResponseDataEnd(LoadingRequestError::LOADING_ERROR_NOT_READY);
207 return DROP_APP_DATA;
208 }
209
210 if (curOffset_ != offset) {
211 MEDIA_LOG_E("0x%{public}06" PRIXPTR " AppClient respondData offset invalid, offset: " PUBLIC_LOG_D64
212 " curOffset_: " PUBLIC_LOG_D32, FAKE_POINTER(this), offset, static_cast<int32_t>(curOffset_));
213 NotifyResponseDataEnd(LoadingRequestError::LOADING_ERROR_NOT_READY);
214 return DROP_APP_DATA;
215 }
216
217 void* buffer = reinterpret_cast<void*>(memory->GetBase());
218 size_t res = rxBody_(buffer, memory->GetSize(), 1, userParam_);
219 curOffset_ += static_cast<int64_t>(res);
220 if (res == 0) {
221 MEDIA_LOG_W("0x%{public}06" PRIXPTR " AppClient respondData buffer full, can not write, uuid: " PUBLIC_LOG_D64,
222 FAKE_POINTER(this), uuid);
223 NotifyResponseDataEnd(LoadingRequestError::LOADING_ERROR_SUCCESS);
224 return BUFFER_FULL;
225 }
226
227 int32_t receiveDataSize = memory->GetSize();
228 MediaAVCodec::AVCodecTrace trace("AppClient RespondData, uuid: " + std::to_string(uuid) +
229 ", offset: " + std::to_string(offset) + ", receiveDataSize: " + std::to_string(receiveDataSize));
230 dataInFlight_ -= receiveDataSize;
231
232 if (len_ > 0 && dataInFlight_ <= 0) {
233 NotifyResponseDataEnd(LoadingRequestError::LOADING_ERROR_SUCCESS);
234 }
235 MEDIA_LOG_D("0x%{public}06" PRIXPTR " AppClient RespondData, uuid " PUBLIC_LOG_D64 " offset " PUBLIC_LOG_D64
236 " dataInFlight_ " PUBLIC_LOG_D32 " size " PUBLIC_LOG_D32, FAKE_POINTER(this), uuid, offset,
237 dataInFlight_, receiveDataSize);
238 return receiveDataSize;
239 }
240
FinishLoading(int64_t uuid,LoadingRequestError state)241 int32_t AppClient::FinishLoading(int64_t uuid, LoadingRequestError state)
242 {
243 FALSE_RETURN_V_MSG_E(uuid == uuid_, 0, "FinishLoading uuid invalid.");
244 MEDIA_LOG_I("0x%{public}06" PRIXPTR "AppClient FinishLoading uuid " PUBLIC_LOG_D64, FAKE_POINTER(this), uuid);
245 Task::SleepInTask(FINISHLOADING_SLEEP_TIME);
246 NotifyResponseDataEnd(state);
247 return 0;
248 }
249
SetUuid(int64_t uuid)250 void AppClient::SetUuid(int64_t uuid)
251 {
252 FALSE_RETURN_MSG(uuid > 0, "SetUuid uuid invalid.");
253 MEDIA_LOG_D("0x%{public}06" PRIXPTR " AppClient SetUuid " PUBLIC_LOG_D64, FAKE_POINTER(this), uuid);
254 uuid_ = uuid;
255 }
256
GetRedirectUrl()257 std::string AppClient::GetRedirectUrl()
258 {
259 return redirectUrl_;
260 }
261 }
262 }
263 }
264 }