• 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     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