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
<
QtCore
/
qtclasshelpermacros
.
h
>
20
#
include
<
QtMultimedia
/
private
/
qaudio_qspan_support_p
.
h
>
21
22
#
include
<
algorithm
>
23
#
include
<
atomic
>
24
#
include
<
cstdlib
>
25
#
include
<
limits
>
26
#
include
<
type_traits
>
27
28
QT_BEGIN_NAMESPACE
29
30
namespace
QtPrivate
{
31
32
// Single-producer, single-consumer wait-free queue
33
template
<
typename
T>
34
class
QAudioRingBuffer
35
{
36
static
constexpr
bool
isTriviallyDestructible =
std
::is_trivially_destructible_v<T>;
37
38
public
:
39
using
ValueType
= T;
40
using
Region
=
QSpan
<
T
>;
41
using
ConstRegion
=
QSpan
<
const
T
>;
42
43
explicit
QAudioRingBuffer
(
int
bufferSize) :
m_bufferSize
(
bufferSize
)
44
{
45
if
(bufferSize)
46
m_buffer =
reinterpret_cast
<T *>(
47
::operator
new
(
sizeof
(T) * bufferSize,
std
::align_val_t(
alignof
(T))));
48
}
49
50
Q_DISABLE_COPY_MOVE
(
QAudioRingBuffer
)
51
52
~
QAudioRingBuffer
()
53
{
54
if
constexpr
(!
isTriviallyDestructible
) {
55
consumeAll
([](
auto
/* elements*/
) {
56
});
57
}
58
59
::
operator
delete
(
reinterpret_cast
<
void
*>(
m_buffer
),
std
::
align_val_t
(
alignof
(
T
)));
60
}
61
62
int
write
(
ConstRegion
region
)
63
{
64
using
namespace
QtMultimediaPrivate
;
// drop
65
return
produceSome
([&](
Region
writeRegion
) {
66
qsizetype
writeSize
=
std
::
min
(
region
.
size
(),
writeRegion
.
size
());
67
std
::
uninitialized_copy_n
(
region
.
data
(),
writeSize
,
writeRegion
.
data
());
68
region
=
drop
(
region
,
writeSize
);
69
70
return
Region
{
71
writeRegion
.
data
(),
72
writeSize
,
73
};
74
});
75
}
76
77
bool
write
(
T
element
)
78
{
79
return
produceOne
([&] {
80
return
std
::
move
(
element
);
81
});
82
}
83
84
template
<
typename
Functor
>
85
bool
produceOne
(
Functor
&&
producer
)
86
#
ifdef
__cpp_concepts
87
requires
88
std
::
is_invocable_v
<
Functor
> &&
std
::
is_constructible_v
<
T
,
std
::
invoke_result_t
<
Functor
>>
89
#
endif
90
{
91
Region
writeRegion
=
acquireWriteRegion
(1);
92
if
(
writeRegion
.
isEmpty
())
93
return
false
;
94
T
*
writeElement
=
writeRegion
.
data
();
95
new
(
writeElement
)
T
{
producer
() };
96
releaseWriteRegion
(1);
97
return
true
;
98
}
99
100
template
<
typename
Functor
>
101
int
produceSome
(
Functor
&&
producer
,
int
elements
=
std
::
numeric_limits
<
int
>::
max
())
102
#
ifdef
__cpp_concepts
103
requires
std
::
is_invocable_v
<
Functor
,
Region
>
104
&&
std
::
is_same_v
<
std
::
invoke_result_t
<
Functor
,
Region
>,
Region
>
105
#
endif
106
{
107
int
elementsRemain
=
elements
;
108
int
elementsWritten
= 0;
109
while
(
elementsRemain
) {
110
Region
writeRegion
=
acquireWriteRegion
(
elementsRemain
);
111
if
(
writeRegion
.
isEmpty
())
112
break
;
113
114
Region
writtenRegion
=
producer
(
writeRegion
);
115
if
(
writtenRegion
.
isEmpty
())
116
break
;
117
118
Q_ASSERT
(
writtenRegion
.
data
() ==
writeRegion
.
data
());
119
Q_ASSERT
(
writtenRegion
.
size
() <=
writeRegion
.
size
());
120
121
elementsRemain
-=
writtenRegion
.
size
();
122
elementsWritten
+=
writtenRegion
.
size
();
123
releaseWriteRegion
(
writtenRegion
.
size
());
124
}
125
return
elementsWritten
;
126
}
127
128
template
<
typename
Functor
>
129
int
consumeAll
(
Functor
&&
consumer
)
130
{
131
return
consumeSome
([&](
Region
region
) {
132
consumer
(
region
);
133
return
region
;
134
});
135
}
136
137
template
<
typename
Functor
>
138
int
consume
(
int
elements
,
Functor
&&
consumer
)
139
{
140
int
remainingElemnts
=
elements
;
141
return
consumeSome
([&](
Region
region
) {
142
if
(
remainingElemnts
== 0)
143
return
Region
{};
144
145
Region
regionToConsume
=
QtMultimediaPrivate
::
take
(
region
,
remainingElemnts
);
146
consumer
(
regionToConsume
);
147
remainingElemnts
-=
regionToConsume
.
size
();
148
return
regionToConsume
;
149
});
150
}
151
152
// consumer has to return the region it has consumed
153
template
<
typename
Functor
>
154
int
consumeSome
(
Functor
&&
consumer
,
int
elements
=
std
::
numeric_limits
<
int
>::
max
())
155
#
ifdef
__cpp_concepts
156
requires
std
::
is_invocable_v
<
Functor
,
Region
>
157
&&
std
::
is_same_v
<
std
::
invoke_result_t
<
Functor
,
Region
>,
Region
>
158
#
endif
159
{
160
int
elementsConsumed
= 0;
161
162
while
(
elements
>
elementsConsumed
) {
163
Region
readRegion
=
acquireReadRegion
(
elements
-
elementsConsumed
);
164
if
(
readRegion
.
isEmpty
())
165
break
;
166
167
Region
consumedRegion
=
consumer
(
readRegion
);
168
if
(
consumedRegion
.
isEmpty
())
169
break
;
170
Q_ASSERT
(
consumedRegion
.
data
() ==
readRegion
.
data
());
171
Q_ASSERT
(
consumedRegion
.
size
() <=
readRegion
.
size
());
172
173
if
constexpr
(!
isTriviallyDestructible
)
174
std
::
destroy
(
consumedRegion
.
begin
(),
consumedRegion
.
end
());
175
176
elementsConsumed
+=
consumedRegion
.
size
();
177
releaseReadRegion
(
consumedRegion
.
size
());
178
}
179
180
return
elementsConsumed
;
181
}
182
183
// CAVEAT: beware of the thread safety
184
int
used
()
const
{
return
m_bufferUsed
.
load
(
std
::
memory_order_relaxed
); }
185
int
free
()
const
{
return
m_bufferSize
-
m_bufferUsed
.
load
(
std
::
memory_order_relaxed
); }
186
187
int
size
()
const
{
return
m_bufferSize
; }
188
189
void
reset
()
190
#
ifdef
__cpp_concepts
191
requires
isTriviallyDestructible
192
#
endif
193
{
194
m_readPos
= 0;
195
m_writePos
= 0;
196
m_bufferUsed
.
store
(0,
std
::
memory_order_relaxed
);
197
}
198
199
private
:
200
Region
acquireWriteRegion
(
int
size
)
201
{
202
const
int
free
=
m_bufferSize
-
m_bufferUsed
.
load
(
std
::
memory_order_acquire
);
203
204
Region
output
;
205
if
(
free
> 0) {
206
const
int
writeSize
=
qMin
(
size
,
qMin
(
m_bufferSize
-
m_writePos
,
free
));
207
output
=
writeSize
> 0 ?
Region
(
m_buffer
+
m_writePos
,
writeSize
) :
Region
();
208
}
else
{
209
output
=
Region
();
210
}
211
return
output
;
212
}
213
214
void
releaseWriteRegion
(
int
elementsRead
)
215
{
216
m_writePos
= (
m_writePos
+
elementsRead
) %
m_bufferSize
;
217
m_bufferUsed
.
fetch_add
(
elementsRead
,
std
::
memory_order_release
);
218
}
219
220
Region
acquireReadRegion
(
int
size
)
221
{
222
const
int
used
=
m_bufferUsed
.
load
(
std
::
memory_order_acquire
);
223
224
if
(
used
> 0) {
225
const
int
readSize
=
qMin
(
size
,
qMin
(
m_bufferSize
-
m_readPos
,
used
));
226
return
readSize
> 0 ?
Region
(
m_buffer
+
m_readPos
,
readSize
) :
Region
();
227
}
228
229
return
Region
();
230
}
231
232
// WARNING: we need to ensure that all elements are destroyed
233
void
releaseReadRegion
(
int
elementsWritten
)
234
{
235
m_readPos
= (
m_readPos
+
elementsWritten
) %
m_bufferSize
;
236
m_bufferUsed
.
fetch_sub
(
elementsWritten
,
std
::
memory_order_release
);
237
}
238
239
const
int
m_bufferSize
;
240
int
m_readPos{};
241
int
m_writePos{};
242
T *m_buffer{};
243
std
::atomic_int m_bufferUsed{};
244
};
245
246
}
// namespace QtPrivate
247
248
QT_END_NAMESPACE
249
250
#
endif
// QAUDIORINGBUFFER_P_H
QtPrivate::QAudioRingBuffer
Definition
qaudioringbuffer_p.h:35
QtPrivate::QAudioRingBuffer::ValueType
T ValueType
Definition
qaudioringbuffer_p.h:39
QtPrivate::QAudioRingBuffer::QAudioRingBuffer
QAudioRingBuffer(int bufferSize)
Definition
qaudioringbuffer_p.h:43
QtPrivate
Definition
qalloc.h:27
std
[33]
Definition
src_corelib_tools_qhash.cpp:421
qtmultimedia
src
multimedia
audio
qaudioringbuffer_p.h
Generated on
for Qt by
1.14.0