1 /*
2 * Copyright (C) 2023 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 #include "av_sync_utils.h"
17
18 #include <sys/mman.h>
19 #include <securec.h>
20 #include <unistd.h>
21 #include "ashmem.h"
22 #include "cJSON.h"
23
24 #include "av_trans_constants.h"
25 #include "av_trans_errno.h"
26 #include "av_trans_log.h"
27
28 namespace OHOS {
29 namespace DistributedHardware {
CreateAVTransSharedMemory(const std::string & name,size_t size)30 AVTransSharedMemory CreateAVTransSharedMemory(const std::string &name, size_t size)
31 {
32 int32_t fd = AshmemCreate(name.c_str(), size);
33 if (fd <= 0) {
34 AVTRANS_LOGE("create av trans shared memory failed, name=%{public}s, fd=%{public}" PRId32, name.c_str(), fd);
35 return AVTransSharedMemory{0, 0, name};
36 }
37
38 unsigned int prot = PROT_READ | PROT_WRITE;
39 int result = AshmemSetProt(fd, static_cast<int>(prot));
40 if (result < 0) {
41 AVTRANS_LOGE("AshmemSetProt failed, name=%{public}s, fd=%{public}" PRId32, name.c_str(), fd);
42 (void)::close(fd);
43 return AVTransSharedMemory{0, 0, name};
44 }
45
46 void *addr = ::mmap(nullptr, size, static_cast<int>(prot), MAP_SHARED, fd, 0);
47 if (addr == MAP_FAILED) {
48 AVTRANS_LOGE("shared memory mmap failed, name=%{public}s, fd=%{public}" PRId32, name.c_str(), fd);
49 (void)::close(fd);
50 return AVTransSharedMemory{0, 0, name};
51 }
52
53 uint8_t *base = reinterpret_cast<uint8_t*>(addr);
54 if (memset_s(base, size, INVALID_VALUE_FALG, size) != EOK) {
55 AVTRANS_LOGE("memset_s failed.");
56 (void)::close(fd);
57 return AVTransSharedMemory{0, 0, name};
58 }
59 uint64_t tmpsize = static_cast<uint64_t>(size);
60 AVTRANS_LOGI("create av trans shared memory success, name=%{public}s, size=%{public}" PRIu64 ", fd=%{public}"
61 PRId32, name.c_str(), tmpsize, fd);
62 return AVTransSharedMemory{fd, size, name};
63 }
64
CloseAVTransSharedMemory(const AVTransSharedMemory & memory)65 void CloseAVTransSharedMemory(const AVTransSharedMemory &memory) noexcept
66 {
67 AVTRANS_LOGI("close shared memory, name=%{public}s, size=%{public}" PRId32 ", fd=%{public}" PRId32,
68 memory.name.c_str(), memory.size, memory.fd);
69 if (IsInValidSharedMemory(memory)) {
70 AVTRANS_LOGE("invalid input shared memory");
71 return;
72 }
73 if (memory.fd > 0) {
74 (void)::close(memory.fd);
75 }
76 }
77
WriteClockUnitToMemory(const AVTransSharedMemory & memory,AVSyncClockUnit & clockUnit)78 int32_t WriteClockUnitToMemory(const AVTransSharedMemory &memory, AVSyncClockUnit &clockUnit)
79 {
80 AVTRANS_LOGI("write clock unit to shared memory, name=%{public}s, size=%{public}" PRId32 ", fd=%{public}" PRId32,
81 memory.name.c_str(), memory.size, memory.fd);
82 TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
83
84 AVTRANS_LOGI("clock unit index=%{public}" PRId32 ", frameNum=%{public}" PRId32 ", pts=%{public}lld",
85 clockUnit.index, clockUnit.frameNum, (long long)clockUnit.pts);
86 TRUE_RETURN_V_MSG_E(IsInValidClockUnit(clockUnit), ERR_DH_AVT_INVALID_PARAM, "invalid input clock unit");
87
88 int size = AshmemGetSize(memory.fd);
89 TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %{public}" PRId32,
90 size);
91
92 unsigned int prot = PROT_WRITE;
93 int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
94 TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
95
96 void *addr = ::mmap(nullptr, static_cast<size_t>(memory.size), static_cast<int>(prot), MAP_SHARED, memory.fd, 0);
97 if (addr == MAP_FAILED) {
98 addr = nullptr;
99 AVTRANS_LOGE("shared memory mmap failed, mmap address is invalid.");
100 return ERR_DH_AVT_SHARED_MEMORY_FAILED;
101 }
102
103 uint8_t *base = reinterpret_cast<uint8_t*>(addr);
104 size_t fOffset = (sizeof(uint32_t) + sizeof(int64_t)) * clockUnit.index;
105 size_t tOffset = fOffset + sizeof(uint32_t);
106 U64ToU8(base + tOffset, clockUnit.pts);
107 U32ToU8(base + fOffset, clockUnit.frameNum);
108
109 clockUnit.index ++;
110 if (clockUnit.index == MAX_CLOCK_UNIT_COUNT) {
111 clockUnit.index = 0;
112 }
113
114 AVTRANS_LOGI("write clock unit frameNum=%{public}" PRId32 ", pts=%{public}lld to shared memory success",
115 clockUnit.frameNum, (long long)(clockUnit.pts));
116 return DH_AVT_SUCCESS;
117 }
118
ReadClockUnitFromMemory(const AVTransSharedMemory & memory,AVSyncClockUnit & clockUnit)119 int32_t ReadClockUnitFromMemory(const AVTransSharedMemory &memory, AVSyncClockUnit &clockUnit)
120 {
121 AVTRANS_LOGI("read clock unit from shared memory, name=%{public}s, size=%{public}" PRId32 ", fd=%{public}" PRId32,
122 memory.name.c_str(), memory.size, memory.fd);
123 TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
124
125 AVTRANS_LOGI("clock unit index=%{public}" PRId32 ", frameNum=%{public}" PRId32,
126 clockUnit.index, clockUnit.frameNum);
127 TRUE_RETURN_V_MSG_E((clockUnit.frameNum <= 0), ERR_DH_AVT_INVALID_PARAM, "invalid input frame number");
128
129 int size = AshmemGetSize(memory.fd);
130 TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %{public}" PRId32,
131 size);
132
133 unsigned int prot = PROT_WRITE;
134 int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
135 TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
136
137 void *addr = ::mmap(nullptr, static_cast<size_t>(memory.size), static_cast<int>(prot), MAP_SHARED, memory.fd, 0);
138 if (addr == MAP_FAILED) {
139 addr = nullptr;
140 AVTRANS_LOGE("shared memory mmap failed, mmap address is invalid.");
141 return ERR_DH_AVT_SHARED_MEMORY_FAILED;
142 }
143
144 uint8_t *base = reinterpret_cast<uint8_t*>(addr);
145 uint32_t firstUnit = U8ToU32(base);
146 TRUE_RETURN_V_MSG_E(firstUnit == 0, ERR_DH_AVT_MASTER_NOT_READY, "master queue not ready, clock is null.");
147
148 uint32_t index = 0;
149 int64_t latestPts = 0;
150 size_t unitSize = sizeof(uint32_t) + sizeof(int64_t);
151 while (index < MAX_CLOCK_UNIT_COUNT) {
152 uint32_t frameNum = U8ToU32(base + (index * unitSize));
153 int64_t pts = static_cast<int64_t>(U8ToU64(base + (index * unitSize) + sizeof(uint32_t)));
154 if (pts > latestPts) {
155 latestPts = pts;
156 clockUnit.pts = pts;
157 clockUnit.frameNum = frameNum;
158 }
159 index++;
160 }
161 AVTRANS_LOGI("read clock unit from shared memory success, frameNum=%{public}" PRId32 ", pts=%{public}lld",
162 clockUnit.frameNum, (long long)clockUnit.pts);
163 return DH_AVT_SUCCESS;
164 }
165
WriteFrameInfoToMemory(const AVTransSharedMemory & memory,uint32_t frameNum,int64_t timestamp)166 int32_t WriteFrameInfoToMemory(const AVTransSharedMemory &memory, uint32_t frameNum, int64_t timestamp)
167 {
168 AVTRANS_LOGI("write frame info to shared memory, name=%{public}s, size=%{public}" PRId32 ", fd=%{public}" PRId32,
169 memory.name.c_str(), memory.size, memory.fd);
170 TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
171
172 TRUE_RETURN_V_MSG_E((frameNum <= 0), ERR_DH_AVT_INVALID_PARAM, "invalid input frame number");
173
174 int size = AshmemGetSize(memory.fd);
175 TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %{public}" PRId32,
176 size);
177
178 unsigned int prot = PROT_WRITE;
179 int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
180 TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
181
182 void *addr = ::mmap(nullptr, static_cast<size_t>(memory.size), static_cast<int>(prot), MAP_SHARED, memory.fd, 0);
183 if (addr == MAP_FAILED) {
184 addr = nullptr;
185 AVTRANS_LOGE("shared memory mmap failed, mmap address is invalid.");
186 return ERR_DH_AVT_SHARED_MEMORY_FAILED;
187 }
188
189 uint8_t *base = reinterpret_cast<uint8_t*>(addr);
190 U32ToU8(base, frameNum);
191 U64ToU8(base + sizeof(uint32_t), timestamp);
192
193 AVTRANS_LOGI("write frameNum=%{public}" PRId32 ", timestamp=%{public}lld to shared memory success",
194 frameNum, (long long)timestamp);
195 return DH_AVT_SUCCESS;
196 }
197
ReadFrameInfoFromMemory(const AVTransSharedMemory & memory,uint32_t & frameNum,int64_t & timestamp)198 int32_t ReadFrameInfoFromMemory(const AVTransSharedMemory &memory, uint32_t &frameNum, int64_t ×tamp)
199 {
200 AVTRANS_LOGI("read frame info from shared memory, name=%{public}s, size=%{public}" PRId32 ", fd=%{public}" PRId32,
201 memory.name.c_str(), memory.size, memory.fd);
202 TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
203
204 int size = AshmemGetSize(memory.fd);
205 TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %{public}" PRId32,
206 size);
207
208 unsigned int prot = PROT_WRITE;
209 int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
210 TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
211
212 void *addr = ::mmap(nullptr, static_cast<size_t>(memory.size), static_cast<int>(prot), MAP_SHARED, memory.fd, 0);
213 if (addr == MAP_FAILED) {
214 addr = nullptr;
215 AVTRANS_LOGE("shared memory mmap failed, mmap address is invalid.");
216 return ERR_DH_AVT_SHARED_MEMORY_FAILED;
217 }
218
219 uint8_t *base = reinterpret_cast<uint8_t*>(addr);
220 frameNum = U8ToU32(base);
221 timestamp = static_cast<int64_t>(U8ToU64(base + sizeof(uint32_t)));
222 TRUE_RETURN_V_MSG_E(frameNum <= 0, ERR_DH_AVT_MASTER_NOT_READY, "master queue not ready, frameNum is null.");
223
224 AVTRANS_LOGI("read frameNum=%{public}" PRId32 ", timestamp=%{public}lld from shared memory success.", frameNum,
225 (long long)timestamp);
226 return DH_AVT_SUCCESS;
227 }
228
ResetSharedMemory(const AVTransSharedMemory & memory)229 int32_t ResetSharedMemory(const AVTransSharedMemory &memory)
230 {
231 AVTRANS_LOGI("reset shared memory, name=%{public}s, size=%{public}" PRId32 ", fd=%{public}" PRId32,
232 memory.name.c_str(), memory.size, memory.fd);
233 TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
234
235 int size = AshmemGetSize(memory.fd);
236 TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %{public}" PRId32,
237 size);
238
239 unsigned int prot = PROT_WRITE;
240 int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
241 TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
242
243 void *addr = ::mmap(nullptr, static_cast<size_t>(memory.size), static_cast<int>(prot), MAP_SHARED, memory.fd, 0);
244 if (addr == MAP_FAILED) {
245 addr = nullptr;
246 AVTRANS_LOGE("shared memory mmap failed, mmap address is invalid.");
247 return ERR_DH_AVT_SHARED_MEMORY_FAILED;
248 }
249 if (memset_s(reinterpret_cast<uint8_t*>(addr), size, INVALID_VALUE_FALG, size) != EOK) {
250 AVTRANS_LOGE("memset_s failed.");
251 return ERR_DH_AVT_SHARED_MEMORY_FAILED;
252 }
253 AVTRANS_LOGI("reset shared memory success.");
254 return DH_AVT_SUCCESS;
255 }
256
IsInValidSharedMemory(const AVTransSharedMemory & memory)257 bool IsInValidSharedMemory(const AVTransSharedMemory &memory)
258 {
259 return (memory.fd <= 0) || (memory.size <= 0) || memory.name.empty();
260 }
261
IsInValidClockUnit(const AVSyncClockUnit & clockUnit)262 bool IsInValidClockUnit(const AVSyncClockUnit &clockUnit)
263 {
264 return (clockUnit.index < 0) || (clockUnit.index >= MAX_CLOCK_UNIT_COUNT) || (clockUnit.frameNum <= 0)
265 || (clockUnit.pts <= 0);
266 }
267
MarshalSharedMemory(const AVTransSharedMemory & memory)268 std::string MarshalSharedMemory(const AVTransSharedMemory &memory)
269 {
270 cJSON *memoryJson = cJSON_CreateObject();
271 if (memoryJson == nullptr) {
272 return "";
273 }
274 cJSON_AddNumberToObject(memoryJson, KEY_SHARED_MEM_FD.c_str(), memory.fd);
275 cJSON_AddNumberToObject(memoryJson, KEY_SHARED_MEM_SIZE.c_str(), memory.size);
276 cJSON_AddStringToObject(memoryJson, KEY_SHARED_MEM_NAME.c_str(), memory.name.c_str());
277
278 char *data = cJSON_PrintUnformatted(memoryJson);
279 if (data == nullptr) {
280 cJSON_Delete(memoryJson);
281 return "";
282 }
283 std::string jsonstr(data);
284 cJSON_free(data);
285 cJSON_Delete(memoryJson);
286 return jsonstr;
287 }
288
UnmarshalSharedMemory(const std::string & jsonStr)289 AVTransSharedMemory UnmarshalSharedMemory(const std::string &jsonStr)
290 {
291 cJSON *paramJson = cJSON_Parse(jsonStr.c_str());
292 if (paramJson == nullptr) {
293 return AVTransSharedMemory{0, 0, ""};
294 }
295 cJSON *fdObj = cJSON_GetObjectItemCaseSensitive(paramJson, KEY_SHARED_MEM_FD.c_str());
296 if (fdObj == nullptr || !cJSON_IsNumber(fdObj)) {
297 cJSON_Delete(paramJson);
298 return AVTransSharedMemory{0, 0, ""};
299 }
300 int32_t fd = fdObj->valueint;
301 cJSON *sizeObj = cJSON_GetObjectItemCaseSensitive(paramJson, KEY_SHARED_MEM_SIZE.c_str());
302 if (sizeObj == nullptr || !cJSON_IsNumber(sizeObj)) {
303 cJSON_Delete(paramJson);
304 return AVTransSharedMemory{0, 0, ""};
305 }
306 int32_t size = sizeObj->valueint;
307 cJSON *nameObj = cJSON_GetObjectItemCaseSensitive(paramJson, KEY_SHARED_MEM_NAME.c_str());
308 if (nameObj == nullptr || !cJSON_IsString(nameObj)) {
309 cJSON_Delete(paramJson);
310 return AVTransSharedMemory{0, 0, ""};
311 }
312 std::string name = nameObj->valuestring;
313 cJSON_Delete(paramJson);
314 return AVTransSharedMemory{ fd, size, name };
315 }
316
U32ToU8(uint8_t * ptr,uint32_t value)317 void U32ToU8(uint8_t *ptr, uint32_t value)
318 {
319 int8_t arrZero = 0;
320 int8_t arrOne = 1;
321 int8_t arrTwo = 2;
322 int8_t arrThree = 3;
323 uint8_t cal = 8;
324 uint8_t calTwo = 16;
325 uint8_t calThree = 24;
326 ptr[arrZero] = (uint8_t)((value) & 0xff);
327 ptr[arrOne] = (uint8_t)((value >> cal) & 0xff);
328 ptr[arrTwo] = (uint8_t)((value >> calTwo) & 0xff);
329 ptr[arrThree] = (uint8_t)((value >> calThree) & 0xff);
330 }
331
U64ToU8(uint8_t * ptr,uint64_t value)332 void U64ToU8(uint8_t *ptr, uint64_t value)
333 {
334 int8_t arrZero = 0;
335 int8_t arrOne = 1;
336 int8_t arrTwo = 2;
337 int8_t arrThree = 3;
338 int8_t arrFour = 4;
339 int8_t arrFive = 5;
340 int8_t arrSix = 6;
341 int8_t arrSeven = 7;
342 uint8_t calOne = 8;
343 uint8_t calTwo = 16;
344 uint8_t calThree = 24;
345 uint8_t calFour = 32;
346 uint8_t calFive = 40;
347 uint8_t calSix = 48;
348 uint8_t calSeven = 56;
349 ptr[arrZero] = (uint8_t)((value) & 0xff);
350 ptr[arrOne] = (uint8_t)((value >> calOne) & 0xff);
351 ptr[arrTwo] = (uint8_t)((value >> calTwo) & 0xff);
352 ptr[arrThree] = (uint8_t)((value >> calThree) & 0xff);
353 ptr[arrFour] = (uint8_t)((value >> calFour) & 0xff);
354 ptr[arrFive] = (uint8_t)((value >> calFive) & 0xff);
355 ptr[arrSix] = (uint8_t)((value >> calSix) & 0xff);
356 ptr[arrSeven] = (uint8_t)((value >> calSeven) & 0xff);
357 }
358
U8ToU32(const uint8_t * ptr)359 uint32_t U8ToU32(const uint8_t *ptr)
360 {
361 int8_t arrZero = 0;
362 int8_t arrOne = 1;
363 int8_t arrTwo = 2;
364 int8_t arrThree = 3;
365 uint8_t calOne = 8;
366 uint8_t calTwo = 16;
367 uint8_t calThree = 24;
368 return (((uint32_t)(ptr[arrZero] & 0xff)) |
369 ((uint32_t)(ptr[arrOne] & 0xff) << calOne) |
370 ((uint32_t)(ptr[arrTwo] & 0xff) << calTwo) |
371 ((uint32_t)(ptr[arrThree] & 0xff) << calThree));
372 }
373
U8ToU64(const uint8_t * ptr)374 uint64_t U8ToU64(const uint8_t *ptr)
375 {
376 int8_t arrZero = 0;
377 int8_t arrOne = 1;
378 int8_t arrTwo = 2;
379 int8_t arrThree = 3;
380 int8_t arrFour = 4;
381 int8_t arrFive = 5;
382 int8_t arrSix = 6;
383 int8_t arrSeven = 7;
384 uint8_t calOne = 8;
385 uint8_t calTwo = 16;
386 uint8_t calThree = 24;
387 uint8_t calFour = 32;
388 uint8_t calFive = 40;
389 uint8_t calSix = 48;
390 uint8_t calSeven = 56;
391 return (((uint64_t)(ptr[arrZero] & 0xff)) |
392 ((uint64_t)(ptr[arrOne] & 0xff) << calOne) |
393 ((uint64_t)(ptr[arrTwo] & 0xff) << calTwo) |
394 ((uint64_t)(ptr[arrThree] & 0xff) << calThree) |
395 ((uint64_t)(ptr[arrFour] & 0xff) << calFour) |
396 ((uint64_t)(ptr[arrFive] & 0xff) << calFive) |
397 ((uint64_t)(ptr[arrSix] & 0xff) << calSix) |
398 ((uint64_t)(ptr[arrSeven] & 0xff) << calSeven));
399 }
400 } // namespace DistributedHardware
401 } // namespace OHOS