1 /* 2 * Copyright (c) 2021-2021 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 #ifndef HISTREAMER_RING_BUFFER_H 17 #define HISTREAMER_RING_BUFFER_H 18 19 #include <atomic> 20 #include <memory> 21 #include "foundation/log.h" 22 #include "foundation/cpp_ext/memory_ext.h" 23 #include "foundation/osal/thread/condition_variable.h" 24 #include "foundation/osal/thread/mutex.h" 25 #include "foundation/osal/thread/scoped_lock.h" 26 #include "securec.h" 27 28 namespace OHOS { 29 namespace Media { 30 class RingBuffer { 31 public: RingBuffer(size_t bufferSize)32 explicit RingBuffer(size_t bufferSize) : bufferSize_(bufferSize) 33 { 34 } 35 36 ~RingBuffer() = default; 37 Init()38 bool Init() 39 { 40 buffer_ = CppExt::make_unique<uint8_t[]>(bufferSize_); 41 return buffer_ != nullptr; 42 } 43 44 size_t ReadBuffer(void* ptr, size_t readSize, int waitTimes = 0) 45 { 46 OSAL::ScopedLock lck(writeMutex_); 47 if (!isActive_) { 48 return 0; 49 } 50 auto available = tail_ - head_; 51 while (waitTimes > 0 && available == 0) { 52 writeCondition_.Wait(lck); 53 if (!isActive_) { 54 return 0; 55 } 56 available = tail_ - head_; 57 waitTimes--; 58 } 59 available = (available > readSize) ? readSize : available; 60 size_t index = head_ % bufferSize_; 61 if (index + available < bufferSize_) { 62 (void)memcpy_s(ptr, available, buffer_.get() + index, available); 63 } else { 64 (void)memcpy_s(ptr, bufferSize_ - index, buffer_.get() + index, bufferSize_ - index); 65 (void)memcpy_s(((uint8_t*)ptr) + (bufferSize_ - index), available - (bufferSize_ - index), buffer_.get(), 66 available - (bufferSize_ - index)); 67 } 68 head_ += available; 69 mediaOffset_ += available; 70 writeCondition_.NotifyOne(); 71 return available; 72 } 73 74 bool WriteBuffer(void* ptr, size_t writeSize, uint64_t mediaOffset = 0) 75 { 76 OSAL::ScopedLock lck(writeMutex_); 77 if (!isActive_) { 78 return false; 79 } 80 while (writeSize + tail_ > head_ + bufferSize_) { 81 writeCondition_.Wait(lck); 82 if (!isActive_) { 83 return false; 84 } 85 } 86 size_t index = tail_ % bufferSize_; 87 if (index + writeSize < bufferSize_) { 88 (void)memcpy_s(buffer_.get() + index, writeSize, ptr, writeSize); 89 } else { 90 (void)memcpy_s(buffer_.get() + index, bufferSize_ - index, ptr, bufferSize_ - index); 91 (void)memcpy_s(buffer_.get(), writeSize - (bufferSize_ - index), ((uint8_t*)ptr) + bufferSize_ - index, 92 writeSize - (bufferSize_ - index)); 93 } 94 tail_ += writeSize; 95 if (head_ == 0) { 96 mediaOffset_ = mediaOffset; 97 } 98 writeCondition_.NotifyOne(); 99 return true; 100 } 101 102 void SetActive(bool active, bool cleanData = true) 103 { 104 OSAL::ScopedLock lck(writeMutex_); 105 isActive_ = active; 106 if (!active) { 107 if (cleanData) { 108 head_ = 0; 109 tail_ = 0; 110 } 111 writeCondition_.NotifyOne(); 112 } 113 } 114 GetSize()115 size_t GetSize() 116 { 117 return (tail_ - head_); 118 } 119 Clear()120 void Clear() 121 { 122 OSAL::ScopedLock lck(writeMutex_); 123 head_ = 0; 124 tail_ = 0; 125 writeCondition_.NotifyOne(); 126 } 127 Seek(uint64_t offset)128 bool Seek(uint64_t offset) 129 { 130 OSAL::ScopedLock lck(writeMutex_); 131 MEDIA_LOG_I("Seek: buffer size " PUBLIC_LOG_ZU ", offset " PUBLIC_LOG_U64 132 ", mediaOffset_ " PUBLIC_LOG_U64, GetSize(), offset, mediaOffset_); 133 bool result = false; 134 if (offset >= mediaOffset_ && offset - mediaOffset_ < GetSize()) { 135 head_ += offset - mediaOffset_; 136 result = true; 137 } 138 writeCondition_.NotifyOne(); 139 return result; 140 } 141 private: 142 const size_t bufferSize_; 143 std::unique_ptr<uint8_t[]> buffer_; 144 size_t head_ {0}; // head 145 size_t tail_ {0}; // tail 146 OSAL::Mutex writeMutex_ {}; 147 OSAL::ConditionVariable writeCondition_ {}; 148 bool isActive_ {true}; 149 uint64_t mediaOffset_ {0}; 150 }; 151 } // namespace Media 152 } // namespace OHOS 153 154 #endif // HISTREAMER_RING_BUFFER_H 155