VirtualBox

source: vbox/trunk/include/VBox/vmm/pdmaudioinline.h@ 89506

Last change on this file since 89506 was 89506, checked in by vboxsync, 3 years ago

pdmaudioinline.h/PDMAudioPropsAreEqual: Compare channel IDs too. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 46.9 KB
Line 
1/* $Id: pdmaudioinline.h 89506 2021-06-04 12:11:56Z 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_pdmaudioinline_h
31#define VBOX_INCLUDED_vmm_pdmaudioinline_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
44#include <iprt/asm.h>
45#include <iprt/asm-math.h>
46#include <iprt/assert.h>
47#include <iprt/mem.h>
48#include <iprt/string.h>
49
50
51/** @defgroup grp_pdm_audio_inline The PDM Audio Helper APIs
52 * @ingroup grp_pdm
53 * @{
54 */
55
56
57/**
58 * Gets the name of an audio direction enum value.
59 *
60 * @returns Pointer to read-only name string on success, "bad" if
61 * passed an invalid enum value.
62 * @param enmDir The audio direction value to name.
63 */
64DECLINLINE(const char *) PDMAudioDirGetName(PDMAUDIODIR enmDir)
65{
66 switch (enmDir)
67 {
68 case PDMAUDIODIR_UNKNOWN: return "Unknown";
69 case PDMAUDIODIR_IN: return "Input";
70 case PDMAUDIODIR_OUT: return "Output";
71 case PDMAUDIODIR_DUPLEX: return "Duplex";
72
73 /* no default */
74 case PDMAUDIODIR_END:
75 case PDMAUDIODIR_INVALID:
76 case PDMAUDIODIR_32BIT_HACK:
77 break;
78 }
79 AssertMsgFailedReturn(("Invalid audio direction %d\n", enmDir), "bad");
80}
81
82/**
83 * Gets the name of an audio mixer control enum value.
84 *
85 * @returns Pointer to read-only name, "bad" if invalid input.
86 * @param enmMixerCtl The audio mixer control value.
87 */
88DECLINLINE(const char *) PDMAudioMixerCtlGetName(PDMAUDIOMIXERCTL enmMixerCtl)
89{
90 switch (enmMixerCtl)
91 {
92 case PDMAUDIOMIXERCTL_UNKNOWN: return "Unknown";
93 case PDMAUDIOMIXERCTL_VOLUME_MASTER: return "Master Volume";
94 case PDMAUDIOMIXERCTL_FRONT: return "Front";
95 case PDMAUDIOMIXERCTL_CENTER_LFE: return "Center / LFE";
96 case PDMAUDIOMIXERCTL_REAR: return "Rear";
97 case PDMAUDIOMIXERCTL_LINE_IN: return "Line-In";
98 case PDMAUDIOMIXERCTL_MIC_IN: return "Microphone-In";
99 /* no default */
100 case PDMAUDIOMIXERCTL_END:
101 case PDMAUDIOMIXERCTL_INVALID:
102 case PDMAUDIOMIXERCTL_32BIT_HACK:
103 break;
104 }
105 AssertMsgFailedReturn(("Invalid mixer control %ld\n", enmMixerCtl), "bad");
106}
107
108/**
109 * Gets the name of a path enum value.
110 *
111 * @returns Pointer to read-only name, "bad" if invalid input.
112 * @param enmPath The path value to name.
113 */
114DECLINLINE(const char *) PDMAudioPathGetName(PDMAUDIOPATH enmPath)
115{
116 switch (enmPath)
117 {
118 case PDMAUDIOPATH_UNKNOWN: return "Unknown";
119
120 case PDMAUDIOPATH_OUT_FRONT: return "Front";
121 case PDMAUDIOPATH_OUT_CENTER_LFE: return "Center / LFE";
122 case PDMAUDIOPATH_OUT_REAR: return "Rear";
123
124 case PDMAUDIOPATH_IN_MIC: return "Microphone In";
125 case PDMAUDIOPATH_IN_CD: return "CD";
126 case PDMAUDIOPATH_IN_VIDEO: return "Video";
127 case PDMAUDIOPATH_IN_AUX: return "AUX";
128 case PDMAUDIOPATH_IN_LINE: return "Line In";
129 case PDMAUDIOPATH_IN_PHONE: return "Phone";
130
131 /* no default */
132 case PDMAUDIOPATH_INVALID:
133 case PDMAUDIOPATH_END:
134 case PDMAUDIOPATH_32BIT_HACK:
135 break;
136 }
137 AssertMsgFailedReturn(("Unknown enmPath=%d\n", enmPath), "bad");
138}
139
140/**
141 * Gets the name of a channel.
142 *
143 * @returns Pointer to read-only name, "bad" if invalid input.
144 * @param enmChannelId The channel ID to name.
145 */
146DECLINLINE(const char *) PDMAudioChannelIdGetName(PDMAUDIOCHANNELID enmChannelId)
147{
148 switch (enmChannelId)
149 {
150 case PDMAUDIOCHANNELID_INVALID: return "invalid";
151 case PDMAUDIOCHANNELID_UNUSED_ZERO: return "unused-zero";
152 case PDMAUDIOCHANNELID_UNUSED_SILENCE: return "unused-silence";
153 case PDMAUDIOCHANNELID_UNKNOWN: return "unknown";
154
155 case PDMAUDIOCHANNELID_FRONT_LEFT: return "FL";
156 case PDMAUDIOCHANNELID_FRONT_RIGHT: return "FR";
157 case PDMAUDIOCHANNELID_FRONT_CENTER: return "FC";
158 case PDMAUDIOCHANNELID_LFE: return "LFE";
159 case PDMAUDIOCHANNELID_REAR_LEFT: return "BL";
160 case PDMAUDIOCHANNELID_REAR_RIGHT: return "BR";
161 case PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER: return "FLC";
162 case PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER: return "FRC";
163 case PDMAUDIOCHANNELID_REAR_CENTER: return "BC";
164 case PDMAUDIOCHANNELID_SIDE_LEFT: return "SL";
165 case PDMAUDIOCHANNELID_SIDE_RIGHT: return "SR";
166 case PDMAUDIOCHANNELID_TOP_CENTER: return "TC";
167 case PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT: return "TFL";
168 case PDMAUDIOCHANNELID_FRONT_CENTER_HEIGHT: return "TFC";
169 case PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT: return "TFR";
170 case PDMAUDIOCHANNELID_REAR_LEFT_HEIGHT: return "TBL";
171 case PDMAUDIOCHANNELID_REAR_CENTER_HEIGHT: return "TBC";
172 case PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT: return "TBR";
173
174 /* no default */
175 case PDMAUDIOCHANNELID_END:
176 case PDMAUDIOCHANNELID_32BIT_HACK:
177 break;
178 }
179 AssertMsgFailedReturn(("Unknown enmChannelId=%d\n", enmChannelId), "bad");
180}
181
182
183/*********************************************************************************************************************************
184* PCM Property Helpers *
185*********************************************************************************************************************************/
186
187/**
188 * Assigns default channel IDs according to the channel count.
189 *
190 * The assignments are taken from the standard speaker channel layouts table
191 * in the wikipedia article on surround sound:
192 * https://en.wikipedia.org/wiki/Surround_sound#Standard_speaker_channels
193 */
194DECLINLINE(void) PDMAudioPropsSetDefaultChannelIds(PPDMAUDIOPCMPROPS pProps)
195{
196 unsigned cChannels = pProps->cChannelsX;
197 switch (cChannels)
198 {
199 case 1:
200 pProps->aidChannels[0] = PDMAUDIOCHANNELID_MONO;
201 break;
202 case 2:
203 pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT;
204 pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT;
205 break;
206 case 3: /* 2.1 */
207 pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT;
208 pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT;
209 pProps->aidChannels[2] = PDMAUDIOCHANNELID_LFE;
210 break;
211 case 4: /* 4.0 */
212 pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT;
213 pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT;
214 pProps->aidChannels[2] = PDMAUDIOCHANNELID_REAR_LEFT;
215 pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_RIGHT;
216 break;
217 case 5: /* 4.1 */
218 pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT;
219 pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT;
220 pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER;
221 pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE;
222 pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_CENTER;
223 break;
224 case 6: /* 5.1 */
225 pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT;
226 pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT;
227 pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER;
228 pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE;
229 pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT;
230 pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT;
231 break;
232 case 7: /* 6.1 */
233 pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT;
234 pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT;
235 pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER;
236 pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE;
237 pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT;
238 pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT;
239 pProps->aidChannels[6] = PDMAUDIOCHANNELID_REAR_CENTER;
240 break;
241 case 8: /* 7.1 */
242 pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT;
243 pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT;
244 pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER;
245 pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE;
246 pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT;
247 pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT;
248 pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER;
249 pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER;
250 break;
251 case 9: /* 9.0 */
252 pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT;
253 pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT;
254 pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER;
255 pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_LEFT;
256 pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_RIGHT;
257 pProps->aidChannels[5] = PDMAUDIOCHANNELID_SIDE_LEFT;
258 pProps->aidChannels[6] = PDMAUDIOCHANNELID_SIDE_RIGHT;
259 pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT;
260 pProps->aidChannels[8] = PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT;
261 break;
262 case 10: /* 9.1 */
263 pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT;
264 pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT;
265 pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER;
266 pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE;
267 pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT;
268 pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT;
269 pProps->aidChannels[6] = PDMAUDIOCHANNELID_SIDE_LEFT;
270 pProps->aidChannels[7] = PDMAUDIOCHANNELID_SIDE_RIGHT;
271 pProps->aidChannels[8] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT;
272 pProps->aidChannels[9] = PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT;
273 break;
274 case 11: /* 11.0 */
275 pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT;
276 pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT;
277 pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER;
278 pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_LEFT;
279 pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_RIGHT;
280 pProps->aidChannels[5] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER;
281 pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER;
282 pProps->aidChannels[7] = PDMAUDIOCHANNELID_SIDE_LEFT;
283 pProps->aidChannels[8] = PDMAUDIOCHANNELID_SIDE_RIGHT;
284 pProps->aidChannels[9] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT;
285 pProps->aidChannels[10]= PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT;
286 break;
287 default:
288 AssertFailed();
289 cChannels = 12;
290 RT_FALL_THROUGH();
291 case 12: /* 11.1 */
292 pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT;
293 pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT;
294 pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER;
295 pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE;
296 pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT;
297 pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT;
298 pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER;
299 pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER;
300 pProps->aidChannels[8] = PDMAUDIOCHANNELID_SIDE_LEFT;
301 pProps->aidChannels[9] = PDMAUDIOCHANNELID_SIDE_RIGHT;
302 pProps->aidChannels[10]= PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT;
303 pProps->aidChannels[11]= PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT;
304 break;
305 case 0:
306 break;
307 }
308 AssertCompile(RT_ELEMENTS(pProps->aidChannels) >= 12);
309
310 while (cChannels < RT_ELEMENTS(pProps->aidChannels))
311 pProps->aidChannels[cChannels++] = PDMAUDIOCHANNELID_INVALID;
312}
313
314
315/**
316 * Initialize PCM audio properties.
317 */
318DECLINLINE(void) PDMAudioPropsInit(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz)
319{
320 pProps->cbFrame = cbSample * cChannels;
321 pProps->cbSampleX = cbSample;
322 pProps->cChannelsX = cChannels;
323 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels);
324 pProps->fSigned = fSigned;
325 pProps->fSwapEndian = false;
326 pProps->fRaw = false;
327 pProps->uHz = uHz;
328
329 Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels);
330 Assert(pProps->cbSampleX == cbSample);
331 Assert(pProps->cChannelsX == cChannels);
332
333 PDMAudioPropsSetDefaultChannelIds(pProps);
334}
335
336/**
337 * Initialize PCM audio properties, extended version.
338 */
339DECLINLINE(void) PDMAudioPropsInitEx(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz,
340 bool fLittleEndian, bool fRaw)
341{
342 Assert(!fRaw || cbSample == sizeof(int64_t));
343 pProps->cbFrame = cbSample * cChannels;
344 pProps->cbSampleX = cbSample;
345 pProps->cChannelsX = cChannels;
346 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels);
347 pProps->fSigned = fSigned;
348#ifdef RT_LITTLE_ENDIAN
349 pProps->fSwapEndian = !fLittleEndian;
350#else
351 pProps->fSwapEndian = fLittleEndian;
352#endif
353 pProps->fRaw = fRaw;
354 pProps->uHz = uHz;
355
356 Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels);
357 Assert(pProps->cbSampleX == cbSample);
358 Assert(pProps->cChannelsX == cChannels);
359
360 PDMAudioPropsSetDefaultChannelIds(pProps);
361}
362
363/**
364 * Modifies the channel count.
365 *
366 * @note This will reset the channel IDs to defaults.
367 *
368 * @param pProps The PCM properties to update.
369 * @param cChannels The new channel count.
370 */
371DECLINLINE(void) PDMAudioPropsSetChannels(PPDMAUDIOPCMPROPS pProps, uint8_t cChannels)
372{
373 Assert(cChannels > 0); Assert(cChannels < 16);
374 pProps->cChannelsX = cChannels;
375 pProps->cbFrame = pProps->cbSampleX * cChannels;
376 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pProps->cbSampleX, cChannels);
377
378 PDMAudioPropsSetDefaultChannelIds(pProps);
379}
380
381/**
382 * Modifies the sample size.
383 *
384 * @param pProps The PCM properties to update.
385 * @param cbSample The new sample size (in bytes).
386 */
387DECLINLINE(void) PDMAudioPropsSetSampleSize(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample)
388{
389 Assert(cbSample == 1 || cbSample == 2 || cbSample == 4 || cbSample == 8);
390 pProps->cbSampleX = cbSample;
391 pProps->cbFrame = cbSample * pProps->cChannelsX;
392 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, pProps->cChannelsX);
393}
394
395/**
396 * Gets the bitrate.
397 *
398 * Divide the result by 8 to get the byte rate.
399 *
400 * @returns Bit rate.
401 * @param pProps PCM properties to calculate bitrate for.
402 */
403DECLINLINE(uint32_t) PDMAudioPropsGetBitrate(PCPDMAUDIOPCMPROPS pProps)
404{
405 Assert(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX);
406 return pProps->cbFrame * pProps->uHz * 8;
407}
408
409/**
410 * Gets the number of channels.
411 * @returns The channel count.
412 * @param pProps The PCM properties.
413 */
414DECL_FORCE_INLINE(uint8_t) PDMAudioPropsChannels(PCPDMAUDIOPCMPROPS pProps)
415{
416 return pProps->cChannelsX;
417}
418
419/**
420 * Gets the sample size in bytes.
421 * @returns Number of bytes per sample.
422 * @param pProps The PCM properties.
423 */
424DECL_FORCE_INLINE(uint8_t) PDMAudioPropsSampleSize(PCPDMAUDIOPCMPROPS pProps)
425{
426 return pProps->cbSampleX;
427}
428
429/**
430 * Gets the sample size in bits.
431 * @returns Number of bits per sample.
432 * @param pProps The PCM properties.
433 */
434DECLINLINE(uint8_t) PDMAudioPropsSampleBits(PCPDMAUDIOPCMPROPS pProps)
435{
436 return pProps->cbSampleX * 8;
437}
438
439/**
440 * Gets the frame size in bytes.
441 * @returns Number of bytes per frame.
442 * @param pProps The PCM properties.
443 */
444DECL_FORCE_INLINE(uint8_t) PDMAudioPropsFrameSize(PCPDMAUDIOPCMPROPS pProps)
445{
446 return pProps->cbFrame;
447}
448
449/**
450 * Gets the frequency.
451 * @returns Frequency.
452 * @param pProps The PCM properties.
453 */
454DECL_FORCE_INLINE(uint32_t) PDMAudioPropsHz(PCPDMAUDIOPCMPROPS pProps)
455{
456 return pProps->uHz;
457}
458
459/**
460 * Checks if the format is signed or unsigned.
461 * @returns true if signed, false if unsigned.
462 * @param pProps The PCM properties.
463 */
464DECL_FORCE_INLINE(bool) PDMAudioPropsIsSigned(PCPDMAUDIOPCMPROPS pProps)
465{
466 return pProps->fSigned;
467}
468
469/**
470 * Checks if the format is little-endian or not.
471 * @returns true if little-endian (or if 8-bit), false if big-endian.
472 * @param pProps The PCM properties.
473 */
474DECL_FORCE_INLINE(bool) PDMAudioPropsIsLittleEndian(PCPDMAUDIOPCMPROPS pProps)
475{
476#ifdef RT_LITTLE_ENDIAN
477 return !pProps->fSwapEndian || pProps->cbSampleX < 2;
478#else
479 return pProps->fSwapEndian || pProps->cbSampleX < 2;
480#endif
481}
482
483/**
484 * Checks if the format is big-endian or not.
485 * @returns true if big-endian (or if 8-bit), false if little-endian.
486 * @param pProps The PCM properties.
487 */
488DECL_FORCE_INLINE(bool) PDMAudioPropsIsBigEndian(PCPDMAUDIOPCMPROPS pProps)
489{
490#ifdef RT_LITTLE_ENDIAN
491 return pProps->fSwapEndian || pProps->cbSampleX < 2;
492#else
493 return !pProps->fSwapEndian || pProps->cbSampleX < 2;
494#endif
495}
496
497/**
498 * Rounds down the given byte amount to the nearest frame boundrary.
499 *
500 * @returns Rounded byte amount.
501 * @param pProps PCM properties to use.
502 * @param cb The size (in bytes) to round.
503 */
504DECLINLINE(uint32_t) PDMAudioPropsFloorBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
505{
506 AssertPtrReturn(pProps, 0);
507 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb));
508}
509
510/**
511 * Rounds up the given byte amount to the nearest frame boundrary.
512 *
513 * @returns Rounded byte amount.
514 * @param pProps PCM properties to use.
515 * @param cb The size (in bytes) to round.
516 */
517DECLINLINE(uint32_t) PDMAudioPropsRoundUpBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
518{
519 AssertPtrReturn(pProps, 0);
520 uint32_t const cbFrame = PDMAudioPropsFrameSize(pProps);
521 AssertReturn(cbFrame, 0);
522 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb + cbFrame - 1));
523}
524
525/**
526 * Checks if the given size is aligned on a frame boundrary.
527 *
528 * @returns @c true if properly aligned, @c false if not.
529 * @param pProps PCM properties to use.
530 * @param cb The size (in bytes) to check.
531 */
532DECLINLINE(bool) PDMAudioPropsIsSizeAligned(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
533{
534 AssertPtrReturn(pProps, false);
535 uint32_t const cbFrame = PDMAudioPropsFrameSize(pProps);
536 AssertReturn(cbFrame, false);
537 return cb % cbFrame == 0;
538}
539
540/**
541 * Converts bytes to frames (rounding down of course).
542 *
543 * @returns Number of frames.
544 * @param pProps PCM properties to use.
545 * @param cb The number of bytes to convert.
546 */
547DECLINLINE(uint32_t) PDMAudioPropsBytesToFrames(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
548{
549 AssertPtrReturn(pProps, 0);
550 return PDMAUDIOPCMPROPS_B2F(pProps, cb);
551}
552
553/**
554 * Converts bytes to milliseconds.
555 *
556 * @return Number milliseconds @a cb takes to play or record.
557 * @param pProps PCM properties to use.
558 * @param cb The number of bytes to convert.
559 *
560 * @note Rounds up the result.
561 */
562DECLINLINE(uint64_t) PDMAudioPropsBytesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
563{
564 AssertPtrReturn(pProps, 0);
565
566 /* Check parameters to prevent division by chainsaw: */
567 uint32_t const uHz = pProps->uHz;
568 if (uHz)
569 {
570 const unsigned cbFrame = PDMAudioPropsFrameSize(pProps);
571 if (cbFrame)
572 {
573 /* Round cb up to closest frame size: */
574 cb = (cb + cbFrame - 1) / cbFrame;
575
576 /* Convert to milliseconds. */
577 return (cb * (uint64_t)RT_MS_1SEC + uHz - 1) / uHz;
578 }
579 }
580 return 0;
581}
582
583/**
584 * Converts bytes to microseconds.
585 *
586 * @return Number microseconds @a cb takes to play or record.
587 * @param pProps PCM properties to use.
588 * @param cb The number of bytes to convert.
589 *
590 * @note Rounds up the result.
591 */
592DECLINLINE(uint64_t) PDMAudioPropsBytesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
593{
594 AssertPtrReturn(pProps, 0);
595
596 /* Check parameters to prevent division by chainsaw: */
597 uint32_t const uHz = pProps->uHz;
598 if (uHz)
599 {
600 const unsigned cbFrame = PDMAudioPropsFrameSize(pProps);
601 if (cbFrame)
602 {
603 /* Round cb up to closest frame size: */
604 cb = (cb + cbFrame - 1) / cbFrame;
605
606 /* Convert to microseconds. */
607 return (cb * (uint64_t)RT_US_1SEC + uHz - 1) / uHz;
608 }
609 }
610 return 0;
611}
612
613/**
614 * Converts bytes to nanoseconds.
615 *
616 * @return Number nanoseconds @a cb takes to play or record.
617 * @param pProps PCM properties to use.
618 * @param cb The number of bytes to convert.
619 *
620 * @note Rounds up the result.
621 */
622DECLINLINE(uint64_t) PDMAudioPropsBytesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
623{
624 AssertPtrReturn(pProps, 0);
625
626 /* Check parameters to prevent division by chainsaw: */
627 uint32_t const uHz = pProps->uHz;
628 if (uHz)
629 {
630 const unsigned cbFrame = PDMAudioPropsFrameSize(pProps);
631 if (cbFrame)
632 {
633 /* Round cb up to closest frame size: */
634 cb = (cb + cbFrame - 1) / cbFrame;
635
636 /* Convert to nanoseconds. */
637 return (cb * (uint64_t)RT_NS_1SEC + uHz - 1) / uHz;
638 }
639 }
640 return 0;
641}
642
643/**
644 * Converts bytes to nanoseconds, 64-bit version.
645 *
646 * @return Number nanoseconds @a cb takes to play or record.
647 * @param pProps PCM properties to use.
648 * @param cb The number of bytes to convert (64-bit).
649 *
650 * @note Rounds up the result.
651 */
652DECLINLINE(uint64_t) PDMAudioPropsBytesToNano64(PCPDMAUDIOPCMPROPS pProps, uint64_t cb)
653{
654 AssertPtrReturn(pProps, 0);
655
656 /* Check parameters to prevent division by chainsaw: */
657 uint32_t const uHz = pProps->uHz;
658 if (uHz)
659 {
660 const unsigned cbFrame = PDMAudioPropsFrameSize(pProps);
661 if (cbFrame)
662 {
663 /* Round cb up to closest frame size: */
664 cb = (cb + cbFrame - 1) / cbFrame;
665
666 /* Convert to nanoseconds. */
667 return (cb * RT_NS_1SEC + uHz - 1) / uHz;
668 }
669 }
670 return 0;
671}
672
673/**
674 * Converts frames to bytes.
675 *
676 * @returns Number of bytes.
677 * @param pProps The PCM properties to use.
678 * @param cFrames Number of audio frames to convert.
679 * @sa PDMAUDIOPCMPROPS_F2B
680 */
681DECLINLINE(uint32_t) PDMAudioPropsFramesToBytes(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
682{
683 AssertPtrReturn(pProps, 0);
684 return PDMAUDIOPCMPROPS_F2B(pProps, cFrames);
685}
686
687/**
688 * Converts frames to milliseconds.
689 *
690 * @returns milliseconds.
691 * @param pProps The PCM properties to use.
692 * @param cFrames Number of audio frames to convert.
693 * @note No rounding here, result is floored.
694 */
695DECLINLINE(uint64_t) PDMAudioPropsFramesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
696{
697 AssertPtrReturn(pProps, 0);
698
699 /* Check input to prevent division by chainsaw: */
700 uint32_t const uHz = pProps->uHz;
701 if (uHz)
702 return ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, uHz);
703 return 0;
704}
705
706/**
707 * Converts frames to microseconds.
708 *
709 * @returns microseconds.
710 * @param pProps The PCM properties to use.
711 * @param cFrames Number of audio frames to convert.
712 * @note No rounding here, result is floored.
713 */
714DECLINLINE(uint64_t) PDMAudioPropsFramesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
715{
716 AssertPtrReturn(pProps, 0);
717
718 /* Check input to prevent division by chainsaw: */
719 uint32_t const uHz = pProps->uHz;
720 if (uHz)
721 return ASMMultU32ByU32DivByU32(cFrames, RT_US_1SEC, uHz);
722 return 0;
723}
724
725/**
726 * Converts frames to nanoseconds.
727 *
728 * @returns Nanoseconds.
729 * @param pProps The PCM properties to use.
730 * @param cFrames Number of audio frames to convert.
731 * @note No rounding here, result is floored.
732 */
733DECLINLINE(uint64_t) PDMAudioPropsFramesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
734{
735 AssertPtrReturn(pProps, 0);
736
737 /* Check input to prevent division by chainsaw: */
738 uint32_t const uHz = pProps->uHz;
739 if (uHz)
740 return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC, uHz);
741 return 0;
742}
743
744/**
745 * Converts frames to NT ticks (100 ns units).
746 *
747 * @returns NT ticks.
748 * @param pProps The PCM properties to use.
749 * @param cFrames Number of audio frames to convert.
750 * @note No rounding here, result is floored.
751 */
752DECLINLINE(uint64_t) PDMAudioPropsFramesToNtTicks(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
753{
754 AssertPtrReturn(pProps, 0);
755
756 /* Check input to prevent division by chainsaw: */
757 uint32_t const uHz = pProps->uHz;
758 if (uHz)
759 return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC / 100, uHz);
760 return 0;
761}
762
763/**
764 * Converts milliseconds to frames.
765 *
766 * @returns Number of frames
767 * @param pProps The PCM properties to use.
768 * @param cMs The number of milliseconds to convert.
769 *
770 * @note The result is rounded rather than floored (hysterical raisins).
771 */
772DECLINLINE(uint32_t) PDMAudioPropsMilliToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)
773{
774 AssertPtrReturn(pProps, 0);
775
776 uint32_t const uHz = pProps->uHz;
777 uint32_t cFrames;
778 if (cMs < RT_MS_1SEC)
779 cFrames = 0;
780 else
781 {
782 cFrames = cMs / RT_MS_1SEC * uHz;
783 cMs %= RT_MS_1SEC;
784 }
785 cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cMs) + RT_MS_1SEC - 1) / RT_MS_1SEC;
786 return cFrames;
787}
788
789/**
790 * Converts milliseconds to bytes.
791 *
792 * @returns Number of bytes (frame aligned).
793 * @param pProps The PCM properties to use.
794 * @param cMs The number of milliseconds to convert.
795 *
796 * @note The result is rounded rather than floored (hysterical raisins).
797 */
798DECLINLINE(uint32_t) PDMAudioPropsMilliToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)
799{
800 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsMilliToFrames(pProps, cMs));
801}
802
803/**
804 * Converts nanoseconds to frames.
805 *
806 * @returns Number of frames.
807 * @param pProps The PCM properties to use.
808 * @param cNs The number of nanoseconds to convert.
809 *
810 * @note The result is rounded rather than floored (hysterical raisins).
811 */
812DECLINLINE(uint32_t) PDMAudioPropsNanoToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
813{
814 AssertPtrReturn(pProps, 0);
815
816 uint32_t const uHz = pProps->uHz;
817 uint32_t cFrames;
818 if (cNs < RT_NS_1SEC)
819 cFrames = 0;
820 else
821 {
822 cFrames = cNs / RT_NS_1SEC * uHz;
823 cNs %= RT_NS_1SEC;
824 }
825 cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cNs) + RT_NS_1SEC - 1) / RT_NS_1SEC;
826 return cFrames;
827}
828
829/**
830 * Converts nanoseconds to frames, 64-bit return.
831 *
832 * @returns Number of frames (64-bit).
833 * @param pProps The PCM properties to use.
834 * @param cNs The number of nanoseconds to convert.
835 *
836 * @note The result is floored!
837 */
838DECLINLINE(uint64_t) PDMAudioPropsNanoToFrames64(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
839{
840 AssertPtrReturn(pProps, 0);
841
842 uint32_t const uHz = pProps->uHz;
843 uint64_t cFrames;
844 if (cNs < RT_NS_1SEC)
845 cFrames = 0;
846 else
847 {
848 cFrames = cNs / RT_NS_1SEC * uHz;
849 cNs %= RT_NS_1SEC;
850 }
851 cFrames += ASMMult2xU32RetU64(uHz, (uint32_t)cNs) / RT_NS_1SEC;
852 return cFrames;
853}
854
855/**
856 * Converts nanoseconds to bytes.
857 *
858 * @returns Number of bytes (frame aligned).
859 * @param pProps The PCM properties to use.
860 * @param cNs The number of nanoseconds to convert.
861 *
862 * @note The result is rounded rather than floored (hysterical raisins).
863 */
864DECLINLINE(uint32_t) PDMAudioPropsNanoToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
865{
866 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs));
867}
868
869/**
870 * Converts nanoseconds to bytes, 64-bit version.
871 *
872 * @returns Number of bytes (frame aligned), 64-bit.
873 * @param pProps The PCM properties to use.
874 * @param cNs The number of nanoseconds to convert.
875 *
876 * @note The result is floored.
877 */
878DECLINLINE(uint64_t) PDMAudioPropsNanoToBytes64(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
879{
880 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs));
881}
882
883/**
884 * Clears a sample buffer by the given amount of audio frames with silence (according to the format
885 * given by the PCM properties).
886 *
887 * @param pProps The PCM properties to apply.
888 * @param pvBuf The buffer to clear.
889 * @param cbBuf The buffer size in bytes.
890 * @param cFrames The number of audio frames to clear. Capped at @a cbBuf
891 * if exceeding the buffer. If the size is an unaligned
892 * number of frames, the extra bytes may be left
893 * uninitialized in some configurations.
894 */
895DECLINLINE(void) PDMAudioPropsClearBuffer(PCPDMAUDIOPCMPROPS pProps, void *pvBuf, size_t cbBuf, uint32_t cFrames)
896{
897 /*
898 * Validate input
899 */
900 AssertPtrReturnVoid(pProps);
901 Assert(pProps->cbSampleX);
902 if (!cbBuf || !cFrames)
903 return;
904 AssertPtrReturnVoid(pvBuf);
905
906 /*
907 * Decide how much needs clearing.
908 */
909 size_t cbToClear = PDMAudioPropsFramesToBytes(pProps, cFrames);
910 AssertStmt(cbToClear <= cbBuf, cbToClear = cbBuf);
911
912 Log2Func(("pProps=%p, pvBuf=%p, cFrames=%RU32, fSigned=%RTbool, cbSample=%RU8\n",
913 pProps, pvBuf, cFrames, pProps->fSigned, pProps->cbSampleX));
914
915 /*
916 * Do the job.
917 */
918 if (pProps->fSigned)
919 RT_BZERO(pvBuf, cbToClear);
920 else /* Unsigned formats. */
921 {
922 switch (pProps->cbSampleX)
923 {
924 case 1: /* 8 bit */
925 memset(pvBuf, 0x80, cbToClear);
926 break;
927
928 case 2: /* 16 bit */
929 {
930 uint16_t *pu16Dst = (uint16_t *)pvBuf;
931 uint16_t const u16Offset = !pProps->fSwapEndian ? UINT16_C(0x8000) : UINT16_C(0x80);
932 cbBuf /= sizeof(*pu16Dst);
933 while (cbBuf-- > 0)
934 *pu16Dst++ = u16Offset;
935 break;
936 }
937
938 case 4: /* 32 bit */
939 ASMMemFill32(pvBuf, cbToClear & ~(size_t)(sizeof(uint32_t) - 1),
940 !pProps->fSwapEndian ? UINT32_C(0x80000000) : UINT32_C(0x80));
941 break;
942
943 default:
944 AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX));
945 }
946 }
947}
948
949/**
950 * Checks if the given buffer is silence.
951 *
952 * @param pProps The PCM properties to use checking the buffer.
953 * @param pvBuf The buffer to check.
954 * @param cbBuf The number of bytes to check (must be frame aligned).
955 */
956DECLINLINE(bool) PDMAudioPropsIsBufferSilence(PCPDMAUDIOPCMPROPS pProps, void const *pvBuf, size_t cbBuf)
957{
958 /*
959 * Validate input
960 */
961 AssertPtrReturn(pProps, false);
962 if (!cbBuf)
963 return false;
964 AssertPtrReturn(pvBuf, false);
965
966 /*
967 * Do the job.
968 */
969 if (pProps->fSigned)
970 return ASMMemIsZero(pvBuf, cbBuf);
971
972 switch (pProps->cbSampleX)
973 {
974 case 1: /* 8 bit */
975 return ASMMemIsAllU8(pvBuf, cbBuf, 0x80);
976
977 case 2: /* 16 bit */
978 {
979 uint16_t const *pu16 = (uint16_t const *)pvBuf;
980 uint16_t const u16Offset = !pProps->fSwapEndian ? UINT16_C(0x8000) : UINT16_C(0x80);
981 cbBuf /= sizeof(*pu16);
982 while (cbBuf-- > 0)
983 if (*pu16 != u16Offset)
984 return false;
985 return true;
986 }
987
988 case 4: /* 32 bit */
989 {
990 uint32_t const *pu32 = (uint32_t const *)pvBuf;
991 uint32_t const u32Offset = !pProps->fSwapEndian ? UINT32_C(0x80000000) : UINT32_C(0x80);
992 cbBuf /= sizeof(*pu32);
993 while (cbBuf-- > 0)
994 if (*pu32 != u32Offset)
995 return false;
996 return true;
997 }
998
999 default:
1000 AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX));
1001 return false;
1002 }
1003}
1004
1005/**
1006 * Compares two sets of PCM properties.
1007 *
1008 * @returns @c true if the same, @c false if not.
1009 * @param pProps1 The first set of properties to compare.
1010 * @param pProps2 The second set of properties to compare.
1011 */
1012DECLINLINE(bool) PDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2)
1013{
1014 uintptr_t idxCh;
1015 AssertPtrReturn(pProps1, false);
1016 AssertPtrReturn(pProps2, false);
1017
1018 if (pProps1 == pProps2) /* If the pointers match, take a shortcut. */
1019 return true;
1020
1021 if (pProps1->uHz != pProps2->uHz)
1022 return false;
1023 if (pProps1->cChannelsX != pProps2->cChannelsX)
1024 return false;
1025 if (pProps1->cbSampleX != pProps2->cbSampleX)
1026 return false;
1027 if (pProps1->fSigned != pProps2->fSigned)
1028 return false;
1029 if (pProps1->fSwapEndian != pProps2->fSwapEndian)
1030 return false;
1031 if (pProps1->fRaw != pProps2->fRaw)
1032 return false;
1033
1034 idxCh = pProps1->cChannelsX;
1035 while (idxCh-- > 0)
1036 if (pProps1->aidChannels[idxCh] != pProps2->aidChannels[idxCh])
1037 return false;
1038
1039 return true;
1040}
1041
1042/**
1043 * Checks whether the given PCM properties are valid or not.
1044 *
1045 * @returns true/false accordingly.
1046 * @param pProps The PCM properties to check.
1047 *
1048 * @remarks This just performs a generic check of value ranges. Further, it
1049 * will assert if the input is invalid.
1050 *
1051 * @sa PDMAudioStrmCfgIsValid
1052 */
1053DECLINLINE(bool) PDMAudioPropsAreValid(PCPDMAUDIOPCMPROPS pProps)
1054{
1055 AssertPtrReturn(pProps, false);
1056
1057 AssertReturn(pProps->cChannelsX != 0, false);
1058 AssertReturn(pProps->cChannelsX <= PDMAUDIO_MAX_CHANNELS, false);
1059 AssertMsgReturn( pProps->cbSampleX == 1 || pProps->cbSampleX == 2 || pProps->cbSampleX == 4 || (pProps->cbSampleX == 8 && pProps->fRaw),
1060 ("%u\n", pProps->cbSampleX), false);
1061 AssertMsgReturn(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX,
1062 ("cbFrame=%u cbSample=%u cChannels=%u\n", pProps->cbFrame, pProps->cbSampleX, pProps->cChannelsX),
1063 false);
1064 AssertMsgReturn(pProps->uHz >= 1000 && pProps->uHz < 1000000, ("%u\n", pProps->uHz), false);
1065 AssertMsgReturn(pProps->cShiftX == PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps),
1066 ("cShift=%u cbSample=%u cChannels=%u\n", pProps->cShiftX, pProps->cbSampleX, pProps->cChannelsX),
1067 false);
1068 AssertReturn(!pProps->fRaw || (pProps->fSigned && pProps->cbSampleX == sizeof(int64_t)), false);
1069 return true;
1070}
1071
1072/**
1073 * Get number of bytes per frame.
1074 *
1075 * @returns Number of bytes per audio frame.
1076 * @param pProps PCM properties to use.
1077 * @sa PDMAUDIOPCMPROPS_F2B
1078 */
1079DECLINLINE(uint32_t) PDMAudioPropsBytesPerFrame(PCPDMAUDIOPCMPROPS pProps)
1080{
1081 return PDMAUDIOPCMPROPS_F2B(pProps, 1 /*cFrames*/);
1082}
1083
1084/**
1085 * Prints PCM properties to the debug log.
1086 *
1087 * @param pProps PCM properties to use.
1088 */
1089DECLINLINE(void) PDMAudioPropsLog(PCPDMAUDIOPCMPROPS pProps)
1090{
1091 AssertPtrReturnVoid(pProps);
1092
1093 Log(("uHz=%RU32, cChannels=%RU8, cBits=%RU8%s",
1094 pProps->uHz, pProps->cChannelsX, pProps->cbSampleX * 8, pProps->fSigned ? "S" : "U"));
1095}
1096
1097/** Max necessary buffer space for PDMAudioPropsToString */
1098#define PDMAUDIOPROPSTOSTRING_MAX sizeof("16ch S64 4294967296Hz swap raw")
1099
1100/**
1101 * Formats the PCM audio properties into a string buffer.
1102 *
1103 * @returns pszDst
1104 * @param pProps PCM properties to use.
1105 * @param pszDst The destination buffer.
1106 * @param cchDst The size of the destination buffer. Recommended to be at
1107 * least PDMAUDIOPROPSTOSTRING_MAX bytes.
1108 */
1109DECLINLINE(char *) PDMAudioPropsToString(PCPDMAUDIOPCMPROPS pProps, char *pszDst, size_t cchDst)
1110{
1111 /* 2ch S64 44100Hz swap raw */
1112 RTStrPrintf(pszDst, cchDst, "%uch %c%u %RU32Hz%s%s",
1113 PDMAudioPropsChannels(pProps), PDMAudioPropsIsSigned(pProps) ? 'S' : 'U', PDMAudioPropsSampleBits(pProps),
1114 PDMAudioPropsHz(pProps), pProps->fSwapEndian ? " swap" : "", pProps->fRaw ? " raw" : "");
1115 return pszDst;
1116}
1117
1118
1119/*********************************************************************************************************************************
1120* Stream Configuration Helpers *
1121*********************************************************************************************************************************/
1122
1123/**
1124 * Initializes a stream configuration from PCM properties.
1125 *
1126 * @returns VBox status code.
1127 * @param pCfg The stream configuration to initialize.
1128 * @param pProps The PCM properties to use.
1129 */
1130DECLINLINE(int) PDMAudioStrmCfgInitWithProps(PPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps)
1131{
1132 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
1133 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1134
1135 RT_ZERO(*pCfg);
1136 pCfg->Backend.cFramesPreBuffering = UINT32_MAX; /* Explicitly set to "undefined". */
1137
1138 memcpy(&pCfg->Props, pProps, sizeof(PDMAUDIOPCMPROPS));
1139
1140 return VINF_SUCCESS;
1141}
1142
1143/**
1144 * Checks whether stream configuration matches the given PCM properties.
1145 *
1146 * @returns @c true if equal, @c false if not.
1147 * @param pCfg The stream configuration.
1148 * @param pProps The PCM properties to match with.
1149 */
1150DECLINLINE(bool) PDMAudioStrmCfgMatchesProps(PCPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps)
1151{
1152 AssertPtrReturn(pCfg, false);
1153 return PDMAudioPropsAreEqual(pProps, &pCfg->Props);
1154}
1155
1156/**
1157 * Checks whether two stream configuration matches.
1158 *
1159 * @returns @c true if equal, @c false if not.
1160 * @param pCfg1 The first stream configuration.
1161 * @param pCfg2 The second stream configuration.
1162 */
1163DECLINLINE(bool) PDMAudioStrmCfgEquals(PCPDMAUDIOSTREAMCFG pCfg1, PCPDMAUDIOSTREAMCFG pCfg2)
1164{
1165 if (!pCfg1 || !pCfg2)
1166 return false;
1167 if (pCfg1 == pCfg2)
1168 return pCfg1 != NULL;
1169 if (PDMAudioPropsAreEqual(&pCfg1->Props, &pCfg2->Props))
1170 return pCfg1->enmDir == pCfg2->enmDir
1171 && pCfg1->enmPath == pCfg2->enmPath
1172 && pCfg1->Device.cMsSchedulingHint == pCfg2->Device.cMsSchedulingHint
1173 && pCfg1->Backend.cFramesPeriod == pCfg2->Backend.cFramesPeriod
1174 && pCfg1->Backend.cFramesBufferSize == pCfg2->Backend.cFramesBufferSize
1175 && pCfg1->Backend.cFramesPreBuffering == pCfg2->Backend.cFramesPreBuffering
1176 && strcmp(pCfg1->szName, pCfg2->szName) == 0;
1177 return false;
1178}
1179
1180/**
1181 * Frees an audio stream allocated by PDMAudioStrmCfgDup().
1182 *
1183 * @param pCfg The stream configuration to free.
1184 */
1185DECLINLINE(void) PDMAudioStrmCfgFree(PPDMAUDIOSTREAMCFG pCfg)
1186{
1187 if (pCfg)
1188 RTMemFree(pCfg);
1189}
1190
1191/**
1192 * Checks whether the given stream configuration is valid or not.
1193 *
1194 * @returns true/false accordingly.
1195 * @param pCfg Stream configuration to check.
1196 *
1197 * @remarks This just performs a generic check of value ranges. Further, it
1198 * will assert if the input is invalid.
1199 *
1200 * @sa PDMAudioPropsAreValid
1201 */
1202DECLINLINE(bool) PDMAudioStrmCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg)
1203{
1204 AssertPtrReturn(pCfg, false);
1205 AssertMsgReturn(pCfg->enmDir >= PDMAUDIODIR_UNKNOWN && pCfg->enmDir < PDMAUDIODIR_END, ("%d\n", pCfg->enmDir), false);
1206 return PDMAudioPropsAreValid(&pCfg->Props);
1207}
1208
1209/**
1210 * Copies one stream configuration to another.
1211 *
1212 * @returns VBox status code.
1213 * @param pDstCfg The destination stream configuration.
1214 * @param pSrcCfg The source stream configuration.
1215 */
1216DECLINLINE(int) PDMAudioStrmCfgCopy(PPDMAUDIOSTREAMCFG pDstCfg, PCPDMAUDIOSTREAMCFG pSrcCfg)
1217{
1218 AssertPtrReturn(pDstCfg, VERR_INVALID_POINTER);
1219 AssertPtrReturn(pSrcCfg, VERR_INVALID_POINTER);
1220
1221 /* This used to be VBOX_STRICT only and return VERR_INVALID_PARAMETER, but
1222 that's making release builds work differently from debug & strict builds,
1223 which is a terrible idea: */
1224 Assert(PDMAudioStrmCfgIsValid(pSrcCfg));
1225
1226 memcpy(pDstCfg, pSrcCfg, sizeof(PDMAUDIOSTREAMCFG));
1227
1228 return VINF_SUCCESS;
1229}
1230
1231/**
1232 * Duplicates an audio stream configuration.
1233 *
1234 * @returns Pointer to duplicate on success, NULL on failure. Must be freed
1235 * using PDMAudioStrmCfgFree().
1236 *
1237 * @param pCfg The audio stream configuration to duplicate.
1238 */
1239DECLINLINE(PPDMAUDIOSTREAMCFG) PDMAudioStrmCfgDup(PCPDMAUDIOSTREAMCFG pCfg)
1240{
1241 AssertPtrReturn(pCfg, NULL);
1242
1243 PPDMAUDIOSTREAMCFG pDst = (PPDMAUDIOSTREAMCFG)RTMemAllocZ(sizeof(PDMAUDIOSTREAMCFG));
1244 if (pDst)
1245 {
1246 int rc = PDMAudioStrmCfgCopy(pDst, pCfg);
1247 if (RT_SUCCESS(rc))
1248 return pDst;
1249
1250 PDMAudioStrmCfgFree(pDst);
1251 }
1252 return NULL;
1253}
1254
1255/**
1256 * Logs an audio stream configuration.
1257 *
1258 * @param pCfg The stream configuration to log.
1259 */
1260DECLINLINE(void) PDMAudioStrmCfgLog(PCPDMAUDIOSTREAMCFG pCfg)
1261{
1262 if (pCfg)
1263 LogFunc(("szName=%s enmDir=%RU32 uHz=%RU32 cBits=%RU8%s cChannels=%RU8\n", pCfg->szName, pCfg->enmDir,
1264 pCfg->Props.uHz, pCfg->Props.cbSampleX * 8, pCfg->Props.fSigned ? "S" : "U", pCfg->Props.cChannelsX));
1265}
1266
1267/**
1268 * Converts a stream command enum value to a string.
1269 *
1270 * @returns Pointer to read-only stream command name on success,
1271 * "bad" if invalid command value.
1272 * @param enmCmd The stream command to name.
1273 */
1274DECLINLINE(const char *) PDMAudioStrmCmdGetName(PDMAUDIOSTREAMCMD enmCmd)
1275{
1276 switch (enmCmd)
1277 {
1278 case PDMAUDIOSTREAMCMD_INVALID: return "Invalid";
1279 case PDMAUDIOSTREAMCMD_ENABLE: return "Enable";
1280 case PDMAUDIOSTREAMCMD_DISABLE: return "Disable";
1281 case PDMAUDIOSTREAMCMD_PAUSE: return "Pause";
1282 case PDMAUDIOSTREAMCMD_RESUME: return "Resume";
1283 case PDMAUDIOSTREAMCMD_DRAIN: return "Drain";
1284 case PDMAUDIOSTREAMCMD_END:
1285 case PDMAUDIOSTREAMCMD_32BIT_HACK:
1286 break;
1287 /* no default! */
1288 }
1289 AssertMsgFailedReturn(("Invalid stream command %d\n", enmCmd), "bad");
1290}
1291
1292/** Max necessary buffer space for PDMAudioStrmCfgToString */
1293#define PDMAUDIOSTRMCFGTOSTRING_MAX \
1294 sizeof("'01234567890123456789012345678901234567890123456789012345678901234' Unknown 16ch S64 4294967296Hz swap raw")
1295
1296/**
1297 * Formats an audio stream configuration.
1298 *
1299 * @param pCfg The stream configuration to stringify.
1300 * @param pszDst The destination buffer.
1301 * @param cbDst The size of the destination buffer. Recommend this be
1302 * at least PDMAUDIOSTRMCFGTOSTRING_MAX bytes.
1303 */
1304DECLINLINE(const char *) PDMAudioStrmCfgToString(PCPDMAUDIOSTREAMCFG pCfg, char *pszDst, size_t cbDst)
1305{
1306 RTStrPrintf(pszDst, cbDst,
1307 "'%s' %s %uch %c%u %RU32Hz%s%s",
1308 pCfg->szName, PDMAudioDirGetName(pCfg->enmDir), PDMAudioPropsChannels(&pCfg->Props),
1309 PDMAudioPropsIsSigned(&pCfg->Props) ? 'S' : 'U', PDMAudioPropsSampleBits(&pCfg->Props),
1310 PDMAudioPropsHz(&pCfg->Props), pCfg->Props.fSwapEndian ? " swap" : "", pCfg->Props.fRaw ? " raw" : "");
1311 return pszDst;
1312}
1313
1314
1315/*********************************************************************************************************************************
1316* Stream Status Helpers *
1317*********************************************************************************************************************************/
1318
1319/**
1320 * Converts a audio stream state enum value to a string.
1321 *
1322 * @returns Pointer to read-only audio stream state string on success,
1323 * "illegal" if invalid command value.
1324 * @param enmStreamState The state to convert.
1325 */
1326DECLINLINE(const char *) PDMAudioStreamStateGetName(PDMAUDIOSTREAMSTATE enmStreamState)
1327{
1328 switch (enmStreamState)
1329 {
1330 case PDMAUDIOSTREAMSTATE_INVALID: return "invalid";
1331 case PDMAUDIOSTREAMSTATE_NOT_WORKING: return "not-working";
1332 case PDMAUDIOSTREAMSTATE_NEED_REINIT: return "need-reinit";
1333 case PDMAUDIOSTREAMSTATE_INACTIVE: return "inactive";
1334 case PDMAUDIOSTREAMSTATE_ENABLED: return "enabled";
1335 case PDMAUDIOSTREAMSTATE_ENABLED_READABLE: return "enabled-readable";
1336 case PDMAUDIOSTREAMSTATE_ENABLED_WRITABLE: return "enabled-writable";
1337 /* no default: */
1338 case PDMAUDIOSTREAMSTATE_END:
1339 case PDMAUDIOSTREAMSTATE_32BIT_HACK:
1340 break;
1341 }
1342 AssertMsgFailedReturn(("Invalid audio stream state: %d\n", enmStreamState), "illegal");
1343}
1344
1345/**
1346 * Converts a host audio (backend) stream state enum value to a string.
1347 *
1348 * @returns Pointer to read-only host audio stream state string on success,
1349 * "illegal" if invalid command value.
1350 * @param enmHostAudioStreamState The state to convert.
1351 */
1352DECLINLINE(const char *) PDMHostAudioStreamStateGetName(PDMHOSTAUDIOSTREAMSTATE enmHostAudioStreamState)
1353{
1354 switch (enmHostAudioStreamState)
1355 {
1356 case PDMHOSTAUDIOSTREAMSTATE_INVALID: return "invalid";
1357 case PDMHOSTAUDIOSTREAMSTATE_INITIALIZING: return "initializing";
1358 case PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING: return "not-working";
1359 case PDMHOSTAUDIOSTREAMSTATE_OKAY: return "okay";
1360 case PDMHOSTAUDIOSTREAMSTATE_DRAINING: return "draining";
1361 case PDMHOSTAUDIOSTREAMSTATE_INACTIVE: return "inactive";
1362 /* no default: */
1363 case PDMHOSTAUDIOSTREAMSTATE_END:
1364 case PDMHOSTAUDIOSTREAMSTATE_32BIT_HACK:
1365 break;
1366 }
1367 AssertMsgFailedReturn(("Invalid host audio stream state: %d\n", enmHostAudioStreamState), "illegal");
1368}
1369
1370/** @} */
1371
1372#endif /* !VBOX_INCLUDED_vmm_pdmaudioinline_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