VirtualBox

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

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

Audio: Fix bug in PDMAudioHostDevDup. bugref:9890

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

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