VirtualBox

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

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

Audio: Moving some of the DrvAudio.h stuff into PDM - VBox/vmm/pdmaudioinline.h. bugref:9890

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