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 basicBufferInfo_->muteFactor.store(MAX_FLOAT_VOLUME);
285
286 if (bufferHolder_ == AUDIO_SERVER_SHARED || bufferHolder_ == AUDIO_SERVER_ONLY) {
287 basicBufferInfo_->handlePos.store(0);
288 basicBufferInfo_->handleTime.store(0);
289 basicBufferInfo_->totalSizeInFrame = totalSizeInFrame_;
290 basicBufferInfo_->spanSizeInFrame = spanSizeInFrame_;
291 basicBufferInfo_->byteSizePerFrame = byteSizePerFrame_;
292 basicBufferInfo_->streamStatus.store(STREAM_INVALID);
293
294 for (uint32_t i = 0; i < spanConut_; i++) {
295 spanInfoList_[i].spanStatus.store(SPAN_INVALID);
296 }
297 }
298
299 AUDIO_DEBUG_LOG("Init done.");
300 return SUCCESS;
301 }
302
CreateFromLocal(uint32_t totalSizeInFrame,uint32_t spanSizeInFrame,uint32_t byteSizePerFrame)303 std::shared_ptr<OHAudioBuffer> OHAudioBuffer::CreateFromLocal(uint32_t totalSizeInFrame, uint32_t spanSizeInFrame,
304 uint32_t byteSizePerFrame)
305 {
306 AUDIO_DEBUG_LOG("totalSizeInFrame %{public}d, spanSizeInFrame %{public}d, byteSizePerFrame"
307 " %{public}d", totalSizeInFrame, spanSizeInFrame, byteSizePerFrame);
308
309 AudioBufferHolder bufferHolder = AudioBufferHolder::AUDIO_SERVER_SHARED;
310 std::shared_ptr<OHAudioBuffer> buffer = std::make_shared<OHAudioBuffer>(bufferHolder, totalSizeInFrame,
311 spanSizeInFrame, byteSizePerFrame);
312 CHECK_AND_RETURN_RET_LOG(buffer->Init(INVALID_FD, INVALID_FD) == SUCCESS,
313 nullptr, "failed to init.");
314 return buffer;
315 }
316
CreateFromRemote(uint32_t totalSizeInFrame,uint32_t spanSizeInFrame,uint32_t byteSizePerFrame,AudioBufferHolder bufferHolder,int dataFd,int infoFd)317 std::shared_ptr<OHAudioBuffer> OHAudioBuffer::CreateFromRemote(uint32_t totalSizeInFrame, uint32_t spanSizeInFrame,
318 uint32_t byteSizePerFrame, AudioBufferHolder bufferHolder, int dataFd, int infoFd)
319 {
320 AUDIO_DEBUG_LOG("dataFd %{public}d, infoFd %{public}d", dataFd, infoFd);
321
322 int minfd = 2; // ignore stdout, stdin and stderr.
323 CHECK_AND_RETURN_RET_LOG(dataFd > minfd, nullptr, "invalid dataFd: %{public}d", dataFd);
324
325 if (infoFd != INVALID_FD) {
326 CHECK_AND_RETURN_RET_LOG(infoFd > minfd, nullptr, "invalid infoFd: %{public}d", infoFd);
327 }
328 std::shared_ptr<OHAudioBuffer> buffer = std::make_shared<OHAudioBuffer>(bufferHolder, totalSizeInFrame,
329 spanSizeInFrame, byteSizePerFrame);
330 if (buffer->Init(dataFd, infoFd) != SUCCESS) {
331 AUDIO_ERR_LOG("failed to init.");
332 return nullptr;
333 }
334 return buffer;
335 }
336
WriteToParcel(const std::shared_ptr<OHAudioBuffer> & buffer,MessageParcel & parcel)337 int32_t OHAudioBuffer::WriteToParcel(const std::shared_ptr<OHAudioBuffer> &buffer, MessageParcel &parcel)
338 {
339 AUDIO_DEBUG_LOG("WriteToParcel start.");
340 AudioBufferHolder bufferHolder = buffer->GetBufferHolder();
341 CHECK_AND_RETURN_RET_LOG(bufferHolder == AudioBufferHolder::AUDIO_SERVER_SHARED ||
342 bufferHolder == AudioBufferHolder::AUDIO_SERVER_INDEPENDENT,
343 ERROR_INVALID_PARAM, "buffer holder error:%{public}d", bufferHolder);
344
345 parcel.WriteUint32(bufferHolder);
346 parcel.WriteUint32(buffer->totalSizeInFrame_);
347 parcel.WriteUint32(buffer->spanSizeInFrame_);
348 parcel.WriteUint32(buffer->byteSizePerFrame_);
349
350 parcel.WriteFileDescriptor(buffer->dataMem_->GetFd());
351 parcel.WriteFileDescriptor(buffer->statusInfoMem_->GetFd());
352
353 AUDIO_DEBUG_LOG("WriteToParcel done.");
354 return SUCCESS;
355 }
356
ReadFromParcel(MessageParcel & parcel)357 std::shared_ptr<OHAudioBuffer> OHAudioBuffer::ReadFromParcel(MessageParcel &parcel)
358 {
359 AUDIO_DEBUG_LOG("ReadFromParcel start.");
360 uint32_t holder = parcel.ReadUint32();
361 AudioBufferHolder bufferHolder = static_cast<AudioBufferHolder>(holder);
362 if (bufferHolder != AudioBufferHolder::AUDIO_SERVER_SHARED &&
363 bufferHolder != AudioBufferHolder::AUDIO_SERVER_INDEPENDENT) {
364 AUDIO_ERR_LOG("ReadFromParcel buffer holder error:%{public}d", bufferHolder);
365 return nullptr;
366 }
367 bufferHolder = bufferHolder == AudioBufferHolder::AUDIO_SERVER_SHARED ?
368 AudioBufferHolder::AUDIO_CLIENT : bufferHolder;
369 uint32_t totalSizeInFrame = parcel.ReadUint32();
370 uint32_t spanSizeInFrame = parcel.ReadUint32();
371 uint32_t byteSizePerFrame = parcel.ReadUint32();
372
373 int dataFd = parcel.ReadFileDescriptor();
374 int infoFd = parcel.ReadFileDescriptor();
375
376 std::shared_ptr<OHAudioBuffer> buffer = OHAudioBuffer::CreateFromRemote(totalSizeInFrame, spanSizeInFrame,
377 byteSizePerFrame, bufferHolder, dataFd, infoFd);
378 if (buffer == nullptr) {
379 AUDIO_ERR_LOG("ReadFromParcel failed.");
380 } else if (totalSizeInFrame != buffer->basicBufferInfo_->totalSizeInFrame ||
381 spanSizeInFrame != buffer->basicBufferInfo_->spanSizeInFrame ||
382 byteSizePerFrame != buffer->basicBufferInfo_->byteSizePerFrame) {
383 AUDIO_WARNING_LOG("data in shared memory diff.");
384 } else {
385 AUDIO_DEBUG_LOG("Read some data done.");
386 }
387 CloseFd(dataFd);
388 CloseFd(infoFd);
389 AUDIO_DEBUG_LOG("ReadFromParcel done.");
390 return buffer;
391 }
392
GetBufferHolder()393 AudioBufferHolder OHAudioBuffer::GetBufferHolder()
394 {
395 return bufferHolder_;
396 }
397
GetSizeParameter(uint32_t & totalSizeInFrame,uint32_t & spanSizeInFrame,uint32_t & byteSizePerFrame)398 int32_t OHAudioBuffer::GetSizeParameter(uint32_t &totalSizeInFrame, uint32_t &spanSizeInFrame,
399 uint32_t &byteSizePerFrame)
400 {
401 totalSizeInFrame = totalSizeInFrame_;
402 spanSizeInFrame = spanSizeInFrame_;
403 byteSizePerFrame = byteSizePerFrame_;
404
405 return SUCCESS;
406 }
407
GetStreamStatus()408 std::atomic<StreamStatus> *OHAudioBuffer::GetStreamStatus()
409 {
410 if (basicBufferInfo_ == nullptr) {
411 return nullptr;
412 }
413 return &basicBufferInfo_->streamStatus;
414 }
415
416
GetStreamVolume()417 float OHAudioBuffer::GetStreamVolume()
418 {
419 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, MAX_FLOAT_VOLUME, "buffer is not inited!");
420 float vol = basicBufferInfo_->streamVolume.load();
421 if (vol < MIN_FLOAT_VOLUME) {
422 AUDIO_WARNING_LOG("vol < 0.0, invalid volume! using 0.0 instead.");
423 return MIN_FLOAT_VOLUME;
424 } else if (vol > MAX_FLOAT_VOLUME) {
425 AUDIO_WARNING_LOG("vol > 0.0, invalid volume! using 1.0 instead.");
426 return MAX_FLOAT_VOLUME;
427 }
428 return vol;
429 }
430
SetStreamVolume(float streamVolume)431 bool OHAudioBuffer::SetStreamVolume(float streamVolume)
432 {
433 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, false, "buffer is not inited!");
434 if (streamVolume < MIN_FLOAT_VOLUME || streamVolume > MAX_FLOAT_VOLUME) {
435 AUDIO_ERR_LOG("invlaid volume:%{public}f", streamVolume);
436 return false;
437 }
438 basicBufferInfo_->streamVolume.store(streamVolume);
439 return true;
440 }
441
GetMuteFactor()442 float OHAudioBuffer::GetMuteFactor()
443 {
444 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, MAX_FLOAT_VOLUME, "buffer is not inited!");
445 float factor = basicBufferInfo_->muteFactor.load();
446 if (factor < MIN_FLOAT_VOLUME) {
447 AUDIO_WARNING_LOG("vol < 0.0, invalid muteFactor! using 0.0 instead.");
448 return MIN_FLOAT_VOLUME;
449 } else if (factor > MAX_FLOAT_VOLUME) {
450 AUDIO_WARNING_LOG("vol > 0.0, invalid muteFactor! using 1.0 instead.");
451 return MAX_FLOAT_VOLUME;
452 }
453 return factor;
454 }
455
SetMuteFactor(float muteFactor)456 bool OHAudioBuffer::SetMuteFactor(float muteFactor)
457 {
458 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, false, "buffer is not inited!");
459 if (muteFactor != MIN_FLOAT_VOLUME && muteFactor != MAX_FLOAT_VOLUME) {
460 AUDIO_ERR_LOG("invlaid factor:%{public}f", muteFactor);
461 return false;
462 }
463 basicBufferInfo_->muteFactor.store(muteFactor);
464 return true;
465 }
466
GetDuckFactor()467 float OHAudioBuffer::GetDuckFactor()
468 {
469 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, MAX_FLOAT_VOLUME, "buffer is not inited!");
470 float factor = basicBufferInfo_->duckFactor.load();
471 if (factor < MIN_FLOAT_VOLUME) {
472 AUDIO_WARNING_LOG("vol < 0.0, invalid duckFactor! using 0.0 instead.");
473 return MIN_FLOAT_VOLUME;
474 } else if (factor > MAX_FLOAT_VOLUME) {
475 AUDIO_WARNING_LOG("vol > 0.0, invalid duckFactor! using 1.0 instead.");
476 return MAX_FLOAT_VOLUME;
477 }
478 return factor;
479 }
480
SetDuckFactor(float duckFactor)481 bool OHAudioBuffer::SetDuckFactor(float duckFactor)
482 {
483 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, false, "buffer is not inited!");
484 if (duckFactor < MIN_FLOAT_VOLUME || duckFactor > MAX_FLOAT_VOLUME) {
485 AUDIO_ERR_LOG("invlaid factor:%{public}f", duckFactor);
486 return false;
487 }
488 basicBufferInfo_->duckFactor.store(duckFactor);
489 return true;
490 }
491
492
GetUnderrunCount()493 uint32_t OHAudioBuffer::GetUnderrunCount()
494 {
495 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, 0,
496 "Get nullptr, buffer is not inited.");
497 return basicBufferInfo_->underrunCount.load();
498 }
499
SetUnderrunCount(uint32_t count)500 bool OHAudioBuffer::SetUnderrunCount(uint32_t count)
501 {
502 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, false,
503 "Get nullptr, buffer is not inited.");
504 basicBufferInfo_->underrunCount.store(count);
505 return true;
506 }
507
GetHandleInfo(uint64_t & frames,int64_t & nanoTime)508 bool OHAudioBuffer::GetHandleInfo(uint64_t &frames, int64_t &nanoTime)
509 {
510 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, false,
511 "Get nullptr, failed to GetHandleInfo.");
512
513 frames = basicBufferInfo_->handlePos.load();
514 nanoTime = basicBufferInfo_->handleTime.load();
515 return true;
516 }
517
SetHandleInfo(uint64_t frames,int64_t nanoTime)518 void OHAudioBuffer::SetHandleInfo(uint64_t frames, int64_t nanoTime)
519 {
520 basicBufferInfo_->handlePos.store(frames);
521 basicBufferInfo_->handleTime.store(nanoTime);
522 }
523
GetAvailableDataFrames()524 int32_t OHAudioBuffer::GetAvailableDataFrames()
525 {
526 int32_t result = -1; // failed
527 uint64_t write = basicBufferInfo_->curWriteFrame.load();
528 uint64_t read = basicBufferInfo_->curReadFrame.load();
529 CHECK_AND_RETURN_RET_LOG(write >= read, result, "invalid write and read position.");
530 uint32_t temp = write - read;
531 CHECK_AND_RETURN_RET_LOG(temp <= INT32_MAX && temp <= totalSizeInFrame_,
532 result, "failed to GetAvailableDataFrames.");
533 result = static_cast<int32_t>(totalSizeInFrame_ - temp);
534 return result;
535 }
536
ResetCurReadWritePos(uint64_t readFrame,uint64_t writeFrame)537 int32_t OHAudioBuffer::ResetCurReadWritePos(uint64_t readFrame, uint64_t writeFrame)
538 {
539 CHECK_AND_RETURN_RET_LOG(readFrame <= writeFrame && writeFrame - readFrame < totalSizeInFrame_,
540 ERR_INVALID_PARAM, "Invalid read or write position:read%{public}" PRIu64" write%{public}" PRIu64".",
541 readFrame, writeFrame);
542 uint64_t tempBase = (readFrame / totalSizeInFrame_) * totalSizeInFrame_;
543 basicBufferInfo_->basePosInFrame.store(tempBase);
544 basicBufferInfo_->curWriteFrame.store(writeFrame);
545 basicBufferInfo_->curReadFrame.store(readFrame);
546
547 AUDIO_DEBUG_LOG("Reset position:read%{public}" PRIu64" write%{public}" PRIu64".", readFrame, writeFrame);
548 return SUCCESS;
549 }
550
GetCurWriteFrame()551 uint64_t OHAudioBuffer::GetCurWriteFrame()
552 {
553 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, 0, "basicBufferInfo_ is null");
554 return basicBufferInfo_->curWriteFrame.load();
555 }
556
GetCurReadFrame()557 uint64_t OHAudioBuffer::GetCurReadFrame()
558 {
559 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, 0, "basicBufferInfo_ is null");
560 return basicBufferInfo_->curReadFrame.load();
561 }
562
SetCurWriteFrame(uint64_t writeFrame)563 int32_t OHAudioBuffer::SetCurWriteFrame(uint64_t writeFrame)
564 {
565 uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
566 uint64_t oldWritePos = basicBufferInfo_->curWriteFrame.load();
567 if (writeFrame == oldWritePos) {
568 return SUCCESS;
569 }
570 CHECK_AND_RETURN_RET_LOG(writeFrame > oldWritePos, ERR_INVALID_PARAM, "Too small writeFrame:%{public}" PRIu64".",
571 writeFrame);
572
573 uint64_t deltaToBase = writeFrame - basePos; // writeFrame % spanSizeInFrame_ --> 0
574 CHECK_AND_RETURN_RET_LOG(deltaToBase / spanSizeInFrame_ * spanSizeInFrame_ == deltaToBase, ERR_INVALID_PARAM,
575 "Invalid deltaToBase, writeFrame:%{public}" PRIu64".", writeFrame);
576
577 // check new pos in range: base ~ base + 2*total
578 CHECK_AND_RETURN_RET_LOG(deltaToBase < (totalSizeInFrame_ + totalSizeInFrame_),
579 ERR_INVALID_PARAM, "Invalid writeFrame %{public}" PRIu64" out of base range.", writeFrame);
580
581 // check new pos in (read + cache) range: read ~ read + totalSize - 1*spanSize
582 uint64_t curRead = basicBufferInfo_->curReadFrame.load();
583 CHECK_AND_RETURN_RET_LOG(writeFrame >= curRead && writeFrame - curRead <= totalSizeInFrame_,
584 ERR_INVALID_PARAM, "Invalid writeFrame %{public}" PRIu64" out of cache range, curRead %{public}" PRIu64".",
585 writeFrame, curRead);
586
587 if (writeFrame - oldWritePos != spanSizeInFrame_) {
588 AUDIO_WARNING_LOG("Not advanced in one step. newWritePos %{public}" PRIu64", oldWritePos %{public}" PRIu64".",
589 writeFrame, oldWritePos);
590 }
591
592 basicBufferInfo_->curWriteFrame.store(writeFrame);
593 return SUCCESS;
594 }
595
SetCurReadFrame(uint64_t readFrame)596 int32_t OHAudioBuffer::SetCurReadFrame(uint64_t readFrame)
597 {
598 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, ERR_INVALID_PARAM, "basicBufferInfo_ is nullptr");
599 uint64_t oldBasePos = basicBufferInfo_->basePosInFrame.load();
600 uint64_t oldReadPos = basicBufferInfo_->curReadFrame.load();
601 if (readFrame == oldReadPos) {
602 return SUCCESS;
603 }
604
605 // new read position should not be bigger than write position or less than old read position
606 CHECK_AND_RETURN_RET_LOG(readFrame >= oldReadPos && readFrame <= basicBufferInfo_->curWriteFrame.load(),
607 ERR_INVALID_PARAM, "Invalid readFrame %{public}" PRIu64".", readFrame);
608
609 uint64_t deltaToBase = readFrame - oldBasePos;
610 CHECK_AND_RETURN_RET_LOG((deltaToBase / spanSizeInFrame_ * spanSizeInFrame_) == deltaToBase,
611 ERR_INVALID_PARAM, "Invalid deltaToBase, readFrame %{public}" PRIu64", oldBasePos %{public}" PRIu64".",
612 readFrame, oldBasePos);
613
614 if (deltaToBase > totalSizeInFrame_) {
615 AUDIO_ERR_LOG("Invalid readFrame:%{public}" PRIu64", out of range.", readFrame);
616 return ERR_INVALID_PARAM;
617 } else if (deltaToBase == totalSizeInFrame_) {
618 basicBufferInfo_->basePosInFrame.store(oldBasePos + totalSizeInFrame_); // move base position
619 }
620
621 if (readFrame - oldReadPos != spanSizeInFrame_) {
622 AUDIO_WARNING_LOG("Not advanced in one step. newReadPos %{public}" PRIu64", oldReadPos %{public}" PRIu64".",
623 readFrame, oldReadPos);
624 }
625
626 basicBufferInfo_->curReadFrame.store(readFrame);
627 return SUCCESS;
628 }
629
GetBufferByFrame(uint64_t posInFrame,BufferDesc & bufferDesc)630 int32_t OHAudioBuffer::GetBufferByFrame(uint64_t posInFrame, BufferDesc &bufferDesc)
631 {
632 uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
633 uint64_t maxDelta = 2 * totalSizeInFrame_; // 0 ~ 2*totalSizeInFrame_
634 CHECK_AND_RETURN_RET_LOG(posInFrame >= basePos && posInFrame - basePos < maxDelta,
635 ERR_INVALID_PARAM, "Invalid position:%{public}" PRIu64".", posInFrame);
636
637 uint32_t deltaToBase = posInFrame - basePos;
638 if (deltaToBase >= totalSizeInFrame_) {
639 deltaToBase -= totalSizeInFrame_;
640 }
641 CHECK_AND_RETURN_RET_LOG(deltaToBase < UINT32_MAX && deltaToBase < totalSizeInFrame_, ERR_INVALID_PARAM,
642 "invalid deltaToBase, posInFrame %{public}" PRIu64" basePos %{public}" PRIu64".", posInFrame, basePos);
643 deltaToBase = (deltaToBase / spanSizeInFrame_) * spanSizeInFrame_;
644 size_t offset = deltaToBase * byteSizePerFrame_;
645 CHECK_AND_RETURN_RET_LOG(offset < totalSizeInByte_, ERR_INVALID_PARAM, "invalid deltaToBase:%{public}zu", offset);
646 bufferDesc.buffer = dataBase_ + offset;
647 bufferDesc.bufLength = spanSizeInByte_;
648 bufferDesc.dataLength = spanSizeInByte_;
649
650 return SUCCESS;
651 }
652
GetSessionId()653 uint32_t OHAudioBuffer::GetSessionId()
654 {
655 return sessionId_;
656 }
657
SetSessionId(uint32_t sessionId)658 int32_t OHAudioBuffer::SetSessionId(uint32_t sessionId)
659 {
660 sessionId_ = sessionId;
661
662 return SUCCESS;
663 }
664
GetWriteBuffer(uint64_t writePosInFrame,BufferDesc & bufferDesc)665 int32_t OHAudioBuffer::GetWriteBuffer(uint64_t writePosInFrame, BufferDesc &bufferDesc)
666 {
667 uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
668 uint64_t readPos = basicBufferInfo_->curReadFrame.load();
669 uint64_t maxWriteDelta = 2 * totalSizeInFrame_; // 0 ~ 2*totalSizeInFrame_
670 CHECK_AND_RETURN_RET_LOG(writePosInFrame >= basePos && writePosInFrame - basePos < maxWriteDelta &&
671 writePosInFrame >= readPos, ERR_INVALID_PARAM, "Invalid write position:%{public}" PRIu64".", writePosInFrame);
672 return GetBufferByFrame(writePosInFrame, bufferDesc);
673 }
674
GetReadbuffer(uint64_t readPosInFrame,BufferDesc & bufferDesc)675 int32_t OHAudioBuffer::GetReadbuffer(uint64_t readPosInFrame, BufferDesc &bufferDesc)
676 {
677 uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
678 CHECK_AND_RETURN_RET_LOG(readPosInFrame >= basePos && readPosInFrame - basePos < totalSizeInFrame_,
679 ERR_INVALID_PARAM, "Invalid read position:%{public}" PRIu64".", readPosInFrame);
680 return GetBufferByFrame(readPosInFrame, bufferDesc);
681 }
682
GetSpanInfo(uint64_t posInFrame)683 SpanInfo *OHAudioBuffer::GetSpanInfo(uint64_t posInFrame)
684 {
685 uint64_t basePos = basicBufferInfo_->basePosInFrame.load();
686 uint64_t maxPos = basePos + totalSizeInFrame_ + totalSizeInFrame_;
687 CHECK_AND_RETURN_RET_LOG((basePos <= posInFrame && posInFrame < maxPos), nullptr, "posInFrame %{public}" PRIu64" "
688 "out of range, basePos %{public}" PRIu64", maxPos %{public}" PRIu64".", posInFrame, basePos, maxPos);
689
690 uint64_t deltaToBase = posInFrame - basePos;
691 if (deltaToBase >= totalSizeInFrame_) {
692 deltaToBase -= totalSizeInFrame_;
693 }
694 CHECK_AND_RETURN_RET_LOG(deltaToBase < UINT32_MAX && deltaToBase < totalSizeInFrame_, nullptr,"invalid "
695 "deltaToBase, posInFrame %{public}" PRIu64" basePos %{public}" PRIu64".", posInFrame, basePos);
696
697 if (spanSizeInFrame_ > 0) {
698 uint32_t spanIndex = deltaToBase / spanSizeInFrame_;
699 CHECK_AND_RETURN_RET_LOG(spanIndex < spanConut_, nullptr, "invalid spanIndex:%{public}d", spanIndex);
700 return &spanInfoList_[spanIndex];
701 }
702 return nullptr;
703 }
704
GetSpanInfoByIndex(uint32_t spanIndex)705 SpanInfo *OHAudioBuffer::GetSpanInfoByIndex(uint32_t spanIndex)
706 {
707 CHECK_AND_RETURN_RET_LOG(spanIndex < spanConut_, nullptr, "invalid spanIndex:%{public}d", spanIndex);
708 return &spanInfoList_[spanIndex];
709 }
710
GetSpanCount()711 uint32_t OHAudioBuffer::GetSpanCount()
712 {
713 return spanConut_;
714 }
715
GetLastWrittenTime()716 int64_t OHAudioBuffer::GetLastWrittenTime()
717 {
718 return lastWrittenTime_;
719 }
720
SetLastWrittenTime(int64_t time)721 void OHAudioBuffer::SetLastWrittenTime(int64_t time)
722 {
723 lastWrittenTime_ = time;
724 }
725
GetFutex()726 std::atomic<uint32_t> *OHAudioBuffer::GetFutex()
727 {
728 if (basicBufferInfo_ == nullptr) {
729 AUDIO_WARNING_LOG("basicBufferInfo_ is nullptr");
730 return nullptr;
731 }
732 return &basicBufferInfo_->futexObj;
733 }
734
GetDataBase()735 uint8_t *OHAudioBuffer::GetDataBase()
736 {
737 return dataBase_;
738 }
739
GetDataSize()740 size_t OHAudioBuffer::GetDataSize()
741 {
742 return totalSizeInByte_;
743 }
744
GetRestoreInfo(RestoreInfo & restoreInfo)745 void OHAudioBuffer::GetRestoreInfo(RestoreInfo &restoreInfo)
746 {
747 CHECK_AND_RETURN_LOG(basicBufferInfo_ != nullptr, "basicBufferInfo_ is nullptr");
748 restoreInfo = basicBufferInfo_->restoreInfo;
749 }
750
SetRestoreInfo(RestoreInfo restoreInfo)751 void OHAudioBuffer::SetRestoreInfo(RestoreInfo restoreInfo)
752 {
753 CHECK_AND_RETURN_LOG(basicBufferInfo_ != nullptr, "basicBufferInfo_ is nullptr");
754 basicBufferInfo_->restoreInfo = restoreInfo;
755 }
756
757 // Compare and swap restore status. If current restore status is NEED_RESTORE, turn it into RESTORING
758 // to avoid multiple restore.
CheckRestoreStatus()759 RestoreStatus OHAudioBuffer::CheckRestoreStatus()
760 {
761 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, RESTORE_ERROR, "basicBufferInfo_ is nullptr");
762 RestoreStatus expectedStatus = NEED_RESTORE;
763 basicBufferInfo_->restoreStatus.compare_exchange_strong(expectedStatus, RESTORING);
764 return expectedStatus;
765 }
766
767 // Allow client to set restore status to NO_NEED_FOR_RESTORE if unnecessary restore happens. Restore status
768 // can be set to NEED_RESTORE only when it is currently NO_NEED_FOR_RESTORE(and vice versa).
SetRestoreStatus(RestoreStatus restoreStatus)769 RestoreStatus OHAudioBuffer::SetRestoreStatus(RestoreStatus restoreStatus)
770 {
771 CHECK_AND_RETURN_RET_LOG(basicBufferInfo_ != nullptr, RESTORE_ERROR, "basicBufferInfo_ is nullptr");
772 RestoreStatus expectedStatus = RESTORE_ERROR;
773 if (restoreStatus == NEED_RESTORE) {
774 expectedStatus = NO_NEED_FOR_RESTORE;
775 basicBufferInfo_->restoreStatus.compare_exchange_strong(expectedStatus, NEED_RESTORE);
776 } else if (restoreStatus == NO_NEED_FOR_RESTORE) {
777 expectedStatus = RESTORING;
778 basicBufferInfo_->restoreStatus.compare_exchange_strong(expectedStatus, NO_NEED_FOR_RESTORE);
779 }
780 return expectedStatus;
781 }
782 } // namespace AudioStandard
783 } // namespace OHOS
784