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