• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023-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 #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, nullptr};
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, nullptr};
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, nullptr};
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         (void)::munmap(addr, size);
58         return AVTransSharedMemory{0, 0, name, nullptr};
59     }
60     AVTRANS_LOGI("create av trans shared memory success, name=%{public}s, size=%{public}zu, fd=%{public}d"
61         PRId32, name.c_str(), size, fd);
62     return AVTransSharedMemory{fd, size, name, addr};
63 }
64 
CloseAVTransSharedMemory(AVTransSharedMemory & memory)65 void CloseAVTransSharedMemory(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         memory.fd = -1;
76     }
77     if (memory.addr != nullptr) {
78         (void)::munmap(memory.addr, memory.size);
79         memory.addr = nullptr;
80     }
81 }
82 
WriteClockUnitToMemory(const AVTransSharedMemory & memory,AVSyncClockUnit & clockUnit)83 int32_t WriteClockUnitToMemory(const AVTransSharedMemory &memory, AVSyncClockUnit &clockUnit)
84 {
85     AVTRANS_LOGI("write clock unit to shared memory, name=%{public}s, size=%{public}" PRId32 ", fd=%{public}" PRId32,
86         memory.name.c_str(), memory.size, memory.fd);
87     TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
88 
89     int mSize = 12;
90     TRUE_RETURN_V_MSG_E(memory.size < mSize, ERR_DH_AVT_INVALID_PARAM,
91         "Memory.size is too small, future access may exceed the limit");
92     AVTRANS_LOGI("clock unit index=%{public}" PRId32 ", frameNum=%{public}" PRId32 ", pts=%{public}lld",
93         clockUnit.index, clockUnit.frameNum, (long long)clockUnit.pts);
94     TRUE_RETURN_V_MSG_E(IsInValidClockUnit(clockUnit), ERR_DH_AVT_INVALID_PARAM, "invalid input clock unit");
95 
96     int size = AshmemGetSize(memory.fd);
97     TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %{public}" PRId32,
98         size);
99 
100     unsigned int prot = PROT_WRITE;
101     int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
102     TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
103 
104     uint8_t *base = reinterpret_cast<uint8_t*>(memory.addr);
105     size_t fOffset = (sizeof(uint32_t) + sizeof(int64_t)) * clockUnit.index;
106     size_t tOffset = fOffset + sizeof(uint32_t);
107     U64ToU8(base + tOffset, clockUnit.pts, NUM_EIGHT);
108     U32ToU8(base + fOffset, clockUnit.frameNum, NUM_FOUR);
109 
110     clockUnit.index ++;
111     if (clockUnit.index == MAX_CLOCK_UNIT_COUNT) {
112         clockUnit.index = 0;
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     int mSize = 12;
126     TRUE_RETURN_V_MSG_E(memory.size < mSize, ERR_DH_AVT_INVALID_PARAM,
127         "Memory.size is too small, future access may exceed the limit");
128     AVTRANS_LOGI("clock unit index=%{public}" PRId32 ", frameNum=%{public}" PRId32,
129         clockUnit.index, clockUnit.frameNum);
130     TRUE_RETURN_V_MSG_E((clockUnit.frameNum <= 0), ERR_DH_AVT_INVALID_PARAM, "invalid input frame number");
131 
132     int size = AshmemGetSize(memory.fd);
133     TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %{public}" PRId32,
134         size);
135 
136     unsigned int prot = PROT_WRITE;
137     int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
138     TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
139     uint8_t *base = reinterpret_cast<uint8_t*>(memory.addr);
140     uint32_t firstUnit = U8ToU32(base, NUM_FOUR);
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), NUM_FOUR);
148         int64_t pts = static_cast<int64_t>(U8ToU64(base + (index * unitSize) + sizeof(uint32_t), NUM_EIGHT));
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=%{public}" PRId32 ", pts=%{public}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=%{public}s, size=%{public}" PRId32 ", fd=%{public}" 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     int mSize = 12;
168     TRUE_RETURN_V_MSG_E(memory.size < mSize, ERR_DH_AVT_INVALID_PARAM,
169         "Memory.size is too small, future access may exceed the limit");
170     TRUE_RETURN_V_MSG_E((frameNum <= 0), ERR_DH_AVT_INVALID_PARAM, "invalid input frame number");
171 
172     int size = AshmemGetSize(memory.fd);
173     TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %{public}" PRId32,
174         size);
175 
176     unsigned int prot = PROT_WRITE;
177     int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
178     TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
179     uint8_t *base = reinterpret_cast<uint8_t*>(memory.addr);
180     U32ToU8(base, frameNum, NUM_FOUR);
181     U64ToU8(base + sizeof(uint32_t), timestamp, NUM_EIGHT);
182 
183     AVTRANS_LOGI("write frameNum=%{public}" PRId32 ", timestamp=%{public}lld to shared memory success",
184         frameNum, (long long)timestamp);
185     return DH_AVT_SUCCESS;
186 }
187 
ReadFrameInfoFromMemory(const AVTransSharedMemory & memory,uint32_t & frameNum,int64_t & timestamp)188 int32_t ReadFrameInfoFromMemory(const AVTransSharedMemory &memory, uint32_t &frameNum, int64_t &timestamp)
189 {
190     AVTRANS_LOGI("read frame info from shared memory, name=%{public}s, size=%{public}" PRId32 ", fd=%{public}" PRId32,
191         memory.name.c_str(), memory.size, memory.fd);
192     TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
193     int mSize = 12;
194     TRUE_RETURN_V_MSG_E(memory.size < mSize, ERR_DH_AVT_INVALID_PARAM,
195         "Memory.size is too small, future access may exceed the limit");
196 
197     int size = AshmemGetSize(memory.fd);
198     TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %{public}" PRId32,
199         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     uint8_t *base = reinterpret_cast<uint8_t*>(memory.addr);
205     frameNum = U8ToU32(base, NUM_FOUR);
206     timestamp = static_cast<int64_t>(U8ToU64(base + sizeof(uint32_t), NUM_EIGHT));
207     TRUE_RETURN_V_MSG_E(frameNum <= 0, ERR_DH_AVT_MASTER_NOT_READY, "master queue not ready, frameNum is null.");
208 
209     AVTRANS_LOGI("read frameNum=%{public}" PRId32 ", timestamp=%{public}lld from shared memory success.", frameNum,
210         (long long)timestamp);
211     return DH_AVT_SUCCESS;
212 }
213 
ResetSharedMemory(const AVTransSharedMemory & memory)214 int32_t ResetSharedMemory(const AVTransSharedMemory &memory)
215 {
216     AVTRANS_LOGI("reset shared memory, name=%{public}s, size=%{public}" PRId32 ", fd=%{public}" PRId32,
217         memory.name.c_str(), memory.size, memory.fd);
218     TRUE_RETURN_V_MSG_E(IsInValidSharedMemory(memory), ERR_DH_AVT_INVALID_PARAM, "invalid input shared memory");
219 
220     int size = AshmemGetSize(memory.fd);
221     TRUE_RETURN_V_MSG_E(size != memory.size, ERR_DH_AVT_SHARED_MEMORY_FAILED, "invalid memory size = %{public}" PRId32,
222         size);
223 
224     unsigned int prot = PROT_WRITE;
225     int result = AshmemSetProt(memory.fd, static_cast<int>(prot));
226     TRUE_RETURN_V_MSG_E(result < 0, ERR_DH_AVT_SHARED_MEMORY_FAILED, "AshmemSetProt failed");
227     if (memset_s(reinterpret_cast<uint8_t*>(memory.addr), size, INVALID_VALUE_FALG, size) != EOK) {
228         AVTRANS_LOGE("memset_s failed.");
229         return ERR_DH_AVT_SHARED_MEMORY_FAILED;
230     }
231     AVTRANS_LOGI("reset shared memory success.");
232     return DH_AVT_SUCCESS;
233 }
234 
IsInValidSharedMemory(const AVTransSharedMemory & memory)235 bool IsInValidSharedMemory(const AVTransSharedMemory &memory)
236 {
237     return (memory.fd <= 0) || (memory.size <= 0) || memory.name.empty() || (memory.addr == nullptr);
238 }
239 
IsInValidClockUnit(const AVSyncClockUnit & clockUnit)240 bool IsInValidClockUnit(const AVSyncClockUnit &clockUnit)
241 {
242     return (clockUnit.index < 0) || (clockUnit.index >= MAX_CLOCK_UNIT_COUNT) || (clockUnit.frameNum <= 0)
243         || (clockUnit.pts <= 0);
244 }
245 
MarshalSharedMemory(const AVTransSharedMemory & memory)246 std::string MarshalSharedMemory(const AVTransSharedMemory &memory)
247 {
248     cJSON *memoryJson = cJSON_CreateObject();
249     if (memoryJson == nullptr) {
250         return "";
251     }
252     cJSON_AddNumberToObject(memoryJson, KEY_SHARED_MEM_FD.c_str(), memory.fd);
253     cJSON_AddNumberToObject(memoryJson, KEY_SHARED_MEM_SIZE.c_str(), memory.size);
254     cJSON_AddStringToObject(memoryJson, KEY_SHARED_MEM_NAME.c_str(), memory.name.c_str());
255 
256     char *data = cJSON_PrintUnformatted(memoryJson);
257     if (data == nullptr) {
258         cJSON_Delete(memoryJson);
259         return "";
260     }
261     std::string jsonstr(data);
262     cJSON_free(data);
263     cJSON_Delete(memoryJson);
264     return jsonstr;
265 }
266 
UnmarshalSharedMemory(const std::string & jsonStr)267 AVTransSharedMemory UnmarshalSharedMemory(const std::string &jsonStr)
268 {
269     cJSON *paramJson = cJSON_Parse(jsonStr.c_str());
270     if (paramJson == nullptr) {
271         return AVTransSharedMemory{0, 0, ""};
272     }
273     cJSON *fdObj = cJSON_GetObjectItemCaseSensitive(paramJson, KEY_SHARED_MEM_FD.c_str());
274     if (fdObj == nullptr || !cJSON_IsNumber(fdObj)) {
275         cJSON_Delete(paramJson);
276         return AVTransSharedMemory{0, 0, ""};
277     }
278     int32_t fd = fdObj->valueint;
279     cJSON *sizeObj = cJSON_GetObjectItemCaseSensitive(paramJson, KEY_SHARED_MEM_SIZE.c_str());
280     if (sizeObj == nullptr || !cJSON_IsNumber(sizeObj)) {
281         cJSON_Delete(paramJson);
282         return AVTransSharedMemory{0, 0, ""};
283     }
284     int32_t size = sizeObj->valueint;
285     cJSON *nameObj = cJSON_GetObjectItemCaseSensitive(paramJson, KEY_SHARED_MEM_NAME.c_str());
286     if (nameObj == nullptr || !cJSON_IsString(nameObj)) {
287         cJSON_Delete(paramJson);
288         return AVTransSharedMemory{0, 0, ""};
289     }
290     std::string name = nameObj->valuestring;
291     cJSON_Delete(paramJson);
292     return AVTransSharedMemory{ fd, size, name };
293 }
294 
U32ToU8(uint8_t * arrayPtr,uint32_t value,size_t arraySize)295 void U32ToU8(uint8_t *arrayPtr, uint32_t value, size_t arraySize)
296 {
297     if (arrayPtr == nullptr || arraySize < NUM_FOUR) {
298         return;
299     }
300     for (auto i = NUM_ZERO; i < NUM_FOUR; ++i) {
301         arrayPtr[i] = static_cast<uint8_t>((value >> (i * NUM_EIGHT)) & 0xff);
302     }
303 }
304 
U64ToU8(uint8_t * arrayPtr,uint64_t value,size_t arraySize)305 void U64ToU8(uint8_t *arrayPtr, uint64_t value, size_t arraySize)
306 {
307     if (arrayPtr == nullptr || arraySize < NUM_EIGHT) {
308         return;
309     }
310     for (auto i = NUM_ZERO; i < NUM_EIGHT; ++i) {
311         arrayPtr[i] = static_cast<uint8_t>((value >> (i * NUM_EIGHT)) & 0xff);
312     }
313 }
314 
U8ToU32(const uint8_t * arrayPtr,size_t arraySize)315 uint32_t U8ToU32(const uint8_t *arrayPtr, size_t arraySize)
316 {
317     if (arrayPtr == nullptr || arraySize < NUM_FOUR) {
318         return -1;
319     }
320     uint32_t result = 0;
321     for (auto i = NUM_ZERO; i < NUM_FOUR; ++i) {
322         result |= static_cast<uint32_t>(arrayPtr[i] & 0xff) << (i * NUM_EIGHT);
323     }
324     return result;
325 }
326 
U8ToU64(const uint8_t * arrayPtr,size_t arraySize)327 uint64_t U8ToU64(const uint8_t *arrayPtr, size_t arraySize)
328 {
329     if (arrayPtr == nullptr || arraySize < NUM_EIGHT) {
330         return -1;
331     }
332     uint64_t result = 0;
333     for (auto i = NUM_ZERO; i < NUM_EIGHT; ++i) {
334         result |= static_cast<uint64_t>(arrayPtr[i] & 0xff) << (i * NUM_EIGHT);
335     }
336     return result;
337 }
338 } // namespace DistributedHardware
339 } // namespace OHOS