VirtualBox

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

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

Audio: We don't return IPRT status codes, but VBox status codes. duh. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.4 KB
Line 
1/* $Id: pdmaudioinline.h 88300 2021-03-26 14:31:55Z 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/* Fix later: */
57DECLINLINE(bool) PDMAudioPropsAreValid(PCPDMAUDIOPCMPROPS pProps);
58DECLINLINE(bool) PDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2);
59
60
61
62/**
63 * Gets the name of an audio direction enum value.
64 *
65 * @returns Pointer to read-only name string on success, "bad" if
66 * passed an invalid enum value.
67 * @param enmDir The audio direction value to name.
68 */
69DECLINLINE(const char *) PDMAudioDirGetName(PDMAUDIODIR enmDir)
70{
71 switch (enmDir)
72 {
73 case PDMAUDIODIR_UNKNOWN: return "Unknown";
74 case PDMAUDIODIR_IN: return "Input";
75 case PDMAUDIODIR_OUT: return "Output";
76 case PDMAUDIODIR_DUPLEX: return "Duplex";
77
78 /* no default */
79 case PDMAUDIODIR_END:
80 case PDMAUDIODIR_INVALID:
81 case PDMAUDIODIR_32BIT_HACK:
82 break;
83 }
84 AssertMsgFailedReturn(("Invalid audio direction %d\n", enmDir), "bad");
85}
86
87/**
88 * Gets the name of an audio mixer control enum value.
89 *
90 * @returns Pointer to read-only name, "bad" if invalid input.
91 * @param enmMixerCtl The audio mixer control value.
92 */
93DECLINLINE(const char *) PDMAudioMixerCtlGetName(PDMAUDIOMIXERCTL enmMixerCtl)
94{
95 switch (enmMixerCtl)
96 {
97 case PDMAUDIOMIXERCTL_UNKNOWN: return "Unknown";
98 case PDMAUDIOMIXERCTL_VOLUME_MASTER: return "Master Volume";
99 case PDMAUDIOMIXERCTL_FRONT: return "Front";
100 case PDMAUDIOMIXERCTL_CENTER_LFE: return "Center / LFE";
101 case PDMAUDIOMIXERCTL_REAR: return "Rear";
102 case PDMAUDIOMIXERCTL_LINE_IN: return "Line-In";
103 case PDMAUDIOMIXERCTL_MIC_IN: return "Microphone-In";
104 /* no default */
105 case PDMAUDIOMIXERCTL_END:
106 case PDMAUDIOMIXERCTL_INVALID:
107 case PDMAUDIOMIXERCTL_32BIT_HACK:
108 break;
109 }
110 AssertMsgFailedReturn(("Invalid mixer control %ld\n", enmMixerCtl), "bad");
111}
112
113/**
114 * Gets the name of a playback destination enum value.
115 *
116 * @returns Pointer to read-only name, "bad" if invalid input.
117 * @param enmPlaybackDst The playback destination value.
118 */
119DECLINLINE(const char *) PDMAudioPlaybackDstGetName(PDMAUDIOPLAYBACKDST enmPlaybackDst)
120{
121 switch (enmPlaybackDst)
122 {
123 case PDMAUDIOPLAYBACKDST_UNKNOWN: return "Unknown";
124 case PDMAUDIOPLAYBACKDST_FRONT: return "Front";
125 case PDMAUDIOPLAYBACKDST_CENTER_LFE: return "Center / LFE";
126 case PDMAUDIOPLAYBACKDST_REAR: return "Rear";
127 /* no default */
128 case PDMAUDIOPLAYBACKDST_INVALID:
129 case PDMAUDIOPLAYBACKDST_END:
130 case PDMAUDIOPLAYBACKDST_32BIT_HACK:
131 break;
132 }
133 AssertMsgFailedReturn(("Invalid playback destination %ld\n", enmPlaybackDst), "bad");
134}
135
136/**
137 * Gets the name of a recording source enum value.
138 *
139 * @returns Pointer to read-only name, "bad" if invalid input.
140 * @param enmRecSrc The recording source value.
141 */
142DECLINLINE(const char *) PDMAudioRecSrcGetName(PDMAUDIORECSRC enmRecSrc)
143{
144 switch (enmRecSrc)
145 {
146 case PDMAUDIORECSRC_UNKNOWN: return "Unknown";
147 case PDMAUDIORECSRC_MIC: return "Microphone In";
148 case PDMAUDIORECSRC_CD: return "CD";
149 case PDMAUDIORECSRC_VIDEO: return "Video";
150 case PDMAUDIORECSRC_AUX: return "AUX";
151 case PDMAUDIORECSRC_LINE: return "Line In";
152 case PDMAUDIORECSRC_PHONE: return "Phone";
153 /* no default */
154 case PDMAUDIORECSRC_END:
155 case PDMAUDIORECSRC_32BIT_HACK:
156 break;
157 }
158 AssertMsgFailedReturn(("Invalid recording source %ld\n", enmRecSrc), "bad");
159}
160
161/**
162 * Checks whether the audio format is signed.
163 *
164 * @returns @c true for signed format, @c false for unsigned.
165 * @param enmFmt The audio format.
166 */
167DECLINLINE(bool) PDMAudioFormatIsSigned(PDMAUDIOFMT enmFmt)
168{
169 switch (enmFmt)
170 {
171 case PDMAUDIOFMT_S8:
172 case PDMAUDIOFMT_S16:
173 case PDMAUDIOFMT_S32:
174 return true;
175
176 case PDMAUDIOFMT_U8:
177 case PDMAUDIOFMT_U16:
178 case PDMAUDIOFMT_U32:
179 return false;
180
181 /* no default */
182 case PDMAUDIOFMT_INVALID:
183 case PDMAUDIOFMT_END:
184 case PDMAUDIOFMT_32BIT_HACK:
185 break;
186 }
187 AssertMsgFailedReturn(("Bogus audio format %ld\n", enmFmt), false);
188}
189
190/**
191 * Gets the encoding width in bits of the give audio format.
192 *
193 * @returns Bit count. 0 if invalid input.
194 * @param enmFmt The audio format.
195 */
196DECLINLINE(uint8_t) PDMAudioFormatGetBits(PDMAUDIOFMT enmFmt)
197{
198 switch (enmFmt)
199 {
200 case PDMAUDIOFMT_S8:
201 case PDMAUDIOFMT_U8:
202 return 8;
203
204 case PDMAUDIOFMT_U16:
205 case PDMAUDIOFMT_S16:
206 return 16;
207
208 case PDMAUDIOFMT_U32:
209 case PDMAUDIOFMT_S32:
210 return 32;
211
212 /* no default */
213 case PDMAUDIOFMT_INVALID:
214 case PDMAUDIOFMT_END:
215 case PDMAUDIOFMT_32BIT_HACK:
216 break;
217 }
218 AssertMsgFailedReturn(("Bogus audio format %ld\n", enmFmt), 0);
219}
220
221/**
222 * Gets the name of an audio format enum value.
223 *
224 * @returns Pointer to read-only name on success, returns "bad" on if
225 * invalid enum value.
226 * @param enmFmt The audio format to name.
227 */
228DECLINLINE(const char *) PDMAudioFormatGetName(PDMAUDIOFMT enmFmt)
229{
230 switch (enmFmt)
231 {
232 case PDMAUDIOFMT_U8: return "U8";
233 case PDMAUDIOFMT_U16: return "U16";
234 case PDMAUDIOFMT_U32: return "U32";
235 case PDMAUDIOFMT_S8: return "S8";
236 case PDMAUDIOFMT_S16: return "S16";
237 case PDMAUDIOFMT_S32: return "S32";
238 /* no default */
239 case PDMAUDIOFMT_INVALID:
240 case PDMAUDIOFMT_END:
241 case PDMAUDIOFMT_32BIT_HACK:
242 break;
243 }
244 AssertMsgFailedReturn(("Bogus audio format %d\n", enmFmt), "bad");
245}
246
247/**
248 * Initializes a stream configuration from PCM properties.
249 *
250 * @returns VBox status code.
251 * @param pCfg The stream configuration to initialize.
252 * @param pProps The PCM properties to use.
253 */
254DECLINLINE(int) PDMAudioStrmCfgInitWithProps(PPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps)
255{
256 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
257 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
258
259 RT_ZERO(*pCfg);
260 pCfg->Backend.cFramesPreBuffering = UINT32_MAX; /* Explicitly set to "undefined". */
261
262 memcpy(&pCfg->Props, pProps, sizeof(PDMAUDIOPCMPROPS));
263
264 return VINF_SUCCESS;
265}
266
267/**
268 * Checks whether stream configuration matches the given PCM properties.
269 *
270 * @returns @c true if equal, @c false if not.
271 * @param pCfg The stream configuration.
272 * @param pProps The PCM properties to match with.
273 */
274DECLINLINE(bool) PDMAudioStrmCfgMatchesProps(PCPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps)
275{
276 AssertPtrReturn(pCfg, false);
277 return PDMAudioPropsAreEqual(pProps, &pCfg->Props);
278}
279
280/**
281 * Frees an audio stream allocated by PDMAudioStrmCfgDup().
282 *
283 * @param pCfg The stream configuration to free.
284 */
285DECLINLINE(void) PDMAudioStrmCfgFree(PPDMAUDIOSTREAMCFG pCfg)
286{
287 if (pCfg)
288 RTMemFree(pCfg);
289}
290
291/**
292 * Checks whether the given stream configuration is valid or not.
293 *
294 * @returns true/false accordingly.
295 * @param pCfg Stream configuration to check.
296 *
297 * @remarks This just performs a generic check of value ranges. Further, it
298 * will assert if the input is invalid.
299 *
300 * @sa PDMAudioPropsAreValid
301 */
302DECLINLINE(bool) PDMAudioStrmCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg)
303{
304 AssertPtrReturn(pCfg, false);
305 AssertMsgReturn(pCfg->enmDir >= PDMAUDIODIR_UNKNOWN && pCfg->enmDir < PDMAUDIODIR_END,
306 ("%d\n", pCfg->enmDir), false);
307 AssertMsgReturn(pCfg->enmLayout >= PDMAUDIOSTREAMLAYOUT_UNKNOWN && pCfg->enmLayout < PDMAUDIOSTREAMLAYOUT_END,
308 ("%d\n", pCfg->enmLayout), false);
309 return PDMAudioPropsAreValid(&pCfg->Props);
310}
311
312/**
313 * Copies one stream configuration to another.
314 *
315 * @returns VBox status code.
316 * @param pDstCfg The destination stream configuration.
317 * @param pSrcCfg The source stream configuration.
318 */
319DECLINLINE(int) PDMAudioStrmCfgCopy(PPDMAUDIOSTREAMCFG pDstCfg, PCPDMAUDIOSTREAMCFG pSrcCfg)
320{
321 AssertPtrReturn(pDstCfg, VERR_INVALID_POINTER);
322 AssertPtrReturn(pSrcCfg, VERR_INVALID_POINTER);
323
324 /* This used to be VBOX_STRICT only and return VERR_INVALID_PARAMETER, but
325 that's making release builds work differently from debug & strict builds,
326 which is a terrible idea: */
327 Assert(PDMAudioStrmCfgIsValid(pSrcCfg));
328
329 memcpy(pDstCfg, pSrcCfg, sizeof(PDMAUDIOSTREAMCFG));
330
331 return VINF_SUCCESS;
332}
333
334/**
335 * Duplicates an audio stream configuration.
336 *
337 * @returns Pointer to duplicate on success, NULL on failure. Must be freed
338 * using PDMAudioStrmCfgFree().
339 *
340 * @param pCfg The audio stream configuration to duplicate.
341 */
342DECLINLINE(PPDMAUDIOSTREAMCFG) PDMAudioStrmCfgDup(PCPDMAUDIOSTREAMCFG pCfg)
343{
344 AssertPtrReturn(pCfg, NULL);
345
346 PPDMAUDIOSTREAMCFG pDst = (PPDMAUDIOSTREAMCFG)RTMemAllocZ(sizeof(PDMAUDIOSTREAMCFG));
347 if (pDst)
348 {
349 int rc = PDMAudioStrmCfgCopy(pDst, pCfg);
350 if (RT_SUCCESS(rc))
351 return pDst;
352
353 PDMAudioStrmCfgFree(pDst);
354 }
355 return NULL;
356}
357
358/**
359 * Logs an audio stream configuration.
360 *
361 * @param pCfg The stream configuration to log.
362 */
363DECLINLINE(void) PDMAudioStrmCfgLog(PCPDMAUDIOSTREAMCFG pCfg)
364{
365 if (pCfg)
366 LogFunc(("szName=%s enmDir=%RU32 uHz=%RU32 cBits=%RU8%s cChannels=%RU8\n", pCfg->szName, pCfg->enmDir,
367 pCfg->Props.uHz, pCfg->Props.cbSampleX * 8, pCfg->Props.fSigned ? "S" : "U", pCfg->Props.cChannelsX));
368}
369
370/**
371 * Converts a stream command enum value to a string.
372 *
373 * @returns Pointer to read-only stream command name on success,
374 * "bad" if invalid command value.
375 * @param enmCmd The stream command to name.
376 */
377DECLINLINE(const char *) PDMAudioStrmCmdGetName(PDMAUDIOSTREAMCMD enmCmd)
378{
379 switch (enmCmd)
380 {
381 case PDMAUDIOSTREAMCMD_INVALID: return "Invalid";
382 case PDMAUDIOSTREAMCMD_UNKNOWN: return "Unknown";
383 case PDMAUDIOSTREAMCMD_ENABLE: return "Enable";
384 case PDMAUDIOSTREAMCMD_DISABLE: return "Disable";
385 case PDMAUDIOSTREAMCMD_PAUSE: return "Pause";
386 case PDMAUDIOSTREAMCMD_RESUME: return "Resume";
387 case PDMAUDIOSTREAMCMD_DRAIN: return "Drain";
388 case PDMAUDIOSTREAMCMD_DROP: return "Drop";
389 case PDMAUDIOSTREAMCMD_END:
390 case PDMAUDIOSTREAMCMD_32BIT_HACK:
391 break;
392 /* no default! */
393 }
394 AssertMsgFailedReturn(("Invalid stream command %d\n", enmCmd), "bad");
395}
396
397/**
398 * Checks if the stream status is one that can be read from.
399 *
400 * @returns @c true if ready to be read from, @c false if not.
401 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAMSTS_FLAGS_XXX.
402 */
403DECLINLINE(bool) PDMAudioStrmStatusCanRead(PDMAUDIOSTREAMSTS fStatus)
404{
405 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false);
406 /*
407 return fStatus & PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
408 && fStatus & PDMAUDIOSTREAMSTS_FLAGS_ENABLED
409 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PAUSED)
410 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT);*/
411 return (fStatus & ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
412 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED
413 | PDMAUDIOSTREAMSTS_FLAGS_PAUSED
414 | PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT ))
415 == ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
416 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED);
417}
418
419/**
420 * Checks if the stream status is one that can be written to.
421 *
422 * @returns @c true if ready to be written to, @c false if not.
423 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAMSTS_FLAGS_XXX.
424 */
425DECLINLINE(bool) PDMAudioStrmStatusCanWrite(PDMAUDIOSTREAMSTS fStatus)
426{
427 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false);
428 /*
429 return fStatus & PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
430 && fStatus & PDMAUDIOSTREAMSTS_FLAGS_ENABLED
431 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PAUSED)
432 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE)
433 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT);*/
434 return (fStatus & ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
435 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED
436 | PDMAUDIOSTREAMSTS_FLAGS_PAUSED
437 | PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE
438 | PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT))
439 == ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
440 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED);
441}
442
443/**
444 * Checks if the stream status is a read-to-operate one.
445 *
446 * @returns @c true if ready to operate, @c false if not.
447 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAMSTS_FLAGS_XXX.
448 */
449DECLINLINE(bool) PDMAudioStrmStatusIsReady(PDMAUDIOSTREAMSTS fStatus)
450{
451 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false);
452 /*
453 return fStatus & PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
454 && fStatus & PDMAUDIOSTREAMSTS_FLAGS_ENABLED
455 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT);*/
456 return (fStatus & ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
457 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED
458 | PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT))
459 == ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
460 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED);
461}
462
463
464/*********************************************************************************************************************************
465* PCM Property Helpers *
466*********************************************************************************************************************************/
467
468/**
469 * Initialize PCM audio properties.
470 */
471DECLINLINE(void) PDMAudioPropsInit(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz)
472{
473 pProps->cbFrame = cbSample * cChannels;
474 pProps->cbSampleX = cbSample;
475 pProps->cChannelsX = cChannels;
476 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels);
477 pProps->fSigned = fSigned;
478 pProps->fSwapEndian = false;
479 pProps->fRaw = false;
480 pProps->uHz = uHz;
481
482 Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels);
483 Assert(pProps->cbSampleX == cbSample);
484 Assert(pProps->cChannelsX == cChannels);
485}
486
487/**
488 * Initialize PCM audio properties, extended version.
489 */
490DECLINLINE(void) PDMAudioPropsInitEx(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz,
491 bool fLittleEndian, bool fRaw)
492{
493 Assert(!fRaw || cbSample == sizeof(int64_t));
494 pProps->cbFrame = cbSample * cChannels;
495 pProps->cbSampleX = cbSample;
496 pProps->cChannelsX = cChannels;
497 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels);
498 pProps->fSigned = fSigned;
499#ifdef RT_LITTLE_ENDIAN
500 pProps->fSwapEndian = !fLittleEndian;
501#else
502 pProps->fSwapEndian = fLittleEndian;
503#endif
504 pProps->fRaw = fRaw;
505 pProps->uHz = uHz;
506
507 Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels);
508 Assert(pProps->cbSampleX == cbSample);
509 Assert(pProps->cChannelsX == cChannels);
510}
511
512/**
513 * Modifies the channel count.
514 *
515 * @param pProps The PCM properties to update.
516 * @param cChannels The new channel count.
517 */
518DECLINLINE(void) PDMAudioPropsSetChannels(PPDMAUDIOPCMPROPS pProps, uint8_t cChannels)
519{
520 Assert(cChannels > 0); Assert(cChannels < 16);
521 pProps->cChannelsX = cChannels;
522 pProps->cbFrame = pProps->cbSampleX * cChannels;
523 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pProps->cbSampleX, cChannels);
524}
525
526/**
527 * Modifies the sample size.
528 *
529 * @param pProps The PCM properties to update.
530 * @param cbSample The new sample size (in bytes).
531 */
532DECLINLINE(void) PDMAudioPropsSetSampleSize(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample)
533{
534 Assert(cbSample == 1 || cbSample == 2 || cbSample == 4 || cbSample == 8);
535 pProps->cbSampleX = cbSample;
536 pProps->cbFrame = cbSample * pProps->cChannelsX;
537 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, pProps->cChannelsX);
538}
539
540/**
541 * Gets the bitrate.
542 *
543 * Divide the result by 8 to get the byte rate.
544 *
545 * @returns Bit rate.
546 * @param pProps PCM properties to calculate bitrate for.
547 */
548DECLINLINE(uint32_t) PDMAudioPropsGetBitrate(PCPDMAUDIOPCMPROPS pProps)
549{
550 Assert(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX);
551 return pProps->cbFrame * pProps->uHz * 8;
552}
553
554/**
555 * Gets the number of channels.
556 * @returns The channel count.
557 * @param pProps The PCM properties.
558 */
559DECL_FORCE_INLINE(uint8_t) PDMAudioPropsChannels(PCPDMAUDIOPCMPROPS pProps)
560{
561 return pProps->cChannelsX;
562}
563
564/**
565 * Gets the sample size in bytes.
566 * @returns Number of bytes per sample.
567 * @param pProps The PCM properties.
568 */
569DECL_FORCE_INLINE(uint8_t) PDMAudioPropsSampleSize(PCPDMAUDIOPCMPROPS pProps)
570{
571 return pProps->cbSampleX;
572}
573
574/**
575 * Gets the sample size in bits.
576 * @returns Number of bits per sample.
577 * @param pProps The PCM properties.
578 */
579DECLINLINE(uint8_t) PDMAudioPropsSampleBits(PCPDMAUDIOPCMPROPS pProps)
580{
581 return pProps->cbSampleX * 8;
582}
583
584/**
585 * Gets the frame size in bytes.
586 * @returns Number of bytes per frame.
587 * @param pProps The PCM properties.
588 */
589DECL_FORCE_INLINE(uint8_t) PDMAudioPropsFrameSize(PCPDMAUDIOPCMPROPS pProps)
590{
591 return pProps->cbFrame;
592}
593
594/**
595 * Gets the frequency.
596 * @returns Frequency.
597 * @param pProps The PCM properties.
598 */
599DECL_FORCE_INLINE(uint32_t) PDMAudioPropsHz(PCPDMAUDIOPCMPROPS pProps)
600{
601 return pProps->uHz;
602}
603
604/**
605 * Checks if the format is signed or unsigned.
606 * @returns true if signed, false if unsigned.
607 * @param pProps The PCM properties.
608 */
609DECL_FORCE_INLINE(bool) PDMAudioPropsIsSigned(PCPDMAUDIOPCMPROPS pProps)
610{
611 return pProps->fSigned;
612}
613
614/**
615 * Checks if the format is little-endian or not.
616 * @returns true if little-endian (or if 8-bit), false if big-endian.
617 * @param pProps The PCM properties.
618 */
619DECL_FORCE_INLINE(bool) PDMAudioPropsIsLittleEndian(PCPDMAUDIOPCMPROPS pProps)
620{
621#ifdef RT_LITTLE_ENDIAN
622 return !pProps->fSwapEndian || pProps->cbSampleX < 2;
623#else
624 return pProps->fSwapEndian || pProps->cbSampleX < 2;
625#endif
626}
627
628/**
629 * Checks if the format is big-endian or not.
630 * @returns true if big-endian (or if 8-bit), false if little-endian.
631 * @param pProps The PCM properties.
632 */
633DECL_FORCE_INLINE(bool) PDMAudioPropsIsBigEndian(PCPDMAUDIOPCMPROPS pProps)
634{
635#ifdef RT_LITTLE_ENDIAN
636 return pProps->fSwapEndian || pProps->cbSampleX < 2;
637#else
638 return !pProps->fSwapEndian || pProps->cbSampleX < 2;
639#endif
640}
641
642/**
643 * Rounds down the given byte amount to the nearest frame boundrary.
644 *
645 * @returns Rounded byte amount.
646 * @param pProps PCM properties to use.
647 * @param cb The size (in bytes) to round.
648 */
649DECLINLINE(uint32_t) PDMAudioPropsFloorBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
650{
651 AssertPtrReturn(pProps, 0);
652 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb));
653}
654
655/**
656 * Rounds up the given byte amount to the nearest frame boundrary.
657 *
658 * @returns Rounded byte amount.
659 * @param pProps PCM properties to use.
660 * @param cb The size (in bytes) to round.
661 */
662DECLINLINE(uint32_t) PDMAudioPropsRoundUpBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
663{
664 AssertPtrReturn(pProps, 0);
665 uint32_t const cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
666 AssertReturn(cbFrame, 0);
667 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb + cbFrame - 1));
668}
669
670/**
671 * Checks if the given size is aligned on a frame boundrary.
672 *
673 * @returns @c true if properly aligned, @c false if not.
674 * @param pProps PCM properties to use.
675 * @param cb The size (in bytes) to check.
676 */
677DECLINLINE(bool) PDMAudioPropsIsSizeAligned(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
678{
679 AssertPtrReturn(pProps, false);
680 uint32_t const cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
681 AssertReturn(cbFrame, false);
682 return cb % cbFrame == 0;
683}
684
685/**
686 * Converts bytes to frames (rounding down of course).
687 *
688 * @returns Number of frames.
689 * @param pProps PCM properties to use.
690 * @param cb The number of bytes to convert.
691 */
692DECLINLINE(uint32_t) PDMAudioPropsBytesToFrames(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
693{
694 AssertPtrReturn(pProps, 0);
695 return PDMAUDIOPCMPROPS_B2F(pProps, cb);
696}
697
698/**
699 * Converts bytes to milliseconds.
700 *
701 * @return Number milliseconds @a cb takes to play or record.
702 * @param pProps PCM properties to use.
703 * @param cb The number of bytes to convert.
704 *
705 * @note Rounds up the result.
706 */
707DECLINLINE(uint64_t) PDMAudioPropsBytesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
708{
709 AssertPtrReturn(pProps, 0);
710
711 /* Check parameters to prevent division by chainsaw: */
712 uint32_t const uHz = pProps->uHz;
713 if (uHz)
714 {
715 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
716 if (cbFrame)
717 {
718 /* Round cb up to closest frame size: */
719 cb = (cb + cbFrame - 1) / cbFrame;
720
721 /* Convert to milliseconds. */
722 return (cb * (uint64_t)RT_MS_1SEC + uHz - 1) / uHz;
723 }
724 }
725 return 0;
726}
727
728/**
729 * Converts bytes to microseconds.
730 *
731 * @return Number microseconds @a cb takes to play or record.
732 * @param pProps PCM properties to use.
733 * @param cb The number of bytes to convert.
734 *
735 * @note Rounds up the result.
736 */
737DECLINLINE(uint64_t) PDMAudioPropsBytesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
738{
739 AssertPtrReturn(pProps, 0);
740
741 /* Check parameters to prevent division by chainsaw: */
742 uint32_t const uHz = pProps->uHz;
743 if (uHz)
744 {
745 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
746 if (cbFrame)
747 {
748 /* Round cb up to closest frame size: */
749 cb = (cb + cbFrame - 1) / cbFrame;
750
751 /* Convert to microseconds. */
752 return (cb * (uint64_t)RT_US_1SEC + uHz - 1) / uHz;
753 }
754 }
755 return 0;
756}
757
758/**
759 * Converts bytes to nanoseconds.
760 *
761 * @return Number nanoseconds @a cb takes to play or record.
762 * @param pProps PCM properties to use.
763 * @param cb The number of bytes to convert.
764 *
765 * @note Rounds up the result.
766 */
767DECLINLINE(uint64_t) PDMAudioPropsBytesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
768{
769 AssertPtrReturn(pProps, 0);
770
771 /* Check parameters to prevent division by chainsaw: */
772 uint32_t const uHz = pProps->uHz;
773 if (uHz)
774 {
775 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
776 if (cbFrame)
777 {
778 /* Round cb up to closest frame size: */
779 cb = (cb + cbFrame - 1) / cbFrame;
780
781 /* Convert to nanoseconds. */
782 return (cb * (uint64_t)RT_NS_1SEC + uHz - 1) / uHz;
783 }
784 }
785 return 0;
786}
787
788/**
789 * Converts frames to bytes.
790 *
791 * @returns Number of bytes.
792 * @param pProps The PCM properties to use.
793 * @param cFrames Number of audio frames to convert.
794 * @sa PDMAUDIOPCMPROPS_F2B
795 */
796DECLINLINE(uint32_t) PDMAudioPropsFramesToBytes(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
797{
798 AssertPtrReturn(pProps, 0);
799 return PDMAUDIOPCMPROPS_F2B(pProps, cFrames);
800}
801
802/**
803 * Converts frames to milliseconds.
804 *
805 * @returns milliseconds.
806 * @param pProps The PCM properties to use.
807 * @param cFrames Number of audio frames to convert.
808 * @note No rounding here, result is floored.
809 */
810DECLINLINE(uint64_t) PDMAudioPropsFramesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
811{
812 AssertPtrReturn(pProps, 0);
813
814 /* Check input to prevent division by chainsaw: */
815 uint32_t const uHz = pProps->uHz;
816 if (uHz)
817 return ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, uHz);
818 return 0;
819}
820
821/**
822 * Converts frames to nanoseconds.
823 *
824 * @returns Nanoseconds.
825 * @param pProps The PCM properties to use.
826 * @param cFrames Number of audio frames to convert.
827 * @note No rounding here, result is floored.
828 */
829DECLINLINE(uint64_t) PDMAudioPropsFramesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
830{
831 AssertPtrReturn(pProps, 0);
832
833 /* Check input to prevent division by chainsaw: */
834 uint32_t const uHz = pProps->uHz;
835 if (uHz)
836 return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC, uHz);
837 return 0;
838}
839
840/**
841 * Converts milliseconds to frames.
842 *
843 * @returns Number of frames
844 * @param pProps The PCM properties to use.
845 * @param cMs The number of milliseconds to convert.
846 *
847 * @note The result is rounded rather than floored (hysterical raisins).
848 */
849DECLINLINE(uint32_t) PDMAudioPropsMilliToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)
850{
851 AssertPtrReturn(pProps, 0);
852
853 uint32_t const uHz = pProps->uHz;
854 uint32_t cFrames;
855 if (cMs < RT_MS_1SEC)
856 cFrames = 0;
857 else
858 {
859 cFrames = cMs / RT_MS_1SEC * uHz;
860 cMs %= RT_MS_1SEC;
861 }
862 cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cMs) + RT_MS_1SEC - 1) / RT_MS_1SEC;
863 return cFrames;
864}
865
866/**
867 * Converts milliseconds to bytes.
868 *
869 * @returns Number of bytes (frame aligned).
870 * @param pProps The PCM properties to use.
871 * @param cMs The number of milliseconds to convert.
872 *
873 * @note The result is rounded rather than floored (hysterical raisins).
874 */
875DECLINLINE(uint32_t) PDMAudioPropsMilliToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)
876{
877 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsMilliToFrames(pProps, cMs));
878}
879
880/**
881 * Converts nanoseconds to frames.
882 *
883 * @returns Number of frames
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) PDMAudioPropsNanoToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
890{
891 AssertPtrReturn(pProps, 0);
892
893 uint32_t const uHz = pProps->uHz;
894 uint32_t cFrames;
895 if (cNs < RT_NS_1SEC)
896 cFrames = 0;
897 else
898 {
899 cFrames = cNs / RT_NS_1SEC * uHz;
900 cNs %= RT_NS_1SEC;
901 }
902 cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cNs) + RT_NS_1SEC - 1) / RT_NS_1SEC;
903 return cFrames;
904}
905
906/**
907 * Converts nanoseconds to bytes.
908 *
909 * @returns Number of bytes (frame aligned).
910 * @param pProps The PCM properties to use.
911 * @param cNs The number of nanoseconds to convert.
912 *
913 * @note The result is rounded rather than floored (hysterical raisins).
914 */
915DECLINLINE(uint32_t) PDMAudioPropsNanoToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
916{
917 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs));
918}
919
920/**
921 * Clears a sample buffer by the given amount of audio frames with silence (according to the format
922 * given by the PCM properties).
923 *
924 * @param pProps The PCM properties to apply.
925 * @param pvBuf The buffer to clear.
926 * @param cbBuf The buffer size in bytes.
927 * @param cFrames The number of audio frames to clear. Capped at @a cbBuf
928 * if exceeding the buffer. If the size is an unaligned
929 * number of frames, the extra bytes may be left
930 * uninitialized in some configurations.
931 */
932DECLINLINE(void) PDMAudioPropsClearBuffer(PCPDMAUDIOPCMPROPS pProps, void *pvBuf, size_t cbBuf, uint32_t cFrames)
933{
934 /*
935 * Validate input
936 */
937 AssertPtrReturnVoid(pProps);
938 Assert(pProps->cbSampleX);
939 if (!cbBuf || !cFrames)
940 return;
941 AssertPtrReturnVoid(pvBuf);
942
943 Assert(pProps->fSwapEndian == false); /** @todo Swapping Endianness is not supported yet. */
944
945 /*
946 * Decide how much needs clearing.
947 */
948 size_t cbToClear = PDMAudioPropsFramesToBytes(pProps, cFrames);
949 AssertStmt(cbToClear <= cbBuf, cbToClear = cbBuf);
950
951 Log2Func(("pProps=%p, pvBuf=%p, cFrames=%RU32, fSigned=%RTbool, cbSample=%RU8\n",
952 pProps, pvBuf, cFrames, pProps->fSigned, pProps->cbSampleX));
953
954 /*
955 * Do the job.
956 */
957 if (pProps->fSigned)
958 RT_BZERO(pvBuf, cbToClear);
959 else /* Unsigned formats. */
960 {
961 switch (pProps->cbSampleX)
962 {
963 case 1: /* 8 bit */
964 memset(pvBuf, 0x80, cbToClear);
965 break;
966
967 case 2: /* 16 bit */
968 {
969 uint16_t *pu16Dst = (uint16_t *)pvBuf;
970 size_t cLeft = cbToClear / sizeof(uint16_t);
971 while (cLeft-- > 0)
972 *pu16Dst++ = 0x80;
973 break;
974 }
975
976 /** @todo Add 24 bit? */
977
978 case 4: /* 32 bit */
979 ASMMemFill32(pvBuf, cbToClear & ~(size_t)3, 0x80);
980 break;
981
982 default:
983 AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX));
984 }
985 }
986}
987
988/**
989 * Compares two sets of PCM properties.
990 *
991 * @returns @c true if the same, @c false if not.
992 * @param pProps1 The first set of properties to compare.
993 * @param pProps2 The second set of properties to compare.
994 */
995DECLINLINE(bool) PDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2)
996{
997 AssertPtrReturn(pProps1, false);
998 AssertPtrReturn(pProps2, false);
999
1000 if (pProps1 == pProps2) /* If the pointers match, take a shortcut. */
1001 return true;
1002
1003 return pProps1->uHz == pProps2->uHz
1004 && pProps1->cChannelsX == pProps2->cChannelsX
1005 && pProps1->cbSampleX == pProps2->cbSampleX
1006 && pProps1->fSigned == pProps2->fSigned
1007 && pProps1->fSwapEndian == pProps2->fSwapEndian;
1008}
1009
1010/**
1011 * Checks whether the given PCM properties are valid or not.
1012 *
1013 * @returns true/false accordingly.
1014 * @param pProps The PCM properties to check.
1015 *
1016 * @remarks This just performs a generic check of value ranges. Further, it
1017 * will assert if the input is invalid.
1018 *
1019 * @sa PDMAudioStrmCfgIsValid
1020 */
1021DECLINLINE(bool) PDMAudioPropsAreValid(PCPDMAUDIOPCMPROPS pProps)
1022{
1023 AssertPtrReturn(pProps, false);
1024
1025 AssertReturn(pProps->cChannelsX != 0, false);
1026 AssertMsgReturn( pProps->cbSampleX == 1 || pProps->cbSampleX == 2 || pProps->cbSampleX == 4 || (pProps->cbSampleX == 8 && pProps->fRaw),
1027 ("%u\n", pProps->cbSampleX), false);
1028 AssertMsgReturn(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX,
1029 ("cbFrame=%u cbSample=%u cChannels=%u\n", pProps->cbFrame, pProps->cbSampleX, pProps->cChannelsX),
1030 false);
1031 AssertMsgReturn(pProps->uHz >= 1000 && pProps->uHz < 1000000, ("%u\n", pProps->uHz), false);
1032 AssertMsgReturn(pProps->cShiftX == PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps),
1033 ("cShift=%u cbSample=%u cChannels=%u\n", pProps->cShiftX, pProps->cbSampleX, pProps->cChannelsX),
1034 false);
1035 AssertReturn(!pProps->fRaw || (pProps->fSigned && pProps->cbSampleX == sizeof(int64_t)), false);
1036 return true;
1037}
1038
1039/**
1040 * Get number of bytes per frame.
1041 *
1042 * @returns Number of bytes per audio frame.
1043 * @param pProps PCM properties to use.
1044 * @sa PDMAUDIOPCMPROPS_F2B
1045 */
1046DECLINLINE(uint32_t) PDMAudioPropsBytesPerFrame(PCPDMAUDIOPCMPROPS pProps)
1047{
1048 return PDMAUDIOPCMPROPS_F2B(pProps, 1 /*cFrames*/);
1049}
1050
1051/**
1052 * Prints PCM properties to the debug log.
1053 *
1054 * @param pProps PCM properties to use.
1055 */
1056DECLINLINE(void) PDMAudioPropsLog(PCPDMAUDIOPCMPROPS pProps)
1057{
1058 AssertPtrReturnVoid(pProps);
1059
1060 Log(("uHz=%RU32, cChannels=%RU8, cBits=%RU8%s",
1061 pProps->uHz, pProps->cChannelsX, pProps->cbSampleX * 8, pProps->fSigned ? "S" : "U"));
1062}
1063
1064/** Max necessary buffer space for PDMAudioPropsToString */
1065#define PDMAUDIOPROPSTOSTRING_MAX sizeof("16ch S64 4294967296Hz swap raw")
1066
1067/**
1068 * Formats the PCM audio properties into a string buffer.
1069 *
1070 * @returns pszDst
1071 * @param pProps PCM properties to use.
1072 * @param pszDst The destination buffer.
1073 * @param cchDst The size of the destination buffer. Recommended to be at
1074 * least PDMAUDIOPROPSTOSTRING_MAX bytes.
1075 */
1076DECLINLINE(char *) PDMAudioPropsToString(PCPDMAUDIOPCMPROPS pProps, char *pszDst, size_t cchDst)
1077{
1078 /* 2ch S64 44100Hz swap raw */
1079 RTStrPrintf(pszDst, cchDst, "%uch %c%u %RU32Hz%s%s",
1080 PDMAudioPropsChannels(pProps), PDMAudioPropsIsSigned(pProps) ? 'S' : 'U', PDMAudioPropsSampleBits(pProps),
1081 PDMAudioPropsHz(pProps), pProps->fSwapEndian ? " swap" : "", pProps->fRaw ? " raw" : "");
1082 return pszDst;
1083}
1084
1085
1086
1087/** @} */
1088
1089#endif /* !VBOX_INCLUDED_vmm_pdmaudioinline_h */
Note: See TracBrowser for help on using the repository browser.

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