VirtualBox

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

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

Audio: Cleaned up the alsa backend. Removed unused+bogus PDMAUDIOSTREAMCMD_DROP command and mixer duplicate. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.2 KB
Line 
1/* $Id: pdmaudioinline.h 88452 2021-04-10 00:19:06Z 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_ENABLE: return "Enable";
383 case PDMAUDIOSTREAMCMD_DISABLE: return "Disable";
384 case PDMAUDIOSTREAMCMD_PAUSE: return "Pause";
385 case PDMAUDIOSTREAMCMD_RESUME: return "Resume";
386 case PDMAUDIOSTREAMCMD_DRAIN: return "Drain";
387 case PDMAUDIOSTREAMCMD_END:
388 case PDMAUDIOSTREAMCMD_32BIT_HACK:
389 break;
390 /* no default! */
391 }
392 AssertMsgFailedReturn(("Invalid stream command %d\n", enmCmd), "bad");
393}
394
395/**
396 * Checks if the stream status is one that can be read from.
397 *
398 * @returns @c true if ready to be read from, @c false if not.
399 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAMSTS_FLAGS_XXX.
400 */
401DECLINLINE(bool) PDMAudioStrmStatusCanRead(PDMAUDIOSTREAMSTS fStatus)
402{
403 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false);
404 /*
405 return fStatus & PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
406 && fStatus & PDMAUDIOSTREAMSTS_FLAGS_ENABLED
407 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PAUSED)
408 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT);*/
409 return (fStatus & ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
410 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED
411 | PDMAUDIOSTREAMSTS_FLAGS_PAUSED
412 | PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT ))
413 == ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
414 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED);
415}
416
417/**
418 * Checks if the stream status is one that can be written to.
419 *
420 * @returns @c true if ready to be written to, @c false if not.
421 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAMSTS_FLAGS_XXX.
422 */
423DECLINLINE(bool) PDMAudioStrmStatusCanWrite(PDMAUDIOSTREAMSTS fStatus)
424{
425 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false);
426 /*
427 return fStatus & PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
428 && fStatus & PDMAUDIOSTREAMSTS_FLAGS_ENABLED
429 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PAUSED)
430 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE)
431 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT);*/
432 return (fStatus & ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
433 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED
434 | PDMAUDIOSTREAMSTS_FLAGS_PAUSED
435 | PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE
436 | PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT))
437 == ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
438 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED);
439}
440
441/**
442 * Checks if the stream status is a read-to-operate one.
443 *
444 * @returns @c true if ready to operate, @c false if not.
445 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAMSTS_FLAGS_XXX.
446 */
447DECLINLINE(bool) PDMAudioStrmStatusIsReady(PDMAUDIOSTREAMSTS fStatus)
448{
449 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false);
450 /*
451 return fStatus & PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
452 && fStatus & PDMAUDIOSTREAMSTS_FLAGS_ENABLED
453 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT);*/
454 return (fStatus & ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
455 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED
456 | PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT))
457 == ( PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
458 | PDMAUDIOSTREAMSTS_FLAGS_ENABLED);
459}
460
461
462/*********************************************************************************************************************************
463* PCM Property Helpers *
464*********************************************************************************************************************************/
465
466/**
467 * Initialize PCM audio properties.
468 */
469DECLINLINE(void) PDMAudioPropsInit(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz)
470{
471 pProps->cbFrame = cbSample * cChannels;
472 pProps->cbSampleX = cbSample;
473 pProps->cChannelsX = cChannels;
474 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels);
475 pProps->fSigned = fSigned;
476 pProps->fSwapEndian = false;
477 pProps->fRaw = false;
478 pProps->uHz = uHz;
479
480 Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels);
481 Assert(pProps->cbSampleX == cbSample);
482 Assert(pProps->cChannelsX == cChannels);
483}
484
485/**
486 * Initialize PCM audio properties, extended version.
487 */
488DECLINLINE(void) PDMAudioPropsInitEx(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz,
489 bool fLittleEndian, bool fRaw)
490{
491 Assert(!fRaw || cbSample == sizeof(int64_t));
492 pProps->cbFrame = cbSample * cChannels;
493 pProps->cbSampleX = cbSample;
494 pProps->cChannelsX = cChannels;
495 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels);
496 pProps->fSigned = fSigned;
497#ifdef RT_LITTLE_ENDIAN
498 pProps->fSwapEndian = !fLittleEndian;
499#else
500 pProps->fSwapEndian = fLittleEndian;
501#endif
502 pProps->fRaw = fRaw;
503 pProps->uHz = uHz;
504
505 Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels);
506 Assert(pProps->cbSampleX == cbSample);
507 Assert(pProps->cChannelsX == cChannels);
508}
509
510/**
511 * Modifies the channel count.
512 *
513 * @param pProps The PCM properties to update.
514 * @param cChannels The new channel count.
515 */
516DECLINLINE(void) PDMAudioPropsSetChannels(PPDMAUDIOPCMPROPS pProps, uint8_t cChannels)
517{
518 Assert(cChannels > 0); Assert(cChannels < 16);
519 pProps->cChannelsX = cChannels;
520 pProps->cbFrame = pProps->cbSampleX * cChannels;
521 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pProps->cbSampleX, cChannels);
522}
523
524/**
525 * Modifies the sample size.
526 *
527 * @param pProps The PCM properties to update.
528 * @param cbSample The new sample size (in bytes).
529 */
530DECLINLINE(void) PDMAudioPropsSetSampleSize(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample)
531{
532 Assert(cbSample == 1 || cbSample == 2 || cbSample == 4 || cbSample == 8);
533 pProps->cbSampleX = cbSample;
534 pProps->cbFrame = cbSample * pProps->cChannelsX;
535 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, pProps->cChannelsX);
536}
537
538/**
539 * Gets the bitrate.
540 *
541 * Divide the result by 8 to get the byte rate.
542 *
543 * @returns Bit rate.
544 * @param pProps PCM properties to calculate bitrate for.
545 */
546DECLINLINE(uint32_t) PDMAudioPropsGetBitrate(PCPDMAUDIOPCMPROPS pProps)
547{
548 Assert(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX);
549 return pProps->cbFrame * pProps->uHz * 8;
550}
551
552/**
553 * Gets the number of channels.
554 * @returns The channel count.
555 * @param pProps The PCM properties.
556 */
557DECL_FORCE_INLINE(uint8_t) PDMAudioPropsChannels(PCPDMAUDIOPCMPROPS pProps)
558{
559 return pProps->cChannelsX;
560}
561
562/**
563 * Gets the sample size in bytes.
564 * @returns Number of bytes per sample.
565 * @param pProps The PCM properties.
566 */
567DECL_FORCE_INLINE(uint8_t) PDMAudioPropsSampleSize(PCPDMAUDIOPCMPROPS pProps)
568{
569 return pProps->cbSampleX;
570}
571
572/**
573 * Gets the sample size in bits.
574 * @returns Number of bits per sample.
575 * @param pProps The PCM properties.
576 */
577DECLINLINE(uint8_t) PDMAudioPropsSampleBits(PCPDMAUDIOPCMPROPS pProps)
578{
579 return pProps->cbSampleX * 8;
580}
581
582/**
583 * Gets the frame size in bytes.
584 * @returns Number of bytes per frame.
585 * @param pProps The PCM properties.
586 */
587DECL_FORCE_INLINE(uint8_t) PDMAudioPropsFrameSize(PCPDMAUDIOPCMPROPS pProps)
588{
589 return pProps->cbFrame;
590}
591
592/**
593 * Gets the frequency.
594 * @returns Frequency.
595 * @param pProps The PCM properties.
596 */
597DECL_FORCE_INLINE(uint32_t) PDMAudioPropsHz(PCPDMAUDIOPCMPROPS pProps)
598{
599 return pProps->uHz;
600}
601
602/**
603 * Checks if the format is signed or unsigned.
604 * @returns true if signed, false if unsigned.
605 * @param pProps The PCM properties.
606 */
607DECL_FORCE_INLINE(bool) PDMAudioPropsIsSigned(PCPDMAUDIOPCMPROPS pProps)
608{
609 return pProps->fSigned;
610}
611
612/**
613 * Checks if the format is little-endian or not.
614 * @returns true if little-endian (or if 8-bit), false if big-endian.
615 * @param pProps The PCM properties.
616 */
617DECL_FORCE_INLINE(bool) PDMAudioPropsIsLittleEndian(PCPDMAUDIOPCMPROPS pProps)
618{
619#ifdef RT_LITTLE_ENDIAN
620 return !pProps->fSwapEndian || pProps->cbSampleX < 2;
621#else
622 return pProps->fSwapEndian || pProps->cbSampleX < 2;
623#endif
624}
625
626/**
627 * Checks if the format is big-endian or not.
628 * @returns true if big-endian (or if 8-bit), false if little-endian.
629 * @param pProps The PCM properties.
630 */
631DECL_FORCE_INLINE(bool) PDMAudioPropsIsBigEndian(PCPDMAUDIOPCMPROPS pProps)
632{
633#ifdef RT_LITTLE_ENDIAN
634 return pProps->fSwapEndian || pProps->cbSampleX < 2;
635#else
636 return !pProps->fSwapEndian || pProps->cbSampleX < 2;
637#endif
638}
639
640/**
641 * Rounds down the given byte amount to the nearest frame boundrary.
642 *
643 * @returns Rounded byte amount.
644 * @param pProps PCM properties to use.
645 * @param cb The size (in bytes) to round.
646 */
647DECLINLINE(uint32_t) PDMAudioPropsFloorBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
648{
649 AssertPtrReturn(pProps, 0);
650 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb));
651}
652
653/**
654 * Rounds up the given byte amount to the nearest frame boundrary.
655 *
656 * @returns Rounded byte amount.
657 * @param pProps PCM properties to use.
658 * @param cb The size (in bytes) to round.
659 */
660DECLINLINE(uint32_t) PDMAudioPropsRoundUpBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
661{
662 AssertPtrReturn(pProps, 0);
663 uint32_t const cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
664 AssertReturn(cbFrame, 0);
665 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb + cbFrame - 1));
666}
667
668/**
669 * Checks if the given size is aligned on a frame boundrary.
670 *
671 * @returns @c true if properly aligned, @c false if not.
672 * @param pProps PCM properties to use.
673 * @param cb The size (in bytes) to check.
674 */
675DECLINLINE(bool) PDMAudioPropsIsSizeAligned(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
676{
677 AssertPtrReturn(pProps, false);
678 uint32_t const cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
679 AssertReturn(cbFrame, false);
680 return cb % cbFrame == 0;
681}
682
683/**
684 * Converts bytes to frames (rounding down of course).
685 *
686 * @returns Number of frames.
687 * @param pProps PCM properties to use.
688 * @param cb The number of bytes to convert.
689 */
690DECLINLINE(uint32_t) PDMAudioPropsBytesToFrames(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
691{
692 AssertPtrReturn(pProps, 0);
693 return PDMAUDIOPCMPROPS_B2F(pProps, cb);
694}
695
696/**
697 * Converts bytes to milliseconds.
698 *
699 * @return Number milliseconds @a cb takes to play or record.
700 * @param pProps PCM properties to use.
701 * @param cb The number of bytes to convert.
702 *
703 * @note Rounds up the result.
704 */
705DECLINLINE(uint64_t) PDMAudioPropsBytesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
706{
707 AssertPtrReturn(pProps, 0);
708
709 /* Check parameters to prevent division by chainsaw: */
710 uint32_t const uHz = pProps->uHz;
711 if (uHz)
712 {
713 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
714 if (cbFrame)
715 {
716 /* Round cb up to closest frame size: */
717 cb = (cb + cbFrame - 1) / cbFrame;
718
719 /* Convert to milliseconds. */
720 return (cb * (uint64_t)RT_MS_1SEC + uHz - 1) / uHz;
721 }
722 }
723 return 0;
724}
725
726/**
727 * Converts bytes to microseconds.
728 *
729 * @return Number microseconds @a cb takes to play or record.
730 * @param pProps PCM properties to use.
731 * @param cb The number of bytes to convert.
732 *
733 * @note Rounds up the result.
734 */
735DECLINLINE(uint64_t) PDMAudioPropsBytesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
736{
737 AssertPtrReturn(pProps, 0);
738
739 /* Check parameters to prevent division by chainsaw: */
740 uint32_t const uHz = pProps->uHz;
741 if (uHz)
742 {
743 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
744 if (cbFrame)
745 {
746 /* Round cb up to closest frame size: */
747 cb = (cb + cbFrame - 1) / cbFrame;
748
749 /* Convert to microseconds. */
750 return (cb * (uint64_t)RT_US_1SEC + uHz - 1) / uHz;
751 }
752 }
753 return 0;
754}
755
756/**
757 * Converts bytes to nanoseconds.
758 *
759 * @return Number nanoseconds @a cb takes to play or record.
760 * @param pProps PCM properties to use.
761 * @param cb The number of bytes to convert.
762 *
763 * @note Rounds up the result.
764 */
765DECLINLINE(uint64_t) PDMAudioPropsBytesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
766{
767 AssertPtrReturn(pProps, 0);
768
769 /* Check parameters to prevent division by chainsaw: */
770 uint32_t const uHz = pProps->uHz;
771 if (uHz)
772 {
773 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
774 if (cbFrame)
775 {
776 /* Round cb up to closest frame size: */
777 cb = (cb + cbFrame - 1) / cbFrame;
778
779 /* Convert to nanoseconds. */
780 return (cb * (uint64_t)RT_NS_1SEC + uHz - 1) / uHz;
781 }
782 }
783 return 0;
784}
785
786/**
787 * Converts frames to bytes.
788 *
789 * @returns Number of bytes.
790 * @param pProps The PCM properties to use.
791 * @param cFrames Number of audio frames to convert.
792 * @sa PDMAUDIOPCMPROPS_F2B
793 */
794DECLINLINE(uint32_t) PDMAudioPropsFramesToBytes(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
795{
796 AssertPtrReturn(pProps, 0);
797 return PDMAUDIOPCMPROPS_F2B(pProps, cFrames);
798}
799
800/**
801 * Converts frames to milliseconds.
802 *
803 * @returns milliseconds.
804 * @param pProps The PCM properties to use.
805 * @param cFrames Number of audio frames to convert.
806 * @note No rounding here, result is floored.
807 */
808DECLINLINE(uint64_t) PDMAudioPropsFramesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
809{
810 AssertPtrReturn(pProps, 0);
811
812 /* Check input to prevent division by chainsaw: */
813 uint32_t const uHz = pProps->uHz;
814 if (uHz)
815 return ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, uHz);
816 return 0;
817}
818
819/**
820 * Converts frames to nanoseconds.
821 *
822 * @returns Nanoseconds.
823 * @param pProps The PCM properties to use.
824 * @param cFrames Number of audio frames to convert.
825 * @note No rounding here, result is floored.
826 */
827DECLINLINE(uint64_t) PDMAudioPropsFramesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
828{
829 AssertPtrReturn(pProps, 0);
830
831 /* Check input to prevent division by chainsaw: */
832 uint32_t const uHz = pProps->uHz;
833 if (uHz)
834 return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC, uHz);
835 return 0;
836}
837
838/**
839 * Converts milliseconds to frames.
840 *
841 * @returns Number of frames
842 * @param pProps The PCM properties to use.
843 * @param cMs The number of milliseconds to convert.
844 *
845 * @note The result is rounded rather than floored (hysterical raisins).
846 */
847DECLINLINE(uint32_t) PDMAudioPropsMilliToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)
848{
849 AssertPtrReturn(pProps, 0);
850
851 uint32_t const uHz = pProps->uHz;
852 uint32_t cFrames;
853 if (cMs < RT_MS_1SEC)
854 cFrames = 0;
855 else
856 {
857 cFrames = cMs / RT_MS_1SEC * uHz;
858 cMs %= RT_MS_1SEC;
859 }
860 cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cMs) + RT_MS_1SEC - 1) / RT_MS_1SEC;
861 return cFrames;
862}
863
864/**
865 * Converts milliseconds to bytes.
866 *
867 * @returns Number of bytes (frame aligned).
868 * @param pProps The PCM properties to use.
869 * @param cMs The number of milliseconds to convert.
870 *
871 * @note The result is rounded rather than floored (hysterical raisins).
872 */
873DECLINLINE(uint32_t) PDMAudioPropsMilliToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)
874{
875 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsMilliToFrames(pProps, cMs));
876}
877
878/**
879 * Converts nanoseconds to frames.
880 *
881 * @returns Number of frames
882 * @param pProps The PCM properties to use.
883 * @param cNs The number of nanoseconds to convert.
884 *
885 * @note The result is rounded rather than floored (hysterical raisins).
886 */
887DECLINLINE(uint32_t) PDMAudioPropsNanoToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
888{
889 AssertPtrReturn(pProps, 0);
890
891 uint32_t const uHz = pProps->uHz;
892 uint32_t cFrames;
893 if (cNs < RT_NS_1SEC)
894 cFrames = 0;
895 else
896 {
897 cFrames = cNs / RT_NS_1SEC * uHz;
898 cNs %= RT_NS_1SEC;
899 }
900 cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cNs) + RT_NS_1SEC - 1) / RT_NS_1SEC;
901 return cFrames;
902}
903
904/**
905 * Converts nanoseconds to bytes.
906 *
907 * @returns Number of bytes (frame aligned).
908 * @param pProps The PCM properties to use.
909 * @param cNs The number of nanoseconds to convert.
910 *
911 * @note The result is rounded rather than floored (hysterical raisins).
912 */
913DECLINLINE(uint32_t) PDMAudioPropsNanoToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
914{
915 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs));
916}
917
918/**
919 * Clears a sample buffer by the given amount of audio frames with silence (according to the format
920 * given by the PCM properties).
921 *
922 * @param pProps The PCM properties to apply.
923 * @param pvBuf The buffer to clear.
924 * @param cbBuf The buffer size in bytes.
925 * @param cFrames The number of audio frames to clear. Capped at @a cbBuf
926 * if exceeding the buffer. If the size is an unaligned
927 * number of frames, the extra bytes may be left
928 * uninitialized in some configurations.
929 */
930DECLINLINE(void) PDMAudioPropsClearBuffer(PCPDMAUDIOPCMPROPS pProps, void *pvBuf, size_t cbBuf, uint32_t cFrames)
931{
932 /*
933 * Validate input
934 */
935 AssertPtrReturnVoid(pProps);
936 Assert(pProps->cbSampleX);
937 if (!cbBuf || !cFrames)
938 return;
939 AssertPtrReturnVoid(pvBuf);
940
941 Assert(pProps->fSwapEndian == false); /** @todo Swapping Endianness is not supported yet. */
942
943 /*
944 * Decide how much needs clearing.
945 */
946 size_t cbToClear = PDMAudioPropsFramesToBytes(pProps, cFrames);
947 AssertStmt(cbToClear <= cbBuf, cbToClear = cbBuf);
948
949 Log2Func(("pProps=%p, pvBuf=%p, cFrames=%RU32, fSigned=%RTbool, cbSample=%RU8\n",
950 pProps, pvBuf, cFrames, pProps->fSigned, pProps->cbSampleX));
951
952 /*
953 * Do the job.
954 */
955 if (pProps->fSigned)
956 RT_BZERO(pvBuf, cbToClear);
957 else /* Unsigned formats. */
958 {
959 switch (pProps->cbSampleX)
960 {
961 case 1: /* 8 bit */
962 memset(pvBuf, 0x80, cbToClear);
963 break;
964
965 case 2: /* 16 bit */
966 {
967 uint16_t *pu16Dst = (uint16_t *)pvBuf;
968 size_t cLeft = cbToClear / sizeof(uint16_t);
969 while (cLeft-- > 0)
970 *pu16Dst++ = 0x80;
971 break;
972 }
973
974 /** @todo Add 24 bit? */
975
976 case 4: /* 32 bit */
977 ASMMemFill32(pvBuf, cbToClear & ~(size_t)3, 0x80);
978 break;
979
980 default:
981 AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX));
982 }
983 }
984}
985
986/**
987 * Compares two sets of PCM properties.
988 *
989 * @returns @c true if the same, @c false if not.
990 * @param pProps1 The first set of properties to compare.
991 * @param pProps2 The second set of properties to compare.
992 */
993DECLINLINE(bool) PDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2)
994{
995 AssertPtrReturn(pProps1, false);
996 AssertPtrReturn(pProps2, false);
997
998 if (pProps1 == pProps2) /* If the pointers match, take a shortcut. */
999 return true;
1000
1001 return pProps1->uHz == pProps2->uHz
1002 && pProps1->cChannelsX == pProps2->cChannelsX
1003 && pProps1->cbSampleX == pProps2->cbSampleX
1004 && pProps1->fSigned == pProps2->fSigned
1005 && pProps1->fSwapEndian == pProps2->fSwapEndian;
1006}
1007
1008/**
1009 * Checks whether the given PCM properties are valid or not.
1010 *
1011 * @returns true/false accordingly.
1012 * @param pProps The PCM properties to check.
1013 *
1014 * @remarks This just performs a generic check of value ranges. Further, it
1015 * will assert if the input is invalid.
1016 *
1017 * @sa PDMAudioStrmCfgIsValid
1018 */
1019DECLINLINE(bool) PDMAudioPropsAreValid(PCPDMAUDIOPCMPROPS pProps)
1020{
1021 AssertPtrReturn(pProps, false);
1022
1023 AssertReturn(pProps->cChannelsX != 0, false);
1024 AssertMsgReturn( pProps->cbSampleX == 1 || pProps->cbSampleX == 2 || pProps->cbSampleX == 4 || (pProps->cbSampleX == 8 && pProps->fRaw),
1025 ("%u\n", pProps->cbSampleX), false);
1026 AssertMsgReturn(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX,
1027 ("cbFrame=%u cbSample=%u cChannels=%u\n", pProps->cbFrame, pProps->cbSampleX, pProps->cChannelsX),
1028 false);
1029 AssertMsgReturn(pProps->uHz >= 1000 && pProps->uHz < 1000000, ("%u\n", pProps->uHz), false);
1030 AssertMsgReturn(pProps->cShiftX == PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps),
1031 ("cShift=%u cbSample=%u cChannels=%u\n", pProps->cShiftX, pProps->cbSampleX, pProps->cChannelsX),
1032 false);
1033 AssertReturn(!pProps->fRaw || (pProps->fSigned && pProps->cbSampleX == sizeof(int64_t)), false);
1034 return true;
1035}
1036
1037/**
1038 * Get number of bytes per frame.
1039 *
1040 * @returns Number of bytes per audio frame.
1041 * @param pProps PCM properties to use.
1042 * @sa PDMAUDIOPCMPROPS_F2B
1043 */
1044DECLINLINE(uint32_t) PDMAudioPropsBytesPerFrame(PCPDMAUDIOPCMPROPS pProps)
1045{
1046 return PDMAUDIOPCMPROPS_F2B(pProps, 1 /*cFrames*/);
1047}
1048
1049/**
1050 * Prints PCM properties to the debug log.
1051 *
1052 * @param pProps PCM properties to use.
1053 */
1054DECLINLINE(void) PDMAudioPropsLog(PCPDMAUDIOPCMPROPS pProps)
1055{
1056 AssertPtrReturnVoid(pProps);
1057
1058 Log(("uHz=%RU32, cChannels=%RU8, cBits=%RU8%s",
1059 pProps->uHz, pProps->cChannelsX, pProps->cbSampleX * 8, pProps->fSigned ? "S" : "U"));
1060}
1061
1062/** Max necessary buffer space for PDMAudioPropsToString */
1063#define PDMAUDIOPROPSTOSTRING_MAX sizeof("16ch S64 4294967296Hz swap raw")
1064
1065/**
1066 * Formats the PCM audio properties into a string buffer.
1067 *
1068 * @returns pszDst
1069 * @param pProps PCM properties to use.
1070 * @param pszDst The destination buffer.
1071 * @param cchDst The size of the destination buffer. Recommended to be at
1072 * least PDMAUDIOPROPSTOSTRING_MAX bytes.
1073 */
1074DECLINLINE(char *) PDMAudioPropsToString(PCPDMAUDIOPCMPROPS pProps, char *pszDst, size_t cchDst)
1075{
1076 /* 2ch S64 44100Hz swap raw */
1077 RTStrPrintf(pszDst, cchDst, "%uch %c%u %RU32Hz%s%s",
1078 PDMAudioPropsChannels(pProps), PDMAudioPropsIsSigned(pProps) ? 'S' : 'U', PDMAudioPropsSampleBits(pProps),
1079 PDMAudioPropsHz(pProps), pProps->fSwapEndian ? " swap" : "", pProps->fRaw ? " raw" : "");
1080 return pszDst;
1081}
1082
1083
1084
1085/** @} */
1086
1087#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