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