Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qaudioringbuffer_p.h
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4//
5// W A R N I N G
6// -------------
7//
8// This file is not part of the Qt API. It exists for the convenience
9// of a number of Qt sources files. This header file may change from
10// version to version without notice, or even be removed.
11//
12// We mean it.
13//
14
15#ifndef QAUDIORINGBUFFER_P_H
16#define QAUDIORINGBUFFER_P_H
17
18#include <QtCore/qspan.h>
19#include <QtMultimedia/private/qaudio_qspan_support_p.h>
20
21#include <algorithm>
22#include <atomic>
23#include <limits>
24
25QT_BEGIN_NAMESPACE
26
27namespace QtPrivate {
28
29// Single-producer, single-consumer wait-free queue
30template <typename T>
32{
33public:
34 using ValueType = T;
35 using Region = QSpan<T>;
36 using ConstRegion = QSpan<const T>;
37
38 explicit QAudioRingBuffer(int bufferSize) : m_bufferSize(bufferSize)
39 {
40 if (bufferSize)
41 m_buffer.reset(new T[bufferSize]); // no value-initialization for trivial types
42 }
43
44 int write(ConstRegion region)
45 {
46 using namespace QtMultimediaPrivate; // drop
47
48 int elementsWritten = 0;
49 while (!region.isEmpty()) {
50 Region writeRegion = acquireWriteRegion(region.size());
51 if (writeRegion.isEmpty())
52 break;
53
54 int toWrite = qMin(writeRegion.size(), region.size());
55 std::copy_n(region.data(), toWrite, writeRegion.data());
56 region = drop(region, toWrite);
58 elementsWritten += toWrite;
59 }
60 return elementsWritten;
61 }
62
63 template <typename Functor>
64 int consume(int elements, Functor &&consumer)
65 {
66 int elementsConsumed = 0;
67
68 while (elements > elementsConsumed) {
69 ConstRegion readRegion = acquireReadRegion(elements - elementsConsumed);
70 if (readRegion.isEmpty())
71 break;
72
73 consumer(readRegion);
74 elementsConsumed += readRegion.size();
75 releaseReadRegion(readRegion.size());
76 }
77
78 return elementsConsumed;
79 }
80
81 template <typename Functor>
82 int consumeAll(Functor &&consumer)
83 {
84 return consume(std::numeric_limits<int>::max(), std::forward<Functor>(consumer));
85 }
86
87 // CAVEAT: beware of the thread safety
88 int used() const { return m_bufferUsed.load(std::memory_order_relaxed); }
89 int free() const { return m_bufferSize - m_bufferUsed.load(std::memory_order_relaxed); }
90
91 int size() const { return m_bufferSize; };
92
93 void reset()
94 {
95 m_readPos = 0;
96 m_writePos = 0;
97 m_bufferUsed.store(0, std::memory_order_relaxed);
98 }
99
101 {
102 const int free = m_bufferSize - m_bufferUsed.load(std::memory_order_acquire);
103
104 Region output;
105 if (free > 0) {
106 const int writeSize = qMin(size, qMin(m_bufferSize - m_writePos, free));
107 output = writeSize > 0 ? Region(m_buffer.get() + m_writePos, writeSize) : Region();
108 } else {
109 output = Region();
110 }
111 return output;
112 }
113
114 void releaseWriteRegion(int elementsRead)
115 {
116 m_writePos = (m_writePos + elementsRead) % m_bufferSize;
117 m_bufferUsed.fetch_add(elementsRead, std::memory_order_release);
118 }
119
121 {
122 const int used = m_bufferUsed.load(std::memory_order_acquire);
123
124 if (used > 0) {
125 const int readSize = qMin(size, qMin(m_bufferSize - m_readPos, used));
126 return readSize > 0 ? Region(m_buffer.get() + m_readPos, readSize) : Region();
127 }
128
129 return Region();
130 }
131
132 void releaseReadRegion(int elementsWritten)
133 {
134 m_readPos = (m_readPos + elementsWritten) % m_bufferSize;
135 m_bufferUsed.fetch_sub(elementsWritten, std::memory_order_release);
136 }
137
138
139private:
140 const int m_bufferSize;
141 int m_readPos{};
142 int m_writePos{};
143 std::unique_ptr<T[]> m_buffer;
144 std::atomic_int m_bufferUsed{};
145};
146
147} // namespace QtPrivate
148
149QT_END_NAMESPACE
150
151#endif // QAUDIORINGBUFFER_P_H
void releaseWriteRegion(int elementsRead)
void releaseReadRegion(int elementsWritten)
ConstRegion acquireReadRegion(int size)
int write(ConstRegion region)
int consumeAll(Functor &&consumer)
int consume(int elements, Functor &&consumer)