1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
|
/* $Id: AudioMixer.h $ */
/** @file
* VBox audio - Mixing routines.
*
* The mixing routines are mainly used by the various audio device emulations
* to achieve proper multiplexing from/to attached devices LUNs.
*/
/*
* Copyright (C) 2014-2023 Oracle and/or its affiliates.
*
* This file is part of VirtualBox base platform packages, as
* available from https://www.virtualbox.org.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, in version 3 of the
* License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses>.
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#ifndef VBOX_INCLUDED_SRC_Audio_AudioMixer_h
#define VBOX_INCLUDED_SRC_Audio_AudioMixer_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif
#include <iprt/cdefs.h>
#include <iprt/critsect.h>
#include <VBox/vmm/pdmaudioifs.h>
#include "AudioMixBuffer.h"
#include "AudioHlp.h"
/** @defgroup grp_pdm_ifs_audio_mixing Audio Mixing
* @ingroup grp_pdm_ifs_audio
*
* @note This is currently placed under PDM Audio Interface as that seemed like
* the best place for it.
*
* @{
*/
/** Pointer to an audio mixer sink. */
typedef struct AUDMIXSINK *PAUDMIXSINK;
/** Pointer to a const audio mixer sink. */
typedef struct AUDMIXSINK const *PCAUDMIXSINK;
/**
* Audio mixer instance.
*/
typedef struct AUDIOMIXER
{
/** Magic value (AUDIOMIXER_MAGIC). */
uintptr_t uMagic;
/** The mixer's name (allocated after this structure). */
char const *pszName;
/** The master volume of this mixer. */
PDMAUDIOVOLUME VolMaster;
/** List of audio mixer sinks (AUDMIXSINK). */
RTLISTANCHOR lstSinks;
/** Number of used audio sinks. */
uint8_t cSinks;
/** Mixer flags. See AUDMIXER_FLAGS_XXX. */
uint32_t fFlags;
/** The mixer's critical section. */
RTCRITSECT CritSect;
} AUDIOMIXER;
/** Pointer to an audio mixer instance. */
typedef AUDIOMIXER *PAUDIOMIXER;
/** Value for AUDIOMIXER::uMagic. (Attilio Joseph "Teo" Macero) */
#define AUDIOMIXER_MAGIC UINT32_C(0x19251030)
/** Value for AUDIOMIXER::uMagic after destruction. */
#define AUDIOMIXER_MAGIC_DEAD UINT32_C(0x20080219)
/** @name AUDMIXER_FLAGS_XXX - For AudioMixerCreate().
* @{ */
/** No mixer flags specified. */
#define AUDMIXER_FLAGS_NONE 0
/** Debug mode enabled.
* This writes .WAV file to the host, usually to the temporary directory. */
#define AUDMIXER_FLAGS_DEBUG RT_BIT(0)
/** Validation mask. */
#define AUDMIXER_FLAGS_VALID_MASK UINT32_C(0x00000001)
/** @} */
/**
* Audio mixer stream.
*/
typedef struct AUDMIXSTREAM
{
/** List entry on AUDMIXSINK::lstStreams. */
RTLISTNODE Node;
/** Magic value (AUDMIXSTREAM_MAGIC). */
uint32_t uMagic;
/** The backend buffer size in frames (for draining deadline calc). */
uint32_t cFramesBackendBuffer;
/** Stream status of type AUDMIXSTREAM_STATUS_. */
uint32_t fStatus;
/** Number of writable/readable frames the last time we checked. */
uint32_t cFramesLastAvail;
/** Set if the stream has been found unreliable wrt. consuming/producing
* samples, and that we shouldn't consider it when deciding how much to move
* from the mixer buffer and to the drivers. */
bool fUnreliable;
/** Name of this stream. */
char *pszName;
/** The statistics prefix. */
char *pszStatPrefix;
/** Sink this stream is attached to. */
PAUDMIXSINK pSink;
/** Pointer to audio connector being used. */
PPDMIAUDIOCONNECTOR pConn;
/** Pointer to PDM audio stream this mixer stream handles. */
PPDMAUDIOSTREAM pStream;
union
{
/** Output: Mixing buffer peeking state & config. */
AUDIOMIXBUFPEEKSTATE PeekState;
/** Input: Mixing buffer writing state & config. */
AUDIOMIXBUFWRITESTATE WriteState;
};
/** Last read (recording) / written (playback) timestamp (in ns). */
uint64_t tsLastReadWrittenNs;
/** The streams's critical section. */
RTCRITSECT CritSect;
} AUDMIXSTREAM;
/** Pointer to an audio mixer stream. */
typedef AUDMIXSTREAM *PAUDMIXSTREAM;
/** Value for AUDMIXSTREAM::uMagic. (Jan Erik Kongshaug) */
#define AUDMIXSTREAM_MAGIC UINT32_C(0x19440704)
/** Value for AUDMIXSTREAM::uMagic after destruction. */
#define AUDMIXSTREAM_MAGIC_DEAD UINT32_C(0x20191105)
/** @name AUDMIXSTREAM_STATUS_XXX - mixer stream status.
* (This is a destilled version of PDMAUDIOSTREAM_STS_XXX.)
* @{ */
/** No status set. */
#define AUDMIXSTREAM_STATUS_NONE UINT32_C(0)
/** The mixing stream is enabled (active). */
#define AUDMIXSTREAM_STATUS_ENABLED RT_BIT_32(0)
/** The mixing stream can be read from.
* Always set together with AUDMIXSTREAM_STATUS_ENABLED. */
#define AUDMIXSTREAM_STATUS_CAN_READ RT_BIT_32(1)
/** The mixing stream can be written to.
* Always set together with AUDMIXSTREAM_STATUS_ENABLED. */
#define AUDMIXSTREAM_STATUS_CAN_WRITE RT_BIT_32(2)
/** @} */
/** Callback for an asynchronous I/O update job. */
typedef DECLCALLBACKTYPE(void, FNAUDMIXSINKUPDATE,(PPDMDEVINS pDevIns, PAUDMIXSINK pSink, void *pvUser));
/** Pointer to a callback for an asynchronous I/O update job. */
typedef FNAUDMIXSINKUPDATE *PFNAUDMIXSINKUPDATE;
/**
* Audio mixer sink.
*/
typedef struct AUDMIXSINK
{
/** List entry on AUDIOMIXER::lstSinks. */
RTLISTNODE Node;
/** Magic value (AUDMIXSINK_MAGIC). */
uint32_t uMagic;
/** The sink direction (either PDMAUDIODIR_IN or PDMAUDIODIR_OUT). */
PDMAUDIODIR enmDir;
/** Pointer to mixer object this sink is bound to. */
PAUDIOMIXER pParent;
/** Name of this sink (allocated after this structure). */
char const *pszName;
/** The sink's PCM format (i.e. the guest device side). */
PDMAUDIOPCMPROPS PCMProps;
/** Sink status bits - AUDMIXSINK_STS_XXX. */
uint32_t fStatus;
/** Number of bytes to be transferred from the device DMA buffer before the
* streams will be put into draining mode. */
uint32_t cbDmaLeftToDrain;
/** The deadline for draining if it's pending. */
uint64_t nsDrainDeadline;
/** When the draining startet (for logging). */
uint64_t nsDrainStarted;
/** Number of streams assigned. */
uint8_t cStreams;
/** List of assigned streams (AUDMIXSTREAM).
* @note All streams have the same PCM properties, so the mixer does not do
* any conversion. bird: That is *NOT* true any more, the mixer has
* encoders/decoder states for each stream (well, input is still a todo).
*
* @todo Use something faster -- vector maybe? bird: It won't be faster. You
* will have a vector of stream pointers (because you cannot have a vector
* of full AUDMIXSTREAM structures since they'll move when the vector is
* reallocated and we need pointers to them to give out to devices), which
* is the same cost as going via Node.pNext/pPrev. */
RTLISTANCHOR lstStreams;
/** The volume of this sink. The volume always will
* be combined with the mixer's master volume. */
PDMAUDIOVOLUME Volume;
/** The volume of this sink, combined with the last set master volume. */
PDMAUDIOVOLUME VolumeCombined;
/** Timestamp since last update (in ms). */
uint64_t tsLastUpdatedMs;
/** Last read (recording) / written (playback) timestamp (in ns). */
uint64_t tsLastReadWrittenNs;
/** Union for input/output specifics. */
union
{
struct
{
/** The sink's peek state. */
AUDIOMIXBUFPEEKSTATE State;
} In;
struct
{
/** The sink's write state. */
AUDIOMIXBUFWRITESTATE State;
} Out;
};
struct
{
PAUDIOHLPFILE pFile;
} Dbg;
/** This sink's mixing buffer. */
AUDIOMIXBUF MixBuf;
/** Asynchronous I/O thread related stuff. */
struct
{
/** The thread handle, NIL_RTTHREAD if not active. */
RTTHREAD hThread;
/** Event for letting the thread know there is some data to process. */
RTSEMEVENT hEvent;
/** The device instance (same for all update jobs). */
PPDMDEVINS pDevIns;
/** Started indicator. */
volatile bool fStarted;
/** Shutdown indicator. */
volatile bool fShutdown;
/** Number of update jobs this sink has (usually zero or one). */
uint8_t cUpdateJobs;
/** The minimum typical interval for all jobs. */
uint32_t cMsMinTypicalInterval;
/** Update jobs for this sink. */
struct
{
/** User specific argument. */
void *pvUser;
/** The callback. */
PFNAUDMIXSINKUPDATE pfnUpdate;
/** Typical interval in milliseconds. */
uint32_t cMsTypicalInterval;
} aUpdateJobs[8];
} AIO;
/** The sink's critical section. */
RTCRITSECT CritSect;
} AUDMIXSINK;
/** Value for AUDMIXSINK::uMagic. (Sir George Martin) */
#define AUDMIXSINK_MAGIC UINT32_C(0x19260103)
/** Value for AUDMIXSINK::uMagic after destruction. */
#define AUDMIXSINK_MAGIC_DEAD UINT32_C(0x20160308)
/** @name AUDMIXSINK_STS_XXX - Sink status bits.
* @{ */
/** No status specified. */
#define AUDMIXSINK_STS_NONE 0
/** The sink is active and running. */
#define AUDMIXSINK_STS_RUNNING RT_BIT(0)
/** Draining the buffers and pending stop - output only. */
#define AUDMIXSINK_STS_DRAINING RT_BIT(1)
/** Drained the DMA buffer. */
#define AUDMIXSINK_STS_DRAINED_DMA RT_BIT(2)
/** Drained the mixer buffer, only waiting for streams (drivers) now. */
#define AUDMIXSINK_STS_DRAINED_MIXBUF RT_BIT(3)
/** Dirty flag.
* - For output sinks this means that there is data in the sink which has not
* been played yet.
* - For input sinks this means that there is data in the sink which has been
* recorded but not transferred to the destination yet.
* @todo This isn't used for *anything* at the moment. Remove? */
#define AUDMIXSINK_STS_DIRTY RT_BIT(4)
/** @} */
/** @name Audio mixer methods
* @{ */
int AudioMixerCreate(const char *pszName, uint32_t fFlags, PAUDIOMIXER *ppMixer);
void AudioMixerDestroy(PAUDIOMIXER pMixer, PPDMDEVINS pDevIns);
void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs);
int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PCPDMAUDIOVOLUME pVol);
int AudioMixerCreateSink(PAUDIOMIXER pMixer, const char *pszName, PDMAUDIODIR enmDir, PPDMDEVINS pDevIns, PAUDMIXSINK *ppSink);
/** @} */
/** @name Audio mixer sink methods
* @{ */
int AudioMixerSinkStart(PAUDMIXSINK pSink);
int AudioMixerSinkDrainAndStop(PAUDMIXSINK pSink, uint32_t cbComming);
void AudioMixerSinkDestroy(PAUDMIXSINK pSink, PPDMDEVINS pDevIns);
uint32_t AudioMixerSinkGetReadable(PAUDMIXSINK pSink);
uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink);
PDMAUDIODIR AudioMixerSinkGetDir(PCAUDMIXSINK pSink);
uint32_t AudioMixerSinkGetStatus(PAUDMIXSINK pSink);
bool AudioMixerSinkIsActive(PAUDMIXSINK pSink);
void AudioMixerSinkReset(PAUDMIXSINK pSink);
int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PCPDMAUDIOPCMPROPS pPCMProps, uint32_t cMsSchedulingHint);
int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PCPDMAUDIOVOLUME pVol);
int AudioMixerSinkUpdate(PAUDMIXSINK pSink, uint32_t cbDmaUsed, uint32_t cbDmaPeriod);
int AudioMixerSinkAddUpdateJob(PAUDMIXSINK pSink, PFNAUDMIXSINKUPDATE pfnUpdate, void *pvUser, uint32_t cMsTypicalInterval);
int AudioMixerSinkRemoveUpdateJob(PAUDMIXSINK pSink, PFNAUDMIXSINKUPDATE pfnUpdate, void *pvUser);
int AudioMixerSinkSignalUpdateJob(PAUDMIXSINK pSink);
uint64_t AudioMixerSinkTransferFromCircBuf(PAUDMIXSINK pSink, PRTCIRCBUF pCircBuf, uint64_t offStream,
uint32_t idStream, PAUDIOHLPFILE pDbgFile);
uint64_t AudioMixerSinkTransferToCircBuf(PAUDMIXSINK pSink, PRTCIRCBUF pCircBuf, uint64_t offStream,
uint32_t idStream, PAUDIOHLPFILE pDbgFile);
bool AudioMixerSinkLockIsOwner(PAUDMIXSINK pSink);
int AudioMixerSinkLock(PAUDMIXSINK pSink);
int AudioMixerSinkTryLock(PAUDMIXSINK pSink);
int AudioMixerSinkUnlock(PAUDMIXSINK pSink);
int AudioMixerSinkCreateStream(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PCPDMAUDIOSTREAMCFG pCfg,
PPDMDEVINS pDevIns, PAUDMIXSTREAM *ppStream);
int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink);
/** @} */
/** @name Audio mixer stream methods
* @{ */
void AudioMixerStreamDestroy(PAUDMIXSTREAM pStream, PPDMDEVINS pDevIns, bool fImmediate);
/** @} */
/** @} */
#endif /* !VBOX_INCLUDED_SRC_Audio_AudioMixer_h */
|