1 /*
2 * Copyright (c) 2021 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 "pcm_iterator.h"
17
18 #include <memory>
19
20 #include "aie_log.h"
21 #include "aie_macros.h"
22 #include "aie_retcode_inner.h"
23 #include "securec.h"
24
25 namespace OHOS {
26 namespace AI {
27 namespace {
28 const int32_t MAX_CACHE_SIZE = 16384; // cache data type is int16_t, so the max size is 32KB
29 }
30
PCMIterator()31 PCMIterator::PCMIterator()
32 : stepSize_(1),
33 windowSize_(1),
34 numCopy_(0),
35 numRealCopy_(0),
36 nextCachePos_(0),
37 maxCacheSize_(0),
38 isInitialized_(false),
39 hasNext_(false)
40 {
41 }
42
~PCMIterator()43 PCMIterator::~PCMIterator()
44 {
45 Release();
46 }
47
Init(size_t stepSize,size_t windowSize)48 int32_t PCMIterator::Init(size_t stepSize, size_t windowSize)
49 {
50 if (isInitialized_) {
51 HILOGE("[PCMIterator]Fail to initialize more than once");
52 return RETCODE_FAILURE;
53 }
54 if (stepSize == 0 || windowSize == 0) {
55 HILOGE("[PCMIterator]StepSize and WindowSize should be greater than zero");
56 return RETCODE_FAILURE;
57 }
58 if (windowSize < stepSize) {
59 HILOGE("[PCMIterator]StepSize can not be greater than WindowSize");
60 return RETCODE_FAILURE;
61 }
62 stepSize_ = stepSize;
63 windowSize_ = windowSize;
64 size_t maxNumRemain = windowSize_ - 1;
65 size_t maxNumSlide = (maxNumRemain - 1) / stepSize_;
66 maxCacheSize_ = maxNumSlide * stepSize_ + windowSize_;
67 if (maxCacheSize_ > MAX_CACHE_SIZE) {
68 HILOGE("[PCMIterator]The required memory size is larger than MAX_CACHE_SIZE[%zu]", MAX_CACHE_SIZE);
69 return RETCODE_FAILURE;
70 }
71 AIE_NEW(pcmCache_.data, int16_t[maxCacheSize_]);
72 if (pcmCache_.data == nullptr) {
73 HILOGE("[PCMIterator]Fail to allocate memory for pcm cache");
74 return RETCODE_OUT_OF_MEMORY;
75 }
76 isInitialized_ = true;
77 return RETCODE_SUCCESS;
78 }
79
Release()80 void PCMIterator::Release()
81 {
82 if (isInitialized_) {
83 AIE_DELETE_ARRAY(pcmCache_.data);
84 Reset();
85 isInitialized_ = false;
86 }
87 }
88
SetInput(const Array<int16_t> & input)89 int32_t PCMIterator::SetInput(const Array<int16_t> &input)
90 {
91 if (!isInitialized_) {
92 HILOGE("[PCMIterator]The iterator has not been initialized");
93 return RETCODE_FAILURE;
94 }
95 if (HasNext()) {
96 HILOGE("[PCMIterator]Reset the iterator, then set input again");
97 return RETCODE_FAILURE;
98 }
99 if (input.data == nullptr || input.size == 0) {
100 HILOGE("[PCMIterator]The input data is nullptr or its size is zero");
101 return RETCODE_NULL_PARAM;
102 }
103 return Prepare(input);
104 }
105
Prepare(const Array<int16_t> & input)106 int32_t PCMIterator::Prepare(const Array<int16_t> &input)
107 {
108 // copy some data from the input to cache
109 numRealCopy_ = 0;
110 if (numCopy_ > 0) {
111 numRealCopy_ = (numCopy_ > input.size) ? input.size : numCopy_;
112 size_t realCacheSize = nextCachePos_ + pcmCache_.size;
113 errno_t retCode = memcpy_s(pcmCache_.data + realCacheSize, (maxCacheSize_ - realCacheSize) * sizeof(int16_t),
114 input.data, numRealCopy_ * sizeof(int16_t));
115 if (retCode != EOK) {
116 HILOGE("[PCMIterator]Fail to copy data from input to pcm cache");
117 return RETCODE_MEMORY_COPY_FAILURE;
118 }
119 pcmCache_.size += numRealCopy_;
120 numCopy_ -= numRealCopy_;
121 if (numCopy_ == 0) {
122 int32_t diff = numRealCopy_ - windowSize_ + stepSize_;
123 if (diff > 0) {
124 pcmData_.data = input.data + diff;
125 pcmData_.size = input.size - diff;
126 } else {
127 pcmData_ = input;
128 }
129 } else {
130 pcmData_ = {0};
131 }
132 } else {
133 pcmData_ = input;
134 }
135 // update hasNext_
136 if (windowSize_ <= pcmCache_.size || windowSize_ <= pcmData_.size) {
137 hasNext_ = true;
138 return RETCODE_SUCCESS;
139 }
140 // if pcm cache is empty and input size is larger than zero but less than window size, then move data to cache
141 if (pcmCache_.size == 0 && pcmData_.size > 0 && pcmData_.size < windowSize_) {
142 return MoveDataToCache(pcmData_);
143 }
144 return RETCODE_SUCCESS;
145 }
146
Reset()147 void PCMIterator::Reset()
148 {
149 numCopy_ = 0;
150 numRealCopy_ = 0;
151 nextCachePos_ = 0;
152 pcmCache_ = {0};
153 pcmData_ = {0};
154 hasNext_ = false;
155 }
156
HasNext()157 bool PCMIterator::HasNext()
158 {
159 // copy data from pcmCache_ or pcmData_ to pcmCache_
160 if (nextCachePos_ > 0 && numCopy_ == 0 && pcmCache_.size > 0 && pcmCache_.size < windowSize_) {
161 Array<int16_t> data = {
162 .data = pcmCache_.data + nextCachePos_,
163 .size = pcmCache_.size
164 };
165 MoveDataToCache(data);
166 Prepare(pcmData_);
167 } else {
168 if (pcmCache_.size == 0 && pcmData_.size > 0 && pcmData_.size < windowSize_) {
169 MoveDataToCache(pcmData_);
170 pcmData_.size = 0;
171 }
172 }
173 return hasNext_;
174 }
175
Next()176 Array<int16_t> PCMIterator::Next()
177 {
178 Array<int16_t> output = {0};
179 if (!HasNext()) {
180 return output;
181 }
182 if (windowSize_ <= pcmCache_.size) {
183 output.data = pcmCache_.data + nextCachePos_;
184 output.size = windowSize_;
185 nextCachePos_ += stepSize_;
186 pcmCache_.size -= stepSize_;
187 if (numCopy_ == 0 && pcmCache_.size < windowSize_) {
188 int32_t diff = windowSize_ - stepSize_ - numRealCopy_;
189 pcmCache_.size = (diff > 0) ? diff : 0;
190 }
191 } else {
192 if (windowSize_ <= pcmData_.size) {
193 output.data = pcmData_.data;
194 output.size = windowSize_;
195 pcmData_.data += stepSize_;
196 pcmData_.size -= stepSize_;
197 }
198 }
199 if (pcmCache_.size < windowSize_ && pcmData_.size < windowSize_) {
200 hasNext_ = false;
201 }
202 return output;
203 }
204
MoveDataToCache(const Array<int16_t> & input)205 int32_t PCMIterator::MoveDataToCache(const Array<int16_t> &input)
206 {
207 errno_t retCode = memcpy_s(pcmCache_.data, maxCacheSize_ * sizeof(int16_t),
208 input.data, input.size * sizeof(int16_t));
209 if (retCode != EOK) {
210 HILOGE("[PCMIterator]Fail to move data to cache");
211 return RETCODE_MEMORY_COPY_FAILURE;
212 }
213 pcmCache_.size = input.size;
214 nextCachePos_ = 0;
215 size_t numSlide = (pcmCache_.size - 1) / stepSize_;
216 numCopy_ = numSlide * stepSize_ + windowSize_ - pcmCache_.size; // data to be copied
217 return RETCODE_SUCCESS;
218 }
219 } // namespace AI
220 } // namespace OHOS