• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     CHECK_AND_RETURN_RET_LOG(sharedMemory->Init() == SUCCESS,
142         nullptr, "CreateFormLocal failed");
143     return sharedMemory;
144 }
145 
CreateFromRemote(int fd,size_t size,const std::string & name)146 std::shared_ptr<AudioSharedMemory> AudioSharedMemory::CreateFromRemote(int fd, size_t size, const std::string &name)
147 {
148     int minfd = 2; // ignore stdout, stdin and stderr.
149     CHECK_AND_RETURN_RET_LOG(fd > minfd, nullptr, "CreateFromRemote failed: invalid fd: %{public}d", fd);
150     std::shared_ptr<AudioSharedMemoryImpl> sharedMemory = std::make_shared<AudioSharedMemoryImpl>(fd, size, name);
151     if (sharedMemory->Init() != SUCCESS) {
152         AUDIO_ERR_LOG("CreateFromRemote failed");
153         return nullptr;
154     }
155     return sharedMemory;
156 }
157 
WriteToParcel(const std::shared_ptr<AudioSharedMemory> & memory,MessageParcel & parcel)158 int32_t AudioSharedMemory::WriteToParcel(const std::shared_ptr<AudioSharedMemory> &memory, MessageParcel &parcel)
159 {
160     std::shared_ptr<AudioSharedMemoryImpl> memoryImpl = std::static_pointer_cast<AudioSharedMemoryImpl>(memory);
161     CHECK_AND_RETURN_RET_LOG(memoryImpl != nullptr, ERR_OPERATION_FAILED, "invalid pointer.");
162 
163     int32_t fd = memoryImpl->GetFd();
164 
165     size_t size = memoryImpl->GetSize();
166     CHECK_AND_RETURN_RET_LOG((size > 0 && size < MAX_MMAP_BUFFER_SIZE), ERR_INVALID_PARAM,
167         "invalid size: %{public}zu", size);
168     uint64_t sizeTmp = static_cast<uint64_t>(size);
169 
170     std::string name = memoryImpl->GetName();
171 
172     parcel.WriteFileDescriptor(fd);
173     parcel.WriteUint64(sizeTmp);
174     parcel.WriteString(name);
175 
176     return SUCCESS;
177 }
178 
ReadFromParcel(MessageParcel & parcel)179 std::shared_ptr<AudioSharedMemory> AudioSharedMemory::ReadFromParcel(MessageParcel &parcel)
180 {
181     int fd = parcel.ReadFileDescriptor();
182 
183     uint64_t sizeTmp = parcel.ReadUint64();
184     CHECK_AND_RETURN_RET_LOG((sizeTmp > 0 && sizeTmp < MAX_MMAP_BUFFER_SIZE), nullptr, "failed with invalid size");
185     size_t size = static_cast<size_t>(sizeTmp);
186 
187     std::string name = parcel.ReadString();
188 
189     std::shared_ptr<AudioSharedMemory> memory = AudioSharedMemory::CreateFromRemote(fd, size, name);
190     if (memory == nullptr || memory->GetBase() == nullptr) {
191         AUDIO_ERR_LOG("ReadFromParcel failed");
192         memory = nullptr;
193     }
194     close(fd);
195     return memory;
196 }
197 
198 // OHAudioBuffer
OHAudioBuffer(AudioBufferHolder bufferHolder,uint32_t totalSizeInFrame,uint32_t spanSizeInFrame,uint32_t byteSizePerFrame)199 OHAudioBuffer::OHAudioBuffer(AudioBufferHolder bufferHolder, uint32_t totalSizeInFrame, uint32_t spanSizeInFrame,
200     uint32_t byteSizePerFrame) : bufferHolder_(bufferHolder), totalSizeInFrame_(totalSizeInFrame),
201     spanSizeInFrame_(spanSizeInFrame), byteSizePerFrame_(byteSizePerFrame), audioMode_(AUDIO_MODE_PLAYBACK),
202     basicBufferInfo_(nullptr), spanInfoList_(nullptr)
203 {
204     AUDIO_INFO_LOG("ctor with holder:%{public}d mode:%{public}d", bufferHolder_, audioMode_);
205 }
206 
~OHAudioBuffer()207 OHAudioBuffer::~OHAudioBuffer()
208 {
209     AUDIO_INFO_LOG("enter ~OHAudioBuffer()");
210     basicBufferInfo_ = nullptr;
211     spanInfoList_ = nullptr;
212     spanConut_ = 0;
213 }
214 
SizeCheck()215 int32_t OHAudioBuffer::SizeCheck()
216 {
217     if (totalSizeInFrame_ < spanSizeInFrame_ || totalSizeInFrame_ % spanSizeInFrame_ != 0 ||
218         totalSizeInFrame_ > UINT_MAX / byteSizePerFrame_) {
219         AUDIO_ERR_LOG("failed: invalid size.");
220         return ERR_INVALID_PARAM;
221     }
222     totalSizeInByte_ = totalSizeInFrame_ * byteSizePerFrame_;
223     // data buffer size check
224     CHECK_AND_RETURN_RET_LOG((totalSizeInByte_ < MAX_MMAP_BUFFER_SIZE), ERR_INVALID_PARAM, "too large totalSizeInByte "
225         "%{public}zu", totalSizeInByte_);
226 
227     spanSizeInByte_ = spanSizeInFrame_ * byteSizePerFrame_;
228     spanConut_ = totalSizeInFrame_ / spanSizeInFrame_;
229 
230     return SUCCESS;
231 }
232 
Init(int dataFd,int infoFd)233 int32_t OHAudioBuffer::Init(int dataFd, int infoFd)
234 {
235     AUDIO_INFO_LOG("Init with dataFd %{public}d, infoFd %{public}d, bufferSize %{public}d, spanSize %{public}d,"
236         " byteSizePerFrame %{public}d", dataFd, infoFd, totalSizeInFrame_, spanSizeInFrame_, byteSizePerFrame_);
237 
238     int32_t ret = SizeCheck();
239     CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_INVALID_PARAM, "failed: invalid size.");
240 
241     // init for statusInfoBuffer
242     size_t statusInfoSize = sizeof(BasicBufferInfo) + spanConut_ * sizeof(SpanInfo);
243     if (infoFd != INVALID_FD && (bufferHolder_ == AUDIO_CLIENT || bufferHolder_ == AUDIO_SERVER_INDEPENDENT)) {
244         statusInfoMem_ = AudioSharedMemory::CreateFromRemote(infoFd, statusInfoSize, STATUS_INFO_BUFFER);
245     } else {
246         statusInfoMem_ = AudioSharedMemory::CreateFormLocal(statusInfoSize, STATUS_INFO_BUFFER);
247     }
248     CHECK_AND_RETURN_RET_LOG(statusInfoMem_ != nullptr, ERR_OPERATION_FAILED, "BasicBufferInfo mmap failed.");
249 
250     // init for dataBuffer
251     if (dataFd == INVALID_FD && bufferHolder_ == AUDIO_SERVER_SHARED) {
252         dataMem_ = AudioSharedMemory::CreateFormLocal(totalSizeInByte_, "server_client_buffer");
253     } else {
254         std::string memoryDesc = (bufferHolder_ == AUDIO_SERVER_ONLY ? "server_hdi_buffer" : "server_client_buffer");
255         dataMem_ = AudioSharedMemory::CreateFromRemote(dataFd, totalSizeInByte_, memoryDesc);
256     }
257     CHECK_AND_RETURN_RET_LOG(dataMem_ != nullptr, ERR_OPERATION_FAILED, "dataMem_ mmap failed.");
258 
259     dataBase_ = dataMem_->GetBase();
260 
261     basicBufferInfo_ = reinterpret_cast<BasicBufferInfo *>(statusInfoMem_->GetBase());
262     spanInfoList_ = reinterpret_cast<SpanInfo *>(statusInfoMem_->GetBase() + sizeof(BasicBufferInfo));
263 
264     // As basicBufferInfo_ is created from memory, we need to set the value with 0.
265     basicBufferInfo_->basePosInFrame.store(0);
266     basicBufferInfo_->curReadFrame.store(0);
267     basicBufferInfo_->curWriteFrame.store(0);
268 
269     if (bufferHolder_ == AUDIO_SERVER_SHARED || bufferHolder_ == AUDIO_SERVER_ONLY) {
270         basicBufferInfo_->handlePos.store(0);
271         basicBufferInfo_->handleTime.store(0);
272         basicBufferInfo_->totalSizeInFrame = totalSizeInFrame_;
273         basicBufferInfo_->spanSizeInFrame = spanSizeInFrame_;
274         basicBufferInfo_->byteSizePerFrame = byteSizePerFrame_;
275         basicBufferInfo_->streamStatus.store(STREAM_INVALID);
276 
277         for (uint32_t i = 0; i < spanConut_; i++) {
278             spanInfoList_[i].spanStatus.store(SPAN_INVALID);
279         }
280     }
281 
282     AUDIO_INFO_LOG("Init done.");
283     return SUCCESS;
284 }
285 
CreateFromLocal(uint32_t totalSizeInFrame,uint32_t spanSizeInFrame,uint32_t byteSizePerFrame)286 std::shared_ptr<OHAudioBuffer> OHAudioBuffer::CreateFromLocal(uint32_t totalSizeInFrame, uint32_t spanSizeInFrame,
287     uint32_t byteSizePerFrame)
288 {
289     AUDIO_INFO_LOG("totalSizeInFrame %{public}d, spanSizeInFrame %{public}d, byteSizePerFrame"
290         " %{public}d", totalSizeInFrame, spanSizeInFrame, byteSizePerFrame);
291 
292     AudioBufferHolder bufferHolder = AudioBufferHolder::AUDIO_SERVER_SHARED;
293     std::shared_ptr<OHAudioBuffer> buffer = std::make_shared<OHAudioBuffer>(bufferHolder, totalSizeInFrame,
294         spanSizeInFrame, byteSizePerFrame);
295     CHECK_AND_RETURN_RET_LOG(buffer->Init(INVALID_FD, INVALID_FD) == SUCCESS,
296         nullptr, "failed to init.");
297     return buffer;
298 }
299 
CreateFromRemote(uint32_t totalSizeInFrame,uint32_t spanSizeInFrame,uint32_t byteSizePerFrame,AudioBufferHolder bufferHolder,int dataFd,int infoFd)300 std::shared_ptr<OHAudioBuffer> OHAudioBuffer::CreateFromRemote(uint32_t totalSizeInFrame, uint32_t spanSizeInFrame,
301     uint32_t byteSizePerFrame, AudioBufferHolder bufferHolder, int dataFd, int infoFd)
302 {
303     AUDIO_INFO_LOG("dataFd %{public}d, infoFd %{public}d", dataFd, infoFd);
304 
305     int minfd = 2; // ignore stdout, stdin and stderr.
306     CHECK_AND_RETURN_RET_LOG(dataFd > minfd, nullptr, "invalid dataFd: %{public}d", dataFd);
307 
308     if (infoFd != INVALID_FD) {
309         CHECK_AND_RETURN_RET_LOG(infoFd > minfd, nullptr, "invalid infoFd: %{public}d", infoFd);
310     }
311     std::shared_ptr<OHAudioBuffer> buffer = std::make_shared<OHAudioBuffer>(bufferHolder, totalSizeInFrame,
312         spanSizeInFrame, byteSizePerFrame);
313     if (buffer->Init(dataFd, infoFd) != SUCCESS) {
314         AUDIO_ERR_LOG("failed to init.");
315         return nullptr;
316     }
317     return buffer;
318 }
319 
WriteToParcel(const std::shared_ptr<OHAudioBuffer> & buffer,MessageParcel & parcel)320 int32_t OHAudioBuffer::WriteToParcel(const std::shared_ptr<OHAudioBuffer> &buffer, MessageParcel &parcel)
321 {
322     AUDIO_INFO_LOG("WriteToParcel start.");
323     AudioBufferHolder bufferHolder = buffer->GetBufferHolder();
324     CHECK_AND_RETURN_RET_LOG(bufferHolder == AudioBufferHolder::AUDIO_SERVER_SHARED ||
325         bufferHolder == AudioBufferHolder::AUDIO_SERVER_INDEPENDENT,
326         ERROR_INVALID_PARAM, "buffer holder error:%{public}d", bufferHolder);
327 
328     parcel.WriteUint32(bufferHolder);
329     parcel.WriteUint32(buffer->totalSizeInFrame_);
330     parcel.WriteUint32(buffer->spanSizeInFrame_);
331     parcel.WriteUint32(buffer->byteSizePerFrame_);
332 
333     parcel.WriteFileDescriptor(buffer->dataMem_->GetFd());
334     parcel.WriteFileDescriptor(buffer->statusInfoMem_->GetFd());
335 
336     AUDIO_INFO_LOG("WriteToParcel done.");
337     return SUCCESS;
338 }
339 
ReadFromParcel(MessageParcel & parcel)340 std::shared_ptr<OHAudioBuffer> OHAudioBuffer::ReadFromParcel(MessageParcel &parcel)
341 {
342     AUDIO_INFO_LOG("ReadFromParcel start.");
343     uint32_t holder = parcel.ReadUint32();
344     AudioBufferHolder bufferHolder = static_cast<AudioBufferHolder>(holder);
345     if (bufferHolder != AudioBufferHolder::AUDIO_SERVER_SHARED &&
346         bufferHolder != AudioBufferHolder::AUDIO_SERVER_INDEPENDENT) {
347         AUDIO_ERR_LOG("ReadFromParcel buffer holder error:%{public}d", bufferHolder);
348         return nullptr;
349     }
350     bufferHolder = bufferHolder == AudioBufferHolder::AUDIO_SERVER_SHARED ?
351          AudioBufferHolder::AUDIO_CLIENT : bufferHolder;
352     uint32_t totalSizeInFrame = parcel.ReadUint32();
353     uint32_t spanSizeInFrame = parcel.ReadUint32();
354     uint32_t byteSizePerFrame = parcel.ReadUint32();
355 
356     int dataFd = parcel.ReadFileDescriptor();
357     int infoFd = parcel.ReadFileDescriptor();
358 
359     std::shared_ptr<OHAudioBuffer> buffer = OHAudioBuffer::CreateFromRemote(totalSizeInFrame, spanSizeInFrame,
360         byteSizePerFrame, bufferHolder, dataFd, infoFd);
361     if (buffer == nullptr) {
362         AUDIO_ERR_LOG("ReadFromParcel failed.");
363     } else if (totalSizeInFrame != buffer->basicBufferInfo_->totalSizeInFrame ||
364         spanSizeInFrame != buffer->basicBufferInfo_->spanSizeInFrame ||
365         byteSizePerFrame != buffer->basicBufferInfo_->byteSizePerFrame) {
366         AUDIO_WARNING_LOG("data in shared memory diff.");
367     } else {
368         AUDIO_INFO_LOG("Read some data done.");
369     }
370     close(dataFd);
371     close(infoFd);
372     AUDIO_INFO_LOG("ReadFromParcel done.");
373     return buffer;
374 }
375 
GetBufferHolder()376 AudioBufferHolder OHAudioBuffer::GetBufferHolder()
377 {
378     return bufferHolder_;
379 }
380 
GetSizeParameter(uint32_t & totalSizeInFrame,uint32_t & spanSizeInFrame,uint32_t & byteSizePerFrame)381 int32_t OHAudioBuffer::GetSizeParameter(uint32_t &totalSizeInFrame, uint32_t &spanSizeInFrame,
382     uint32_t &byteSizePerFrame)
383 {
384     totalSizeInFrame = totalSizeInFrame_;
385     spanSizeInFrame = spanSizeInFrame_;
386     byteSizePerFrame = byteSizePerFrame_;
387 
388     return SUCCESS;
389 }
390 
GetStreamStatus()391 std::atomic<StreamStatus> *OHAudioBuffer::GetStreamStatus()
392 {
393     return &basicBufferInfo_->streamStatus;
394 }
395 
GetHandleInfo(uint64_t & frames,int64_t & nanoTime)396 bool OHAudioBuffer::GetHandleInfo(uint64_t &frames, int64_t &nanoTime)
397 {
398     CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, false,
399         "Get nullptr, failed to GetHandleInfo.");
400 
401     frames = basicBufferInfo_->handlePos.load();
402     nanoTime = basicBufferInfo_->handleTime.load();
403     return true;
404 }
405 
SetHandleInfo(uint64_t frames,int64_t nanoTime)406 void OHAudioBuffer::SetHandleInfo(uint64_t frames, int64_t nanoTime)
407 {
408     basicBufferInfo_->handlePos.store(frames);
409     basicBufferInfo_->handleTime.store(nanoTime);
410 }
411 
GetAvailableDataFrames()412 int32_t OHAudioBuffer::GetAvailableDataFrames()
413 {
414     int32_t result = -1; // failed
415     uint64_t write = basicBufferInfo_->curWriteFrame.load();
416     uint64_t read = basicBufferInfo_->curReadFrame.load();
417     CHECK_AND_RETURN_RET_LOG(write >= read, result, "invalid write and read position.");
418     uint32_t temp = write - read;
419     CHECK_AND_RETURN_RET_LOG(temp <= INT32_MAX && temp <= totalSizeInFrame_,
420         result, "failed to GetAvailableDataFrames.");
421     result = static_cast<int32_t>(totalSizeInFrame_ - temp);
422     return result;
423 }
424 
ResetCurReadWritePos(uint64_t readFrame,uint64_t writeFrame)425 int32_t OHAudioBuffer::ResetCurReadWritePos(uint64_t readFrame, uint64_t writeFrame)
426 {
427     CHECK_AND_RETURN_RET_LOG(readFrame <= writeFrame && writeFrame - readFrame < totalSizeInFrame_,
428         ERR_INVALID_PARAM, "Invalid read or write position:read%{public}" PRIu64" write%{public}" PRIu64".",
429         readFrame, writeFrame);
430     uint64_t tempBase = (readFrame / totalSizeInFrame_) * totalSizeInFrame_;
431     basicBufferInfo_->basePosInFrame.store(tempBase);
432     basicBufferInfo_->curWriteFrame.store(writeFrame);
433     basicBufferInfo_->curReadFrame.store(readFrame);
434 
435     AUDIO_INFO_LOG("Reset position:read%{public}" PRIu64" write%{public}" PRIu64".", readFrame, writeFrame);
436     return SUCCESS;
437 }
438 
GetCurWriteFrame()439 uint64_t OHAudioBuffer::GetCurWriteFrame()
440 {
441     return basicBufferInfo_->curWriteFrame.load();
442 }
443 
GetCurReadFrame()444 uint64_t OHAudioBuffer::GetCurReadFrame()
445 {
446     return basicBufferInfo_->curReadFrame.load();
447 }
448 
SetCurWriteFrame(uint64_t writeFrame)449 int32_t OHAudioBuffer::SetCurWriteFrame(uint64_t writeFrame)
450 {
451     uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
452     uint64_t oldWritePos = basicBufferInfo_->curWriteFrame.load();
453     if (writeFrame == oldWritePos) {
454         return SUCCESS;
455     }
456     CHECK_AND_RETURN_RET_LOG(writeFrame > oldWritePos, ERR_INVALID_PARAM, "Too small writeFrame:%{public}" PRIu64".",
457         writeFrame);
458 
459     uint64_t deltaToBase = writeFrame - basePos; // writeFrame % spanSizeInFrame_ --> 0
460     CHECK_AND_RETURN_RET_LOG(deltaToBase / spanSizeInFrame_ * spanSizeInFrame_ == deltaToBase, ERR_INVALID_PARAM,
461         "Invalid deltaToBase, writeFrame:%{public}" PRIu64".", writeFrame);
462 
463     // check new pos in range: base ~ base + 2*total
464     CHECK_AND_RETURN_RET_LOG(deltaToBase < (totalSizeInFrame_ + totalSizeInFrame_),
465         ERR_INVALID_PARAM, "Invalid writeFrame %{public}" PRIu64" out of base range.", writeFrame);
466 
467     // check new pos in (read + cache) range: read ~ read + totalSize - 1*spanSize
468     uint64_t curRead = basicBufferInfo_->curReadFrame.load();
469     CHECK_AND_RETURN_RET_LOG(writeFrame >= curRead && writeFrame - curRead <= totalSizeInFrame_,
470         ERR_INVALID_PARAM, "Invalid writeFrame %{public}" PRIu64" out of cache range, curRead %{public}" PRIu64".",
471         writeFrame, curRead);
472 
473     if (writeFrame - oldWritePos != spanSizeInFrame_) {
474         AUDIO_WARNING_LOG("Not advanced in one step. newWritePos %{public}" PRIu64", oldWritePos %{public}" PRIu64".",
475             writeFrame, oldWritePos);
476     }
477 
478     basicBufferInfo_->curWriteFrame.store(writeFrame);
479     return SUCCESS;
480 }
481 
SetCurReadFrame(uint64_t readFrame)482 int32_t OHAudioBuffer::SetCurReadFrame(uint64_t readFrame)
483 {
484     uint64_t oldBasePos = basicBufferInfo_->basePosInFrame.load();
485     uint64_t oldReadPos = basicBufferInfo_->curReadFrame.load();
486     if (readFrame == oldReadPos) {
487         return SUCCESS;
488     }
489 
490     // new read position should not be bigger than write position or less than old read position
491     CHECK_AND_RETURN_RET_LOG(readFrame >= oldReadPos && readFrame <= basicBufferInfo_->curWriteFrame.load(),
492         ERR_INVALID_PARAM, "Invalid readFrame %{public}" PRIu64".", readFrame);
493 
494     uint64_t deltaToBase = readFrame - oldBasePos;
495     CHECK_AND_RETURN_RET_LOG((deltaToBase / spanSizeInFrame_ * spanSizeInFrame_) == deltaToBase,
496         ERR_INVALID_PARAM, "Invalid deltaToBase, readFrame %{public}" PRIu64", oldBasePos %{public}" PRIu64".",
497             readFrame, oldBasePos);
498 
499     if (deltaToBase > totalSizeInFrame_) {
500         AUDIO_ERR_LOG("Invalid readFrame:%{public}" PRIu64", out of range.", readFrame);
501         return ERR_INVALID_PARAM;
502     } else if (deltaToBase == totalSizeInFrame_) {
503         basicBufferInfo_->basePosInFrame.store(oldBasePos + totalSizeInFrame_); // move base position
504     }
505 
506     if (readFrame - oldReadPos != spanSizeInFrame_) {
507         AUDIO_WARNING_LOG("Not advanced in one step. newReadPos %{public}" PRIu64", oldReadPos %{public}" PRIu64".",
508             readFrame, oldReadPos);
509     }
510 
511     basicBufferInfo_->curReadFrame.store(readFrame);
512     return SUCCESS;
513 }
514 
GetBufferByFrame(uint64_t posInFrame,BufferDesc & bufferDesc)515 int32_t OHAudioBuffer::GetBufferByFrame(uint64_t posInFrame, BufferDesc &bufferDesc)
516 {
517     uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
518     uint64_t maxDelta = 2 * totalSizeInFrame_; // 0 ~ 2*totalSizeInFrame_
519     CHECK_AND_RETURN_RET_LOG(posInFrame >= basePos && posInFrame - basePos < maxDelta,
520         ERR_INVALID_PARAM, "Invalid position:%{public}" PRIu64".", posInFrame);
521 
522     uint32_t deltaToBase = posInFrame - basePos;
523     if (deltaToBase >= totalSizeInFrame_) {
524         deltaToBase -= totalSizeInFrame_;
525     }
526     CHECK_AND_RETURN_RET_LOG(deltaToBase < UINT32_MAX && deltaToBase < totalSizeInFrame_, ERR_INVALID_PARAM,
527         "invalid deltaToBase, posInFrame %{public}" PRIu64" basePos %{public}" PRIu64".", posInFrame, basePos);
528     deltaToBase = (deltaToBase / spanSizeInFrame_) * spanSizeInFrame_;
529     size_t offset = deltaToBase * byteSizePerFrame_;
530     CHECK_AND_RETURN_RET_LOG(offset < totalSizeInByte_, ERR_INVALID_PARAM, "invalid deltaToBase:%{public}zu", offset);
531 
532     bufferDesc.buffer = dataBase_ + offset;
533     bufferDesc.bufLength = spanSizeInByte_;
534     bufferDesc.dataLength = spanSizeInByte_;
535 
536     return SUCCESS;
537 }
538 
GetWriteBuffer(uint64_t writePosInFrame,BufferDesc & bufferDesc)539 int32_t OHAudioBuffer::GetWriteBuffer(uint64_t writePosInFrame, BufferDesc &bufferDesc)
540 {
541     uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
542     uint64_t readPos = basicBufferInfo_->curReadFrame.load();
543     uint64_t maxWriteDelta = 2 * totalSizeInFrame_; // 0 ~ 2*totalSizeInFrame_
544     CHECK_AND_RETURN_RET_LOG(writePosInFrame >= basePos && writePosInFrame - basePos < maxWriteDelta &&
545         writePosInFrame >= readPos, ERR_INVALID_PARAM, "Invalid write position:%{public}" PRIu64".", writePosInFrame);
546     return GetBufferByFrame(writePosInFrame, bufferDesc);
547 }
548 
GetReadbuffer(uint64_t readPosInFrame,BufferDesc & bufferDesc)549 int32_t OHAudioBuffer::GetReadbuffer(uint64_t readPosInFrame, BufferDesc &bufferDesc)
550 {
551     uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
552     CHECK_AND_RETURN_RET_LOG(readPosInFrame >= basePos && readPosInFrame - basePos < totalSizeInFrame_,
553         ERR_INVALID_PARAM, "Invalid read position:%{public}" PRIu64".", readPosInFrame);
554     return GetBufferByFrame(readPosInFrame, bufferDesc);
555 }
556 
GetSpanInfo(uint64_t posInFrame)557 SpanInfo *OHAudioBuffer::GetSpanInfo(uint64_t posInFrame)
558 {
559     uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
560     uint64_t maxPos = basePos + totalSizeInFrame_ + totalSizeInFrame_;
561     CHECK_AND_RETURN_RET_LOG((basePos <= posInFrame && posInFrame < maxPos), nullptr, "posInFrame %{public}" PRIu64" "
562         "out of range, basePos %{public}" PRIu64", maxPos %{public}" PRIu64".", posInFrame, basePos, maxPos);
563 
564     uint64_t deltaToBase = posInFrame - basePos;
565     if (deltaToBase >= totalSizeInFrame_) {
566         deltaToBase -= totalSizeInFrame_;
567     }
568     CHECK_AND_RETURN_RET_LOG(deltaToBase < UINT32_MAX && deltaToBase < totalSizeInFrame_, nullptr, "invalid "
569         "deltaToBase, posInFrame %{public}" PRIu64" basePos %{public}" PRIu64".", posInFrame, basePos);
570     uint32_t spanIndex = deltaToBase / spanSizeInFrame_;
571     CHECK_AND_RETURN_RET_LOG(spanIndex < spanConut_, nullptr, "invalid spanIndex:%{public}d", spanIndex);
572     return &spanInfoList_[spanIndex];
573 }
574 
GetSpanInfoByIndex(uint32_t spanIndex)575 SpanInfo *OHAudioBuffer::GetSpanInfoByIndex(uint32_t spanIndex)
576 {
577     CHECK_AND_RETURN_RET_LOG(spanIndex < spanConut_, nullptr, "invalid spanIndex:%{public}d", spanIndex);
578     return &spanInfoList_[spanIndex];
579 }
580 
GetSpanCount()581 uint32_t OHAudioBuffer::GetSpanCount()
582 {
583     return spanConut_;
584 }
585 
GetDataBase()586 uint8_t *OHAudioBuffer::GetDataBase()
587 {
588     return dataBase_;
589 }
590 
GetDataSize()591 size_t OHAudioBuffer::GetDataSize()
592 {
593     return totalSizeInByte_;
594 }
595 
596 } // namespace AudioStandard
597 } // namespace OHOS
598