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 "nlohmann/json.hpp"
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=%s, fd=%" 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=%s, fd=%" 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=%s, fd=%" 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 (void)memset_s(base, size, INVALID_VALUE_FALG, size);
55
56 AVTRANS_LOGI("create av trans shared memory success, name=%s, size=%" PRId32 ", fd=%" PRId32,
57 name.c_str(), size, fd);
58 return AVTransSharedMemory{fd, size, name};
59 }
60
CloseAVTransSharedMemory(const AVTransSharedMemory & memory)61 void CloseAVTransSharedMemory(const AVTransSharedMemory &memory) noexcept
62 {
63 AVTRANS_LOGI("close shared memory, name=%s, size=%" PRId32 ", fd=%" PRId32, memory.name.c_str(),
64 memory.size, memory.fd);
65 if (IsInValidSharedMemory(memory)) {
66 AVTRANS_LOGE("invalid input shared memory");
67 return;
68 }
69 if (memory.fd > 0) {
70 (void)::close(memory.fd);
71 }
72 }
73
WriteClockUnitToMemory(const AVTransSharedMemory & memory,AVSyncClockUnit & clockUnit)74 int32_t WriteClockUnitToMemory(const AVTransSharedMemory &memory, AVSyncClockUnit &clockUnit)
75 {
76 AVTRANS_LOGI("write clock unit to shared memory, name=%s, size=%" PRId32 ", fd=%" PRId32,
77 memory.name.c_str(), memory.size, memory.fd);
78 TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
79
80 AVTRANS_LOGI("clock unit index=%" PRId32 ", frameNum=%" PRId32 ", pts=%lld", clockUnit.index,
81 clockUnit.frameNum, (long long)clockUnit.pts);
82 TRUE_RETURN_V_MSG_E(IsInValidClockUnit(clockUnit), ERR_DH_AVT_INVALID_PARAM, "invalid input clock unit");
83
84 int size = AshmemGetSize(memory.fd);
85 TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %" PRId32, size);
86
87 unsigned int prot = PROT_WRITE;
88 int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
89 TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
90
91 void *addr = ::mmap(nullptr, static_cast<size_t>(memory.size), static_cast<int>(prot), MAP_SHARED, memory.fd, 0);
92 if (addr == MAP_FAILED) {
93 free(addr);
94 addr = nullptr;
95 AVTRANS_LOGE("shared memory mmap failed, mmap address is invalid.");
96 return ERR_DH_AVT_SHARED_MEMORY_FAILED;
97 }
98
99 uint8_t *base = reinterpret_cast<uint8_t*>(addr);
100 size_t fOffset = (sizeof(uint32_t) + sizeof(int64_t)) * clockUnit.index;
101 size_t tOffset = fOffset + sizeof(uint32_t);
102 U64ToU8(base + tOffset, clockUnit.pts);
103 U32ToU8(base + fOffset, clockUnit.frameNum);
104
105 clockUnit.index ++;
106 if (clockUnit.index == MAX_CLOCK_UNIT_COUNT) {
107 clockUnit.index = 0;
108 }
109
110 AVTRANS_LOGI("write clock unit frameNum=%" PRId32 ", pts=%lld to shared memory success",
111 clockUnit.frameNum, (long long)(clockUnit.pts));
112 return DH_AVT_SUCCESS;
113 }
114
ReadClockUnitFromMemory(const AVTransSharedMemory & memory,AVSyncClockUnit & clockUnit)115 int32_t ReadClockUnitFromMemory(const AVTransSharedMemory &memory, AVSyncClockUnit &clockUnit)
116 {
117 AVTRANS_LOGI("read clock unit from shared memory, name=%s, size=%" PRId32 ", fd=%" PRId32,
118 memory.name.c_str(), memory.size, memory.fd);
119 TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
120
121 AVTRANS_LOGI("clock unit index=%" PRId32 ", frameNum=%" PRId32, clockUnit.index, clockUnit.frameNum);
122 TRUE_RETURN_V_MSG_E((clockUnit.frameNum <= 0), ERR_DH_AVT_INVALID_PARAM, "invalid input frame number");
123
124 int size = AshmemGetSize(memory.fd);
125 TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %" PRId32, size);
126
127 unsigned int prot = PROT_WRITE;
128 int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
129 TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
130
131 void *addr = ::mmap(nullptr, static_cast<size_t>(memory.size), static_cast<int>(prot), MAP_SHARED, memory.fd, 0);
132 if (addr == MAP_FAILED) {
133 free(addr);
134 addr = nullptr;
135 AVTRANS_LOGE("shared memory mmap failed, mmap address is invalid.");
136 return ERR_DH_AVT_SHARED_MEMORY_FAILED;
137 }
138
139 uint8_t *base = reinterpret_cast<uint8_t*>(addr);
140 uint32_t firstUnit = U8ToU32(base);
141 TRUE_RETURN_V_MSG_E(firstUnit == 0, ERR_DH_AVT_MASTER_NOT_READY, "master queue not ready, clock is null.");
142
143 uint32_t index = 0;
144 int64_t latestPts = 0;
145 size_t unitSize = sizeof(uint32_t) + sizeof(int64_t);
146 while (index < MAX_CLOCK_UNIT_COUNT) {
147 uint32_t frameNum = U8ToU32(base + (index * unitSize));
148 int64_t pts = static_cast<int64_t>(U8ToU64(base + (index * unitSize) + sizeof(uint32_t)));
149 if (pts > latestPts) {
150 latestPts = pts;
151 clockUnit.pts = pts;
152 clockUnit.frameNum = frameNum;
153 }
154 index++;
155 }
156 AVTRANS_LOGI("read clock unit from shared memory success, frameNum=%" PRId32 ", pts=%lld",
157 clockUnit.frameNum, (long long)clockUnit.pts);
158 return DH_AVT_SUCCESS;
159 }
160
WriteFrameInfoToMemory(const AVTransSharedMemory & memory,uint32_t frameNum,int64_t timestamp)161 int32_t WriteFrameInfoToMemory(const AVTransSharedMemory &memory, uint32_t frameNum, int64_t timestamp)
162 {
163 AVTRANS_LOGI("write frame info to shared memory, name=%s, size=%" PRId32 ", fd=%" PRId32,
164 memory.name.c_str(), memory.size, memory.fd);
165 TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
166
167 TRUE_RETURN_V_MSG_E((frameNum <= 0), ERR_DH_AVT_INVALID_PARAM, "invalid input frame number");
168
169 int size = AshmemGetSize(memory.fd);
170 TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %" PRId32, size);
171
172 unsigned int prot = PROT_WRITE;
173 int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
174 TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
175
176 void *addr = ::mmap(nullptr, static_cast<size_t>(memory.size), static_cast<int>(prot), MAP_SHARED, memory.fd, 0);
177 if (addr == MAP_FAILED) {
178 free(addr);
179 addr = nullptr;
180 AVTRANS_LOGE("shared memory mmap failed, mmap address is invalid.");
181 return ERR_DH_AVT_SHARED_MEMORY_FAILED;
182 }
183
184 uint8_t *base = reinterpret_cast<uint8_t*>(addr);
185 U32ToU8(base, frameNum);
186 U64ToU8(base + sizeof(uint32_t), timestamp);
187
188 AVTRANS_LOGI("write frameNum=%" PRId32 ", timestamp=%lld to shared memory success", frameNum, (long long)timestamp);
189 return DH_AVT_SUCCESS;
190 }
191
ReadFrameInfoFromMemory(const AVTransSharedMemory & memory,uint32_t & frameNum,int64_t & timestamp)192 int32_t ReadFrameInfoFromMemory(const AVTransSharedMemory &memory, uint32_t &frameNum, int64_t ×tamp)
193 {
194 AVTRANS_LOGI("read frame info from shared memory, name=%s, size=%" PRId32 ", fd=%" PRId32,
195 memory.name.c_str(), memory.size, memory.fd);
196 TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
197
198 int size = AshmemGetSize(memory.fd);
199 TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %" PRId32, size);
200
201 unsigned int prot = PROT_WRITE;
202 int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
203 TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
204
205 void *addr = ::mmap(nullptr, static_cast<size_t>(memory.size), static_cast<int>(prot), MAP_SHARED, memory.fd, 0);
206 if (addr == MAP_FAILED) {
207 free(addr);
208 addr = nullptr;
209 AVTRANS_LOGE("shared memory mmap failed, mmap address is invalid.");
210 return ERR_DH_AVT_SHARED_MEMORY_FAILED;
211 }
212
213 uint8_t *base = reinterpret_cast<uint8_t*>(addr);
214 frameNum = U8ToU32(base);
215 timestamp = static_cast<int64_t>(U8ToU64(base + sizeof(uint32_t)));
216 TRUE_RETURN_V_MSG_E(frameNum <= 0, ERR_DH_AVT_MASTER_NOT_READY, "master queue not ready, frameNum is null.");
217
218 AVTRANS_LOGI("read frameNum=%" PRId32 ", timestamp=%lld from shared memory success.", frameNum,
219 (long long)timestamp);
220 return DH_AVT_SUCCESS;
221 }
222
ResetSharedMemory(const AVTransSharedMemory & memory)223 int32_t ResetSharedMemory(const AVTransSharedMemory &memory)
224 {
225 AVTRANS_LOGI("reset shared memory, name=%s, size=%" PRId32 ", fd=%" PRId32, memory.name.c_str(),
226 memory.size, memory.fd);
227 TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
228
229 int size = AshmemGetSize(memory.fd);
230 TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %" PRId32, size);
231
232 unsigned int prot = PROT_WRITE;
233 int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
234 TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
235
236 void *addr = ::mmap(nullptr, static_cast<size_t>(memory.size), static_cast<int>(prot), MAP_SHARED, memory.fd, 0);
237 if (addr == MAP_FAILED) {
238 free(addr);
239 addr = nullptr;
240 AVTRANS_LOGE("shared memory mmap failed, mmap address is invalid.");
241 return ERR_DH_AVT_SHARED_MEMORY_FAILED;
242 }
243 (void)memset_s(reinterpret_cast<uint8_t*>(addr), size, INVALID_VALUE_FALG, size);
244
245 AVTRANS_LOGI("reset shared memory success.");
246 return DH_AVT_SUCCESS;
247 }
248
IsInValidSharedMemory(const AVTransSharedMemory & memory)249 bool IsInValidSharedMemory(const AVTransSharedMemory &memory)
250 {
251 return (memory.fd <= 0) || (memory.size <= 0) || memory.name.empty();
252 }
253
IsInValidClockUnit(const AVSyncClockUnit & clockUnit)254 bool IsInValidClockUnit(const AVSyncClockUnit &clockUnit)
255 {
256 return (clockUnit.index < 0) || (clockUnit.index >= MAX_CLOCK_UNIT_COUNT) || (clockUnit.frameNum <= 0)
257 || (clockUnit.pts <= 0);
258 }
259
MarshalSharedMemory(const AVTransSharedMemory & memory)260 std::string MarshalSharedMemory(const AVTransSharedMemory &memory)
261 {
262 nlohmann::json memoryJson;
263
264 memoryJson[KEY_SHARED_MEM_FD] = memory.fd;
265 memoryJson[KEY_SHARED_MEM_SIZE] = memory.size;
266 memoryJson[KEY_SHARED_MEM_NAME] = memory.name;
267
268 return memoryJson.dump();
269 }
270
UnmarshalSharedMemory(const std::string & jsonStr)271 AVTransSharedMemory UnmarshalSharedMemory(const std::string &jsonStr)
272 {
273 nlohmann::json paramJson = nlohmann::json::parse(jsonStr, nullptr, false);
274 if (paramJson.is_discarded()) {
275 return AVTransSharedMemory{0, 0, ""};
276 }
277
278 if (!paramJson.contains(KEY_SHARED_MEM_FD) || !paramJson.contains(KEY_SHARED_MEM_SIZE) ||
279 !paramJson.contains(KEY_SHARED_MEM_NAME)) {
280 return AVTransSharedMemory{0, 0, ""};
281 }
282
283 if (!paramJson[KEY_SHARED_MEM_FD].is_number_integer() || !paramJson[KEY_SHARED_MEM_SIZE].is_number_integer() ||
284 !paramJson[KEY_SHARED_MEM_NAME].is_string()) {
285 return AVTransSharedMemory{0, 0, ""};
286 }
287
288 int32_t fd = paramJson[KEY_SHARED_MEM_FD].get<int32_t>();
289 int32_t size = paramJson[KEY_SHARED_MEM_SIZE].get<int32_t>();
290 std::string name = paramJson[KEY_SHARED_MEM_NAME].get<std::string>();
291
292 return AVTransSharedMemory{ fd, size, name };
293 }
294
U32ToU8(uint8_t * ptr,uint32_t value)295 void U32ToU8(uint8_t *ptr, uint32_t value)
296 {
297 ptr[0] = (uint8_t)((value) & 0xff);
298 ptr[1] = (uint8_t)((value >> 8) & 0xff);
299 ptr[2] = (uint8_t)((value >> 16) & 0xff);
300 ptr[3] = (uint8_t)((value >> 24) & 0xff);
301 }
302
U64ToU8(uint8_t * ptr,uint64_t value)303 void U64ToU8(uint8_t *ptr, uint64_t value)
304 {
305 ptr[0] = (uint8_t)((value) & 0xff);
306 ptr[1] = (uint8_t)((value >> 8) & 0xff);
307 ptr[2] = (uint8_t)((value >> 16) & 0xff);
308 ptr[3] = (uint8_t)((value >> 24) & 0xff);
309 ptr[4] = (uint8_t)((value >> 32) & 0xff);
310 ptr[5] = (uint8_t)((value >> 40) & 0xff);
311 ptr[6] = (uint8_t)((value >> 48) & 0xff);
312 ptr[7] = (uint8_t)((value >> 56) & 0xff);
313 }
314
U8ToU32(const uint8_t * ptr)315 uint32_t U8ToU32(const uint8_t *ptr)
316 {
317 return (((uint32_t)(ptr[0] & 0xff)) |
318 ((uint32_t)(ptr[1] & 0xff) << 8) |
319 ((uint32_t)(ptr[2] & 0xff) << 16) |
320 ((uint32_t)(ptr[3] & 0xff) << 24));
321 }
322
U8ToU64(const uint8_t * ptr)323 uint64_t U8ToU64(const uint8_t *ptr)
324 {
325 return (((uint64_t)(ptr[0] & 0xff)) |
326 ((uint64_t)(ptr[1] & 0xff) << 8) |
327 ((uint64_t)(ptr[2] & 0xff) << 16) |
328 ((uint64_t)(ptr[3] & 0xff) << 24) |
329 ((uint64_t)(ptr[4] & 0xff) << 32) |
330 ((uint64_t)(ptr[5] & 0xff) << 40) |
331 ((uint64_t)(ptr[6] & 0xff) << 48) |
332 ((uint64_t)(ptr[7] & 0xff) << 56));
333 }
334 } // namespace DistributedHardware
335 } // namespace OHOS