VirtualBox

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

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

Audio: Need to copy PDMAUDIOHOSTDEV::pszId in PDMAudioHostDevDup. bugref:9890

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

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