VirtualBox

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

最後變更 在這個檔案從89229是 89229,由 vboxsync 提交於 4 年 前

Audio: Must have a PDMAUDIOHOSTDEV_F_DEFAULT flag for each direction or we'll mess up when two duplex devices are default devices for one direction each. Added a pszId member to the enumeration entires. Rewrote the core audio enumeration code. bugref:9890

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 14.1 KB
 
1/* $Id: pdmaudiohostenuminline.h 89229 2021-05-23 01:21:16Z vboxsync $ */
2/** @file
3 * PDM - Audio Helpers for host audio device enumeration, 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.alldomusa.eu.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/assert.h>
46#include <iprt/mem.h>
47#include <iprt/string.h>
48
49
50/** @defgroup grp_pdm_audio_host_enum_inline The PDM Host Audio Enumeration Helper APIs
51 * @ingroup grp_pdm
52 * @{
53 */
54
55
56/**
57 * Allocates a host audio device for an enumeration result.
58 *
59 * @returns Newly allocated audio device, or NULL on failure.
60 * @param cb The total device structure size. This must be at least the
61 * size of PDMAUDIOHOSTDEV. The idea is that the caller extends
62 * the PDMAUDIOHOSTDEV structure and appends additional data
63 * after it in its private structure.
64 */
65DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostDevAlloc(size_t cb)
66{
67 AssertReturn(cb >= sizeof(PDMAUDIOHOSTDEV), NULL);
68 AssertReturn(cb < _4M, NULL);
69
70 PPDMAUDIOHOSTDEV pDev = (PPDMAUDIOHOSTDEV)RTMemAllocZ(RT_ALIGN_Z(cb, 64));
71 if (pDev)
72 {
73 pDev->uMagic = PDMAUDIOHOSTDEV_MAGIC;
74 pDev->cbSelf = (uint32_t)cb;
75 RTListInit(&pDev->ListEntry);
76
77 //pDev->cMaxInputChannels = 0;
78 //pDev->cMaxOutputChannels = 0;
79 }
80 return pDev;
81}
82
83/**
84 * Frees a host audio device allocated by PDMAudioHostDevAlloc.
85 *
86 * @param pDev The device to free. NULL is ignored.
87 */
88DECLINLINE(void) PDMAudioHostDevFree(PPDMAUDIOHOSTDEV pDev)
89{
90 if (pDev)
91 {
92 Assert(pDev->uMagic == PDMAUDIOHOSTDEV_MAGIC);
93 pDev->uMagic = ~PDMAUDIOHOSTDEV_MAGIC;
94 pDev->cbSelf = 0;
95
96 RTMemFree(pDev);
97 }
98}
99
100/**
101 * Duplicates a host audio device enumeration entry.
102 *
103 * @returns Duplicated audio device entry on success, or NULL on failure.
104 * @param pDev The audio device enum entry to duplicate.
105 * @param fOnlyCoreData
106 */
107DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostDevDup(PCPDMAUDIOHOSTDEV pDev, bool fOnlyCoreData)
108{
109 AssertPtrReturn(pDev, NULL);
110 Assert(pDev->uMagic == PDMAUDIOHOSTDEV_MAGIC);
111 Assert(fOnlyCoreData || !(pDev->fFlags & PDMAUDIOHOSTDEV_F_NO_DUP));
112
113 uint32_t cbToDup = fOnlyCoreData ? sizeof(PDMAUDIOHOSTDEV) : pDev->cbSelf;
114 AssertReturn(cbToDup >= sizeof(*pDev), NULL);
115
116 PPDMAUDIOHOSTDEV pDevDup = PDMAudioHostDevAlloc(cbToDup);
117 if (pDevDup)
118 {
119 memcpy(pDevDup, pDev, cbToDup);
120 RTListInit(&pDevDup->ListEntry);
121 pDevDup->cbSelf = cbToDup;
122 }
123
124 return pDevDup;
125}
126
127/**
128 * Initializes a host audio device enumeration.
129 *
130 * @param pDevEnm The enumeration to initialize.
131 */
132DECLINLINE(void) PDMAudioHostEnumInit(PPDMAUDIOHOSTENUM pDevEnm)
133{
134 AssertPtr(pDevEnm);
135
136 pDevEnm->uMagic = PDMAUDIOHOSTENUM_MAGIC;
137 pDevEnm->cDevices = 0;
138 RTListInit(&pDevEnm->LstDevices);
139}
140
141/**
142 * Deletes the host audio device enumeration and frees all device entries
143 * associated with it.
144 *
145 * The user must call PDMAudioHostEnumInit again to use it again.
146 *
147 * @param pDevEnm The host audio device enumeration to delete.
148 */
149DECLINLINE(void) PDMAudioHostEnumDelete(PPDMAUDIOHOSTENUM pDevEnm)
150{
151 if (pDevEnm)
152 {
153 AssertPtr(pDevEnm);
154 AssertReturnVoid(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC);
155
156 PPDMAUDIOHOSTDEV pDev, pDevNext;
157 RTListForEachSafe(&pDevEnm->LstDevices, pDev, pDevNext, PDMAUDIOHOSTDEV, ListEntry)
158 {
159 RTListNodeRemove(&pDev->ListEntry);
160
161 PDMAudioHostDevFree(pDev);
162
163 pDevEnm->cDevices--;
164 }
165
166 /* Sanity. */
167 Assert(RTListIsEmpty(&pDevEnm->LstDevices));
168 Assert(pDevEnm->cDevices == 0);
169
170 pDevEnm->uMagic = ~PDMAUDIOHOSTENUM_MAGIC;
171 }
172}
173
174/**
175 * Adds an audio device to a device enumeration.
176 *
177 * @param pDevEnm Device enumeration to add device to.
178 * @param pDev Device to add. The pointer will be owned by the device enumeration then.
179 */
180DECLINLINE(void) PDMAudioHostEnumAppend(PPDMAUDIOHOSTENUM pDevEnm, PPDMAUDIOHOSTDEV pDev)
181{
182 AssertPtr(pDevEnm);
183 AssertPtr(pDev);
184 Assert(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC);
185
186 RTListAppend(&pDevEnm->LstDevices, &pDev->ListEntry);
187 pDevEnm->cDevices++;
188}
189
190/**
191 * Appends copies of matching host device entries from one to another enumeration.
192 *
193 * @returns VBox status code.
194 * @param pDstDevEnm The target to append copies of matching device to.
195 * @param pSrcDevEnm The source to copy matching devices from.
196 * @param enmUsage The usage to match for copying.
197 * Use PDMAUDIODIR_INVALID to match all entries.
198 * @param fOnlyCoreData Set this to only copy the PDMAUDIOHOSTDEV part.
199 * Careful with passing @c false here as not all
200 * backends have data that can be copied.
201 */
202DECLINLINE(int) PDMAudioHostEnumCopy(PPDMAUDIOHOSTENUM pDstDevEnm, PCPDMAUDIOHOSTENUM pSrcDevEnm,
203 PDMAUDIODIR enmUsage, bool fOnlyCoreData)
204{
205 AssertPtrReturn(pDstDevEnm, VERR_INVALID_POINTER);
206 AssertReturn(pDstDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER);
207
208 AssertPtrReturn(pSrcDevEnm, VERR_INVALID_POINTER);
209 AssertReturn(pSrcDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER);
210
211 PPDMAUDIOHOSTDEV pSrcDev;
212 RTListForEach(&pSrcDevEnm->LstDevices, pSrcDev, PDMAUDIOHOSTDEV, ListEntry)
213 {
214 if ( enmUsage == pSrcDev->enmUsage
215 || enmUsage == PDMAUDIODIR_INVALID /*all*/)
216 {
217 PPDMAUDIOHOSTDEV pDstDev = PDMAudioHostDevDup(pSrcDev, fOnlyCoreData);
218 AssertReturn(pDstDev, VERR_NO_MEMORY);
219
220 PDMAudioHostEnumAppend(pDstDevEnm, pDstDev);
221 }
222 }
223
224 return VINF_SUCCESS;
225}
226
227/**
228 * Moves all the device entries from one enumeration to another, destroying the
229 * former.
230 *
231 * @returns VBox status code.
232 * @param pDstDevEnm The target to put move @a pSrcDevEnm to. This
233 * does not need to be initialized, but if it is it
234 * must not have any device entries.
235 * @param pSrcDevEnm The source to move from. This will be empty
236 * upon successful return.
237 */
238DECLINLINE(int) PDMAudioHostEnumMove(PPDMAUDIOHOSTENUM pDstDevEnm, PPDMAUDIOHOSTENUM pSrcDevEnm)
239{
240 AssertPtrReturn(pDstDevEnm, VERR_INVALID_POINTER);
241 AssertReturn(pDstDevEnm->uMagic != PDMAUDIOHOSTENUM_MAGIC || pDstDevEnm->cDevices == 0, VERR_WRONG_ORDER);
242
243 AssertPtrReturn(pSrcDevEnm, VERR_INVALID_POINTER);
244 AssertReturn(pSrcDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER);
245
246 pDstDevEnm->uMagic = PDMAUDIOHOSTENUM_MAGIC;
247 RTListInit(&pDstDevEnm->LstDevices);
248 pDstDevEnm->cDevices = pSrcDevEnm->cDevices;
249 if (pSrcDevEnm->cDevices)
250 {
251 PPDMAUDIOHOSTDEV pCur;
252 while ((pCur = RTListRemoveFirst(&pSrcDevEnm->LstDevices, PDMAUDIOHOSTDEV, ListEntry)) != NULL)
253 RTListAppend(&pDstDevEnm->LstDevices, &pCur->ListEntry);
254 }
255 return VINF_SUCCESS;
256}
257
258/**
259 * Get the default device with the given usage.
260 *
261 * This assumes that only one default device per usage is set, if there should
262 * be more than one, the first one is returned.
263 *
264 * @returns Default device if found, or NULL if not.
265 * @param pDevEnm Device enumeration to get default device for.
266 * @param enmUsage Usage to get default device for.
267 * Pass PDMAUDIODIR_INVALID to get the first device with
268 * either PDMAUDIOHOSTDEV_F_DEFAULT_OUT or
269 * PDMAUDIOHOSTDEV_F_DEFAULT_IN set.
270 */
271DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostEnumGetDefault(PCPDMAUDIOHOSTENUM pDevEnm, PDMAUDIODIR enmUsage)
272{
273 AssertPtrReturn(pDevEnm, NULL);
274 AssertReturn(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, NULL);
275
276 Assert(enmUsage == PDMAUDIODIR_IN || enmUsage == PDMAUDIODIR_OUT || enmUsage == PDMAUDIODIR_INVALID);
277 uint32_t const fFlags = enmUsage == PDMAUDIODIR_IN ? PDMAUDIOHOSTDEV_F_DEFAULT_IN
278 : enmUsage == PDMAUDIODIR_OUT ? PDMAUDIOHOSTDEV_F_DEFAULT_OUT
279 : enmUsage == PDMAUDIODIR_INVALID ? PDMAUDIOHOSTDEV_F_DEFAULT_IN | PDMAUDIOHOSTDEV_F_DEFAULT_OUT
280 : 0;
281
282 PPDMAUDIOHOSTDEV pDev;
283 RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry)
284 {
285 if (pDev->fFlags & fFlags)
286 {
287 Assert(pDev->enmUsage == enmUsage || pDev->enmUsage == PDMAUDIODIR_DUPLEX || enmUsage == PDMAUDIODIR_INVALID);
288 return pDev;
289 }
290 }
291
292 return NULL;
293}
294
295/**
296 * Get the number of device with the given usage.
297 *
298 * @returns Number of matching devices.
299 * @param pDevEnm Device enumeration to get default device for.
300 * @param enmUsage Usage to count devices for.
301 * Pass PDMAUDIODIR_INVALID to get the total number of devices.
302 */
303DECLINLINE(uint32_t) PDMAudioHostEnumCountMatching(PCPDMAUDIOHOSTENUM pDevEnm, PDMAUDIODIR enmUsage)
304{
305 AssertPtrReturn(pDevEnm, 0);
306 AssertReturn(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, 0);
307
308 if (enmUsage == PDMAUDIODIR_INVALID)
309 return pDevEnm->cDevices;
310
311 uint32_t cDevs = 0;
312 PPDMAUDIOHOSTDEV pDev;
313 RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry)
314 {
315 if (enmUsage == pDev->enmUsage)
316 cDevs++;
317 }
318
319 return cDevs;
320}
321
322/** The max string length for all PDMAUDIOHOSTDEV_F_XXX.
323 * @sa PDMAudioHostDevFlagsToString */
324#define PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN sizeof("DEFAULT_OUT DEFAULT_IN HOTPLUG BUGGY IGNORE LOCKED DEAD NO_DUP ")
325
326/**
327 * Converts an audio device flags to a string.
328 *
329 * @returns
330 * @param pszDst Destination buffer with a size of at least
331 * PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN bytes (including
332 * the string terminator).
333 * @param fFlags Audio flags (PDMAUDIOHOSTDEV_F_XXX) to convert.
334 */
335DECLINLINE(const char *) PDMAudioHostDevFlagsToString(char pszDst[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN], uint32_t fFlags)
336{
337 static const struct { const char *pszMnemonic; uint32_t cchMnemonic; uint32_t fFlag; } s_aFlags[] =
338 {
339 { RT_STR_TUPLE("DEFAULT_OUT "), PDMAUDIOHOSTDEV_F_DEFAULT_OUT },
340 { RT_STR_TUPLE("DEFAULT_IN "), PDMAUDIOHOSTDEV_F_DEFAULT_IN },
341 { RT_STR_TUPLE("HOTPLUG "), PDMAUDIOHOSTDEV_F_HOTPLUG },
342 { RT_STR_TUPLE("BUGGY "), PDMAUDIOHOSTDEV_F_BUGGY },
343 { RT_STR_TUPLE("IGNORE "), PDMAUDIOHOSTDEV_F_IGNORE },
344 { RT_STR_TUPLE("LOCKED "), PDMAUDIOHOSTDEV_F_LOCKED },
345 { RT_STR_TUPLE("DEAD "), PDMAUDIOHOSTDEV_F_DEAD },
346 { RT_STR_TUPLE("NO_DUP "), PDMAUDIOHOSTDEV_F_NO_DUP },
347 };
348 size_t offDst = 0;
349 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFlags); i++)
350 if (fFlags & s_aFlags[i].fFlag)
351 {
352 fFlags &= ~s_aFlags[i].fFlag;
353 memcpy(&pszDst[offDst], s_aFlags[i].pszMnemonic, s_aFlags[i].cchMnemonic);
354 offDst += s_aFlags[i].cchMnemonic;
355 }
356 Assert(fFlags == 0);
357 Assert(offDst < PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN);
358
359 if (offDst)
360 pszDst[offDst - 1] = '\0';
361 else
362 memcpy(pszDst, "NONE", sizeof("NONE"));
363 return pszDst;
364}
365
366/**
367 * Logs an audio device enumeration.
368 *
369 * @param pDevEnm Device enumeration to log.
370 * @param pszDesc Logging description (prefix).
371 */
372DECLINLINE(void) PDMAudioHostEnumLog(PCPDMAUDIOHOSTENUM pDevEnm, const char *pszDesc)
373{
374#ifdef LOG_ENABLED
375 AssertPtrReturnVoid(pDevEnm);
376 AssertPtrReturnVoid(pszDesc);
377 AssertReturnVoid(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC);
378
379 if (LogIsEnabled())
380 {
381 LogFunc(("%s: %RU32 devices\n", pszDesc, pDevEnm->cDevices));
382
383 PPDMAUDIOHOSTDEV pDev;
384 RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry)
385 {
386 char szFlags[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN];
387 LogFunc(("Device '%s':\n", pDev->szName));
388 LogFunc((" Usage = %s\n", PDMAudioDirGetName(pDev->enmUsage)));
389 LogFunc((" Flags = %s\n", PDMAudioHostDevFlagsToString(szFlags, pDev->fFlags)));
390 LogFunc((" Input channels = %RU8\n", pDev->cMaxInputChannels));
391 LogFunc((" Output channels = %RU8\n", pDev->cMaxOutputChannels));
392 LogFunc((" cbExtra = %RU32 bytes\n", pDev->cbSelf - sizeof(PDMAUDIOHOSTDEV)));
393 }
394 }
395#else
396 RT_NOREF(pDevEnm, pszDesc);
397#endif
398}
399
400/** @} */
401
402#endif /* !VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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