VirtualBox

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

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

Audio: Lowered cased the output of PDMAudioDirGetName and PDMAudioPathGetName, added PDMAudioPropsFramesToMilliMax, and expaneded PDMAudioStrmCfgToString to include everything (enmPath, Device.cMsSchedulingHint, Backend.cFramesBuffer, Backend.cFramesPeriod, Backend.cFramesPreBuffer). bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.4 KB
Line 
1/* $Id: pdmaudioinline.h 89569 2021-06-08 10:37:41Z 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 passed an
61 * 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 "mic";
125 case PDMAUDIOPATH_IN_CD: return "cd";
126 case PDMAUDIOPATH_IN_VIDEO: return "video-in";
127 case PDMAUDIOPATH_IN_AUX: return "aux-in";
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 milliseconds, but not returning more than @a cMsMax
708 *
709 * This is a convenience for logging and such.
710 *
711 * @returns milliseconds (32-bit).
712 * @param pProps The PCM properties to use.
713 * @param cFrames Number of audio frames to convert.
714 * @param cMsMax Max return value (32-bit).
715 * @note No rounding here, result is floored.
716 */
717DECLINLINE(uint32_t) PDMAudioPropsFramesToMilliMax(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames, uint32_t cMsMax)
718{
719 AssertPtrReturn(pProps, 0);
720
721 /* Check input to prevent division by chainsaw: */
722 uint32_t const uHz = pProps->uHz;
723 if (uHz)
724 {
725 uint32_t const cMsResult = ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, uHz);
726 return RT_MIN(cMsResult, cMsMax);
727 }
728 return 0;
729}
730
731/**
732 * Converts frames to microseconds.
733 *
734 * @returns microseconds.
735 * @param pProps The PCM properties to use.
736 * @param cFrames Number of audio frames to convert.
737 * @note No rounding here, result is floored.
738 */
739DECLINLINE(uint64_t) PDMAudioPropsFramesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
740{
741 AssertPtrReturn(pProps, 0);
742
743 /* Check input to prevent division by chainsaw: */
744 uint32_t const uHz = pProps->uHz;
745 if (uHz)
746 return ASMMultU32ByU32DivByU32(cFrames, RT_US_1SEC, uHz);
747 return 0;
748}
749
750/**
751 * Converts frames to nanoseconds.
752 *
753 * @returns Nanoseconds.
754 * @param pProps The PCM properties to use.
755 * @param cFrames Number of audio frames to convert.
756 * @note No rounding here, result is floored.
757 */
758DECLINLINE(uint64_t) PDMAudioPropsFramesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
759{
760 AssertPtrReturn(pProps, 0);
761
762 /* Check input to prevent division by chainsaw: */
763 uint32_t const uHz = pProps->uHz;
764 if (uHz)
765 return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC, uHz);
766 return 0;
767}
768
769/**
770 * Converts frames to NT ticks (100 ns units).
771 *
772 * @returns NT ticks.
773 * @param pProps The PCM properties to use.
774 * @param cFrames Number of audio frames to convert.
775 * @note No rounding here, result is floored.
776 */
777DECLINLINE(uint64_t) PDMAudioPropsFramesToNtTicks(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
778{
779 AssertPtrReturn(pProps, 0);
780
781 /* Check input to prevent division by chainsaw: */
782 uint32_t const uHz = pProps->uHz;
783 if (uHz)
784 return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC / 100, uHz);
785 return 0;
786}
787
788/**
789 * Converts milliseconds to frames.
790 *
791 * @returns Number of frames
792 * @param pProps The PCM properties to use.
793 * @param cMs The number of milliseconds to convert.
794 *
795 * @note The result is rounded rather than floored (hysterical raisins).
796 */
797DECLINLINE(uint32_t) PDMAudioPropsMilliToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)
798{
799 AssertPtrReturn(pProps, 0);
800
801 uint32_t const uHz = pProps->uHz;
802 uint32_t cFrames;
803 if (cMs < RT_MS_1SEC)
804 cFrames = 0;
805 else
806 {
807 cFrames = cMs / RT_MS_1SEC * uHz;
808 cMs %= RT_MS_1SEC;
809 }
810 cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cMs) + RT_MS_1SEC - 1) / RT_MS_1SEC;
811 return cFrames;
812}
813
814/**
815 * Converts milliseconds to bytes.
816 *
817 * @returns Number of bytes (frame aligned).
818 * @param pProps The PCM properties to use.
819 * @param cMs The number of milliseconds to convert.
820 *
821 * @note The result is rounded rather than floored (hysterical raisins).
822 */
823DECLINLINE(uint32_t) PDMAudioPropsMilliToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)
824{
825 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsMilliToFrames(pProps, cMs));
826}
827
828/**
829 * Converts nanoseconds to frames.
830 *
831 * @returns Number of frames.
832 * @param pProps The PCM properties to use.
833 * @param cNs The number of nanoseconds to convert.
834 *
835 * @note The result is rounded rather than floored (hysterical raisins).
836 */
837DECLINLINE(uint32_t) PDMAudioPropsNanoToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
838{
839 AssertPtrReturn(pProps, 0);
840
841 uint32_t const uHz = pProps->uHz;
842 uint32_t cFrames;
843 if (cNs < RT_NS_1SEC)
844 cFrames = 0;
845 else
846 {
847 cFrames = cNs / RT_NS_1SEC * uHz;
848 cNs %= RT_NS_1SEC;
849 }
850 cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cNs) + RT_NS_1SEC - 1) / RT_NS_1SEC;
851 return cFrames;
852}
853
854/**
855 * Converts nanoseconds to frames, 64-bit return.
856 *
857 * @returns Number of frames (64-bit).
858 * @param pProps The PCM properties to use.
859 * @param cNs The number of nanoseconds to convert.
860 *
861 * @note The result is floored!
862 */
863DECLINLINE(uint64_t) PDMAudioPropsNanoToFrames64(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
864{
865 AssertPtrReturn(pProps, 0);
866
867 uint32_t const uHz = pProps->uHz;
868 uint64_t cFrames;
869 if (cNs < RT_NS_1SEC)
870 cFrames = 0;
871 else
872 {
873 cFrames = cNs / RT_NS_1SEC * uHz;
874 cNs %= RT_NS_1SEC;
875 }
876 cFrames += ASMMult2xU32RetU64(uHz, (uint32_t)cNs) / RT_NS_1SEC;
877 return cFrames;
878}
879
880/**
881 * Converts nanoseconds to bytes.
882 *
883 * @returns Number of bytes (frame aligned).
884 * @param pProps The PCM properties to use.
885 * @param cNs The number of nanoseconds to convert.
886 *
887 * @note The result is rounded rather than floored (hysterical raisins).
888 */
889DECLINLINE(uint32_t) PDMAudioPropsNanoToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
890{
891 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs));
892}
893
894/**
895 * Converts nanoseconds to bytes, 64-bit version.
896 *
897 * @returns Number of bytes (frame aligned), 64-bit.
898 * @param pProps The PCM properties to use.
899 * @param cNs The number of nanoseconds to convert.
900 *
901 * @note The result is floored.
902 */
903DECLINLINE(uint64_t) PDMAudioPropsNanoToBytes64(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
904{
905 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs));
906}
907
908/**
909 * Clears a sample buffer by the given amount of audio frames with silence (according to the format
910 * given by the PCM properties).
911 *
912 * @param pProps The PCM properties to apply.
913 * @param pvBuf The buffer to clear.
914 * @param cbBuf The buffer size in bytes.
915 * @param cFrames The number of audio frames to clear. Capped at @a cbBuf
916 * if exceeding the buffer. If the size is an unaligned
917 * number of frames, the extra bytes may be left
918 * uninitialized in some configurations.
919 */
920DECLINLINE(void) PDMAudioPropsClearBuffer(PCPDMAUDIOPCMPROPS pProps, void *pvBuf, size_t cbBuf, uint32_t cFrames)
921{
922 /*
923 * Validate input
924 */
925 AssertPtrReturnVoid(pProps);
926 Assert(pProps->cbSampleX);
927 if (!cbBuf || !cFrames)
928 return;
929 AssertPtrReturnVoid(pvBuf);
930
931 /*
932 * Decide how much needs clearing.
933 */
934 size_t cbToClear = PDMAudioPropsFramesToBytes(pProps, cFrames);
935 AssertStmt(cbToClear <= cbBuf, cbToClear = cbBuf);
936
937 Log2Func(("pProps=%p, pvBuf=%p, cFrames=%RU32, fSigned=%RTbool, cbSample=%RU8\n",
938 pProps, pvBuf, cFrames, pProps->fSigned, pProps->cbSampleX));
939
940 /*
941 * Do the job.
942 */
943 if (pProps->fSigned)
944 RT_BZERO(pvBuf, cbToClear);
945 else /* Unsigned formats. */
946 {
947 switch (pProps->cbSampleX)
948 {
949 case 1: /* 8 bit */
950 memset(pvBuf, 0x80, cbToClear);
951 break;
952
953 case 2: /* 16 bit */
954 {
955 uint16_t *pu16Dst = (uint16_t *)pvBuf;
956 uint16_t const u16Offset = !pProps->fSwapEndian ? UINT16_C(0x8000) : UINT16_C(0x80);
957 cbBuf /= sizeof(*pu16Dst);
958 while (cbBuf-- > 0)
959 *pu16Dst++ = u16Offset;
960 break;
961 }
962
963 case 4: /* 32 bit */
964 ASMMemFill32(pvBuf, cbToClear & ~(size_t)(sizeof(uint32_t) - 1),
965 !pProps->fSwapEndian ? UINT32_C(0x80000000) : UINT32_C(0x80));
966 break;
967
968 default:
969 AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX));
970 }
971 }
972}
973
974/**
975 * Checks if the given buffer is silence.
976 *
977 * @param pProps The PCM properties to use checking the buffer.
978 * @param pvBuf The buffer to check.
979 * @param cbBuf The number of bytes to check (must be frame aligned).
980 */
981DECLINLINE(bool) PDMAudioPropsIsBufferSilence(PCPDMAUDIOPCMPROPS pProps, void const *pvBuf, size_t cbBuf)
982{
983 /*
984 * Validate input
985 */
986 AssertPtrReturn(pProps, false);
987 if (!cbBuf)
988 return false;
989 AssertPtrReturn(pvBuf, false);
990
991 /*
992 * Do the job.
993 */
994 if (pProps->fSigned)
995 return ASMMemIsZero(pvBuf, cbBuf);
996
997 switch (pProps->cbSampleX)
998 {
999 case 1: /* 8 bit */
1000 return ASMMemIsAllU8(pvBuf, cbBuf, 0x80);
1001
1002 case 2: /* 16 bit */
1003 {
1004 uint16_t const *pu16 = (uint16_t const *)pvBuf;
1005 uint16_t const u16Offset = !pProps->fSwapEndian ? UINT16_C(0x8000) : UINT16_C(0x80);
1006 cbBuf /= sizeof(*pu16);
1007 while (cbBuf-- > 0)
1008 if (*pu16 != u16Offset)
1009 return false;
1010 return true;
1011 }
1012
1013 case 4: /* 32 bit */
1014 {
1015 uint32_t const *pu32 = (uint32_t const *)pvBuf;
1016 uint32_t const u32Offset = !pProps->fSwapEndian ? UINT32_C(0x80000000) : UINT32_C(0x80);
1017 cbBuf /= sizeof(*pu32);
1018 while (cbBuf-- > 0)
1019 if (*pu32 != u32Offset)
1020 return false;
1021 return true;
1022 }
1023
1024 default:
1025 AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX));
1026 return false;
1027 }
1028}
1029
1030/**
1031 * Compares two sets of PCM properties.
1032 *
1033 * @returns @c true if the same, @c false if not.
1034 * @param pProps1 The first set of properties to compare.
1035 * @param pProps2 The second set of properties to compare.
1036 */
1037DECLINLINE(bool) PDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2)
1038{
1039 uintptr_t idxCh;
1040 AssertPtrReturn(pProps1, false);
1041 AssertPtrReturn(pProps2, false);
1042
1043 if (pProps1 == pProps2) /* If the pointers match, take a shortcut. */
1044 return true;
1045
1046 if (pProps1->uHz != pProps2->uHz)
1047 return false;
1048 if (pProps1->cChannelsX != pProps2->cChannelsX)
1049 return false;
1050 if (pProps1->cbSampleX != pProps2->cbSampleX)
1051 return false;
1052 if (pProps1->fSigned != pProps2->fSigned)
1053 return false;
1054 if (pProps1->fSwapEndian != pProps2->fSwapEndian)
1055 return false;
1056 if (pProps1->fRaw != pProps2->fRaw)
1057 return false;
1058
1059 idxCh = pProps1->cChannelsX;
1060 while (idxCh-- > 0)
1061 if (pProps1->aidChannels[idxCh] != pProps2->aidChannels[idxCh])
1062 return false;
1063
1064 return true;
1065}
1066
1067/**
1068 * Checks whether the given PCM properties are valid or not.
1069 *
1070 * @returns true/false accordingly.
1071 * @param pProps The PCM properties to check.
1072 *
1073 * @remarks This just performs a generic check of value ranges. Further, it
1074 * will assert if the input is invalid.
1075 *
1076 * @sa PDMAudioStrmCfgIsValid
1077 */
1078DECLINLINE(bool) PDMAudioPropsAreValid(PCPDMAUDIOPCMPROPS pProps)
1079{
1080 AssertPtrReturn(pProps, false);
1081
1082 AssertReturn(pProps->cChannelsX != 0, false);
1083 AssertReturn(pProps->cChannelsX <= PDMAUDIO_MAX_CHANNELS, false);
1084 AssertMsgReturn( pProps->cbSampleX == 1 || pProps->cbSampleX == 2 || pProps->cbSampleX == 4 || (pProps->cbSampleX == 8 && pProps->fRaw),
1085 ("%u\n", pProps->cbSampleX), false);
1086 AssertMsgReturn(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX,
1087 ("cbFrame=%u cbSample=%u cChannels=%u\n", pProps->cbFrame, pProps->cbSampleX, pProps->cChannelsX),
1088 false);
1089 AssertMsgReturn(pProps->uHz >= 1000 && pProps->uHz < 1000000, ("%u\n", pProps->uHz), false);
1090 AssertMsgReturn(pProps->cShiftX == PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps),
1091 ("cShift=%u cbSample=%u cChannels=%u\n", pProps->cShiftX, pProps->cbSampleX, pProps->cChannelsX),
1092 false);
1093 AssertReturn(!pProps->fRaw || (pProps->fSigned && pProps->cbSampleX == sizeof(int64_t)), false);
1094 return true;
1095}
1096
1097/**
1098 * Get number of bytes per frame.
1099 *
1100 * @returns Number of bytes per audio frame.
1101 * @param pProps PCM properties to use.
1102 * @sa PDMAUDIOPCMPROPS_F2B
1103 */
1104DECLINLINE(uint32_t) PDMAudioPropsBytesPerFrame(PCPDMAUDIOPCMPROPS pProps)
1105{
1106 return PDMAUDIOPCMPROPS_F2B(pProps, 1 /*cFrames*/);
1107}
1108
1109/**
1110 * Prints PCM properties to the debug log.
1111 *
1112 * @param pProps PCM properties to use.
1113 */
1114DECLINLINE(void) PDMAudioPropsLog(PCPDMAUDIOPCMPROPS pProps)
1115{
1116 AssertPtrReturnVoid(pProps);
1117
1118 Log(("uHz=%RU32, cChannels=%RU8, cBits=%RU8%s",
1119 pProps->uHz, pProps->cChannelsX, pProps->cbSampleX * 8, pProps->fSigned ? "S" : "U"));
1120}
1121
1122/** Max necessary buffer space for PDMAudioPropsToString */
1123#define PDMAUDIOPROPSTOSTRING_MAX sizeof("16ch S64 4294967296Hz swap raw")
1124
1125/**
1126 * Formats the PCM audio properties into a string buffer.
1127 *
1128 * @returns pszDst
1129 * @param pProps PCM properties to use.
1130 * @param pszDst The destination buffer.
1131 * @param cchDst The size of the destination buffer. Recommended to be at
1132 * least PDMAUDIOPROPSTOSTRING_MAX bytes.
1133 */
1134DECLINLINE(char *) PDMAudioPropsToString(PCPDMAUDIOPCMPROPS pProps, char *pszDst, size_t cchDst)
1135{
1136 /* 2ch S64 44100Hz swap raw */
1137 RTStrPrintf(pszDst, cchDst, "%uch %c%u %RU32Hz%s%s",
1138 PDMAudioPropsChannels(pProps), PDMAudioPropsIsSigned(pProps) ? 'S' : 'U', PDMAudioPropsSampleBits(pProps),
1139 PDMAudioPropsHz(pProps), pProps->fSwapEndian ? " swap" : "", pProps->fRaw ? " raw" : "");
1140 return pszDst;
1141}
1142
1143
1144/*********************************************************************************************************************************
1145* Stream Configuration Helpers *
1146*********************************************************************************************************************************/
1147
1148/**
1149 * Initializes a stream configuration from PCM properties.
1150 *
1151 * @returns VBox status code.
1152 * @param pCfg The stream configuration to initialize.
1153 * @param pProps The PCM properties to use.
1154 */
1155DECLINLINE(int) PDMAudioStrmCfgInitWithProps(PPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps)
1156{
1157 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
1158 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
1159
1160 RT_ZERO(*pCfg);
1161 pCfg->Backend.cFramesPreBuffering = UINT32_MAX; /* Explicitly set to "undefined". */
1162
1163 memcpy(&pCfg->Props, pProps, sizeof(PDMAUDIOPCMPROPS));
1164
1165 return VINF_SUCCESS;
1166}
1167
1168/**
1169 * Checks whether stream configuration matches the given PCM properties.
1170 *
1171 * @returns @c true if equal, @c false if not.
1172 * @param pCfg The stream configuration.
1173 * @param pProps The PCM properties to match with.
1174 */
1175DECLINLINE(bool) PDMAudioStrmCfgMatchesProps(PCPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps)
1176{
1177 AssertPtrReturn(pCfg, false);
1178 return PDMAudioPropsAreEqual(pProps, &pCfg->Props);
1179}
1180
1181/**
1182 * Checks whether two stream configuration matches.
1183 *
1184 * @returns @c true if equal, @c false if not.
1185 * @param pCfg1 The first stream configuration.
1186 * @param pCfg2 The second stream configuration.
1187 */
1188DECLINLINE(bool) PDMAudioStrmCfgEquals(PCPDMAUDIOSTREAMCFG pCfg1, PCPDMAUDIOSTREAMCFG pCfg2)
1189{
1190 if (!pCfg1 || !pCfg2)
1191 return false;
1192 if (pCfg1 == pCfg2)
1193 return pCfg1 != NULL;
1194 if (PDMAudioPropsAreEqual(&pCfg1->Props, &pCfg2->Props))
1195 return pCfg1->enmDir == pCfg2->enmDir
1196 && pCfg1->enmPath == pCfg2->enmPath
1197 && pCfg1->Device.cMsSchedulingHint == pCfg2->Device.cMsSchedulingHint
1198 && pCfg1->Backend.cFramesPeriod == pCfg2->Backend.cFramesPeriod
1199 && pCfg1->Backend.cFramesBufferSize == pCfg2->Backend.cFramesBufferSize
1200 && pCfg1->Backend.cFramesPreBuffering == pCfg2->Backend.cFramesPreBuffering
1201 && strcmp(pCfg1->szName, pCfg2->szName) == 0;
1202 return false;
1203}
1204
1205/**
1206 * Frees an audio stream allocated by PDMAudioStrmCfgDup().
1207 *
1208 * @param pCfg The stream configuration to free.
1209 */
1210DECLINLINE(void) PDMAudioStrmCfgFree(PPDMAUDIOSTREAMCFG pCfg)
1211{
1212 if (pCfg)
1213 RTMemFree(pCfg);
1214}
1215
1216/**
1217 * Checks whether the given stream configuration is valid or not.
1218 *
1219 * @returns true/false accordingly.
1220 * @param pCfg Stream configuration to check.
1221 *
1222 * @remarks This just performs a generic check of value ranges. Further, it
1223 * will assert if the input is invalid.
1224 *
1225 * @sa PDMAudioPropsAreValid
1226 */
1227DECLINLINE(bool) PDMAudioStrmCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg)
1228{
1229 AssertPtrReturn(pCfg, false);
1230 AssertMsgReturn(pCfg->enmDir >= PDMAUDIODIR_UNKNOWN && pCfg->enmDir < PDMAUDIODIR_END, ("%d\n", pCfg->enmDir), false);
1231 return PDMAudioPropsAreValid(&pCfg->Props);
1232}
1233
1234/**
1235 * Copies one stream configuration to another.
1236 *
1237 * @returns VBox status code.
1238 * @param pDstCfg The destination stream configuration.
1239 * @param pSrcCfg The source stream configuration.
1240 */
1241DECLINLINE(int) PDMAudioStrmCfgCopy(PPDMAUDIOSTREAMCFG pDstCfg, PCPDMAUDIOSTREAMCFG pSrcCfg)
1242{
1243 AssertPtrReturn(pDstCfg, VERR_INVALID_POINTER);
1244 AssertPtrReturn(pSrcCfg, VERR_INVALID_POINTER);
1245
1246 /* This used to be VBOX_STRICT only and return VERR_INVALID_PARAMETER, but
1247 that's making release builds work differently from debug & strict builds,
1248 which is a terrible idea: */
1249 Assert(PDMAudioStrmCfgIsValid(pSrcCfg));
1250
1251 memcpy(pDstCfg, pSrcCfg, sizeof(PDMAUDIOSTREAMCFG));
1252
1253 return VINF_SUCCESS;
1254}
1255
1256/**
1257 * Duplicates an audio stream configuration.
1258 *
1259 * @returns Pointer to duplicate on success, NULL on failure. Must be freed
1260 * using PDMAudioStrmCfgFree().
1261 *
1262 * @param pCfg The audio stream configuration to duplicate.
1263 */
1264DECLINLINE(PPDMAUDIOSTREAMCFG) PDMAudioStrmCfgDup(PCPDMAUDIOSTREAMCFG pCfg)
1265{
1266 AssertPtrReturn(pCfg, NULL);
1267
1268 PPDMAUDIOSTREAMCFG pDst = (PPDMAUDIOSTREAMCFG)RTMemAllocZ(sizeof(PDMAUDIOSTREAMCFG));
1269 if (pDst)
1270 {
1271 int rc = PDMAudioStrmCfgCopy(pDst, pCfg);
1272 if (RT_SUCCESS(rc))
1273 return pDst;
1274
1275 PDMAudioStrmCfgFree(pDst);
1276 }
1277 return NULL;
1278}
1279
1280/**
1281 * Logs an audio stream configuration.
1282 *
1283 * @param pCfg The stream configuration to log.
1284 */
1285DECLINLINE(void) PDMAudioStrmCfgLog(PCPDMAUDIOSTREAMCFG pCfg)
1286{
1287 if (pCfg)
1288 LogFunc(("szName=%s enmDir=%RU32 uHz=%RU32 cBits=%RU8%s cChannels=%RU8\n", pCfg->szName, pCfg->enmDir,
1289 pCfg->Props.uHz, pCfg->Props.cbSampleX * 8, pCfg->Props.fSigned ? "S" : "U", pCfg->Props.cChannelsX));
1290}
1291
1292/**
1293 * Converts a stream command enum value to a string.
1294 *
1295 * @returns Pointer to read-only stream command name on success,
1296 * "bad" if invalid command value.
1297 * @param enmCmd The stream command to name.
1298 */
1299DECLINLINE(const char *) PDMAudioStrmCmdGetName(PDMAUDIOSTREAMCMD enmCmd)
1300{
1301 switch (enmCmd)
1302 {
1303 case PDMAUDIOSTREAMCMD_INVALID: return "Invalid";
1304 case PDMAUDIOSTREAMCMD_ENABLE: return "Enable";
1305 case PDMAUDIOSTREAMCMD_DISABLE: return "Disable";
1306 case PDMAUDIOSTREAMCMD_PAUSE: return "Pause";
1307 case PDMAUDIOSTREAMCMD_RESUME: return "Resume";
1308 case PDMAUDIOSTREAMCMD_DRAIN: return "Drain";
1309 case PDMAUDIOSTREAMCMD_END:
1310 case PDMAUDIOSTREAMCMD_32BIT_HACK:
1311 break;
1312 /* no default! */
1313 }
1314 AssertMsgFailedReturn(("Invalid stream command %d\n", enmCmd), "bad");
1315}
1316
1317/** Max necessary buffer space for PDMAudioStrmCfgToString */
1318#define PDMAUDIOSTRMCFGTOSTRING_MAX \
1319 sizeof("'01234567890123456789012345678901234567890123456789012345678901234' unknown 16ch S64 4294967295Hz swap raw, 9999999ms buffer, 9999999ms period, 9999999ms pre-buffer, 4294967295ms sched, center-lfe")
1320
1321/**
1322 * Formats an audio stream configuration.
1323 *
1324 * @param pCfg The stream configuration to stringify.
1325 * @param pszDst The destination buffer.
1326 * @param cbDst The size of the destination buffer. Recommend this be
1327 * at least PDMAUDIOSTRMCFGTOSTRING_MAX bytes.
1328 */
1329DECLINLINE(const char *) PDMAudioStrmCfgToString(PCPDMAUDIOSTREAMCFG pCfg, char *pszDst, size_t cbDst)
1330{
1331 /* 'front' output 2ch 44100Hz raw, 300ms buffer, 75ms period, 150ms pre-buffer, 10ms sched */
1332 RTStrPrintf(pszDst, cbDst,
1333 "'%s' %s %uch %c%u %RU32Hz%s%s, %RU32ms buffer, %RU32ms period, %RU32ms pre-buffer, %RU32ms sched%s%s",
1334 pCfg->szName, PDMAudioDirGetName(pCfg->enmDir), PDMAudioPropsChannels(&pCfg->Props),
1335 PDMAudioPropsIsSigned(&pCfg->Props) ? 'S' : 'U', PDMAudioPropsSampleBits(&pCfg->Props),
1336 PDMAudioPropsHz(&pCfg->Props), pCfg->Props.fSwapEndian ? " swap" : "", pCfg->Props.fRaw ? " raw" : "",
1337 PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesBufferSize, 9999999),
1338 PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesPeriod, 9999999),
1339 PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesPreBuffering, 9999999),
1340 pCfg->Device.cMsSchedulingHint,
1341 pCfg->enmPath == PDMAUDIOPATH_UNKNOWN ? ", " : "",
1342 pCfg->enmPath == PDMAUDIOPATH_UNKNOWN ? "" : PDMAudioPathGetName(pCfg->enmPath) );
1343 return pszDst;
1344}
1345
1346
1347/*********************************************************************************************************************************
1348* Stream Status Helpers *
1349*********************************************************************************************************************************/
1350
1351/**
1352 * Converts a audio stream state enum value to a string.
1353 *
1354 * @returns Pointer to read-only audio stream state string on success,
1355 * "illegal" if invalid command value.
1356 * @param enmStreamState The state to convert.
1357 */
1358DECLINLINE(const char *) PDMAudioStreamStateGetName(PDMAUDIOSTREAMSTATE enmStreamState)
1359{
1360 switch (enmStreamState)
1361 {
1362 case PDMAUDIOSTREAMSTATE_INVALID: return "invalid";
1363 case PDMAUDIOSTREAMSTATE_NOT_WORKING: return "not-working";
1364 case PDMAUDIOSTREAMSTATE_NEED_REINIT: return "need-reinit";
1365 case PDMAUDIOSTREAMSTATE_INACTIVE: return "inactive";
1366 case PDMAUDIOSTREAMSTATE_ENABLED: return "enabled";
1367 case PDMAUDIOSTREAMSTATE_ENABLED_READABLE: return "enabled-readable";
1368 case PDMAUDIOSTREAMSTATE_ENABLED_WRITABLE: return "enabled-writable";
1369 /* no default: */
1370 case PDMAUDIOSTREAMSTATE_END:
1371 case PDMAUDIOSTREAMSTATE_32BIT_HACK:
1372 break;
1373 }
1374 AssertMsgFailedReturn(("Invalid audio stream state: %d\n", enmStreamState), "illegal");
1375}
1376
1377/**
1378 * Converts a host audio (backend) stream state enum value to a string.
1379 *
1380 * @returns Pointer to read-only host audio stream state string on success,
1381 * "illegal" if invalid command value.
1382 * @param enmHostAudioStreamState The state to convert.
1383 */
1384DECLINLINE(const char *) PDMHostAudioStreamStateGetName(PDMHOSTAUDIOSTREAMSTATE enmHostAudioStreamState)
1385{
1386 switch (enmHostAudioStreamState)
1387 {
1388 case PDMHOSTAUDIOSTREAMSTATE_INVALID: return "invalid";
1389 case PDMHOSTAUDIOSTREAMSTATE_INITIALIZING: return "initializing";
1390 case PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING: return "not-working";
1391 case PDMHOSTAUDIOSTREAMSTATE_OKAY: return "okay";
1392 case PDMHOSTAUDIOSTREAMSTATE_DRAINING: return "draining";
1393 case PDMHOSTAUDIOSTREAMSTATE_INACTIVE: return "inactive";
1394 /* no default: */
1395 case PDMHOSTAUDIOSTREAMSTATE_END:
1396 case PDMHOSTAUDIOSTREAMSTATE_32BIT_HACK:
1397 break;
1398 }
1399 AssertMsgFailedReturn(("Invalid host audio stream state: %d\n", enmHostAudioStreamState), "illegal");
1400}
1401
1402/** @} */
1403
1404#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