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 #ifndef AUDIO_RING_CACHE_H
17 #define AUDIO_RING_CACHE_H
18 
19 #include "stdint.h"
20 #include <atomic>
21 #include <cstddef>
22 #include <memory>
23 #include <mutex>
24 
25 namespace OHOS {
26 namespace AudioStandard {
27 // in plan: Using a globally unified buffer description in AudioStandard namesapce.
28 struct BufferWrap {
29     uint8_t *dataPtr = nullptr;
30     size_t dataSize = 0;
31 };
32 enum RetType : uint32_t {
33     OPERATION_SUCCESS = 0,
34     OPERATION_FAILED,
35     INDEX_OUT_OF_RANGE,
36     DATA_INSUFFICIENT,
37     INVALID_STATUS,
38     INVALID_OPERATION,
39     INVALID_PARAMS,
40 };
41 struct OptResult {
42     RetType ret = INVALID_OPERATION;
43     size_t size = 0;
44 };
45 
46 /**
47  * AudioRingCache itself is thread safe, but you must be careful when combining calls to GetWriteableSize and Enqueue.
48  * As the actual writable size may have changed when Enqueue is called. In this case, enqueue will return a error, and
49  * you need to handle it. The combination of calling GetReadableSize and Dequeue all also requires handling this issue.
50 */
51 class AudioRingCache {
52 public:
53     static std::unique_ptr<AudioRingCache> Create(size_t cacheSize);
54     AudioRingCache(size_t cacheSize);
55     ~AudioRingCache();
56 
57     OptResult ReConfig(size_t cacheSize, bool copyRemained = true);
58 
59     // This operation will clear the buffer and reset inner read/write index.
60     void ResetBuffer();
61 
62     size_t GetCahceSize();
63 
64     // Get the buffer size that can be written. 0 <= WritableSize <= cacheTotalSize_
65     OptResult GetWritableSize();
66 
67     // Get the buffer size that can be read. 0 <= ReadableSize <= cacheTotalSize_
68     OptResult GetReadableSize();
69 
70     // Call GetWritableSize first, than call Enqueue with valid buffer size that <= WritableSize.
71     // Call Enqueue will move write index ahead.
72     OptResult Enqueue(const BufferWrap &buffer);
73 
74     // Call GetReadableSize first, than call Dequeue with valid buffer size that <= ReadableSize.
75     // Call Dequeue will move read index ahead, together with inner base index ahead.
76     OptResult Dequeue(const BufferWrap &buffer);
77 
78 private:
79     bool Init();
80     OptResult GetWritableSizeNoLock();
81     OptResult GetReadableSizeNoLock();
82     OptResult HandleCrossDequeue(size_t tempReadIndex, size_t readableSize, const BufferWrap &buffer);
83     void ReIndex();
84 private:
85     std::mutex cacheMutex_;
86     std::unique_ptr<uint8_t[]> basePtr_;
87     size_t cacheTotalSize_ = 0;
88 
89     size_t baseIndex_ = 0;
90     size_t writeIndex_ = 0;
91     size_t readIndex_ = 0;
92 };
93 } // namespace AudioStandard
94 } // namespace OHOS
95 #endif // AUDIO_RING_CACHE_H
96