1 /*
2 * Copyright (c) 2023 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 "oh_audio_buffer.h"
17
18 #include <cinttypes>
19 #include <climits>
20 #include <memory>
21 #include <sys/mman.h>
22 #include "ashmem.h"
23
24 #include "audio_errors.h"
25 #include "audio_log.h"
26
27 namespace OHOS {
28 namespace AudioStandard {
29 namespace {
30 static const int INVALID_FD = -1;
31 static const size_t MAX_MMAP_BUFFER_SIZE = 10 * 1024 * 1024; // 10M
32 static const std::string STATUS_INFO_BUFFER = "status_info_buffer";
33 }
34 class AudioSharedMemoryImpl : public AudioSharedMemory {
35 public:
36 uint8_t *GetBase() override;
37 size_t GetSize() override;
38 int GetFd() override;
39 std::string GetName() override;
40
41 AudioSharedMemoryImpl(size_t size, const std::string &name);
42
43 AudioSharedMemoryImpl(int fd, size_t size, const std::string &name);
44
45 ~AudioSharedMemoryImpl();
46
47 int32_t Init();
48
49 private:
50 void Close();
51
52 uint8_t *base_;
53 int fd_;
54 size_t size_;
55 std::string name_;
56 };
57
AudioSharedMemoryImpl(size_t size,const std::string & name)58 AudioSharedMemoryImpl::AudioSharedMemoryImpl(size_t size, const std::string &name)
59 : base_(nullptr), fd_(INVALID_FD), size_(size), name_(name)
60 {
61 AUDIO_INFO_LOG("AudioSharedMemory ctor with size: %{public}zu name: %{public}s", size_, name_.c_str());
62 }
63
AudioSharedMemoryImpl(int fd,size_t size,const std::string & name)64 AudioSharedMemoryImpl::AudioSharedMemoryImpl(int fd, size_t size, const std::string &name)
65 : base_(nullptr), fd_(dup(fd)), size_(size), name_(name)
66 {
67 AUDIO_INFO_LOG("AudioSharedMemory ctor with fd %{public}d size %{public}zu name %{public}s", fd_, size_,
68 name_.c_str());
69 }
70
~AudioSharedMemoryImpl()71 AudioSharedMemoryImpl::~AudioSharedMemoryImpl()
72 {
73 AUDIO_INFO_LOG(" %{public}s enter ~AudioSharedMemoryImpl()", name_.c_str());
74 Close();
75 }
76
Init()77 int32_t AudioSharedMemoryImpl::Init()
78 {
79 CHECK_AND_RETURN_RET_LOG((size_ > 0 && size_ < MAX_MMAP_BUFFER_SIZE), ERR_INVALID_PARAM,
80 "Init falied: size out of range: %{public}zu", size_);
81 bool isFromRemote = false;
82 if (fd_ > 0) {
83 isFromRemote = true;
84 int size = AshmemGetSize(fd_); // hdi fd may not support
85 if (size < 0 || static_cast<size_t>(size) != size_) {
86 AUDIO_WARNING_LOG("AshmemGetSize faied, get %{public}d", size);
87 }
88 } else {
89 fd_ = AshmemCreate(name_.c_str(), size_);
90 CHECK_AND_RETURN_RET_LOG((fd_ > 0), ERR_OPERATION_FAILED, "Init falied: fd %{public}d", fd_);
91 }
92
93 void *addr = mmap(nullptr, size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0);
94 CHECK_AND_RETURN_RET_LOG(addr != MAP_FAILED, ERR_OPERATION_FAILED, "Init falied: fd %{public}d size %{public}zu",
95 fd_, size_);
96 base_ = static_cast<uint8_t *>(addr);
97 AUDIO_INFO_LOG("Init %{public}s <%{public}s> done.", (isFromRemote ? "remote" : "local"),
98 name_.c_str());
99 return SUCCESS;
100 }
101
Close()102 void AudioSharedMemoryImpl::Close()
103 {
104 if (base_ != nullptr) {
105 (void)munmap(base_, size_);
106 base_ = nullptr;
107 size_ = 0;
108 AUDIO_INFO_LOG("%{public}s munmap done", name_.c_str());
109 }
110
111 if (fd_ > 0) {
112 (void)close(fd_);
113 fd_ = INVALID_FD;
114 AUDIO_INFO_LOG("%{public}s close fd done", name_.c_str());
115 }
116 }
117
GetBase()118 uint8_t *AudioSharedMemoryImpl::GetBase()
119 {
120 return base_;
121 }
122
GetSize()123 size_t AudioSharedMemoryImpl::GetSize()
124 {
125 return size_;
126 }
127
GetName()128 std::string AudioSharedMemoryImpl::GetName()
129 {
130 return name_;
131 }
132
GetFd()133 int AudioSharedMemoryImpl::GetFd()
134 {
135 return fd_;
136 }
137
CreateFormLocal(size_t size,const std::string & name)138 std::shared_ptr<AudioSharedMemory> AudioSharedMemory::CreateFormLocal(size_t size, const std::string &name)
139 {
140 std::shared_ptr<AudioSharedMemoryImpl> sharedMemory = std::make_shared<AudioSharedMemoryImpl>(size, name);
141 if (sharedMemory->Init() != SUCCESS) {
142 AUDIO_ERR_LOG("CreateFormLocal failed");
143 return nullptr;
144 }
145 return sharedMemory;
146 }
147
CreateFromRemote(int fd,size_t size,const std::string & name)148 std::shared_ptr<AudioSharedMemory> AudioSharedMemory::CreateFromRemote(int fd, size_t size, const std::string &name)
149 {
150 int minfd = 2; // ignore stdout, stdin and stderr.
151 CHECK_AND_RETURN_RET_LOG(fd > minfd, nullptr, "CreateFromRemote failed: invalid fd: %{public}d", fd);
152 std::shared_ptr<AudioSharedMemoryImpl> sharedMemory = std::make_shared<AudioSharedMemoryImpl>(fd, size, name);
153 if (sharedMemory->Init() != SUCCESS) {
154 AUDIO_ERR_LOG("CreateFromRemote failed");
155 return nullptr;
156 }
157 close(fd);
158 return sharedMemory;
159 }
160
WriteToParcel(const std::shared_ptr<AudioSharedMemory> & memory,MessageParcel & parcel)161 int32_t AudioSharedMemory::WriteToParcel(const std::shared_ptr<AudioSharedMemory> &memory, MessageParcel &parcel)
162 {
163 std::shared_ptr<AudioSharedMemoryImpl> memoryImpl = std::static_pointer_cast<AudioSharedMemoryImpl>(memory);
164 CHECK_AND_RETURN_RET_LOG(memoryImpl != nullptr, ERR_OPERATION_FAILED, "invalid pointer.");
165
166 int32_t fd = memoryImpl->GetFd();
167
168 size_t size = memoryImpl->GetSize();
169 CHECK_AND_RETURN_RET_LOG((size > 0 && size < MAX_MMAP_BUFFER_SIZE), ERR_INVALID_PARAM,
170 "invalid size: %{public}zu", size);
171 uint64_t sizeTmp = static_cast<uint64_t>(size);
172
173 std::string name = memoryImpl->GetName();
174
175 parcel.WriteFileDescriptor(fd);
176 parcel.WriteUint64(sizeTmp);
177 parcel.WriteString(name);
178
179 return SUCCESS;
180 }
181
ReadFromParcel(MessageParcel & parcel)182 std::shared_ptr<AudioSharedMemory> AudioSharedMemory::ReadFromParcel(MessageParcel &parcel)
183 {
184 int fd = parcel.ReadFileDescriptor();
185
186 uint64_t sizeTmp = parcel.ReadUint64();
187 CHECK_AND_RETURN_RET_LOG((sizeTmp > 0 && sizeTmp < MAX_MMAP_BUFFER_SIZE), nullptr, "failed with invalid size");
188 size_t size = static_cast<size_t>(sizeTmp);
189
190 std::string name = parcel.ReadString();
191
192 std::shared_ptr<AudioSharedMemory> memory = AudioSharedMemory::CreateFromRemote(fd, size, name);
193 if (memory == nullptr || memory->GetBase() == nullptr) {
194 AUDIO_ERR_LOG("ReadFromParcel failed");
195 memory = nullptr;
196 }
197 return memory;
198 }
199
200 // OHAudioBuffer
OHAudioBuffer(AudioBufferHolder bufferHolder,uint32_t totalSizeInFrame,uint32_t spanSizeInFrame,uint32_t byteSizePerFrame)201 OHAudioBuffer::OHAudioBuffer(AudioBufferHolder bufferHolder, uint32_t totalSizeInFrame, uint32_t spanSizeInFrame,
202 uint32_t byteSizePerFrame) : bufferHolder_(bufferHolder), totalSizeInFrame_(totalSizeInFrame),
203 spanSizeInFrame_(spanSizeInFrame), byteSizePerFrame_(byteSizePerFrame), audioMode_(AUDIO_MODE_PLAYBACK),
204 basicBufferInfo_(nullptr), spanInfoList_(nullptr)
205 {
206 AUDIO_INFO_LOG("ctor with holder:%{public}d mode:%{public}d", bufferHolder_, audioMode_);
207 }
208
~OHAudioBuffer()209 OHAudioBuffer::~OHAudioBuffer()
210 {
211 AUDIO_INFO_LOG("enter ~OHAudioBuffer()");
212 basicBufferInfo_ = nullptr;
213 spanInfoList_ = nullptr;
214 spanConut_ = 0;
215 }
216
SizeCheck()217 int32_t OHAudioBuffer::SizeCheck()
218 {
219 if (totalSizeInFrame_ < spanSizeInFrame_ || totalSizeInFrame_ % spanSizeInFrame_ != 0 ||
220 totalSizeInFrame_ > UINT_MAX / byteSizePerFrame_) {
221 AUDIO_ERR_LOG("failed: invalid size.");
222 return ERR_INVALID_PARAM;
223 }
224 totalSizeInByte_ = totalSizeInFrame_ * byteSizePerFrame_;
225 // data buffer size check
226 CHECK_AND_RETURN_RET_LOG((totalSizeInByte_ < MAX_MMAP_BUFFER_SIZE), ERR_INVALID_PARAM, "too large totalSizeInByte "
227 "%{public}zu", totalSizeInByte_);
228
229 spanSizeInByte_ = spanSizeInFrame_ * byteSizePerFrame_;
230 spanConut_ = totalSizeInFrame_ / spanSizeInFrame_;
231
232 return SUCCESS;
233 }
234
Init(int dataFd,int infoFd)235 int32_t OHAudioBuffer::Init(int dataFd, int infoFd)
236 {
237 AUDIO_INFO_LOG("Init with dataFd %{public}d, infoFd %{public}d, bufferSize %{public}d, spanSize %{public}d,"
238 " byteSizePerFrame %{public}d", dataFd, infoFd, totalSizeInFrame_, spanSizeInFrame_, byteSizePerFrame_);
239
240 int32_t ret = SizeCheck();
241 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_INVALID_PARAM, "failed: invalid size.");
242
243 // init for statusInfoBuffer
244 size_t statusInfoSize = sizeof(BasicBufferInfo) + spanConut_ * sizeof(SpanInfo);
245 if (infoFd != INVALID_FD && bufferHolder_ == AUDIO_CLIENT) {
246 statusInfoMem_ = AudioSharedMemory::CreateFromRemote(infoFd, statusInfoSize, STATUS_INFO_BUFFER);
247 } else {
248 statusInfoMem_ = AudioSharedMemory::CreateFormLocal(statusInfoSize, STATUS_INFO_BUFFER);
249 }
250 CHECK_AND_RETURN_RET_LOG(statusInfoMem_ != nullptr, ERR_OPERATION_FAILED, "BasicBufferInfo mmap failed.");
251
252 // init for dataBuffer
253 if (dataFd == INVALID_FD && bufferHolder_ == AUDIO_SERVER_SHARED) {
254 dataMem_ = AudioSharedMemory::CreateFormLocal(totalSizeInByte_, "server_client_buffer");
255 } else {
256 std::string memoryDesc = (bufferHolder_ == AUDIO_SERVER_ONLY ? "server_hdi_buffer" : "server_client_buffer");
257 dataMem_ = AudioSharedMemory::CreateFromRemote(dataFd, totalSizeInByte_, memoryDesc);
258 }
259 CHECK_AND_RETURN_RET_LOG(dataMem_ != nullptr, ERR_OPERATION_FAILED, "dataMem_ mmap failed.");
260
261 dataBase_ = dataMem_->GetBase();
262
263 basicBufferInfo_ = reinterpret_cast<BasicBufferInfo *>(statusInfoMem_->GetBase());
264 spanInfoList_ = reinterpret_cast<SpanInfo *>(statusInfoMem_->GetBase() + sizeof(BasicBufferInfo));
265
266 // As basicBufferInfo_ is created from memory, we need to set the value with 0.
267 basicBufferInfo_->basePosInFrame.store(0);
268 basicBufferInfo_->curReadFrame.store(0);
269 basicBufferInfo_->curWriteFrame.store(0);
270
271 if (bufferHolder_ == AUDIO_SERVER_SHARED || bufferHolder_ == AUDIO_SERVER_ONLY) {
272 basicBufferInfo_->handlePos.store(0);
273 basicBufferInfo_->handleTime.store(0);
274 basicBufferInfo_->totalSizeInFrame = totalSizeInFrame_;
275 basicBufferInfo_->spanSizeInFrame = spanSizeInFrame_;
276 basicBufferInfo_->byteSizePerFrame = byteSizePerFrame_;
277 basicBufferInfo_->streamStatus.store(STREAM_INVALID);
278
279 for (uint32_t i = 0; i < spanConut_; i++) {
280 spanInfoList_[i].spanStatus.store(SPAN_INVALID);
281 }
282 }
283
284 AUDIO_INFO_LOG("Init done.");
285 return SUCCESS;
286 }
287
CreateFormLocal(uint32_t totalSizeInFrame,uint32_t spanSizeInFrame,uint32_t byteSizePerFrame)288 std::shared_ptr<OHAudioBuffer> OHAudioBuffer::CreateFormLocal(uint32_t totalSizeInFrame, uint32_t spanSizeInFrame,
289 uint32_t byteSizePerFrame)
290 {
291 AUDIO_INFO_LOG("CreateFormLocal:totalSizeInFrame %{public}d, spanSizeInFrame %{public}d, byteSizePerFrame"
292 " %{public}d", totalSizeInFrame, spanSizeInFrame, byteSizePerFrame);
293
294 AudioBufferHolder bufferHolder = AudioBufferHolder::AUDIO_SERVER_SHARED;
295 std::shared_ptr<OHAudioBuffer> buffer = std::make_shared<OHAudioBuffer>(bufferHolder, totalSizeInFrame,
296 spanSizeInFrame, byteSizePerFrame);
297 if (buffer->Init(INVALID_FD, INVALID_FD) != SUCCESS) {
298 AUDIO_ERR_LOG("failed to init.");
299 return nullptr;
300 }
301 return buffer;
302 }
303
CreateFromRemote(uint32_t totalSizeInFrame,uint32_t spanSizeInFrame,uint32_t byteSizePerFrame,int dataFd,int infoFd)304 std::shared_ptr<OHAudioBuffer> OHAudioBuffer::CreateFromRemote(uint32_t totalSizeInFrame, uint32_t spanSizeInFrame,
305 uint32_t byteSizePerFrame, int dataFd, int infoFd)
306 {
307 AUDIO_INFO_LOG("CreateFromRemote: dataFd %{public}d, infoFd %{public}d", dataFd, infoFd);
308
309 int minfd = 2; // ignore stdout, stdin and stderr.
310 CHECK_AND_RETURN_RET_LOG(dataFd > minfd, nullptr, "CreateFromRemote invalid dataFd: %{public}d", dataFd);
311
312 AudioBufferHolder bufferHolder = AUDIO_SERVER_ONLY;
313 if (infoFd != INVALID_FD) {
314 CHECK_AND_RETURN_RET_LOG(infoFd > minfd, nullptr, "CreateFromRemote invalid infoFd: %{public}d", infoFd);
315 bufferHolder = AUDIO_CLIENT;
316 }
317 std::shared_ptr<OHAudioBuffer> buffer = std::make_shared<OHAudioBuffer>(bufferHolder, totalSizeInFrame,
318 spanSizeInFrame, byteSizePerFrame);
319 if (buffer->Init(dataFd, infoFd) != SUCCESS) {
320 AUDIO_ERR_LOG("failed to init.");
321 return nullptr;
322 }
323 return buffer;
324 }
325
WriteToParcel(const std::shared_ptr<OHAudioBuffer> & buffer,MessageParcel & parcel)326 int32_t OHAudioBuffer::WriteToParcel(const std::shared_ptr<OHAudioBuffer> &buffer, MessageParcel &parcel)
327 {
328 AUDIO_INFO_LOG("WriteToParcel start.");
329 AudioBufferHolder bufferHolder = buffer->GetBufferHolder();
330 if (bufferHolder != AudioBufferHolder::AUDIO_SERVER_SHARED) {
331 AUDIO_ERR_LOG("buffer holder error:%{public}d", bufferHolder);
332 return ERROR_INVALID_PARAM;
333 }
334
335 parcel.WriteUint32(bufferHolder);
336 parcel.WriteUint32(buffer->totalSizeInFrame_);
337 parcel.WriteUint32(buffer->spanSizeInFrame_);
338 parcel.WriteUint32(buffer->byteSizePerFrame_);
339
340 parcel.WriteFileDescriptor(buffer->dataMem_->GetFd());
341 parcel.WriteFileDescriptor(buffer->statusInfoMem_->GetFd());
342
343 AUDIO_INFO_LOG("WriteToParcel done.");
344 return SUCCESS;
345 }
346
ReadFromParcel(MessageParcel & parcel)347 std::shared_ptr<OHAudioBuffer> OHAudioBuffer::ReadFromParcel(MessageParcel &parcel)
348 {
349 AUDIO_INFO_LOG("ReadFromParcel start.");
350 uint32_t holder = parcel.ReadUint32();
351 AudioBufferHolder bufferHolder = static_cast<AudioBufferHolder>(holder);
352 if (bufferHolder != AudioBufferHolder::AUDIO_SERVER_SHARED) {
353 AUDIO_ERR_LOG("buffer holder error:%{public}d", bufferHolder);
354 return nullptr;
355 }
356 uint32_t totalSizeInFrame = parcel.ReadUint32();
357 uint32_t spanSizeInFrame = parcel.ReadUint32();
358 uint32_t byteSizePerFrame = parcel.ReadUint32();
359
360 int dataFd = parcel.ReadFileDescriptor();
361 int infoFd = parcel.ReadFileDescriptor();
362
363 std::shared_ptr<OHAudioBuffer> buffer = OHAudioBuffer::CreateFromRemote(totalSizeInFrame, spanSizeInFrame,
364 byteSizePerFrame, dataFd, infoFd);
365 if (buffer == nullptr) {
366 AUDIO_ERR_LOG("ReadFromParcel failed.");
367 } else if (totalSizeInFrame != buffer->basicBufferInfo_->totalSizeInFrame ||
368 spanSizeInFrame != buffer->basicBufferInfo_->spanSizeInFrame ||
369 byteSizePerFrame != buffer->basicBufferInfo_->byteSizePerFrame) {
370 AUDIO_WARNING_LOG("ReadFromParcel data in shared memory diff.");
371 } else {
372 AUDIO_INFO_LOG("Read some data done.");
373 }
374 close(dataFd);
375 close(infoFd);
376 AUDIO_INFO_LOG("ReadFromParcel done.");
377 return buffer;
378 }
379
GetBufferHolder()380 AudioBufferHolder OHAudioBuffer::GetBufferHolder()
381 {
382 return bufferHolder_;
383 }
384
GetSizeParameter(uint32_t & totalSizeInFrame,uint32_t & spanSizeInFrame,uint32_t & byteSizePerFrame)385 int32_t OHAudioBuffer::GetSizeParameter(uint32_t &totalSizeInFrame, uint32_t &spanSizeInFrame,
386 uint32_t &byteSizePerFrame)
387 {
388 totalSizeInFrame = totalSizeInFrame_;
389 spanSizeInFrame = spanSizeInFrame_;
390 byteSizePerFrame = byteSizePerFrame_;
391
392 return SUCCESS;
393 }
394
GetStreamStatus()395 std::atomic<StreamStatus> *OHAudioBuffer::GetStreamStatus()
396 {
397 return &basicBufferInfo_->streamStatus;
398 }
399
GetHandleInfo(uint64_t & frames,int64_t & nanoTime)400 bool OHAudioBuffer::GetHandleInfo(uint64_t &frames, int64_t &nanoTime)
401 {
402 if (basicBufferInfo_ == nullptr) {
403 AUDIO_ERR_LOG("Get nullptr, failed to GetHandleInfo.");
404 return false;
405 }
406 frames = basicBufferInfo_->handlePos.load();
407 nanoTime = basicBufferInfo_->handleTime.load();
408 return true;
409 }
410
SetHandleInfo(uint64_t frames,int64_t nanoTime)411 void OHAudioBuffer::SetHandleInfo(uint64_t frames, int64_t nanoTime)
412 {
413 basicBufferInfo_->handlePos.store(frames);
414 basicBufferInfo_->handleTime.store(nanoTime);
415 }
416
GetAvailableDataFrames()417 int32_t OHAudioBuffer::GetAvailableDataFrames()
418 {
419 int32_t result = -1; // failed
420 uint64_t write = basicBufferInfo_->curWriteFrame.load();
421 uint64_t read = basicBufferInfo_->curReadFrame.load();
422 CHECK_AND_RETURN_RET_LOG(write >= read, result, "invalid write and read position.");
423 uint32_t temp = write - read;
424 if (temp > INT32_MAX || temp > totalSizeInFrame_) {
425 AUDIO_ERR_LOG("failed to GetAvailableDataFrames.");
426 return result;
427 }
428 result = static_cast<int32_t>(totalSizeInFrame_ - temp);
429 return result;
430 }
431
ResetCurReadWritePos(uint64_t readFrame,uint64_t writeFrame)432 int32_t OHAudioBuffer::ResetCurReadWritePos(uint64_t readFrame, uint64_t writeFrame)
433 {
434 if (readFrame > writeFrame || writeFrame - readFrame >= totalSizeInFrame_) {
435 AUDIO_ERR_LOG("Invalid read or write position:read%{public}" PRIu64" write%{public}" PRIu64".",
436 readFrame, writeFrame);
437 return ERR_INVALID_PARAM;
438 }
439 uint64_t tempBase = (readFrame / totalSizeInFrame_) * totalSizeInFrame_;
440 basicBufferInfo_->basePosInFrame.store(tempBase);
441 basicBufferInfo_->curWriteFrame.store(writeFrame);
442 basicBufferInfo_->curReadFrame.store(readFrame);
443
444 AUDIO_INFO_LOG("Reset position:read%{public}" PRIu64" write%{public}" PRIu64".", readFrame, writeFrame);
445 return SUCCESS;
446 }
447
GetCurWriteFrame()448 uint64_t OHAudioBuffer::GetCurWriteFrame()
449 {
450 return basicBufferInfo_->curWriteFrame.load();
451 }
452
GetCurReadFrame()453 uint64_t OHAudioBuffer::GetCurReadFrame()
454 {
455 return basicBufferInfo_->curReadFrame.load();
456 }
457
SetCurWriteFrame(uint64_t writeFrame)458 int32_t OHAudioBuffer::SetCurWriteFrame(uint64_t writeFrame)
459 {
460 uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
461 uint64_t oldWritePos = basicBufferInfo_->curWriteFrame.load();
462 if (writeFrame == oldWritePos) {
463 return SUCCESS;
464 }
465 CHECK_AND_RETURN_RET_LOG(writeFrame > oldWritePos, ERR_INVALID_PARAM, "Too small writeFrame:%{public}" PRIu64".",
466 writeFrame);
467
468 uint64_t deltaToBase = writeFrame - basePos; // writeFrame % spanSizeInFrame_ --> 0
469 CHECK_AND_RETURN_RET_LOG(deltaToBase / spanSizeInFrame_ * spanSizeInFrame_ == deltaToBase, ERR_INVALID_PARAM,
470 "Invalid deltaToBase, writeFrame:%{public}" PRIu64".", writeFrame);
471
472 // check new pos in range: base ~ base + 2*total
473 if (deltaToBase >= (totalSizeInFrame_ + totalSizeInFrame_)) {
474 AUDIO_ERR_LOG("Invalid writeFrame %{public}" PRIu64" out of base range.", writeFrame);
475 return ERR_INVALID_PARAM;
476 }
477
478 // check new pos in (read + cache) range: read ~ read + totalSize - 1*spanSize
479 uint64_t curRead = basicBufferInfo_->curReadFrame.load();
480 if (writeFrame < curRead || writeFrame - curRead > totalSizeInFrame_ - spanSizeInFrame_) {
481 AUDIO_ERR_LOG("Invalid writeFrame %{public}" PRIu64" out of cache range, curRead %{public}" PRIu64".",
482 writeFrame, curRead);
483 return ERR_INVALID_PARAM;
484 }
485
486 if (writeFrame - oldWritePos != spanSizeInFrame_) {
487 AUDIO_WARNING_LOG("Not advanced in one step. newWritePos %{public}" PRIu64", oldWritePos %{public}" PRIu64".",
488 writeFrame, oldWritePos);
489 }
490
491 basicBufferInfo_->curWriteFrame.store(writeFrame);
492 return SUCCESS;
493 }
494
SetCurReadFrame(uint64_t readFrame)495 int32_t OHAudioBuffer::SetCurReadFrame(uint64_t readFrame)
496 {
497 uint64_t oldBasePos = basicBufferInfo_->basePosInFrame.load();
498 uint64_t oldReadPos = basicBufferInfo_->curReadFrame.load();
499 if (readFrame == oldReadPos) {
500 return SUCCESS;
501 }
502
503 // new read position should not be bigger than write position or less than old read position
504 if (readFrame < oldReadPos || readFrame > basicBufferInfo_->curWriteFrame.load()) {
505 AUDIO_ERR_LOG("Invalid readFrame %{public}" PRIu64".", readFrame);
506 return ERR_INVALID_PARAM;
507 }
508
509 uint64_t deltaToBase = readFrame - oldBasePos;
510 CHECK_AND_RETURN_RET_LOG((deltaToBase / spanSizeInFrame_ * spanSizeInFrame_) == deltaToBase,
511 ERR_INVALID_PARAM, "Invalid deltaToBase, readFrame %{public}" PRIu64", oldBasePos %{public}" PRIu64".",
512 readFrame, oldBasePos);
513
514 if (deltaToBase > totalSizeInFrame_) {
515 AUDIO_ERR_LOG("Invalid readFrame:%{public}" PRIu64", out of range.", readFrame);
516 return ERR_INVALID_PARAM;
517 } else if (deltaToBase == totalSizeInFrame_) {
518 basicBufferInfo_->basePosInFrame.store(oldBasePos + totalSizeInFrame_); // move base position
519 }
520
521 if (readFrame - oldReadPos != spanSizeInFrame_) {
522 AUDIO_WARNING_LOG("Not advanced in one step. newReadPos %{public}" PRIu64", oldReadPos %{public}" PRIu64".",
523 readFrame, oldReadPos);
524 }
525
526 basicBufferInfo_->curReadFrame.store(readFrame);
527 return SUCCESS;
528 }
529
GetBufferByFrame(uint64_t posInFrame,BufferDesc & bufferDesc)530 int32_t OHAudioBuffer::GetBufferByFrame(uint64_t posInFrame, BufferDesc &bufferDesc)
531 {
532 uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
533 uint64_t maxDelta = 2 * totalSizeInFrame_; // 0 ~ 2*totalSizeInFrame_
534 if (posInFrame < basePos || posInFrame - basePos >= maxDelta) {
535 AUDIO_ERR_LOG("Invalid position:%{public}" PRIu64".", posInFrame);
536 return ERR_INVALID_PARAM;
537 }
538 uint32_t deltaToBase = posInFrame - basePos;
539 if (deltaToBase >= totalSizeInFrame_) {
540 deltaToBase -= totalSizeInFrame_;
541 }
542 CHECK_AND_RETURN_RET_LOG(deltaToBase < UINT32_MAX && deltaToBase < totalSizeInFrame_, ERR_INVALID_PARAM,
543 "invalid deltaToBase, posInFrame %{public}" PRIu64" basePos %{public}" PRIu64".", posInFrame, basePos);
544 deltaToBase = (deltaToBase / spanSizeInFrame_) * spanSizeInFrame_;
545 size_t offset = deltaToBase * byteSizePerFrame_;
546 CHECK_AND_RETURN_RET_LOG(offset < totalSizeInByte_, ERR_INVALID_PARAM, "invalid deltaToBase:%{public}zu", offset);
547
548 bufferDesc.buffer = dataBase_ + offset;
549 bufferDesc.bufLength = spanSizeInByte_;
550 bufferDesc.dataLength = spanSizeInByte_;
551
552 return SUCCESS;
553 }
554
GetWriteBuffer(uint64_t writePosInFrame,BufferDesc & bufferDesc)555 int32_t OHAudioBuffer::GetWriteBuffer(uint64_t writePosInFrame, BufferDesc &bufferDesc)
556 {
557 uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
558 uint64_t readPos = basicBufferInfo_->curReadFrame.load();
559 uint64_t maxWriteDelta = 2 * totalSizeInFrame_; // 0 ~ 2*totalSizeInFrame_
560 if (writePosInFrame < basePos || writePosInFrame - basePos >= maxWriteDelta || writePosInFrame < readPos) {
561 AUDIO_ERR_LOG("Invalid write position:%{public}" PRIu64".", writePosInFrame);
562 return ERR_INVALID_PARAM;
563 }
564 return GetBufferByFrame(writePosInFrame, bufferDesc);
565 }
566
GetReadbuffer(uint64_t readPosInFrame,BufferDesc & bufferDesc)567 int32_t OHAudioBuffer::GetReadbuffer(uint64_t readPosInFrame, BufferDesc &bufferDesc)
568 {
569 uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
570 if (readPosInFrame < basePos || readPosInFrame - basePos >= totalSizeInFrame_) {
571 AUDIO_ERR_LOG("Invalid read position:%{public}" PRIu64".", readPosInFrame);
572 return ERR_INVALID_PARAM;
573 }
574 return GetBufferByFrame(readPosInFrame, bufferDesc);
575 }
576
GetSpanInfo(uint64_t posInFrame)577 SpanInfo *OHAudioBuffer::GetSpanInfo(uint64_t posInFrame)
578 {
579 uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
580 uint64_t maxPos = basePos + totalSizeInFrame_ + totalSizeInFrame_;
581 CHECK_AND_RETURN_RET_LOG((basePos <= posInFrame && posInFrame < maxPos), nullptr, "posInFrame %{public}" PRIu64" "
582 "out of range, basePos %{public}" PRIu64", maxPos %{public}" PRIu64".", posInFrame, basePos, maxPos);
583
584 uint64_t deltaToBase = posInFrame - basePos;
585 if (deltaToBase >= totalSizeInFrame_) {
586 deltaToBase -= totalSizeInFrame_;
587 }
588 CHECK_AND_RETURN_RET_LOG(deltaToBase < UINT32_MAX && deltaToBase < totalSizeInFrame_, nullptr, "invalid "
589 "deltaToBase, posInFrame %{public}" PRIu64" basePos %{public}" PRIu64".", posInFrame, basePos);
590 uint32_t spanIndex = deltaToBase / spanSizeInFrame_;
591 CHECK_AND_RETURN_RET_LOG(spanIndex < spanConut_, nullptr, "invalid spanIndex:%{public}d", spanIndex);
592 return &spanInfoList_[spanIndex];
593 }
594
GetSpanInfoByIndex(uint32_t spanIndex)595 SpanInfo *OHAudioBuffer::GetSpanInfoByIndex(uint32_t spanIndex)
596 {
597 CHECK_AND_RETURN_RET_LOG(spanIndex < spanConut_, nullptr, "invalid spanIndex:%{public}d", spanIndex);
598 return &spanInfoList_[spanIndex];
599 }
600
GetSpanCount()601 uint32_t OHAudioBuffer::GetSpanCount()
602 {
603 return spanConut_;
604 }
605
GetDataBase()606 uint8_t *OHAudioBuffer::GetDataBase()
607 {
608 return dataBase_;
609 }
610
GetDataSize()611 size_t OHAudioBuffer::GetDataSize()
612 {
613 return totalSizeInByte_;
614 }
615
616 } // namespace AudioStandard
617 } // namespace OHOS
618