VirtualBox

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

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

DrvAudio: Working on support for asynchronous stream backend init and smoother device switch. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.3 KB
Line 
1/* $Id: pdmaudioinline.h 88760 2021-04-29 00:54:45Z 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 * Checks whether two stream configuration matches.
282 *
283 * @returns @c true if equal, @c false if not.
284 * @param pCfg1 The first stream configuration.
285 * @param pCfg2 The second stream configuration.
286 */
287DECLINLINE(bool) PDMAudioStrmCfgEquals(PCPDMAUDIOSTREAMCFG pCfg1, PCPDMAUDIOSTREAMCFG pCfg2)
288{
289 if (!pCfg1 || !pCfg2)
290 return false;
291 if (pCfg1 == pCfg2)
292 return pCfg1 != NULL;
293 if (PDMAudioPropsAreEqual(&pCfg1->Props, &pCfg2->Props))
294 return pCfg1->enmDir == pCfg2->enmDir
295 && pCfg1->u.enmDst == pCfg2->u.enmDst
296 && pCfg1->enmLayout == pCfg2->enmLayout
297 && pCfg1->Device.cMsSchedulingHint == pCfg2->Device.cMsSchedulingHint
298 && pCfg1->Backend.cFramesPeriod == pCfg2->Backend.cFramesPeriod
299 && pCfg1->Backend.cFramesBufferSize == pCfg2->Backend.cFramesBufferSize
300 && pCfg1->Backend.cFramesPreBuffering == pCfg2->Backend.cFramesPreBuffering
301 && strcmp(pCfg1->szName, pCfg2->szName) == 0;
302 return false;
303}
304
305/**
306 * Frees an audio stream allocated by PDMAudioStrmCfgDup().
307 *
308 * @param pCfg The stream configuration to free.
309 */
310DECLINLINE(void) PDMAudioStrmCfgFree(PPDMAUDIOSTREAMCFG pCfg)
311{
312 if (pCfg)
313 RTMemFree(pCfg);
314}
315
316/**
317 * Checks whether the given stream configuration is valid or not.
318 *
319 * @returns true/false accordingly.
320 * @param pCfg Stream configuration to check.
321 *
322 * @remarks This just performs a generic check of value ranges. Further, it
323 * will assert if the input is invalid.
324 *
325 * @sa PDMAudioPropsAreValid
326 */
327DECLINLINE(bool) PDMAudioStrmCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg)
328{
329 AssertPtrReturn(pCfg, false);
330 AssertMsgReturn(pCfg->enmDir >= PDMAUDIODIR_UNKNOWN && pCfg->enmDir < PDMAUDIODIR_END,
331 ("%d\n", pCfg->enmDir), false);
332 AssertMsgReturn(pCfg->enmLayout >= PDMAUDIOSTREAMLAYOUT_UNKNOWN && pCfg->enmLayout < PDMAUDIOSTREAMLAYOUT_END,
333 ("%d\n", pCfg->enmLayout), false);
334 return PDMAudioPropsAreValid(&pCfg->Props);
335}
336
337/**
338 * Copies one stream configuration to another.
339 *
340 * @returns VBox status code.
341 * @param pDstCfg The destination stream configuration.
342 * @param pSrcCfg The source stream configuration.
343 */
344DECLINLINE(int) PDMAudioStrmCfgCopy(PPDMAUDIOSTREAMCFG pDstCfg, PCPDMAUDIOSTREAMCFG pSrcCfg)
345{
346 AssertPtrReturn(pDstCfg, VERR_INVALID_POINTER);
347 AssertPtrReturn(pSrcCfg, VERR_INVALID_POINTER);
348
349 /* This used to be VBOX_STRICT only and return VERR_INVALID_PARAMETER, but
350 that's making release builds work differently from debug & strict builds,
351 which is a terrible idea: */
352 Assert(PDMAudioStrmCfgIsValid(pSrcCfg));
353
354 memcpy(pDstCfg, pSrcCfg, sizeof(PDMAUDIOSTREAMCFG));
355
356 return VINF_SUCCESS;
357}
358
359/**
360 * Duplicates an audio stream configuration.
361 *
362 * @returns Pointer to duplicate on success, NULL on failure. Must be freed
363 * using PDMAudioStrmCfgFree().
364 *
365 * @param pCfg The audio stream configuration to duplicate.
366 */
367DECLINLINE(PPDMAUDIOSTREAMCFG) PDMAudioStrmCfgDup(PCPDMAUDIOSTREAMCFG pCfg)
368{
369 AssertPtrReturn(pCfg, NULL);
370
371 PPDMAUDIOSTREAMCFG pDst = (PPDMAUDIOSTREAMCFG)RTMemAllocZ(sizeof(PDMAUDIOSTREAMCFG));
372 if (pDst)
373 {
374 int rc = PDMAudioStrmCfgCopy(pDst, pCfg);
375 if (RT_SUCCESS(rc))
376 return pDst;
377
378 PDMAudioStrmCfgFree(pDst);
379 }
380 return NULL;
381}
382
383/**
384 * Logs an audio stream configuration.
385 *
386 * @param pCfg The stream configuration to log.
387 */
388DECLINLINE(void) PDMAudioStrmCfgLog(PCPDMAUDIOSTREAMCFG pCfg)
389{
390 if (pCfg)
391 LogFunc(("szName=%s enmDir=%RU32 uHz=%RU32 cBits=%RU8%s cChannels=%RU8\n", pCfg->szName, pCfg->enmDir,
392 pCfg->Props.uHz, pCfg->Props.cbSampleX * 8, pCfg->Props.fSigned ? "S" : "U", pCfg->Props.cChannelsX));
393}
394
395/**
396 * Converts a stream command enum value to a string.
397 *
398 * @returns Pointer to read-only stream command name on success,
399 * "bad" if invalid command value.
400 * @param enmCmd The stream command to name.
401 */
402DECLINLINE(const char *) PDMAudioStrmCmdGetName(PDMAUDIOSTREAMCMD enmCmd)
403{
404 switch (enmCmd)
405 {
406 case PDMAUDIOSTREAMCMD_INVALID: return "Invalid";
407 case PDMAUDIOSTREAMCMD_ENABLE: return "Enable";
408 case PDMAUDIOSTREAMCMD_DISABLE: return "Disable";
409 case PDMAUDIOSTREAMCMD_PAUSE: return "Pause";
410 case PDMAUDIOSTREAMCMD_RESUME: return "Resume";
411 case PDMAUDIOSTREAMCMD_DRAIN: return "Drain";
412 case PDMAUDIOSTREAMCMD_END:
413 case PDMAUDIOSTREAMCMD_32BIT_HACK:
414 break;
415 /* no default! */
416 }
417 AssertMsgFailedReturn(("Invalid stream command %d\n", enmCmd), "bad");
418}
419
420/**
421 * Checks if the stream status is one that can be read from.
422 *
423 * @returns @c true if ready to be read from, @c false if not.
424 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAM_STS_XXX.
425 * @note Not for backend statuses (use PDMAudioStrmStatusBackendCanRead)!
426 */
427DECLINLINE(bool) PDMAudioStrmStatusCanRead(uint32_t fStatus)
428{
429 PDMAUDIOSTREAM_STS_ASSERT_VALID(fStatus);
430 AssertReturn(!(fStatus & ~PDMAUDIOSTREAM_STS_VALID_MASK), false);
431 return (fStatus & ( PDMAUDIOSTREAM_STS_INITIALIZED
432 | PDMAUDIOSTREAM_STS_ENABLED
433 | PDMAUDIOSTREAM_STS_PAUSED
434 | PDMAUDIOSTREAM_STS_NEED_REINIT))
435 == ( PDMAUDIOSTREAM_STS_INITIALIZED
436 | PDMAUDIOSTREAM_STS_ENABLED);
437}
438
439/**
440 * Checks if the stream status is one that can be read from.
441 *
442 * @returns @c true if ready to be read from, @c false if not.
443 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAM_STS_XXX.
444 * @note Only for backend statuses.
445 */
446DECLINLINE(bool) PDMAudioStrmStatusBackendCanRead(uint32_t fStatus)
447{
448 PDMAUDIOSTREAM_STS_ASSERT_VALID_BACKEND(fStatus);
449 AssertReturn(!(fStatus & ~PDMAUDIOSTREAM_STS_VALID_MASK_BACKEND), false);
450 return (fStatus & ( PDMAUDIOSTREAM_STS_INITIALIZED
451 | PDMAUDIOSTREAM_STS_ENABLED
452 | PDMAUDIOSTREAM_STS_PAUSED
453 | PDMAUDIOSTREAM_STS_NEED_REINIT ))
454 == ( PDMAUDIOSTREAM_STS_INITIALIZED
455 | PDMAUDIOSTREAM_STS_ENABLED);
456}
457
458/**
459 * Checks if the stream status is one that can be written to.
460 *
461 * @returns @c true if ready to be written to, @c false if not.
462 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAM_STS_XXX.
463 * @note Not for backend statuses (use PDMAudioStrmStatusBackendCanWrite)!
464 */
465DECLINLINE(bool) PDMAudioStrmStatusCanWrite(uint32_t fStatus)
466{
467 PDMAUDIOSTREAM_STS_ASSERT_VALID(fStatus);
468 AssertReturn(!(fStatus & ~PDMAUDIOSTREAM_STS_VALID_MASK), false);
469 return (fStatus & ( PDMAUDIOSTREAM_STS_INITIALIZED
470 | PDMAUDIOSTREAM_STS_ENABLED
471 | PDMAUDIOSTREAM_STS_PAUSED
472 | PDMAUDIOSTREAM_STS_PENDING_DISABLE
473 | PDMAUDIOSTREAM_STS_NEED_REINIT))
474 == ( PDMAUDIOSTREAM_STS_INITIALIZED
475 | PDMAUDIOSTREAM_STS_ENABLED);
476}
477
478/**
479 * Checks if the stream status is one that can be written to, backend edition.
480 *
481 * @returns @c true if ready to be written to, @c false if not.
482 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAM_STS_XXX.
483 * @note Only for backend statuses.
484 */
485DECLINLINE(bool) PDMAudioStrmStatusBackendCanWrite(uint32_t fStatus)
486{
487 PDMAUDIOSTREAM_STS_ASSERT_VALID_BACKEND(fStatus);
488 AssertReturn(!(fStatus & ~PDMAUDIOSTREAM_STS_VALID_MASK_BACKEND), false);
489 return (fStatus & ( PDMAUDIOSTREAM_STS_INITIALIZED
490 | PDMAUDIOSTREAM_STS_ENABLED
491 | PDMAUDIOSTREAM_STS_PAUSED
492 | PDMAUDIOSTREAM_STS_PENDING_DISABLE))
493 == ( PDMAUDIOSTREAM_STS_INITIALIZED
494 | PDMAUDIOSTREAM_STS_ENABLED);
495}
496
497/**
498 * Checks if the stream status is a read-to-operate one.
499 *
500 * @returns @c true if ready to operate, @c false if not.
501 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAM_STS_XXX.
502 * @note Not for backend statuses!
503 */
504DECLINLINE(bool) PDMAudioStrmStatusIsReady(uint32_t fStatus)
505{
506 PDMAUDIOSTREAM_STS_ASSERT_VALID(fStatus);
507 AssertReturn(!(fStatus & ~PDMAUDIOSTREAM_STS_VALID_MASK), false);
508 return (fStatus & ( PDMAUDIOSTREAM_STS_INITIALIZED
509 | PDMAUDIOSTREAM_STS_ENABLED
510 | PDMAUDIOSTREAM_STS_NEED_REINIT))
511 == ( PDMAUDIOSTREAM_STS_INITIALIZED
512 | PDMAUDIOSTREAM_STS_ENABLED);
513}
514
515
516/*********************************************************************************************************************************
517* PCM Property Helpers *
518*********************************************************************************************************************************/
519
520/**
521 * Initialize PCM audio properties.
522 */
523DECLINLINE(void) PDMAudioPropsInit(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz)
524{
525 pProps->cbFrame = cbSample * cChannels;
526 pProps->cbSampleX = cbSample;
527 pProps->cChannelsX = cChannels;
528 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels);
529 pProps->fSigned = fSigned;
530 pProps->fSwapEndian = false;
531 pProps->fRaw = false;
532 pProps->uHz = uHz;
533
534 Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels);
535 Assert(pProps->cbSampleX == cbSample);
536 Assert(pProps->cChannelsX == cChannels);
537}
538
539/**
540 * Initialize PCM audio properties, extended version.
541 */
542DECLINLINE(void) PDMAudioPropsInitEx(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz,
543 bool fLittleEndian, bool fRaw)
544{
545 Assert(!fRaw || cbSample == sizeof(int64_t));
546 pProps->cbFrame = cbSample * cChannels;
547 pProps->cbSampleX = cbSample;
548 pProps->cChannelsX = cChannels;
549 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels);
550 pProps->fSigned = fSigned;
551#ifdef RT_LITTLE_ENDIAN
552 pProps->fSwapEndian = !fLittleEndian;
553#else
554 pProps->fSwapEndian = fLittleEndian;
555#endif
556 pProps->fRaw = fRaw;
557 pProps->uHz = uHz;
558
559 Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels);
560 Assert(pProps->cbSampleX == cbSample);
561 Assert(pProps->cChannelsX == cChannels);
562}
563
564/**
565 * Modifies the channel count.
566 *
567 * @param pProps The PCM properties to update.
568 * @param cChannels The new channel count.
569 */
570DECLINLINE(void) PDMAudioPropsSetChannels(PPDMAUDIOPCMPROPS pProps, uint8_t cChannels)
571{
572 Assert(cChannels > 0); Assert(cChannels < 16);
573 pProps->cChannelsX = cChannels;
574 pProps->cbFrame = pProps->cbSampleX * cChannels;
575 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pProps->cbSampleX, cChannels);
576}
577
578/**
579 * Modifies the sample size.
580 *
581 * @param pProps The PCM properties to update.
582 * @param cbSample The new sample size (in bytes).
583 */
584DECLINLINE(void) PDMAudioPropsSetSampleSize(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample)
585{
586 Assert(cbSample == 1 || cbSample == 2 || cbSample == 4 || cbSample == 8);
587 pProps->cbSampleX = cbSample;
588 pProps->cbFrame = cbSample * pProps->cChannelsX;
589 pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, pProps->cChannelsX);
590}
591
592/**
593 * Gets the bitrate.
594 *
595 * Divide the result by 8 to get the byte rate.
596 *
597 * @returns Bit rate.
598 * @param pProps PCM properties to calculate bitrate for.
599 */
600DECLINLINE(uint32_t) PDMAudioPropsGetBitrate(PCPDMAUDIOPCMPROPS pProps)
601{
602 Assert(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX);
603 return pProps->cbFrame * pProps->uHz * 8;
604}
605
606/**
607 * Gets the number of channels.
608 * @returns The channel count.
609 * @param pProps The PCM properties.
610 */
611DECL_FORCE_INLINE(uint8_t) PDMAudioPropsChannels(PCPDMAUDIOPCMPROPS pProps)
612{
613 return pProps->cChannelsX;
614}
615
616/**
617 * Gets the sample size in bytes.
618 * @returns Number of bytes per sample.
619 * @param pProps The PCM properties.
620 */
621DECL_FORCE_INLINE(uint8_t) PDMAudioPropsSampleSize(PCPDMAUDIOPCMPROPS pProps)
622{
623 return pProps->cbSampleX;
624}
625
626/**
627 * Gets the sample size in bits.
628 * @returns Number of bits per sample.
629 * @param pProps The PCM properties.
630 */
631DECLINLINE(uint8_t) PDMAudioPropsSampleBits(PCPDMAUDIOPCMPROPS pProps)
632{
633 return pProps->cbSampleX * 8;
634}
635
636/**
637 * Gets the frame size in bytes.
638 * @returns Number of bytes per frame.
639 * @param pProps The PCM properties.
640 */
641DECL_FORCE_INLINE(uint8_t) PDMAudioPropsFrameSize(PCPDMAUDIOPCMPROPS pProps)
642{
643 return pProps->cbFrame;
644}
645
646/**
647 * Gets the frequency.
648 * @returns Frequency.
649 * @param pProps The PCM properties.
650 */
651DECL_FORCE_INLINE(uint32_t) PDMAudioPropsHz(PCPDMAUDIOPCMPROPS pProps)
652{
653 return pProps->uHz;
654}
655
656/**
657 * Checks if the format is signed or unsigned.
658 * @returns true if signed, false if unsigned.
659 * @param pProps The PCM properties.
660 */
661DECL_FORCE_INLINE(bool) PDMAudioPropsIsSigned(PCPDMAUDIOPCMPROPS pProps)
662{
663 return pProps->fSigned;
664}
665
666/**
667 * Checks if the format is little-endian or not.
668 * @returns true if little-endian (or if 8-bit), false if big-endian.
669 * @param pProps The PCM properties.
670 */
671DECL_FORCE_INLINE(bool) PDMAudioPropsIsLittleEndian(PCPDMAUDIOPCMPROPS pProps)
672{
673#ifdef RT_LITTLE_ENDIAN
674 return !pProps->fSwapEndian || pProps->cbSampleX < 2;
675#else
676 return pProps->fSwapEndian || pProps->cbSampleX < 2;
677#endif
678}
679
680/**
681 * Checks if the format is big-endian or not.
682 * @returns true if big-endian (or if 8-bit), false if little-endian.
683 * @param pProps The PCM properties.
684 */
685DECL_FORCE_INLINE(bool) PDMAudioPropsIsBigEndian(PCPDMAUDIOPCMPROPS pProps)
686{
687#ifdef RT_LITTLE_ENDIAN
688 return pProps->fSwapEndian || pProps->cbSampleX < 2;
689#else
690 return !pProps->fSwapEndian || pProps->cbSampleX < 2;
691#endif
692}
693
694/**
695 * Rounds down the given byte amount to the nearest frame boundrary.
696 *
697 * @returns Rounded byte amount.
698 * @param pProps PCM properties to use.
699 * @param cb The size (in bytes) to round.
700 */
701DECLINLINE(uint32_t) PDMAudioPropsFloorBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
702{
703 AssertPtrReturn(pProps, 0);
704 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb));
705}
706
707/**
708 * Rounds up the given byte amount to the nearest frame boundrary.
709 *
710 * @returns Rounded byte amount.
711 * @param pProps PCM properties to use.
712 * @param cb The size (in bytes) to round.
713 */
714DECLINLINE(uint32_t) PDMAudioPropsRoundUpBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
715{
716 AssertPtrReturn(pProps, 0);
717 uint32_t const cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
718 AssertReturn(cbFrame, 0);
719 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb + cbFrame - 1));
720}
721
722/**
723 * Checks if the given size is aligned on a frame boundrary.
724 *
725 * @returns @c true if properly aligned, @c false if not.
726 * @param pProps PCM properties to use.
727 * @param cb The size (in bytes) to check.
728 */
729DECLINLINE(bool) PDMAudioPropsIsSizeAligned(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
730{
731 AssertPtrReturn(pProps, false);
732 uint32_t const cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
733 AssertReturn(cbFrame, false);
734 return cb % cbFrame == 0;
735}
736
737/**
738 * Converts bytes to frames (rounding down of course).
739 *
740 * @returns Number of frames.
741 * @param pProps PCM properties to use.
742 * @param cb The number of bytes to convert.
743 */
744DECLINLINE(uint32_t) PDMAudioPropsBytesToFrames(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
745{
746 AssertPtrReturn(pProps, 0);
747 return PDMAUDIOPCMPROPS_B2F(pProps, cb);
748}
749
750/**
751 * Converts bytes to milliseconds.
752 *
753 * @return Number milliseconds @a cb takes to play or record.
754 * @param pProps PCM properties to use.
755 * @param cb The number of bytes to convert.
756 *
757 * @note Rounds up the result.
758 */
759DECLINLINE(uint64_t) PDMAudioPropsBytesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
760{
761 AssertPtrReturn(pProps, 0);
762
763 /* Check parameters to prevent division by chainsaw: */
764 uint32_t const uHz = pProps->uHz;
765 if (uHz)
766 {
767 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
768 if (cbFrame)
769 {
770 /* Round cb up to closest frame size: */
771 cb = (cb + cbFrame - 1) / cbFrame;
772
773 /* Convert to milliseconds. */
774 return (cb * (uint64_t)RT_MS_1SEC + uHz - 1) / uHz;
775 }
776 }
777 return 0;
778}
779
780/**
781 * Converts bytes to microseconds.
782 *
783 * @return Number microseconds @a cb takes to play or record.
784 * @param pProps PCM properties to use.
785 * @param cb The number of bytes to convert.
786 *
787 * @note Rounds up the result.
788 */
789DECLINLINE(uint64_t) PDMAudioPropsBytesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
790{
791 AssertPtrReturn(pProps, 0);
792
793 /* Check parameters to prevent division by chainsaw: */
794 uint32_t const uHz = pProps->uHz;
795 if (uHz)
796 {
797 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
798 if (cbFrame)
799 {
800 /* Round cb up to closest frame size: */
801 cb = (cb + cbFrame - 1) / cbFrame;
802
803 /* Convert to microseconds. */
804 return (cb * (uint64_t)RT_US_1SEC + uHz - 1) / uHz;
805 }
806 }
807 return 0;
808}
809
810/**
811 * Converts bytes to nanoseconds.
812 *
813 * @return Number nanoseconds @a cb takes to play or record.
814 * @param pProps PCM properties to use.
815 * @param cb The number of bytes to convert.
816 *
817 * @note Rounds up the result.
818 */
819DECLINLINE(uint64_t) PDMAudioPropsBytesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
820{
821 AssertPtrReturn(pProps, 0);
822
823 /* Check parameters to prevent division by chainsaw: */
824 uint32_t const uHz = pProps->uHz;
825 if (uHz)
826 {
827 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
828 if (cbFrame)
829 {
830 /* Round cb up to closest frame size: */
831 cb = (cb + cbFrame - 1) / cbFrame;
832
833 /* Convert to nanoseconds. */
834 return (cb * (uint64_t)RT_NS_1SEC + uHz - 1) / uHz;
835 }
836 }
837 return 0;
838}
839
840/**
841 * Converts frames to bytes.
842 *
843 * @returns Number of bytes.
844 * @param pProps The PCM properties to use.
845 * @param cFrames Number of audio frames to convert.
846 * @sa PDMAUDIOPCMPROPS_F2B
847 */
848DECLINLINE(uint32_t) PDMAudioPropsFramesToBytes(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
849{
850 AssertPtrReturn(pProps, 0);
851 return PDMAUDIOPCMPROPS_F2B(pProps, cFrames);
852}
853
854/**
855 * Converts frames to milliseconds.
856 *
857 * @returns milliseconds.
858 * @param pProps The PCM properties to use.
859 * @param cFrames Number of audio frames to convert.
860 * @note No rounding here, result is floored.
861 */
862DECLINLINE(uint64_t) PDMAudioPropsFramesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
863{
864 AssertPtrReturn(pProps, 0);
865
866 /* Check input to prevent division by chainsaw: */
867 uint32_t const uHz = pProps->uHz;
868 if (uHz)
869 return ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, uHz);
870 return 0;
871}
872
873/**
874 * Converts frames to microseconds.
875 *
876 * @returns microseconds.
877 * @param pProps The PCM properties to use.
878 * @param cFrames Number of audio frames to convert.
879 * @note No rounding here, result is floored.
880 */
881DECLINLINE(uint64_t) PDMAudioPropsFramesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
882{
883 AssertPtrReturn(pProps, 0);
884
885 /* Check input to prevent division by chainsaw: */
886 uint32_t const uHz = pProps->uHz;
887 if (uHz)
888 return ASMMultU32ByU32DivByU32(cFrames, RT_US_1SEC, uHz);
889 return 0;
890}
891
892/**
893 * Converts frames to nanoseconds.
894 *
895 * @returns Nanoseconds.
896 * @param pProps The PCM properties to use.
897 * @param cFrames Number of audio frames to convert.
898 * @note No rounding here, result is floored.
899 */
900DECLINLINE(uint64_t) PDMAudioPropsFramesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
901{
902 AssertPtrReturn(pProps, 0);
903
904 /* Check input to prevent division by chainsaw: */
905 uint32_t const uHz = pProps->uHz;
906 if (uHz)
907 return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC, uHz);
908 return 0;
909}
910
911/**
912 * Converts frames to NT ticks (100 ns units).
913 *
914 * @returns NT ticks.
915 * @param pProps The PCM properties to use.
916 * @param cFrames Number of audio frames to convert.
917 * @note No rounding here, result is floored.
918 */
919DECLINLINE(uint64_t) PDMAudioPropsFramesToNtTicks(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
920{
921 AssertPtrReturn(pProps, 0);
922
923 /* Check input to prevent division by chainsaw: */
924 uint32_t const uHz = pProps->uHz;
925 if (uHz)
926 return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC / 100, uHz);
927 return 0;
928}
929
930/**
931 * Converts milliseconds to frames.
932 *
933 * @returns Number of frames
934 * @param pProps The PCM properties to use.
935 * @param cMs The number of milliseconds to convert.
936 *
937 * @note The result is rounded rather than floored (hysterical raisins).
938 */
939DECLINLINE(uint32_t) PDMAudioPropsMilliToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)
940{
941 AssertPtrReturn(pProps, 0);
942
943 uint32_t const uHz = pProps->uHz;
944 uint32_t cFrames;
945 if (cMs < RT_MS_1SEC)
946 cFrames = 0;
947 else
948 {
949 cFrames = cMs / RT_MS_1SEC * uHz;
950 cMs %= RT_MS_1SEC;
951 }
952 cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cMs) + RT_MS_1SEC - 1) / RT_MS_1SEC;
953 return cFrames;
954}
955
956/**
957 * Converts milliseconds to bytes.
958 *
959 * @returns Number of bytes (frame aligned).
960 * @param pProps The PCM properties to use.
961 * @param cMs The number of milliseconds to convert.
962 *
963 * @note The result is rounded rather than floored (hysterical raisins).
964 */
965DECLINLINE(uint32_t) PDMAudioPropsMilliToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)
966{
967 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsMilliToFrames(pProps, cMs));
968}
969
970/**
971 * Converts nanoseconds to frames.
972 *
973 * @returns Number of frames
974 * @param pProps The PCM properties to use.
975 * @param cNs The number of nanoseconds to convert.
976 *
977 * @note The result is rounded rather than floored (hysterical raisins).
978 */
979DECLINLINE(uint32_t) PDMAudioPropsNanoToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
980{
981 AssertPtrReturn(pProps, 0);
982
983 uint32_t const uHz = pProps->uHz;
984 uint32_t cFrames;
985 if (cNs < RT_NS_1SEC)
986 cFrames = 0;
987 else
988 {
989 cFrames = cNs / RT_NS_1SEC * uHz;
990 cNs %= RT_NS_1SEC;
991 }
992 cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cNs) + RT_NS_1SEC - 1) / RT_NS_1SEC;
993 return cFrames;
994}
995
996/**
997 * Converts nanoseconds to bytes.
998 *
999 * @returns Number of bytes (frame aligned).
1000 * @param pProps The PCM properties to use.
1001 * @param cNs The number of nanoseconds to convert.
1002 *
1003 * @note The result is rounded rather than floored (hysterical raisins).
1004 */
1005DECLINLINE(uint32_t) PDMAudioPropsNanoToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)
1006{
1007 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs));
1008}
1009
1010/**
1011 * Clears a sample buffer by the given amount of audio frames with silence (according to the format
1012 * given by the PCM properties).
1013 *
1014 * @param pProps The PCM properties to apply.
1015 * @param pvBuf The buffer to clear.
1016 * @param cbBuf The buffer size in bytes.
1017 * @param cFrames The number of audio frames to clear. Capped at @a cbBuf
1018 * if exceeding the buffer. If the size is an unaligned
1019 * number of frames, the extra bytes may be left
1020 * uninitialized in some configurations.
1021 */
1022DECLINLINE(void) PDMAudioPropsClearBuffer(PCPDMAUDIOPCMPROPS pProps, void *pvBuf, size_t cbBuf, uint32_t cFrames)
1023{
1024 /*
1025 * Validate input
1026 */
1027 AssertPtrReturnVoid(pProps);
1028 Assert(pProps->cbSampleX);
1029 if (!cbBuf || !cFrames)
1030 return;
1031 AssertPtrReturnVoid(pvBuf);
1032
1033 Assert(pProps->fSwapEndian == false); /** @todo Swapping Endianness is not supported yet. */
1034
1035 /*
1036 * Decide how much needs clearing.
1037 */
1038 size_t cbToClear = PDMAudioPropsFramesToBytes(pProps, cFrames);
1039 AssertStmt(cbToClear <= cbBuf, cbToClear = cbBuf);
1040
1041 Log2Func(("pProps=%p, pvBuf=%p, cFrames=%RU32, fSigned=%RTbool, cbSample=%RU8\n",
1042 pProps, pvBuf, cFrames, pProps->fSigned, pProps->cbSampleX));
1043
1044 /*
1045 * Do the job.
1046 */
1047 if (pProps->fSigned)
1048 RT_BZERO(pvBuf, cbToClear);
1049 else /* Unsigned formats. */
1050 {
1051 switch (pProps->cbSampleX)
1052 {
1053 case 1: /* 8 bit */
1054 memset(pvBuf, 0x80, cbToClear);
1055 break;
1056
1057 case 2: /* 16 bit */
1058 {
1059 uint16_t *pu16Dst = (uint16_t *)pvBuf;
1060 size_t cLeft = cbToClear / sizeof(uint16_t);
1061 while (cLeft-- > 0)
1062 *pu16Dst++ = 0x80;
1063 break;
1064 }
1065
1066 /** @todo Add 24 bit? */
1067
1068 case 4: /* 32 bit */
1069 ASMMemFill32(pvBuf, cbToClear & ~(size_t)3, 0x80);
1070 break;
1071
1072 default:
1073 AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX));
1074 }
1075 }
1076}
1077
1078/**
1079 * Compares two sets of PCM properties.
1080 *
1081 * @returns @c true if the same, @c false if not.
1082 * @param pProps1 The first set of properties to compare.
1083 * @param pProps2 The second set of properties to compare.
1084 */
1085DECLINLINE(bool) PDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2)
1086{
1087 AssertPtrReturn(pProps1, false);
1088 AssertPtrReturn(pProps2, false);
1089
1090 if (pProps1 == pProps2) /* If the pointers match, take a shortcut. */
1091 return true;
1092
1093 return pProps1->uHz == pProps2->uHz
1094 && pProps1->cChannelsX == pProps2->cChannelsX
1095 && pProps1->cbSampleX == pProps2->cbSampleX
1096 && pProps1->fSigned == pProps2->fSigned
1097 && pProps1->fSwapEndian == pProps2->fSwapEndian;
1098}
1099
1100/**
1101 * Checks whether the given PCM properties are valid or not.
1102 *
1103 * @returns true/false accordingly.
1104 * @param pProps The PCM properties to check.
1105 *
1106 * @remarks This just performs a generic check of value ranges. Further, it
1107 * will assert if the input is invalid.
1108 *
1109 * @sa PDMAudioStrmCfgIsValid
1110 */
1111DECLINLINE(bool) PDMAudioPropsAreValid(PCPDMAUDIOPCMPROPS pProps)
1112{
1113 AssertPtrReturn(pProps, false);
1114
1115 AssertReturn(pProps->cChannelsX != 0, false);
1116 AssertMsgReturn( pProps->cbSampleX == 1 || pProps->cbSampleX == 2 || pProps->cbSampleX == 4 || (pProps->cbSampleX == 8 && pProps->fRaw),
1117 ("%u\n", pProps->cbSampleX), false);
1118 AssertMsgReturn(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX,
1119 ("cbFrame=%u cbSample=%u cChannels=%u\n", pProps->cbFrame, pProps->cbSampleX, pProps->cChannelsX),
1120 false);
1121 AssertMsgReturn(pProps->uHz >= 1000 && pProps->uHz < 1000000, ("%u\n", pProps->uHz), false);
1122 AssertMsgReturn(pProps->cShiftX == PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps),
1123 ("cShift=%u cbSample=%u cChannels=%u\n", pProps->cShiftX, pProps->cbSampleX, pProps->cChannelsX),
1124 false);
1125 AssertReturn(!pProps->fRaw || (pProps->fSigned && pProps->cbSampleX == sizeof(int64_t)), false);
1126 return true;
1127}
1128
1129/**
1130 * Get number of bytes per frame.
1131 *
1132 * @returns Number of bytes per audio frame.
1133 * @param pProps PCM properties to use.
1134 * @sa PDMAUDIOPCMPROPS_F2B
1135 */
1136DECLINLINE(uint32_t) PDMAudioPropsBytesPerFrame(PCPDMAUDIOPCMPROPS pProps)
1137{
1138 return PDMAUDIOPCMPROPS_F2B(pProps, 1 /*cFrames*/);
1139}
1140
1141/**
1142 * Prints PCM properties to the debug log.
1143 *
1144 * @param pProps PCM properties to use.
1145 */
1146DECLINLINE(void) PDMAudioPropsLog(PCPDMAUDIOPCMPROPS pProps)
1147{
1148 AssertPtrReturnVoid(pProps);
1149
1150 Log(("uHz=%RU32, cChannels=%RU8, cBits=%RU8%s",
1151 pProps->uHz, pProps->cChannelsX, pProps->cbSampleX * 8, pProps->fSigned ? "S" : "U"));
1152}
1153
1154/** Max necessary buffer space for PDMAudioPropsToString */
1155#define PDMAUDIOPROPSTOSTRING_MAX sizeof("16ch S64 4294967296Hz swap raw")
1156
1157/**
1158 * Formats the PCM audio properties into a string buffer.
1159 *
1160 * @returns pszDst
1161 * @param pProps PCM properties to use.
1162 * @param pszDst The destination buffer.
1163 * @param cchDst The size of the destination buffer. Recommended to be at
1164 * least PDMAUDIOPROPSTOSTRING_MAX bytes.
1165 */
1166DECLINLINE(char *) PDMAudioPropsToString(PCPDMAUDIOPCMPROPS pProps, char *pszDst, size_t cchDst)
1167{
1168 /* 2ch S64 44100Hz swap raw */
1169 RTStrPrintf(pszDst, cchDst, "%uch %c%u %RU32Hz%s%s",
1170 PDMAudioPropsChannels(pProps), PDMAudioPropsIsSigned(pProps) ? 'S' : 'U', PDMAudioPropsSampleBits(pProps),
1171 PDMAudioPropsHz(pProps), pProps->fSwapEndian ? " swap" : "", pProps->fRaw ? " raw" : "");
1172 return pszDst;
1173}
1174
1175
1176
1177/** @} */
1178
1179#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