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 #include "daudio_ringbuffer.h"
17
18 #include <cstdint>
19 #include <securec.h>
20
21 #undef DH_LOG_TAG
22 #define DH_LOG_TAG "DaudioRingBuffer"
23
24 namespace OHOS {
25 namespace DistributedHardware {
~DaudioRingBuffer()26 DaudioRingBuffer::~DaudioRingBuffer()
27 {
28 if (array_ != nullptr) {
29 delete[] array_;
30 array_ = nullptr;
31 }
32 }
33
RingBufferInit(uint8_t * & audioData)34 int32_t DaudioRingBuffer::RingBufferInit(uint8_t *&audioData)
35 {
36 array_ = new (std::nothrow) uint8_t[RINGBUFFERLEN] {0};
37 CHECK_AND_RETURN_RET_LOG(array_ == nullptr, ERR_DH_AUDIO_FAILED, "Buffer is malloced failed.");
38 writePos_ = 0;
39 readPos_ = 0;
40 tag_ = 0;
41 audioData = new (std::nothrow) uint8_t[DAUDIO_DATA_SIZE] {0};
42 CHECK_AND_RETURN_RET_LOG(audioData == nullptr, ERR_DH_AUDIO_FAILED, "Audio data is malloced failed.");
43 return DH_SUCCESS;
44 }
45
GetFullState()46 bool DaudioRingBuffer::GetFullState()
47 {
48 if ((writePos_ == readPos_) && tag_ == 1) {
49 return true;
50 }
51 return false;
52 }
53
GetEmptyState()54 bool DaudioRingBuffer::GetEmptyState()
55 {
56 if ((writePos_ == readPos_) && tag_ == 0) {
57 return true;
58 }
59 return false;
60 }
61
RingBufferInsert(uint8_t * data,int32_t len)62 int32_t DaudioRingBuffer::RingBufferInsert(uint8_t *data, int32_t len)
63 {
64 int32_t avaliable = RINGBUFFERLEN - writePos_;
65 if (avaliable < len) {
66 int32_t ret = RingBufferInsertOnce(data, avaliable);
67 CHECK_AND_RETURN_RET_LOG(ret != DH_SUCCESS, ERR_DH_AUDIO_FAILED,
68 "write first once error. errorcode: %{public}d", ret);
69 ret = RingBufferInsertOnce(data + avaliable, len - avaliable);
70 CHECK_AND_RETURN_RET_LOG(ret != DH_SUCCESS, ERR_DH_AUDIO_FAILED,
71 "write next once error. errorcode: %{public}d", ret);
72 } else {
73 int32_t ret = RingBufferInsertOnce(data, len);
74 CHECK_AND_RETURN_RET_LOG(ret != DH_SUCCESS, ERR_DH_AUDIO_FAILED,
75 "write only once error. errorcode: %{public}d", ret);
76 }
77 return DH_SUCCESS;
78 }
79
RingBufferInsertOnce(uint8_t * data,int32_t len)80 int32_t DaudioRingBuffer::RingBufferInsertOnce(uint8_t *data, int32_t len)
81 {
82 CHECK_AND_RETURN_RET_LOG(array_ == nullptr, ERR_DH_AUDIO_NULLPTR, "buffer is nullptr.");
83 CHECK_AND_RETURN_RET_LOG(data == nullptr, ERR_DH_AUDIO_NULLPTR, "data is nullptr.");
84 if (len < 0) {
85 DHLOGE("len < 0 error.");
86 return ERR_DH_AUDIO_NULLPTR;
87 }
88 if (GetFullState()) {
89 DHLOGE("buffer is full.");
90 return ERR_DH_AUDIO_FAILED;
91 }
92 int32_t avaliable = RINGBUFFERLEN - writePos_;
93 if (avaliable < len) {
94 DHLOGE("buffer is not avaliable. now avaliable: %{public}d.", avaliable);
95 return ERR_DH_AUDIO_FAILED;
96 }
97 if (writePos_ >= RINGBUFFERLEN || len >= RINGBUFFERLEN) {
98 DHLOGE("writePos_ or len is out of range.");
99 return ERR_DH_AUDIO_FAILED;
100 }
101 int32_t ret = memcpy_s(array_ + writePos_, len, data, len);
102 CHECK_AND_RETURN_RET_LOG(ret!= EOK, ERR_DH_AUDIO_FAILED, "memcpy_s error.");
103 writePos_ = (writePos_ + len) % RINGBUFFERLEN;
104 if (writePos_ == readPos_) {
105 tag_ = 1;
106 }
107 return DH_SUCCESS;
108 }
109
RingBufferGetData(uint8_t * data,int32_t len)110 int32_t DaudioRingBuffer::RingBufferGetData(uint8_t *data, int32_t len)
111 {
112 CHECK_AND_RETURN_RET_LOG(array_ == nullptr, ERR_DH_AUDIO_NULLPTR, "buffer is nullptr.");
113 CHECK_AND_RETURN_RET_LOG(data == nullptr, ERR_DH_AUDIO_NULLPTR, "data is nullptr.");
114 int32_t avaliable = writePos_ - readPos_;
115 if (avaliable >= len) {
116 int32_t ret = RingBufferGetDataOnce(data, len);
117 CHECK_AND_RETURN_RET_LOG(ret!= DH_SUCCESS, ERR_DH_AUDIO_FAILED, "read only once error");
118 } else if (avaliable > 0) {
119 DHLOGI("buffer is not enough. avaliable: %{public}d. len: %{public}d.", avaliable, len);
120 return ERR_DH_AUDIO_FAILED;
121 } else {
122 int32_t firstReadLen = RINGBUFFERLEN - readPos_;
123 if (firstReadLen >= len) {
124 int32_t ret = RingBufferGetDataOnce(data, len);
125 CHECK_AND_RETURN_RET_LOG(ret!= DH_SUCCESS, ERR_DH_AUDIO_FAILED, "read only once error");
126 } else {
127 int32_t ret = RingBufferGetDataOnce(data, firstReadLen);
128 CHECK_AND_RETURN_RET_LOG(ret!= DH_SUCCESS, ERR_DH_AUDIO_FAILED, "read first once error");
129 ret = RingBufferGetDataOnce(data + firstReadLen, len - firstReadLen);
130 CHECK_AND_RETURN_RET_LOG(ret!= DH_SUCCESS, ERR_DH_AUDIO_FAILED, "read next once error");
131 }
132 }
133 return DH_SUCCESS;
134 }
135
RingBufferGetDataOnce(uint8_t * data,int32_t len)136 int32_t DaudioRingBuffer::RingBufferGetDataOnce(uint8_t *data, int32_t len)
137 {
138 CHECK_AND_RETURN_RET_LOG(array_ == nullptr, ERR_DH_AUDIO_NULLPTR, "buffer is nullptr.");
139 CHECK_AND_RETURN_RET_LOG(data == nullptr, ERR_DH_AUDIO_NULLPTR, "data is nullptr.");
140 if (len < 0) {
141 DHLOGE("len < 0 error.");
142 return ERR_DH_AUDIO_NULLPTR;
143 }
144 int32_t avaliable = writePos_ - readPos_;
145 if (GetEmptyState()) {
146 DHLOGE("buffer is empty.");
147 return ERR_DH_AUDIO_FAILED;
148 }
149 if ((avaliable < len && avaliable > 0) ||
150 (avaliable < 0 && RINGBUFFERLEN - readPos_ + writePos_ < len)) {
151 DHLOGE("buffer is not enough.");
152 return ERR_DH_AUDIO_FAILED;
153 }
154 if (readPos_ >= RINGBUFFERLEN || len >= RINGBUFFERLEN) {
155 DHLOGE("readPos_ or len is out of range.");
156 return ERR_DH_AUDIO_FAILED;
157 }
158 int32_t ret = memcpy_s(data, len, array_ + readPos_, len);
159 CHECK_AND_RETURN_RET_LOG(ret != EOK, ERR_DH_AUDIO_FAILED, "memcpy_s error.");
160 readPos_ = (readPos_ + len) % RINGBUFFERLEN;
161 if (readPos_ == writePos_) {
162 tag_ = 0;
163 }
164 return DH_SUCCESS;
165 }
166
CanBufferReadLen(int32_t readLen)167 bool DaudioRingBuffer::CanBufferReadLen(int32_t readLen)
168 {
169 if (GetEmptyState()) {
170 DHLOGD("buffer is empty.");
171 return false;
172 }
173 int32_t aval = writePos_ - readPos_;
174 if ((aval < readLen) && (aval > 0)) {
175 DHLOGD("remain : %{public}d, but not enough readLen: %{public}d", aval, readLen);
176 return false;
177 } else if (aval <= 0) {
178 int32_t avalRead = RINGBUFFERLEN - readPos_ + writePos_;
179 if (avalRead < readLen) {
180 DHLOGD("avalRead : %{public}d, but not enough readLen: %{public}d", avalRead, readLen);
181 return false;
182 }
183 }
184 return true;
185 }
186 } // namespace DistributedHardware
187 } // namespace OHOS