VirtualBox

source: vbox/trunk/include/VBox/vmm/pdmaudiohostenuminline.h@ 88047

Last change on this file since 88047 was 88047, checked in by vboxsync, 4 years ago

Audio: Moved the host audio device enumeration code to PDM (VBox/vmm/pdmaudiohostenuminline.h). bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1/* $Id: pdmaudiohostenuminline.h 88047 2021-03-09 14:06:20Z vboxsync $ */
2/** @file
3 * PDM - Audio Helpers, Inlined Code. (DEV,++)
4 *
5 * This is all inlined because it's too tedious to create a couple libraries to
6 * contain it all (same bad excuse as for intnetinline.h & pdmnetinline.h).
7 */
8
9/*
10 * Copyright (C) 2006-2020 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * The contents of this file may alternatively be used under the terms
21 * of the Common Development and Distribution License Version 1.0
22 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
23 * VirtualBox OSE distribution, in which case the provisions of the
24 * CDDL are applicable instead of those of the GPL.
25 *
26 * You may elect to license modified versions of this file under the
27 * terms and conditions of either the GPL or the CDDL or both.
28 */
29
30#ifndef VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h
31#define VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h
32#ifndef RT_WITHOUT_PRAGMA_ONCE
33# pragma once
34#endif
35
36
37/*********************************************************************************************************************************
38* Header Files *
39*********************************************************************************************************************************/
40#include <VBox/err.h>
41#include <VBox/log.h>
42#include <VBox/vmm/pdmaudioifs.h>
43#include <VBox/vmm/pdmaudioinline.h>
44
45#include <iprt/asm.h>
46#include <iprt/asm-math.h>
47#include <iprt/assert.h>
48#include <iprt/mem.h>
49#include <iprt/string.h>
50
51
52/**
53 * Allocates an audio device.
54 *
55 * @returns Newly allocated audio device, or NULL on failure.
56 * @param cb The total device structure size. This must be at least the
57 * size of PDMAUDIOHOSTDEV. The idea is that the caller extends
58 * the PDMAUDIOHOSTDEV structure and appends additional data
59 * after it in its private structure.
60 */
61DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioDeviceAlloc(size_t cb)
62{
63 AssertReturn(cb >= sizeof(PDMAUDIOHOSTDEV), NULL);
64 AssertReturn(cb < _4M, NULL);
65
66 PPDMAUDIOHOSTDEV pDev = (PPDMAUDIOHOSTDEV)RTMemAllocZ(RT_ALIGN_Z(cb, 64));
67 if (pDev)
68 {
69 pDev->uMagic = PDMAUDIOHOSTDEV_MAGIC;
70 pDev->cbSelf = (uint32_t)cb;
71 RTListInit(&pDev->Node);
72
73 //pDev->cMaxInputChannels = 0;
74 //pDev->cMaxOutputChannels = 0;
75 }
76 return pDev;
77}
78
79/**
80 * Frees an audio device allocated by PDMAudioDeviceAlloc.
81 *
82 * @param pDev The device to free. NULL is ignored.
83 */
84DECLINLINE(void) PDMAudioDeviceFree(PPDMAUDIOHOSTDEV pDev)
85{
86 if (pDev)
87 {
88 Assert(pDev->uMagic == PDMAUDIOHOSTDEV_MAGIC);
89 Assert(pDev->cRefCount == 0);
90 pDev->uMagic = PDMAUDIOHOSTDEV_MAGIC_DEAD;
91 pDev->cbSelf = 0;
92
93 RTMemFree(pDev);
94 }
95}
96
97/**
98 * Duplicates an audio device entry.
99 *
100 * @returns Duplicated audio device entry on success, or NULL on failure.
101 * @param pDev The audio device enum entry to duplicate.
102 * @param fOnlyCoreData
103 */
104DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioDeviceDup(PPDMAUDIOHOSTDEV pDev, bool fOnlyCoreData)
105{
106 AssertPtrReturn(pDev, NULL);
107 Assert(pDev->uMagic == PDMAUDIOHOSTDEV_MAGIC);
108 Assert(fOnlyCoreData || !(pDev->fFlags & PDMAUDIOHOSTDEV_F_NO_DUP));
109
110 uint32_t cbToDup = fOnlyCoreData ? sizeof(PDMAUDIOHOSTDEV) : pDev->cbSelf;
111 AssertReturn(cbToDup >= sizeof(*pDev), NULL);
112
113 PPDMAUDIOHOSTDEV pDevDup = PDMAudioDeviceAlloc(cbToDup);
114 if (pDevDup)
115 {
116 memcpy(pDevDup, pDev, cbToDup);
117 RTListInit(&pDevDup->Node);
118 pDev->cbSelf = cbToDup;
119 }
120
121 return pDevDup;
122}
123
124/**
125 * Initializes a host audio device enumeration.
126 *
127 * @param pDevEnm The enumeration to initialize.
128 */
129DECLINLINE(void) PDMAudioHostEnumInit(PPDMAUDIOHOSTENUM pDevEnm)
130{
131 AssertPtr(pDevEnm);
132
133 pDevEnm->uMagic = PDMAUDIOHOSTENUM_MAGIC;
134 pDevEnm->cDevices = 0;
135 RTListInit(&pDevEnm->LstDevices);
136}
137
138/**
139 * Deletes the host audio device enumeration and frees all device entries
140 * associated with it.
141 *
142 * The user must call PDMAudioHostEnumInit again to use it again.
143 *
144 * @param pDevEnm The host audio device enumeration to delete.
145 */
146DECLINLINE(void) PDMAudioHostEnumDelete(PPDMAUDIOHOSTENUM pDevEnm)
147{
148 if (pDevEnm)
149 {
150 AssertPtr(pDevEnm);
151 AssertReturnVoid(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC);
152
153 PPDMAUDIOHOSTDEV pDev, pDevNext;
154 RTListForEachSafe(&pDevEnm->LstDevices, pDev, pDevNext, PDMAUDIOHOSTDEV, Node)
155 {
156 RTListNodeRemove(&pDev->Node);
157
158 PDMAudioDeviceFree(pDev);
159
160 pDevEnm->cDevices--;
161 }
162
163 /* Sanity. */
164 Assert(RTListIsEmpty(&pDevEnm->LstDevices));
165 Assert(pDevEnm->cDevices == 0);
166
167 pDevEnm->uMagic = ~PDMAUDIOHOSTENUM_MAGIC;
168 }
169}
170
171/**
172 * Adds an audio device to a device enumeration.
173 *
174 * @param pDevEnm Device enumeration to add device to.
175 * @param pDev Device to add. The pointer will be owned by the device enumeration then.
176 */
177DECLINLINE(void) PDMAudioHostEnumAppend(PPDMAUDIOHOSTENUM pDevEnm, PPDMAUDIOHOSTDEV pDev)
178{
179 AssertPtr(pDevEnm);
180 AssertPtr(pDev);
181 Assert(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC);
182
183 RTListAppend(&pDevEnm->LstDevices, &pDev->Node);
184 pDevEnm->cDevices++;
185}
186
187/**
188 * Appends copies of matching host device entries from one to another enumeration.
189 *
190 * @returns IPRT status code.
191 * @param pDstDevEnm The target to append copies of matching device to.
192 * @param pSrcDevEnm The source to copy matching devices from.
193 * @param enmUsage The usage to match for copying.
194 * Use PDMAUDIODIR_INVALID to match all entries.
195 * @param fOnlyCoreData Set this to only copy the PDMAUDIOHOSTDEV part.
196 * Careful with passing @c false here as not all
197 * backends have data that can be copied.
198 */
199DECLINLINE(int) PDMAudioHostEnumCopy(PPDMAUDIOHOSTENUM pDstDevEnm, PCPDMAUDIOHOSTENUM pSrcDevEnm,
200 PDMAUDIODIR enmUsage, bool fOnlyCoreData)
201{
202 AssertPtrReturn(pDstDevEnm, VERR_INVALID_POINTER);
203 AssertReturn(pDstDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER);
204
205 AssertPtrReturn(pSrcDevEnm, VERR_INVALID_POINTER);
206 AssertReturn(pSrcDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER);
207
208 PPDMAUDIOHOSTDEV pSrcDev;
209 RTListForEach(&pSrcDevEnm->LstDevices, pSrcDev, PDMAUDIOHOSTDEV, Node)
210 {
211 if ( enmUsage == pSrcDev->enmUsage
212 || enmUsage == PDMAUDIODIR_INVALID /*all*/)
213 {
214 PPDMAUDIOHOSTDEV pDstDev = PDMAudioDeviceDup(pSrcDev, fOnlyCoreData);
215 AssertReturn(pDstDev, VERR_NO_MEMORY);
216
217 PDMAudioHostEnumAppend(pDstDevEnm, pDstDev);
218 }
219 }
220
221 return VINF_SUCCESS;
222}
223
224/**
225 * Get the default device with the given usage.
226 *
227 * This assumes that only one default device per usage is set, if there should
228 * be more than one, the first one is returned.
229 *
230 * @returns Default device if found, or NULL if not.
231 * @param pDevEnm Device enumeration to get default device for.
232 * @param enmUsage Usage to get default device for.
233 * Pass PDMAUDIODIR_INVALID to get the first device with
234 * PDMAUDIOHOSTDEV_F_DEFAULT set.
235 */
236DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostEnumGetDefault(PCPDMAUDIOHOSTENUM pDevEnm, PDMAUDIODIR enmUsage)
237{
238 AssertPtrReturn(pDevEnm, NULL);
239 AssertReturn(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, NULL);
240
241 PPDMAUDIOHOSTDEV pDev;
242 RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, Node)
243 {
244 if (pDev->fFlags & PDMAUDIOHOSTDEV_F_DEFAULT)
245 {
246 if ( enmUsage == pDev->enmUsage
247 || enmUsage == PDMAUDIODIR_INVALID)
248 return pDev;
249 }
250 }
251
252 return NULL;
253}
254
255/**
256 * Get the number of device with the given usage.
257 *
258 * @returns Number of matching devices.
259 * @param pDevEnm Device enumeration to get default device for.
260 * @param enmUsage Usage to count devices for.
261 * Pass PDMAUDIODIR_INVALID to get the total number of devices.
262 */
263DECLINLINE(uint32_t) PDMAudioHostEnumCountMatching(PCPDMAUDIOHOSTENUM pDevEnm, PDMAUDIODIR enmUsage)
264{
265 AssertPtrReturn(pDevEnm, 0);
266 AssertReturn(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, 0);
267
268 if (enmUsage == PDMAUDIODIR_INVALID)
269 return pDevEnm->cDevices;
270
271 uint32_t cDevs = 0;
272 PPDMAUDIOHOSTDEV pDev;
273 RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, Node)
274 {
275 if (enmUsage == pDev->enmUsage)
276 cDevs++;
277 }
278
279 return cDevs;
280}
281
282/** The max string length for all PDMAUDIOHOSTDEV_F_XXX.
283 * @sa PDMAudioDeviceFlagsToString */
284#define PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN (7 * 8)
285
286/**
287 * Converts an audio device flags to a string.
288 *
289 * @returns
290 * @param pszDst Destination buffer with a size of at least
291 * PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN bytes (including
292 * the string terminator).
293 * @param fFlags Audio flags (PDMAUDIOHOSTDEV_F_XXX) to convert.
294 */
295DECLINLINE(const char *) PDMAudioDeviceFlagsToString(char pszDst[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN], uint32_t fFlags)
296{
297 static const struct { const char *pszMnemonic; uint32_t cchMnemonic; uint32_t fFlag; } s_aFlags[] =
298 {
299 { RT_STR_TUPLE("DEFAULT "), PDMAUDIOHOSTDEV_F_DEFAULT },
300 { RT_STR_TUPLE("HOTPLUG "), PDMAUDIOHOSTDEV_F_HOTPLUG },
301 { RT_STR_TUPLE("BUGGY "), PDMAUDIOHOSTDEV_F_BUGGY },
302 { RT_STR_TUPLE("IGNORE "), PDMAUDIOHOSTDEV_F_IGNORE },
303 { RT_STR_TUPLE("LOCKED "), PDMAUDIOHOSTDEV_F_LOCKED },
304 { RT_STR_TUPLE("DEAD "), PDMAUDIOHOSTDEV_F_DEAD },
305 { RT_STR_TUPLE("NO_DUP "), PDMAUDIOHOSTDEV_F_NO_DUP },
306 };
307 size_t offDst = 0;
308 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
309 if (fFlags & s_aFlags[i].fFlag)
310 {
311 fFlags &= ~s_aFlags[i].fFlag;
312 memcpy(&pszDst[offDst], s_aFlags[i].pszMnemonic, s_aFlags[i].cchMnemonic);
313 offDst += s_aFlags[i].cchMnemonic;
314 }
315 Assert(fFlags == 0);
316 Assert(offDst < PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN);
317
318 if (offDst)
319 pszDst[offDst - 1] = '\0';
320 else
321 memcpy(pszDst, "NONE", sizeof("NONE"));
322 return pszDst;
323}
324
325/**
326 * Logs an audio device enumeration.
327 *
328 * @param pDevEnm Device enumeration to log.
329 * @param pszDesc Logging description (prefix).
330 */
331DECLINLINE(void) PDMAudioHostEnumLog(PCPDMAUDIOHOSTENUM pDevEnm, const char *pszDesc)
332{
333 AssertPtrReturnVoid(pDevEnm);
334 AssertPtrReturnVoid(pszDesc);
335 AssertReturnVoid(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC);
336
337 LogFunc(("%s: %RU32 devices\n", pszDesc, pDevEnm->cDevices));
338
339 PPDMAUDIOHOSTDEV pDev;
340 RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, Node)
341 {
342 char szFlags[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN];
343 LogFunc(("Device '%s':\n", pDev->szName));
344 LogFunc((" Usage = %s\n", PDMAudioDirGetName(pDev->enmUsage)));
345 LogFunc((" Flags = %s\n", PDMAudioDeviceFlagsToString(szFlags, pDev->fFlags)));
346 LogFunc((" Input channels = %RU8\n", pDev->cMaxInputChannels));
347 LogFunc((" Output channels = %RU8\n", pDev->cMaxOutputChannels));
348 LogFunc((" cbExtra = %RU32 bytes\n", pDev->cbSelf - sizeof(PDMAUDIOHOSTDEV)));
349 }
350}
351
352#endif /* VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette