• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef RING_BUFFER_WRAPPER_H
16 #define RING_BUFFER_WRAPPER_H
17 
18 #include <map>
19 #include <set>
20 #include <string>
21 #include <unordered_map>
22 #include <parcel.h>
23 
24 #include "audio_buffer_desc.h"
25 #include "audio_errors.h"
26 #include "audio_log.h"
27 #include "securec.h"
28 
29 namespace OHOS {
30 namespace AudioStandard {
31 /* If buflength is 0, buffer must be nullptr;
32    conversely, if buffer is nullptr, buflength must be 0.
33    Otherwise, the behavior is undefined. */
34 struct BasicBufferDesc {
35     uint8_t *buffer = nullptr;
36     size_t bufLength = 0;
37 
IsLegalBasicBufferDesc38     bool IsLegal() const
39     {
40         if ((buffer == nullptr) && (bufLength == 0)) {
41             return true;
42         }
43 
44         if ((buffer != nullptr) && (bufLength > 0)) {
45             return true;
46         }
47 
48         return false;
49     }
50 
IsBufferOverlapBasicBufferDesc51     bool IsBufferOverlap(const BasicBufferDesc &inBuffer) const
52     {
53         if ((buffer == nullptr) || (inBuffer.buffer == nullptr)) {
54             return false;
55         }
56 
57         if ((buffer >= (inBuffer.buffer + inBuffer.bufLength)) || (inBuffer.buffer >= buffer + bufLength)) {
58             return false;
59         }
60 
61         return true;
62     }
63 
SeekFromStartBasicBufferDesc64     int32_t SeekFromStart(size_t offset)
65     {
66         if (offset > bufLength) {
67             return ERR_INVALID_PARAM;
68         }
69 
70         bufLength -= offset;
71 
72         if (bufLength == 0) {
73             buffer = nullptr;
74         } else {
75             buffer += offset;
76         }
77         return SUCCESS;
78     }
79 };
80 
81 /**
82  * Precondition: dataLength must not exceed the total buffer capacity
83  * (sum of all bufLength).
84  * The two memory blocks must not overlap in any part of their address ranges.
85  * If first buffer is null, second is null.
86  * Violation results in undefined behavior.
87  */
88 struct RingBufferWrapper {
89     static inline constexpr size_t DESC_SIZE = 2;
90 
91     std::array<BasicBufferDesc, DESC_SIZE> basicBufferDescs = {};
92     size_t dataLength = 0;
93 
GetBufferSizeRingBufferWrapper94     size_t GetBufferSize() const
95     {
96         size_t size = 0;
97         for (const auto &[buffer, bufLength] : basicBufferDescs) {
98             size += bufLength;
99         }
100         return size;
101     }
102 
IsLegalRingBufferWrapper103     bool IsLegal() const
104     {
105         if ((!basicBufferDescs[0].IsLegal()) || (!basicBufferDescs[1].IsLegal())) {
106             return false;
107         }
108 
109         if (basicBufferDescs[0].IsBufferOverlap(basicBufferDescs[1])) {
110             return false;
111         }
112 
113         if (dataLength > GetBufferSize()) {
114             return false;
115         }
116 
117         if ((basicBufferDescs[0].buffer) == nullptr && (basicBufferDescs[1].buffer != nullptr)) {
118             return false;
119         }
120 
121         return true;
122     }
123 
ResetRingBufferWrapper124     void Reset()
125     {
126         dataLength = 0;
127         for (auto &[buffer, bufLength] : basicBufferDescs) {
128             buffer = nullptr;
129             bufLength = 0;
130         }
131     }
132 
SetBuffersValueWithBufLenRingBufferWrapper133     void SetBuffersValueWithBufLen(int8_t ch) const
134     {
135         for (auto &[buffer, bufLength] : basicBufferDescs) {
136             if (buffer != nullptr && bufLength != 0) {
137                 memset_s(buffer, bufLength, ch, bufLength);
138             }
139         }
140     }
141 
SetBuffersValueWithSpecifyDataLenRingBufferWrapper142     void SetBuffersValueWithSpecifyDataLen(int8_t ch) const
143     {
144         size_t remainSize = dataLength;
145         for (auto &[buffer, bufLength] : basicBufferDescs) {
146             size_t setSize = std::min(remainSize, bufLength);
147             remainSize -= setSize;
148             if (buffer != nullptr && bufLength != 0 && setSize != 0) {
149                 auto ret = memset_s(buffer, bufLength, ch, setSize);
150                 [[unlikely]] if (ret != EOK) {
151                     AUDIO_ERR_LOG("memset err :%{public}d", ret);
152                 }
153             }
154         }
155     }
156 
SeekFromStartRingBufferWrapper157     int32_t SeekFromStart(size_t offset)
158     {
159         if (offset > GetBufferSize()) {
160             return ERR_INVALID_PARAM;
161         }
162 
163         size_t remainSeek = offset;
164         dataLength <= offset ? dataLength = 0 : dataLength -= offset;
165 
166         for (auto &basicBuffer : basicBufferDescs) {
167             size_t seekSize = std::min(remainSeek, basicBuffer.bufLength);
168             basicBuffer.SeekFromStart(seekSize);
169             remainSeek -= seekSize;
170         }
171 
172         if (basicBufferDescs[0].bufLength == 0) {
173             std::swap(basicBufferDescs[0], basicBufferDescs[1]);
174         }
175         return SUCCESS;
176     }
177 
CopyInputBufferValueToCurBufferRingBufferWrapper178     int32_t CopyInputBufferValueToCurBuffer(const RingBufferWrapper &buffer)
179     {
180         if (GetBufferSize() < buffer.dataLength) {
181             return ERR_INVALID_PARAM;
182         }
183 
184         RingBufferWrapper dstBuffer(*this);
185         RingBufferWrapper srcBuffer(buffer);
186         dstBuffer.dataLength = buffer.dataLength;
187 
188         size_t remainSize = buffer.dataLength;
189         while (remainSize > 0) {
190             auto copySize = std::min({srcBuffer.basicBufferDescs[0].bufLength, dstBuffer.basicBufferDescs[0].bufLength,
191                 remainSize});
192             remainSize -= copySize;
193 
194             [[unlikely]] if (copySize == 0) {
195                 // This branch should never be executed under any valid conditions. Consider let it crash?
196                 AUDIO_ERR_LOG("copySize is 0");
197                 return ERR_INVALID_PARAM;
198             }
199             auto ret = memcpy_s(dstBuffer.basicBufferDescs[0].buffer, dstBuffer.basicBufferDescs[0].bufLength,
200                 srcBuffer.basicBufferDescs[0].buffer, copySize);
201             [[unlikely]] if (ret != EOK) {
202                 AUDIO_ERR_LOG("memcpy err :%{public}d", ret);
203             }
204             dstBuffer.SeekFromStart(copySize);
205             srcBuffer.SeekFromStart(copySize);
206         }
207 
208         dataLength = buffer.dataLength;
209         return SUCCESS;
210     }
211 };
212 } // namespace AudioStandard
213 } // namespace OHOS
214 #endif // RING_BUFFER_WRAPPER_H
215