VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp@ 87992

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

Audio: Switched DrvAudioHlpFramesToNano parameters. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 56.3 KB
Line 
1/* $Id: DrvAudioCommon.cpp 87992 2021-03-07 15:14:14Z vboxsync $ */
2/** @file
3 * Intermedia audio driver, common routines.
4 *
5 * These are also used in the drivers which are bound to Main, e.g. the VRDE
6 * or the video audio recording drivers.
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
21
22/*********************************************************************************************************************************
23* Header Files *
24*********************************************************************************************************************************/
25#include <iprt/alloc.h>
26#include <iprt/asm-math.h>
27#include <iprt/assert.h>
28#include <iprt/dir.h>
29#include <iprt/file.h>
30#include <iprt/string.h>
31#include <iprt/uuid.h>
32
33#define LOG_GROUP LOG_GROUP_DRV_AUDIO
34#include <VBox/log.h>
35
36#include <VBox/err.h>
37#include <VBox/vmm/pdmdev.h>
38#include <VBox/vmm/pdm.h>
39#include <VBox/vmm/mm.h>
40
41#include <ctype.h>
42#include <stdlib.h>
43
44#include "DrvAudio.h"
45#include "AudioMixBuffer.h"
46
47
48/*********************************************************************************************************************************
49* Structures and Typedefs *
50*********************************************************************************************************************************/
51/**
52 * Structure for building up a .WAV file header.
53 */
54typedef struct AUDIOWAVFILEHDR
55{
56 uint32_t u32RIFF;
57 uint32_t u32Size;
58 uint32_t u32WAVE;
59
60 uint32_t u32Fmt;
61 uint32_t u32Size1;
62 uint16_t u16AudioFormat;
63 uint16_t u16NumChannels;
64 uint32_t u32SampleRate;
65 uint32_t u32ByteRate;
66 uint16_t u16BlockAlign;
67 uint16_t u16BitsPerSample;
68
69 uint32_t u32ID2;
70 uint32_t u32Size2;
71} AUDIOWAVFILEHDR, *PAUDIOWAVFILEHDR;
72AssertCompileSize(AUDIOWAVFILEHDR, 11*4);
73
74/**
75 * Structure for keeeping the internal .WAV file data
76 */
77typedef struct AUDIOWAVFILEDATA
78{
79 /** The file header/footer. */
80 AUDIOWAVFILEHDR Hdr;
81} AUDIOWAVFILEDATA, *PAUDIOWAVFILEDATA;
82
83
84
85
86/**
87 * Retrieves the matching PDMAUDIOFMT for given bits + signing flag.
88 *
89 * @return IPRT status code.
90 * @return PDMAUDIOFMT Resulting audio format or PDMAUDIOFMT_INVALID if invalid.
91 * @param cBits Bits to retrieve audio format for.
92 * @param fSigned Signed flag for bits to retrieve audio format for.
93 */
94PDMAUDIOFMT DrvAudioAudFmtBitsToAudFmt(uint8_t cBits, bool fSigned)
95{
96 if (fSigned)
97 {
98 switch (cBits)
99 {
100 case 8: return PDMAUDIOFMT_S8;
101 case 16: return PDMAUDIOFMT_S16;
102 case 32: return PDMAUDIOFMT_S32;
103 default: break;
104 }
105 }
106 else
107 {
108 switch (cBits)
109 {
110 case 8: return PDMAUDIOFMT_U8;
111 case 16: return PDMAUDIOFMT_U16;
112 case 32: return PDMAUDIOFMT_U32;
113 default: break;
114 }
115 }
116
117 AssertMsgFailed(("Bogus audio bits %RU8\n", cBits));
118 return PDMAUDIOFMT_INVALID;
119}
120
121/**
122 * Clears a sample buffer by the given amount of audio frames with silence (according to the format
123 * given by the PCM properties).
124 *
125 * @param pPCMProps PCM properties to use for the buffer to clear.
126 * @param pvBuf Buffer to clear.
127 * @param cbBuf Size (in bytes) of the buffer.
128 * @param cFrames Number of audio frames to clear in the buffer.
129 */
130void DrvAudioHlpClearBuf(PCPDMAUDIOPCMPROPS pPCMProps, void *pvBuf, size_t cbBuf, uint32_t cFrames)
131{
132 AssertPtrReturnVoid(pPCMProps);
133 AssertPtrReturnVoid(pvBuf);
134
135 if (!cbBuf || !cFrames)
136 return;
137
138 Assert(pPCMProps->cbSample);
139 size_t cbToClear = DrvAudioHlpFramesToBytes(cFrames, pPCMProps);
140 Assert(cbBuf >= cbToClear);
141
142 if (cbBuf < cbToClear)
143 cbToClear = cbBuf;
144
145 Log2Func(("pPCMProps=%p, pvBuf=%p, cFrames=%RU32, fSigned=%RTbool, cBytes=%RU8\n",
146 pPCMProps, pvBuf, cFrames, pPCMProps->fSigned, pPCMProps->cbSample));
147
148 Assert(pPCMProps->fSwapEndian == false); /** @todo Swapping Endianness is not supported yet. */
149
150 if (pPCMProps->fSigned)
151 {
152 RT_BZERO(pvBuf, cbToClear);
153 }
154 else /* Unsigned formats. */
155 {
156 switch (pPCMProps->cbSample)
157 {
158 case 1: /* 8 bit */
159 {
160 memset(pvBuf, 0x80, cbToClear);
161 break;
162 }
163
164 case 2: /* 16 bit */
165 {
166 uint16_t *p = (uint16_t *)pvBuf;
167 uint16_t s = 0x0080;
168
169 for (uint32_t i = 0; i < DrvAudioHlpBytesToFrames((uint32_t)cbToClear, pPCMProps); i++)
170 p[i] = s;
171
172 break;
173 }
174
175 /** @todo Add 24 bit? */
176
177 case 4: /* 32 bit */
178 {
179 uint32_t *p = (uint32_t *)pvBuf;
180 uint32_t s = 0x00000080;
181
182 for (uint32_t i = 0; i < DrvAudioHlpBytesToFrames((uint32_t)cbToClear, pPCMProps); i++)
183 p[i] = s;
184
185 break;
186 }
187
188 default:
189 {
190 AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pPCMProps->cbSample));
191 break;
192 }
193 }
194 }
195}
196
197/**
198 * Returns an unique file name for this given audio connector instance.
199 *
200 * @return Allocated file name. Must be free'd using RTStrFree().
201 * @param uInstance Driver / device instance.
202 * @param pszPath Path name of the file to delete. The path must exist.
203 * @param pszSuffix File name suffix to use.
204 */
205char *DrvAudioDbgGetFileNameA(uint8_t uInstance, const char *pszPath, const char *pszSuffix)
206{
207 char szFileName[64];
208 RTStrPrintf(szFileName, sizeof(szFileName), "drvAudio%RU8-%s", uInstance, pszSuffix);
209
210 char szFilePath[RTPATH_MAX];
211 int rc2 = RTStrCopy(szFilePath, sizeof(szFilePath), pszPath);
212 AssertRC(rc2);
213 rc2 = RTPathAppend(szFilePath, sizeof(szFilePath), szFileName);
214 AssertRC(rc2);
215
216 return RTStrDup(szFilePath);
217}
218
219/**
220 * Allocates an audio device.
221 *
222 * @returns Newly allocated audio device, or NULL if failed.
223 * @param cbData How much additional data (in bytes) should be allocated to provide
224 * a (backend) specific area to store additional data.
225 * Optional, can be 0.
226 */
227PPDMAUDIODEVICE DrvAudioHlpDeviceAlloc(size_t cbData)
228{
229 PPDMAUDIODEVICE pDev = (PPDMAUDIODEVICE)RTMemAllocZ(sizeof(PDMAUDIODEVICE));
230 if (!pDev)
231 return NULL;
232
233 if (cbData)
234 {
235 pDev->pvData = RTMemAllocZ(cbData);
236 if (!pDev->pvData)
237 {
238 RTMemFree(pDev);
239 return NULL;
240 }
241 }
242
243 pDev->cbData = cbData;
244
245 pDev->cMaxInputChannels = 0;
246 pDev->cMaxOutputChannels = 0;
247
248 return pDev;
249}
250
251/**
252 * Frees an audio device.
253 *
254 * @param pDev Device to free.
255 */
256void DrvAudioHlpDeviceFree(PPDMAUDIODEVICE pDev)
257{
258 if (!pDev)
259 return;
260
261 Assert(pDev->cRefCount == 0);
262
263 if (pDev->pvData)
264 {
265 Assert(pDev->cbData);
266
267 RTMemFree(pDev->pvData);
268 pDev->pvData = NULL;
269 }
270
271 RTMemFree(pDev);
272 pDev = NULL;
273}
274
275/**
276 * Duplicates an audio device entry.
277 *
278 * @returns Duplicated audio device entry on success, or NULL on failure.
279 * @param pDev Audio device entry to duplicate.
280 * @param fCopyUserData Whether to also copy the user data portion or not.
281 */
282PPDMAUDIODEVICE DrvAudioHlpDeviceDup(const PPDMAUDIODEVICE pDev, bool fCopyUserData)
283{
284 AssertPtrReturn(pDev, NULL);
285
286 PPDMAUDIODEVICE pDevDup = DrvAudioHlpDeviceAlloc(fCopyUserData ? pDev->cbData : 0);
287 if (pDevDup)
288 {
289 memcpy(pDevDup, pDev, sizeof(PDMAUDIODEVICE));
290
291 if ( fCopyUserData
292 && pDevDup->cbData)
293 {
294 memcpy(pDevDup->pvData, pDev->pvData, pDevDup->cbData);
295 }
296 else
297 {
298 pDevDup->cbData = 0;
299 pDevDup->pvData = NULL;
300 }
301 }
302
303 return pDevDup;
304}
305
306/**
307 * Initializes an audio device enumeration structure.
308 *
309 * @returns IPRT status code.
310 * @param pDevEnm Device enumeration to initialize.
311 */
312int DrvAudioHlpDeviceEnumInit(PPDMAUDIODEVICEENUM pDevEnm)
313{
314 AssertPtrReturn(pDevEnm, VERR_INVALID_POINTER);
315
316 RTListInit(&pDevEnm->lstDevices);
317 pDevEnm->cDevices = 0;
318
319 return VINF_SUCCESS;
320}
321
322/**
323 * Frees audio device enumeration data.
324 *
325 * @param pDevEnm Device enumeration to destroy.
326 */
327void DrvAudioHlpDeviceEnumFree(PPDMAUDIODEVICEENUM pDevEnm)
328{
329 if (!pDevEnm)
330 return;
331
332 PPDMAUDIODEVICE pDev, pDevNext;
333 RTListForEachSafe(&pDevEnm->lstDevices, pDev, pDevNext, PDMAUDIODEVICE, Node)
334 {
335 RTListNodeRemove(&pDev->Node);
336
337 DrvAudioHlpDeviceFree(pDev);
338
339 pDevEnm->cDevices--;
340 }
341
342 /* Sanity. */
343 Assert(RTListIsEmpty(&pDevEnm->lstDevices));
344 Assert(pDevEnm->cDevices == 0);
345}
346
347/**
348 * Adds an audio device to a device enumeration.
349 *
350 * @return IPRT status code.
351 * @param pDevEnm Device enumeration to add device to.
352 * @param pDev Device to add. The pointer will be owned by the device enumeration then.
353 */
354int DrvAudioHlpDeviceEnumAdd(PPDMAUDIODEVICEENUM pDevEnm, PPDMAUDIODEVICE pDev)
355{
356 AssertPtrReturn(pDevEnm, VERR_INVALID_POINTER);
357 AssertPtrReturn(pDev, VERR_INVALID_POINTER);
358
359 RTListAppend(&pDevEnm->lstDevices, &pDev->Node);
360 pDevEnm->cDevices++;
361
362 return VINF_SUCCESS;
363}
364
365/**
366 * Duplicates a device enumeration.
367 *
368 * @returns Duplicated device enumeration, or NULL on failure.
369 * Must be free'd with DrvAudioHlpDeviceEnumFree().
370 * @param pDevEnm Device enumeration to duplicate.
371 */
372PPDMAUDIODEVICEENUM DrvAudioHlpDeviceEnumDup(const PPDMAUDIODEVICEENUM pDevEnm)
373{
374 AssertPtrReturn(pDevEnm, NULL);
375
376 PPDMAUDIODEVICEENUM pDevEnmDup = (PPDMAUDIODEVICEENUM)RTMemAlloc(sizeof(PDMAUDIODEVICEENUM));
377 if (!pDevEnmDup)
378 return NULL;
379
380 int rc2 = DrvAudioHlpDeviceEnumInit(pDevEnmDup);
381 AssertRC(rc2);
382
383 PPDMAUDIODEVICE pDev;
384 RTListForEach(&pDevEnm->lstDevices, pDev, PDMAUDIODEVICE, Node)
385 {
386 PPDMAUDIODEVICE pDevDup = DrvAudioHlpDeviceDup(pDev, true /* fCopyUserData */);
387 if (!pDevDup)
388 {
389 rc2 = VERR_NO_MEMORY;
390 break;
391 }
392
393 rc2 = DrvAudioHlpDeviceEnumAdd(pDevEnmDup, pDevDup);
394 if (RT_FAILURE(rc2))
395 {
396 DrvAudioHlpDeviceFree(pDevDup);
397 break;
398 }
399 }
400
401 if (RT_FAILURE(rc2))
402 {
403 DrvAudioHlpDeviceEnumFree(pDevEnmDup);
404 pDevEnmDup = NULL;
405 }
406
407 return pDevEnmDup;
408}
409
410/**
411 * Copies device enumeration entries from the source to the destination enumeration.
412 *
413 * @returns IPRT status code.
414 * @param pDstDevEnm Destination enumeration to store enumeration entries into.
415 * @param pSrcDevEnm Source enumeration to use.
416 * @param enmUsage Which entries to copy. Specify PDMAUDIODIR_ANY to copy all entries.
417 * @param fCopyUserData Whether to also copy the user data portion or not.
418 */
419int DrvAudioHlpDeviceEnumCopyEx(PPDMAUDIODEVICEENUM pDstDevEnm, const PPDMAUDIODEVICEENUM pSrcDevEnm,
420 PDMAUDIODIR enmUsage, bool fCopyUserData)
421{
422 AssertPtrReturn(pDstDevEnm, VERR_INVALID_POINTER);
423 AssertPtrReturn(pSrcDevEnm, VERR_INVALID_POINTER);
424
425 int rc = VINF_SUCCESS;
426
427 PPDMAUDIODEVICE pSrcDev;
428 RTListForEach(&pSrcDevEnm->lstDevices, pSrcDev, PDMAUDIODEVICE, Node)
429 {
430 if ( enmUsage != PDMAUDIODIR_ANY
431 && enmUsage != pSrcDev->enmUsage)
432 {
433 continue;
434 }
435
436 PPDMAUDIODEVICE pDstDev = DrvAudioHlpDeviceDup(pSrcDev, fCopyUserData);
437 if (!pDstDev)
438 {
439 rc = VERR_NO_MEMORY;
440 break;
441 }
442
443 rc = DrvAudioHlpDeviceEnumAdd(pDstDevEnm, pDstDev);
444 if (RT_FAILURE(rc))
445 break;
446 }
447
448 return rc;
449}
450
451/**
452 * Copies all device enumeration entries from the source to the destination enumeration.
453 *
454 * Note: Does *not* copy the user-specific data assigned to a device enumeration entry.
455 * To do so, use DrvAudioHlpDeviceEnumCopyEx().
456 *
457 * @returns IPRT status code.
458 * @param pDstDevEnm Destination enumeration to store enumeration entries into.
459 * @param pSrcDevEnm Source enumeration to use.
460 */
461int DrvAudioHlpDeviceEnumCopy(PPDMAUDIODEVICEENUM pDstDevEnm, const PPDMAUDIODEVICEENUM pSrcDevEnm)
462{
463 return DrvAudioHlpDeviceEnumCopyEx(pDstDevEnm, pSrcDevEnm, PDMAUDIODIR_ANY, false /* fCopyUserData */);
464}
465
466/**
467 * Returns the default device of a given device enumeration.
468 * This assumes that only one default device per usage is set.
469 *
470 * @returns Default device if found, or NULL if none found.
471 * @param pDevEnm Device enumeration to get default device for.
472 * @param enmUsage Usage to get default device for.
473 */
474PPDMAUDIODEVICE DrvAudioHlpDeviceEnumGetDefaultDevice(const PPDMAUDIODEVICEENUM pDevEnm, PDMAUDIODIR enmUsage)
475{
476 AssertPtrReturn(pDevEnm, NULL);
477
478 PPDMAUDIODEVICE pDev;
479 RTListForEach(&pDevEnm->lstDevices, pDev, PDMAUDIODEVICE, Node)
480 {
481 if (enmUsage != PDMAUDIODIR_ANY)
482 {
483 if (enmUsage != pDev->enmUsage) /* Wrong usage? Skip. */
484 continue;
485 }
486
487 if (pDev->fFlags & PDMAUDIODEV_FLAGS_DEFAULT)
488 return pDev;
489 }
490
491 return NULL;
492}
493
494/**
495 * Returns the number of enumerated devices of a given device enumeration.
496 *
497 * @returns Number of devices if found, or 0 if none found.
498 * @param pDevEnm Device enumeration to get default device for.
499 * @param enmUsage Usage to get default device for.
500 */
501uint16_t DrvAudioHlpDeviceEnumGetDeviceCount(const PPDMAUDIODEVICEENUM pDevEnm, PDMAUDIODIR enmUsage)
502{
503 AssertPtrReturn(pDevEnm, 0);
504
505 if (enmUsage == PDMAUDIODIR_ANY)
506 return pDevEnm->cDevices;
507
508 uint32_t cDevs = 0;
509
510 PPDMAUDIODEVICE pDev;
511 RTListForEach(&pDevEnm->lstDevices, pDev, PDMAUDIODEVICE, Node)
512 {
513 if (enmUsage == pDev->enmUsage)
514 cDevs++;
515 }
516
517 return cDevs;
518}
519
520/**
521 * Logs an audio device enumeration.
522 *
523 * @param pszDesc Logging description.
524 * @param pDevEnm Device enumeration to log.
525 */
526void DrvAudioHlpDeviceEnumPrint(const char *pszDesc, const PPDMAUDIODEVICEENUM pDevEnm)
527{
528 AssertPtrReturnVoid(pszDesc);
529 AssertPtrReturnVoid(pDevEnm);
530
531 LogFunc(("%s: %RU16 devices\n", pszDesc, pDevEnm->cDevices));
532
533 PPDMAUDIODEVICE pDev;
534 RTListForEach(&pDevEnm->lstDevices, pDev, PDMAUDIODEVICE, Node)
535 {
536 char *pszFlags = DrvAudioHlpAudDevFlagsToStrA(pDev->fFlags);
537
538 LogFunc(("Device '%s':\n", pDev->szName));
539 LogFunc(("\tUsage = %s\n", DrvAudioHlpAudDirToStr(pDev->enmUsage)));
540 LogFunc(("\tFlags = %s\n", pszFlags ? pszFlags : "<NONE>"));
541 LogFunc(("\tInput channels = %RU8\n", pDev->cMaxInputChannels));
542 LogFunc(("\tOutput channels = %RU8\n", pDev->cMaxOutputChannels));
543 LogFunc(("\tData = %p (%zu bytes)\n", pDev->pvData, pDev->cbData));
544
545 if (pszFlags)
546 RTStrFree(pszFlags);
547 }
548}
549
550/**
551 * Converts an audio direction to a string.
552 *
553 * @returns Stringified audio direction, or "Unknown", if not found.
554 * @param enmDir Audio direction to convert.
555 */
556const char *DrvAudioHlpAudDirToStr(PDMAUDIODIR enmDir)
557{
558 switch (enmDir)
559 {
560 case PDMAUDIODIR_UNKNOWN: return "Unknown";
561 case PDMAUDIODIR_IN: return "Input";
562 case PDMAUDIODIR_OUT: return "Output";
563 case PDMAUDIODIR_ANY: return "Duplex";
564 default: break;
565 }
566
567 AssertMsgFailed(("Invalid audio direction %ld\n", enmDir));
568 return "Unknown";
569}
570
571/**
572 * Converts an audio mixer control to a string.
573 *
574 * @returns Stringified audio mixer control or "Unknown", if not found.
575 * @param enmMixerCtl Audio mixer control to convert.
576 */
577const char *DrvAudioHlpAudMixerCtlToStr(PDMAUDIOMIXERCTL enmMixerCtl)
578{
579 switch (enmMixerCtl)
580 {
581 case PDMAUDIOMIXERCTL_VOLUME_MASTER: return "Master Volume";
582 case PDMAUDIOMIXERCTL_FRONT: return "Front";
583 case PDMAUDIOMIXERCTL_CENTER_LFE: return "Center / LFE";
584 case PDMAUDIOMIXERCTL_REAR: return "Rear";
585 case PDMAUDIOMIXERCTL_LINE_IN: return "Line-In";
586 case PDMAUDIOMIXERCTL_MIC_IN: return "Microphone-In";
587 default: break;
588 }
589
590 AssertMsgFailed(("Invalid mixer control %ld\n", enmMixerCtl));
591 return "Unknown";
592}
593
594/**
595 * Converts an audio device flags to a string.
596 *
597 * @returns Stringified audio flags. Must be free'd with RTStrFree().
598 * NULL if no flags set.
599 * @param fFlags Audio flags (PDMAUDIODEV_FLAGS_XXX) to convert.
600 */
601char *DrvAudioHlpAudDevFlagsToStrA(uint32_t fFlags)
602{
603#define APPEND_FLAG_TO_STR(_aFlag) \
604 if (fFlags & PDMAUDIODEV_FLAGS_##_aFlag) \
605 { \
606 if (pszFlags) \
607 { \
608 rc2 = RTStrAAppend(&pszFlags, " "); \
609 if (RT_FAILURE(rc2)) \
610 break; \
611 } \
612 \
613 rc2 = RTStrAAppend(&pszFlags, #_aFlag); \
614 if (RT_FAILURE(rc2)) \
615 break; \
616 } \
617
618 char *pszFlags = NULL;
619 int rc2 = VINF_SUCCESS;
620
621 do
622 {
623 APPEND_FLAG_TO_STR(DEFAULT);
624 APPEND_FLAG_TO_STR(HOTPLUG);
625 APPEND_FLAG_TO_STR(BUGGY);
626 APPEND_FLAG_TO_STR(IGNORE);
627 APPEND_FLAG_TO_STR(LOCKED);
628 APPEND_FLAG_TO_STR(DEAD);
629
630 } while (0);
631
632 if (!pszFlags)
633 rc2 = RTStrAAppend(&pszFlags, "NONE");
634
635 if ( RT_FAILURE(rc2)
636 && pszFlags)
637 {
638 RTStrFree(pszFlags);
639 pszFlags = NULL;
640 }
641
642#undef APPEND_FLAG_TO_STR
643
644 return pszFlags;
645}
646
647/**
648 * Converts a playback destination enumeration to a string.
649 *
650 * @returns Stringified playback destination, or "Unknown", if not found.
651 * @param enmPlaybackDst Playback destination to convert.
652 */
653const char *DrvAudioHlpPlaybackDstToStr(const PDMAUDIOPLAYBACKDST enmPlaybackDst)
654{
655 switch (enmPlaybackDst)
656 {
657 case PDMAUDIOPLAYBACKDST_UNKNOWN: return "Unknown";
658 case PDMAUDIOPLAYBACKDST_FRONT: return "Front";
659 case PDMAUDIOPLAYBACKDST_CENTER_LFE: return "Center / LFE";
660 case PDMAUDIOPLAYBACKDST_REAR: return "Rear";
661 default:
662 break;
663 }
664
665 AssertMsgFailed(("Invalid playback destination %ld\n", enmPlaybackDst));
666 return "Unknown";
667}
668
669/**
670 * Converts a recording source enumeration to a string.
671 *
672 * @returns Stringified recording source, or "Unknown", if not found.
673 * @param enmRecSrc Recording source to convert.
674 */
675const char *DrvAudioHlpRecSrcToStr(const PDMAUDIORECSRC enmRecSrc)
676{
677 switch (enmRecSrc)
678 {
679 case PDMAUDIORECSRC_UNKNOWN: return "Unknown";
680 case PDMAUDIORECSRC_MIC: return "Microphone In";
681 case PDMAUDIORECSRC_CD: return "CD";
682 case PDMAUDIORECSRC_VIDEO: return "Video";
683 case PDMAUDIORECSRC_AUX: return "AUX";
684 case PDMAUDIORECSRC_LINE: return "Line In";
685 case PDMAUDIORECSRC_PHONE: return "Phone";
686 default:
687 break;
688 }
689
690 AssertMsgFailed(("Invalid recording source %ld\n", enmRecSrc));
691 return "Unknown";
692}
693
694/**
695 * Returns wether the given audio format has signed bits or not.
696 *
697 * @return IPRT status code.
698 * @return bool @c true for signed bits, @c false for unsigned.
699 * @param enmFmt Audio format to retrieve value for.
700 */
701bool DrvAudioHlpAudFmtIsSigned(PDMAUDIOFMT enmFmt)
702{
703 switch (enmFmt)
704 {
705 case PDMAUDIOFMT_S8:
706 case PDMAUDIOFMT_S16:
707 case PDMAUDIOFMT_S32:
708 return true;
709
710 case PDMAUDIOFMT_U8:
711 case PDMAUDIOFMT_U16:
712 case PDMAUDIOFMT_U32:
713 return false;
714
715 default:
716 break;
717 }
718
719 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
720 return false;
721}
722
723/**
724 * Returns the bits of a given audio format.
725 *
726 * @return IPRT status code.
727 * @return uint8_t Bits of audio format.
728 * @param enmFmt Audio format to retrieve value for.
729 */
730uint8_t DrvAudioHlpAudFmtToBits(PDMAUDIOFMT enmFmt)
731{
732 switch (enmFmt)
733 {
734 case PDMAUDIOFMT_S8:
735 case PDMAUDIOFMT_U8:
736 return 8;
737
738 case PDMAUDIOFMT_U16:
739 case PDMAUDIOFMT_S16:
740 return 16;
741
742 case PDMAUDIOFMT_U32:
743 case PDMAUDIOFMT_S32:
744 return 32;
745
746 default:
747 break;
748 }
749
750 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
751 return 0;
752}
753
754/**
755 * Converts an audio format to a string.
756 *
757 * @returns Stringified audio format, or "Unknown", if not found.
758 * @param enmFmt Audio format to convert.
759 */
760const char *DrvAudioHlpAudFmtToStr(PDMAUDIOFMT enmFmt)
761{
762 switch (enmFmt)
763 {
764 case PDMAUDIOFMT_U8:
765 return "U8";
766
767 case PDMAUDIOFMT_U16:
768 return "U16";
769
770 case PDMAUDIOFMT_U32:
771 return "U32";
772
773 case PDMAUDIOFMT_S8:
774 return "S8";
775
776 case PDMAUDIOFMT_S16:
777 return "S16";
778
779 case PDMAUDIOFMT_S32:
780 return "S32";
781
782 default:
783 break;
784 }
785
786 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
787 return "Unknown";
788}
789
790/**
791 * Converts a given string to an audio format.
792 *
793 * @returns Audio format for the given string, or PDMAUDIOFMT_INVALID if not found.
794 * @param pszFmt String to convert to an audio format.
795 */
796PDMAUDIOFMT DrvAudioHlpStrToAudFmt(const char *pszFmt)
797{
798 AssertPtrReturn(pszFmt, PDMAUDIOFMT_INVALID);
799
800 if (!RTStrICmp(pszFmt, "u8"))
801 return PDMAUDIOFMT_U8;
802 else if (!RTStrICmp(pszFmt, "u16"))
803 return PDMAUDIOFMT_U16;
804 else if (!RTStrICmp(pszFmt, "u32"))
805 return PDMAUDIOFMT_U32;
806 else if (!RTStrICmp(pszFmt, "s8"))
807 return PDMAUDIOFMT_S8;
808 else if (!RTStrICmp(pszFmt, "s16"))
809 return PDMAUDIOFMT_S16;
810 else if (!RTStrICmp(pszFmt, "s32"))
811 return PDMAUDIOFMT_S32;
812
813 AssertMsgFailed(("Invalid audio format '%s'\n", pszFmt));
814 return PDMAUDIOFMT_INVALID;
815}
816
817/**
818 * Checks whether two given PCM properties are equal.
819 *
820 * @returns @c true if equal, @c false if not.
821 * @param pProps1 First properties to compare.
822 * @param pProps2 Second properties to compare.
823 */
824bool DrvAudioHlpPCMPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2)
825{
826 AssertPtrReturn(pProps1, false);
827 AssertPtrReturn(pProps2, false);
828
829 if (pProps1 == pProps2) /* If the pointers match, take a shortcut. */
830 return true;
831
832 return pProps1->uHz == pProps2->uHz
833 && pProps1->cChannels == pProps2->cChannels
834 && pProps1->cbSample == pProps2->cbSample
835 && pProps1->fSigned == pProps2->fSigned
836 && pProps1->fSwapEndian == pProps2->fSwapEndian;
837}
838
839/**
840 * Checks whether given PCM properties are valid or not.
841 *
842 * Returns @c true if properties are valid, @c false if not.
843 * @param pProps PCM properties to check.
844 */
845bool DrvAudioHlpPCMPropsAreValid(PCPDMAUDIOPCMPROPS pProps)
846{
847 AssertPtrReturn(pProps, false);
848
849 /* Minimum 1 channel (mono), maximum 7.1 (= 8) channels. */
850 bool fValid = ( pProps->cChannels >= 1
851 && pProps->cChannels <= 8);
852
853 if (fValid)
854 {
855 switch (pProps->cbSample)
856 {
857 case 1: /* 8 bit */
858 if (pProps->fSigned)
859 fValid = false;
860 break;
861 case 2: /* 16 bit */
862 if (!pProps->fSigned)
863 fValid = false;
864 break;
865 /** @todo Do we need support for 24 bit samples? */
866 case 4: /* 32 bit */
867 if (!pProps->fSigned)
868 fValid = false;
869 break;
870 default:
871 fValid = false;
872 break;
873 }
874 }
875
876 if (!fValid)
877 return false;
878
879 fValid &= pProps->uHz > 0;
880 fValid &= pProps->cShift == PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pProps->cbSample, pProps->cChannels);
881 fValid &= pProps->fSwapEndian == false; /** @todo Handling Big Endian audio data is not supported yet. */
882
883 return fValid;
884}
885
886/**
887 * Checks whether the given PCM properties are equal with the given
888 * stream configuration.
889 *
890 * @returns @c true if equal, @c false if not.
891 * @param pProps PCM properties to compare.
892 * @param pCfg Stream configuration to compare.
893 */
894bool DrvAudioHlpPCMPropsAreEqual(PCPDMAUDIOPCMPROPS pProps, PCPDMAUDIOSTREAMCFG pCfg)
895{
896 AssertPtrReturn(pProps, false);
897 AssertPtrReturn(pCfg, false);
898
899 return DrvAudioHlpPCMPropsAreEqual(pProps, &pCfg->Props);
900}
901
902/**
903 * Returns the bytes per frame for given PCM properties.
904 *
905 * @return Bytes per (audio) frame.
906 * @param pProps PCM properties to retrieve bytes per frame for.
907 */
908uint32_t DrvAudioHlpPCMPropsBytesPerFrame(PCPDMAUDIOPCMPROPS pProps)
909{
910 return PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
911}
912
913/**
914 * Prints PCM properties to the debug log.
915 *
916 * @param pProps Stream configuration to log.
917 */
918void DrvAudioHlpPCMPropsPrint(PCPDMAUDIOPCMPROPS pProps)
919{
920 AssertPtrReturnVoid(pProps);
921
922 Log(("uHz=%RU32, cChannels=%RU8, cBits=%RU8%s",
923 pProps->uHz, pProps->cChannels, pProps->cbSample * 8, pProps->fSigned ? "S" : "U"));
924}
925
926/**
927 * Converts PCM properties to a audio stream configuration.
928 *
929 * @return IPRT status code.
930 * @param pProps PCM properties to convert.
931 * @param pCfg Stream configuration to store result into.
932 */
933int DrvAudioHlpPCMPropsToStreamCfg(PCPDMAUDIOPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg)
934{
935 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
936 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
937
938 DrvAudioHlpStreamCfgInit(pCfg);
939
940 memcpy(&pCfg->Props, pProps, sizeof(PDMAUDIOPCMPROPS));
941 return VINF_SUCCESS;
942}
943
944/**
945 * Initializes a stream configuration with its default values.
946 *
947 * @param pCfg Stream configuration to initialize.
948 */
949void DrvAudioHlpStreamCfgInit(PPDMAUDIOSTREAMCFG pCfg)
950{
951 AssertPtrReturnVoid(pCfg);
952
953 RT_ZERO(*pCfg);
954
955 pCfg->Backend.cFramesPreBuffering = UINT32_MAX; /* Explicitly set to "undefined". */
956}
957
958/**
959 * Checks whether a given stream configuration is valid or not.
960 *
961 * Returns @c true if configuration is valid, @c false if not.
962 * @param pCfg Stream configuration to check.
963 */
964bool DrvAudioHlpStreamCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg)
965{
966 AssertPtrReturn(pCfg, false);
967
968 bool fValid = ( pCfg->enmDir == PDMAUDIODIR_IN
969 || pCfg->enmDir == PDMAUDIODIR_OUT);
970
971 fValid &= ( pCfg->enmLayout == PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED
972 || pCfg->enmLayout == PDMAUDIOSTREAMLAYOUT_RAW);
973
974 if (fValid)
975 fValid = DrvAudioHlpPCMPropsAreValid(&pCfg->Props);
976
977 return fValid;
978}
979
980/**
981 * Frees an allocated audio stream configuration.
982 *
983 * @param pCfg Audio stream configuration to free.
984 */
985void DrvAudioHlpStreamCfgFree(PPDMAUDIOSTREAMCFG pCfg)
986{
987 if (pCfg)
988 {
989 RTMemFree(pCfg);
990 pCfg = NULL;
991 }
992}
993
994/**
995 * Copies a source stream configuration to a destination stream configuration.
996 *
997 * @returns IPRT status code.
998 * @param pDstCfg Destination stream configuration to copy source to.
999 * @param pSrcCfg Source stream configuration to copy to destination.
1000 */
1001int DrvAudioHlpStreamCfgCopy(PPDMAUDIOSTREAMCFG pDstCfg, PCPDMAUDIOSTREAMCFG pSrcCfg)
1002{
1003 AssertPtrReturn(pDstCfg, VERR_INVALID_POINTER);
1004 AssertPtrReturn(pSrcCfg, VERR_INVALID_POINTER);
1005
1006#ifdef VBOX_STRICT
1007 if (!DrvAudioHlpStreamCfgIsValid(pSrcCfg))
1008 {
1009 AssertMsgFailed(("Stream config '%s' (%p) is invalid\n", pSrcCfg->szName, pSrcCfg));
1010 return VERR_INVALID_PARAMETER;
1011 }
1012#endif
1013
1014 memcpy(pDstCfg, pSrcCfg, sizeof(PDMAUDIOSTREAMCFG));
1015
1016 return VINF_SUCCESS;
1017}
1018
1019/**
1020 * Duplicates an audio stream configuration.
1021 * Must be free'd with DrvAudioHlpStreamCfgFree().
1022 *
1023 * @return Duplicates audio stream configuration on success, or NULL on failure.
1024 * @param pCfg Audio stream configuration to duplicate.
1025 */
1026PPDMAUDIOSTREAMCFG DrvAudioHlpStreamCfgDup(PCPDMAUDIOSTREAMCFG pCfg)
1027{
1028 AssertPtrReturn(pCfg, NULL);
1029
1030#ifdef VBOX_STRICT
1031 if (!DrvAudioHlpStreamCfgIsValid(pCfg))
1032 {
1033 AssertMsgFailed(("Stream config '%s' (%p) is invalid\n", pCfg->szName, pCfg));
1034 return NULL;
1035 }
1036#endif
1037
1038 PPDMAUDIOSTREAMCFG pDst = (PPDMAUDIOSTREAMCFG)RTMemAllocZ(sizeof(PDMAUDIOSTREAMCFG));
1039 if (!pDst)
1040 return NULL;
1041
1042 int rc2 = DrvAudioHlpStreamCfgCopy(pDst, pCfg);
1043 if (RT_FAILURE(rc2))
1044 {
1045 DrvAudioHlpStreamCfgFree(pDst);
1046 pDst = NULL;
1047 }
1048
1049 AssertPtr(pDst);
1050 return pDst;
1051}
1052
1053/**
1054 * Prints an audio stream configuration to the debug log.
1055 *
1056 * @param pCfg Stream configuration to log.
1057 */
1058void DrvAudioHlpStreamCfgPrint(PCPDMAUDIOSTREAMCFG pCfg)
1059{
1060 if (!pCfg)
1061 return;
1062
1063 LogFunc(("szName=%s, enmDir=%RU32 (uHz=%RU32, cBits=%RU8%s, cChannels=%RU8)\n",
1064 pCfg->szName, pCfg->enmDir,
1065 pCfg->Props.uHz, pCfg->Props.cbSample * 8, pCfg->Props.fSigned ? "S" : "U", pCfg->Props.cChannels));
1066}
1067
1068/**
1069 * Converts a stream command to a string.
1070 *
1071 * @returns Stringified stream command, or "Unknown", if not found.
1072 * @param enmCmd Stream command to convert.
1073 */
1074const char *DrvAudioHlpStreamCmdToStr(PDMAUDIOSTREAMCMD enmCmd)
1075{
1076 switch (enmCmd)
1077 {
1078 case PDMAUDIOSTREAMCMD_INVALID: return "Invalid";
1079 case PDMAUDIOSTREAMCMD_UNKNOWN: return "Unknown";
1080 case PDMAUDIOSTREAMCMD_ENABLE: return "Enable";
1081 case PDMAUDIOSTREAMCMD_DISABLE: return "Disable";
1082 case PDMAUDIOSTREAMCMD_PAUSE: return "Pause";
1083 case PDMAUDIOSTREAMCMD_RESUME: return "Resume";
1084 case PDMAUDIOSTREAMCMD_DRAIN: return "Drain";
1085 case PDMAUDIOSTREAMCMD_DROP: return "Drop";
1086 case PDMAUDIOSTREAMCMD_32BIT_HACK:
1087 break;
1088 }
1089 AssertMsgFailed(("Invalid stream command %d\n", enmCmd));
1090 return "Unknown";
1091}
1092
1093/**
1094 * Returns @c true if the given stream status indicates a can-be-read-from stream,
1095 * @c false if not.
1096 *
1097 * @returns @c true if ready to be read from, @c if not.
1098 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAMSTS_FLAGS_XXX.
1099 */
1100bool DrvAudioHlpStreamStatusCanRead(PDMAUDIOSTREAMSTS fStatus)
1101{
1102 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false);
1103
1104 return fStatus & PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
1105 && fStatus & PDMAUDIOSTREAMSTS_FLAGS_ENABLED
1106 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PAUSED)
1107 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT);
1108}
1109
1110/**
1111 * Returns @c true if the given stream status indicates a can-be-written-to stream,
1112 * @c false if not.
1113 *
1114 * @returns @c true if ready to be written to, @c if not.
1115 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAMSTS_FLAGS_XXX.
1116 */
1117bool DrvAudioHlpStreamStatusCanWrite(PDMAUDIOSTREAMSTS fStatus)
1118{
1119 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false);
1120
1121 return fStatus & PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
1122 && fStatus & PDMAUDIOSTREAMSTS_FLAGS_ENABLED
1123 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PAUSED)
1124 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_DISABLE)
1125 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT);
1126}
1127
1128/**
1129 * Returns @c true if the given stream status indicates a ready-to-operate stream,
1130 * @c false if not.
1131 *
1132 * @returns @c true if ready to operate, @c if not.
1133 * @param fStatus Stream status to evaluate.
1134 */
1135bool DrvAudioHlpStreamStatusIsReady(PDMAUDIOSTREAMSTS fStatus)
1136{
1137 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false);
1138
1139 return fStatus & PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED
1140 && fStatus & PDMAUDIOSTREAMSTS_FLAGS_ENABLED
1141 && !(fStatus & PDMAUDIOSTREAMSTS_FLAGS_PENDING_REINIT);
1142}
1143
1144/**
1145 * Calculates the audio bit rate of the given bits per sample, the Hz and the number
1146 * of audio channels.
1147 *
1148 * Divide the result by 8 to get the byte rate.
1149 *
1150 * @returns The calculated bit rate.
1151 * @param cBits Number of bits per sample.
1152 * @param uHz Hz (Hertz) rate.
1153 * @param cChannels Number of audio channels.
1154 */
1155uint32_t DrvAudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels)
1156{
1157 return (cBits * uHz * cChannels);
1158}
1159
1160/**
1161 * Calculates the audio bit rate out of a given audio stream configuration.
1162 *
1163 * Divide the result by 8 to get the byte rate.
1164 *
1165 * @returns The calculated bit rate.
1166 * @param pProps PCM properties to calculate bitrate for.
1167 *
1168 * @remark
1169 */
1170uint32_t DrvAudioHlpCalcBitrate(PCPDMAUDIOPCMPROPS pProps)
1171{
1172 return DrvAudioHlpCalcBitrate(pProps->cbSample * 8, pProps->uHz, pProps->cChannels);
1173}
1174
1175/**
1176 * Aligns the given byte amount to the given PCM properties and returns the aligned
1177 * size.
1178 *
1179 * @return Aligned size (in bytes).
1180 * @param cbSize Size (in bytes) to align.
1181 * @param pProps PCM properties to align size to.
1182 */
1183uint32_t DrvAudioHlpBytesAlign(uint32_t cbSize, PCPDMAUDIOPCMPROPS pProps)
1184{
1185 AssertPtrReturn(pProps, 0);
1186
1187 if (!cbSize)
1188 return 0;
1189
1190 return PDMAUDIOPCMPROPS_B2F(pProps, cbSize) * PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
1191}
1192
1193/**
1194 * Returns if the the given size is properly aligned to the given PCM properties.
1195 *
1196 * @return @c true if properly aligned, @c false if not.
1197 * @param cbSize Size (in bytes) to check alignment for.
1198 * @param pProps PCM properties to use for checking the alignment.
1199 */
1200bool DrvAudioHlpBytesIsAligned(uint32_t cbSize, PCPDMAUDIOPCMPROPS pProps)
1201{
1202 AssertPtrReturn(pProps, 0);
1203
1204 if (!cbSize)
1205 return true;
1206
1207 return (cbSize % PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */) == 0);
1208}
1209
1210/**
1211 * Returns the bytes per second for given PCM properties.
1212 *
1213 * @returns Bytes per second.
1214 * @param pProps PCM properties to retrieve size for.
1215 */
1216DECLINLINE(uint64_t) drvAudioHlpBytesPerSec(PCPDMAUDIOPCMPROPS pProps)
1217{
1218 return PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */) * pProps->uHz;
1219}
1220
1221/**
1222 * Returns the number of audio frames for a given amount of bytes.
1223 *
1224 * @return Calculated audio frames for given bytes.
1225 * @param cbBytes Bytes to convert to audio frames.
1226 * @param pProps PCM properties to calulate frames for.
1227 */
1228uint32_t DrvAudioHlpBytesToFrames(uint32_t cbBytes, PCPDMAUDIOPCMPROPS pProps)
1229{
1230 AssertPtrReturn(pProps, 0);
1231
1232 return PDMAUDIOPCMPROPS_B2F(pProps, cbBytes);
1233}
1234
1235/**
1236 * Converts bytes to milliseconds.
1237 *
1238 * @return Number milliseconds @a cb takes to play or record.
1239 * @param pProps PCM properties to use.
1240 * @param cb The number of bytes to convert.
1241 *
1242 * @note Rounds up the result.
1243 */
1244uint64_t DrvAudioHlpBytesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
1245{
1246 AssertPtrReturn(pProps, 0);
1247
1248 /* Check parameters to prevent division by chainsaw: */
1249 uint32_t const uHz = pProps->uHz;
1250 if (uHz)
1251 {
1252 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
1253 if (cbFrame)
1254 {
1255 /* Round cb up to closest frame size: */
1256 cb = (cb + cbFrame - 1) / cbFrame;
1257
1258 /* Convert to milliseconds. */
1259 return (cb * (uint64_t)RT_MS_1SEC + uHz - 1) / uHz;
1260 }
1261 }
1262 return 0;
1263}
1264
1265/**
1266 * Converts bytes to microseconds.
1267 *
1268 * @return Number microseconds @a cb takes to play or record.
1269 * @param pProps PCM properties to use.
1270 * @param cb The number of bytes to convert.
1271 *
1272 * @note Rounds up the result.
1273 */
1274uint64_t DrvAudioHlpBytesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
1275{
1276 AssertPtrReturn(pProps, 0);
1277
1278 /* Check parameters to prevent division by chainsaw: */
1279 uint32_t const uHz = pProps->uHz;
1280 if (uHz)
1281 {
1282 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
1283 if (cbFrame)
1284 {
1285 /* Round cb up to closest frame size: */
1286 cb = (cb + cbFrame - 1) / cbFrame;
1287
1288 /* Convert to microseconds. */
1289 return (cb * (uint64_t)RT_US_1SEC + uHz - 1) / uHz;
1290 }
1291 }
1292 return 0;
1293}
1294
1295/**
1296 * Converts bytes to nanoseconds.
1297 *
1298 * @return Number nanoseconds @a cb takes to play or record.
1299 * @param pProps PCM properties to use.
1300 * @param cb The number of bytes to convert.
1301 *
1302 * @note Rounds up the result.
1303 */
1304uint64_t DrvAudioHlpBytesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)
1305{
1306 AssertPtrReturn(pProps, 0);
1307
1308 /* Check parameters to prevent division by chainsaw: */
1309 uint32_t const uHz = pProps->uHz;
1310 if (uHz)
1311 {
1312 const unsigned cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
1313 if (cbFrame)
1314 {
1315 /* Round cb up to closest frame size: */
1316 cb = (cb + cbFrame - 1) / cbFrame;
1317
1318 /* Convert to nanoseconds. */
1319 return (cb * (uint64_t)RT_NS_1SEC + uHz - 1) / uHz;
1320 }
1321 }
1322 return 0;
1323}
1324
1325/**
1326 * Returns the bytes for a given audio frames amount and PCM properties.
1327 *
1328 * @return Calculated bytes for given audio frames.
1329 * @param cFrames Amount of audio frames to calculate bytes for.
1330 * @param pProps PCM properties to calculate bytes for.
1331 */
1332uint32_t DrvAudioHlpFramesToBytes(uint32_t cFrames, PCPDMAUDIOPCMPROPS pProps)
1333{
1334 AssertPtrReturn(pProps, 0);
1335
1336 if (!cFrames)
1337 return 0;
1338
1339 return cFrames * PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
1340}
1341
1342/**
1343 * Converts frames to milliseconds.
1344 *
1345 * @returns milliseconds.
1346 * @param pProps The PCM properties to use.
1347 * @param cFrames Number of audio frames to convert.
1348 */
1349uint64_t DrvAudioHlpFramesToMilli(uint32_t cFrames, PCPDMAUDIOPCMPROPS pProps)
1350{
1351 AssertPtrReturn(pProps, 0);
1352
1353 if (!cFrames)
1354 return 0;
1355
1356 if (!pProps->uHz) /* Prevent division by zero. */
1357 return 0;
1358
1359 /** @todo r=bird: How to do this w/o any floating point:
1360 * @code
1361 * ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, pProps->uHz);
1362 * // or
1363 * (uint64_t)cFrames * RT_MS_1SEC / pProps->uHz
1364 * @endcode
1365 */
1366 return cFrames / ((double)pProps->uHz / (double)RT_MS_1SEC);
1367}
1368
1369/**
1370 * Converts frames to nanoseconds.
1371 *
1372 * @returns Nanoseconds.
1373 * @param pProps The PCM properties to use.
1374 * @param cFrames Number of audio frames to convert.
1375 */
1376uint64_t DrvAudioHlpFramesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
1377{
1378 AssertPtrReturn(pProps, 0);
1379
1380 if (!cFrames)
1381 return 0;
1382
1383 if (!pProps->uHz) /* Prevent division by zero. */
1384 return 0;
1385
1386 return cFrames / ((double)pProps->uHz / (double)RT_NS_1SEC);
1387}
1388
1389/**
1390 * Returns the amount of bytes for a given time (in ms) and PCM properties.
1391 *
1392 * Note: The result will return an amount of bytes which is aligned to the audio frame size.
1393 *
1394 * @return uint32_t Calculated amount of bytes.
1395 * @param uMs Time (in ms) to calculate amount of bytes for.
1396 * @param pProps PCM properties to calculate amount of bytes for.
1397 */
1398uint32_t DrvAudioHlpMilliToBytes(uint64_t uMs, PCPDMAUDIOPCMPROPS pProps)
1399{
1400 AssertPtrReturn(pProps, 0);
1401
1402 if (!uMs)
1403 return 0;
1404
1405 const uint32_t uBytesPerFrame = DrvAudioHlpPCMPropsBytesPerFrame(pProps);
1406
1407 uint32_t uBytes = ((double)drvAudioHlpBytesPerSec(pProps) / (double)RT_MS_1SEC) * uMs;
1408 if (uBytes % uBytesPerFrame) /* Any remainder? Make the returned bytes an integral number to the given frames. */
1409 uBytes = uBytes + (uBytesPerFrame - uBytes % uBytesPerFrame);
1410
1411 Assert(uBytes % uBytesPerFrame == 0); /* Paranoia. */
1412
1413 return uBytes;
1414}
1415
1416/**
1417 * Returns the amount of bytes for a given time (in ns) and PCM properties.
1418 *
1419 * Note: The result will return an amount of bytes which is aligned to the audio frame size.
1420 *
1421 * @return uint32_t Calculated amount of bytes.
1422 * @param uNs Time (in ns) to calculate amount of bytes for.
1423 * @param pProps PCM properties to calculate amount of bytes for.
1424 */
1425uint32_t DrvAudioHlpNanoToBytes(uint64_t uNs, PCPDMAUDIOPCMPROPS pProps)
1426{
1427 AssertPtrReturn(pProps, 0);
1428
1429 if (!uNs)
1430 return 0;
1431
1432 const uint32_t uBytesPerFrame = DrvAudioHlpPCMPropsBytesPerFrame(pProps);
1433
1434 uint32_t uBytes = ((double)drvAudioHlpBytesPerSec(pProps) / (double)RT_NS_1SEC) * uNs;
1435 if (uBytes % uBytesPerFrame) /* Any remainder? Make the returned bytes an integral number to the given frames. */
1436 uBytes = uBytes + (uBytesPerFrame - uBytes % uBytesPerFrame);
1437
1438 Assert(uBytes % uBytesPerFrame == 0); /* Paranoia. */
1439
1440 return uBytes;
1441}
1442
1443/**
1444 * Returns the amount of audio frames for a given time (in ms) and PCM properties.
1445 *
1446 * @return uint32_t Calculated amount of audio frames.
1447 * @param uMs Time (in ms) to calculate amount of frames for.
1448 * @param pProps PCM properties to calculate amount of frames for.
1449 */
1450uint32_t DrvAudioHlpMilliToFrames(uint64_t uMs, PCPDMAUDIOPCMPROPS pProps)
1451{
1452 AssertPtrReturn(pProps, 0);
1453
1454 const uint32_t cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
1455 if (!cbFrame) /* Prevent division by zero. */
1456 return 0;
1457
1458 return DrvAudioHlpMilliToBytes(uMs, pProps) / cbFrame;
1459}
1460
1461/**
1462 * Returns the amount of audio frames for a given time (in ns) and PCM properties.
1463 *
1464 * @return uint32_t Calculated amount of audio frames.
1465 * @param uNs Time (in ns) to calculate amount of frames for.
1466 * @param pProps PCM properties to calculate amount of frames for.
1467 */
1468uint32_t DrvAudioHlpNanoToFrames(uint64_t uNs, PCPDMAUDIOPCMPROPS pProps)
1469{
1470 AssertPtrReturn(pProps, 0);
1471
1472 const uint32_t cbFrame = PDMAUDIOPCMPROPS_F2B(pProps, 1 /* Frame */);
1473 if (!cbFrame) /* Prevent division by zero. */
1474 return 0;
1475
1476 return DrvAudioHlpNanoToBytes(uNs, pProps) / cbFrame;
1477}
1478
1479/**
1480 * Sanitizes the file name component so that unsupported characters
1481 * will be replaced by an underscore ("_").
1482 *
1483 * @return IPRT status code.
1484 * @param pszPath Path to sanitize.
1485 * @param cbPath Size (in bytes) of path to sanitize.
1486 */
1487int DrvAudioHlpFileNameSanitize(char *pszPath, size_t cbPath)
1488{
1489 RT_NOREF(cbPath);
1490 int rc = VINF_SUCCESS;
1491#ifdef RT_OS_WINDOWS
1492 /* Filter out characters not allowed on Windows platforms, put in by
1493 RTTimeSpecToString(). */
1494 /** @todo Use something like RTPathSanitize() if available later some time. */
1495 static RTUNICP const s_uszValidRangePairs[] =
1496 {
1497 ' ', ' ',
1498 '(', ')',
1499 '-', '.',
1500 '0', '9',
1501 'A', 'Z',
1502 'a', 'z',
1503 '_', '_',
1504 0xa0, 0xd7af,
1505 '\0'
1506 };
1507 ssize_t cReplaced = RTStrPurgeComplementSet(pszPath, s_uszValidRangePairs, '_' /* Replacement */);
1508 if (cReplaced < 0)
1509 rc = VERR_INVALID_UTF8_ENCODING;
1510#else
1511 RT_NOREF(pszPath);
1512#endif
1513 return rc;
1514}
1515
1516/**
1517 * Constructs an unique file name, based on the given path and the audio file type.
1518 *
1519 * @returns IPRT status code.
1520 * @param pszFile Where to store the constructed file name.
1521 * @param cchFile Size (in characters) of the file name buffer.
1522 * @param pszPath Base path to use.
1523 * If NULL or empty, the system's temporary directory will be used.
1524 * @param pszName A name for better identifying the file.
1525 * @param uInstance Device / driver instance which is using this file.
1526 * @param enmType Audio file type to construct file name for.
1527 * @param fFlags File naming flags, PDMAUDIOFILENAME_FLAGS_XXX.
1528 */
1529int DrvAudioHlpFileNameGet(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName,
1530 uint32_t uInstance, PDMAUDIOFILETYPE enmType, uint32_t fFlags)
1531{
1532 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
1533 AssertReturn(cchFile, VERR_INVALID_PARAMETER);
1534 /* pszPath can be NULL. */
1535 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1536 /** @todo Validate fFlags. */
1537
1538 int rc;
1539
1540 char *pszPathTmp = NULL;
1541
1542 do
1543 {
1544 if ( pszPath == NULL
1545 || !strlen(pszPath))
1546 {
1547 char szTemp[RTPATH_MAX];
1548 rc = RTPathTemp(szTemp, sizeof(szTemp));
1549 if (RT_SUCCESS(rc))
1550 {
1551 pszPathTmp = RTStrDup(szTemp);
1552 }
1553 else
1554 break;
1555 }
1556 else
1557 pszPathTmp = RTStrDup(pszPath);
1558
1559 AssertPtrBreakStmt(pszPathTmp, rc = VERR_NO_MEMORY);
1560
1561 char szFilePath[RTPATH_MAX];
1562 rc = RTStrCopy(szFilePath, sizeof(szFilePath), pszPathTmp);
1563 AssertRCBreak(rc);
1564
1565 /* Create it when necessary. */
1566 if (!RTDirExists(szFilePath))
1567 {
1568 rc = RTDirCreateFullPath(szFilePath, RTFS_UNIX_IRWXU);
1569 if (RT_FAILURE(rc))
1570 break;
1571 }
1572
1573 char szFileName[RTPATH_MAX];
1574 szFileName[0] = '\0';
1575
1576 if (fFlags & PDMAUDIOFILENAME_FLAGS_TS)
1577 {
1578 RTTIMESPEC time;
1579 if (!RTTimeSpecToString(RTTimeNow(&time), szFileName, sizeof(szFileName)))
1580 {
1581 rc = VERR_BUFFER_OVERFLOW;
1582 break;
1583 }
1584
1585 rc = DrvAudioHlpFileNameSanitize(szFileName, sizeof(szFileName));
1586 if (RT_FAILURE(rc))
1587 break;
1588
1589 rc = RTStrCat(szFileName, sizeof(szFileName), "-");
1590 if (RT_FAILURE(rc))
1591 break;
1592 }
1593
1594 rc = RTStrCat(szFileName, sizeof(szFileName), pszName);
1595 if (RT_FAILURE(rc))
1596 break;
1597
1598 rc = RTStrCat(szFileName, sizeof(szFileName), "-");
1599 if (RT_FAILURE(rc))
1600 break;
1601
1602 char szInst[16];
1603 RTStrPrintf2(szInst, sizeof(szInst), "%RU32", uInstance);
1604 rc = RTStrCat(szFileName, sizeof(szFileName), szInst);
1605 if (RT_FAILURE(rc))
1606 break;
1607
1608 switch (enmType)
1609 {
1610 case PDMAUDIOFILETYPE_RAW:
1611 rc = RTStrCat(szFileName, sizeof(szFileName), ".pcm");
1612 break;
1613
1614 case PDMAUDIOFILETYPE_WAV:
1615 rc = RTStrCat(szFileName, sizeof(szFileName), ".wav");
1616 break;
1617
1618 default:
1619 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
1620 break;
1621 }
1622
1623 if (RT_FAILURE(rc))
1624 break;
1625
1626 rc = RTPathAppend(szFilePath, sizeof(szFilePath), szFileName);
1627 if (RT_FAILURE(rc))
1628 break;
1629
1630 rc = RTStrCopy(pszFile, cchFile, szFilePath);
1631
1632 } while (0);
1633
1634 RTStrFree(pszPathTmp);
1635
1636 LogFlowFuncLeaveRC(rc);
1637 return rc;
1638}
1639
1640/**
1641 * Creates an audio file.
1642 *
1643 * @returns IPRT status code.
1644 * @param enmType Audio file type to open / create.
1645 * @param pszFile File path of file to open or create.
1646 * @param fFlags Audio file flags, PDMAUDIOFILE_FLAGS_XXX.
1647 * @param ppFile Where to store the created audio file handle.
1648 * Needs to be destroyed with DrvAudioHlpFileDestroy().
1649 */
1650int DrvAudioHlpFileCreate(PDMAUDIOFILETYPE enmType, const char *pszFile, uint32_t fFlags, PPDMAUDIOFILE *ppFile)
1651{
1652 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
1653 /** @todo Validate fFlags. */
1654
1655 PPDMAUDIOFILE pFile = (PPDMAUDIOFILE)RTMemAlloc(sizeof(PDMAUDIOFILE));
1656 if (!pFile)
1657 return VERR_NO_MEMORY;
1658
1659 int rc = VINF_SUCCESS;
1660
1661 switch (enmType)
1662 {
1663 case PDMAUDIOFILETYPE_RAW:
1664 case PDMAUDIOFILETYPE_WAV:
1665 pFile->enmType = enmType;
1666 break;
1667
1668 default:
1669 rc = VERR_INVALID_PARAMETER;
1670 break;
1671 }
1672
1673 if (RT_SUCCESS(rc))
1674 {
1675 RTStrPrintf(pFile->szName, RT_ELEMENTS(pFile->szName), "%s", pszFile);
1676 pFile->hFile = NIL_RTFILE;
1677 pFile->fFlags = fFlags;
1678 pFile->pvData = NULL;
1679 pFile->cbData = 0;
1680 }
1681
1682 if (RT_FAILURE(rc))
1683 {
1684 RTMemFree(pFile);
1685 pFile = NULL;
1686 }
1687 else
1688 *ppFile = pFile;
1689
1690 return rc;
1691}
1692
1693/**
1694 * Destroys a formerly created audio file.
1695 *
1696 * @param pFile Audio file (object) to destroy.
1697 */
1698void DrvAudioHlpFileDestroy(PPDMAUDIOFILE pFile)
1699{
1700 if (!pFile)
1701 return;
1702
1703 DrvAudioHlpFileClose(pFile);
1704
1705 RTMemFree(pFile);
1706 pFile = NULL;
1707}
1708
1709/**
1710 * Opens or creates an audio file.
1711 *
1712 * @returns IPRT status code.
1713 * @param pFile Pointer to audio file handle to use.
1714 * @param fOpen Open flags.
1715 * Use PDMAUDIOFILE_DEFAULT_OPEN_FLAGS for the default open flags.
1716 * @param pProps PCM properties to use.
1717 */
1718int DrvAudioHlpFileOpen(PPDMAUDIOFILE pFile, uint32_t fOpen, PCPDMAUDIOPCMPROPS pProps)
1719{
1720 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
1721 /** @todo Validate fOpen flags. */
1722 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
1723
1724 int rc;
1725
1726 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)
1727 {
1728 rc = RTFileOpen(&pFile->hFile, pFile->szName, fOpen);
1729 }
1730 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)
1731 {
1732 Assert(pProps->cChannels);
1733 Assert(pProps->uHz);
1734 Assert(pProps->cbSample);
1735
1736 pFile->pvData = (PAUDIOWAVFILEDATA)RTMemAllocZ(sizeof(AUDIOWAVFILEDATA));
1737 if (pFile->pvData)
1738 {
1739 pFile->cbData = sizeof(PAUDIOWAVFILEDATA);
1740
1741 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
1742 AssertPtr(pData);
1743
1744 /* Header. */
1745 pData->Hdr.u32RIFF = AUDIO_MAKE_FOURCC('R','I','F','F');
1746 pData->Hdr.u32Size = 36;
1747 pData->Hdr.u32WAVE = AUDIO_MAKE_FOURCC('W','A','V','E');
1748
1749 pData->Hdr.u32Fmt = AUDIO_MAKE_FOURCC('f','m','t',' ');
1750 pData->Hdr.u32Size1 = 16; /* Means PCM. */
1751 pData->Hdr.u16AudioFormat = 1; /* PCM, linear quantization. */
1752 pData->Hdr.u16NumChannels = pProps->cChannels;
1753 pData->Hdr.u32SampleRate = pProps->uHz;
1754 pData->Hdr.u32ByteRate = DrvAudioHlpCalcBitrate(pProps) / 8;
1755 pData->Hdr.u16BlockAlign = pProps->cChannels * pProps->cbSample;
1756 pData->Hdr.u16BitsPerSample = pProps->cbSample * 8;
1757
1758 /* Data chunk. */
1759 pData->Hdr.u32ID2 = AUDIO_MAKE_FOURCC('d','a','t','a');
1760 pData->Hdr.u32Size2 = 0;
1761
1762 rc = RTFileOpen(&pFile->hFile, pFile->szName, fOpen);
1763 if (RT_SUCCESS(rc))
1764 {
1765 rc = RTFileWrite(pFile->hFile, &pData->Hdr, sizeof(pData->Hdr), NULL);
1766 if (RT_FAILURE(rc))
1767 {
1768 RTFileClose(pFile->hFile);
1769 pFile->hFile = NIL_RTFILE;
1770 }
1771 }
1772
1773 if (RT_FAILURE(rc))
1774 {
1775 RTMemFree(pFile->pvData);
1776 pFile->pvData = NULL;
1777 pFile->cbData = 0;
1778 }
1779 }
1780 else
1781 rc = VERR_NO_MEMORY;
1782 }
1783 else
1784 rc = VERR_INVALID_PARAMETER;
1785
1786 if (RT_SUCCESS(rc))
1787 {
1788 LogRel2(("Audio: Opened file '%s'\n", pFile->szName));
1789 }
1790 else
1791 LogRel(("Audio: Failed opening file '%s', rc=%Rrc\n", pFile->szName, rc));
1792
1793 return rc;
1794}
1795
1796/**
1797 * Closes an audio file.
1798 *
1799 * @returns IPRT status code.
1800 * @param pFile Audio file handle to close.
1801 */
1802int DrvAudioHlpFileClose(PPDMAUDIOFILE pFile)
1803{
1804 if (!pFile)
1805 return VINF_SUCCESS;
1806
1807 size_t cbSize = DrvAudioHlpFileGetDataSize(pFile);
1808
1809 int rc = VINF_SUCCESS;
1810
1811 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)
1812 {
1813 if (RTFileIsValid(pFile->hFile))
1814 rc = RTFileClose(pFile->hFile);
1815 }
1816 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)
1817 {
1818 if (RTFileIsValid(pFile->hFile))
1819 {
1820 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
1821 if (pData) /* The .WAV file data only is valid when a file actually has been created. */
1822 {
1823 /* Update the header with the current data size. */
1824 RTFileWriteAt(pFile->hFile, 0, &pData->Hdr, sizeof(pData->Hdr), NULL);
1825 }
1826
1827 rc = RTFileClose(pFile->hFile);
1828 }
1829
1830 if (pFile->pvData)
1831 {
1832 RTMemFree(pFile->pvData);
1833 pFile->pvData = NULL;
1834 }
1835 }
1836 else
1837 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
1838
1839 if ( RT_SUCCESS(rc)
1840 && !cbSize
1841 && !(pFile->fFlags & PDMAUDIOFILE_FLAGS_KEEP_IF_EMPTY))
1842 {
1843 rc = DrvAudioHlpFileDelete(pFile);
1844 }
1845
1846 pFile->cbData = 0;
1847
1848 if (RT_SUCCESS(rc))
1849 {
1850 pFile->hFile = NIL_RTFILE;
1851 LogRel2(("Audio: Closed file '%s' (%zu bytes)\n", pFile->szName, cbSize));
1852 }
1853 else
1854 LogRel(("Audio: Failed closing file '%s', rc=%Rrc\n", pFile->szName, rc));
1855
1856 return rc;
1857}
1858
1859/**
1860 * Deletes an audio file.
1861 *
1862 * @returns IPRT status code.
1863 * @param pFile Audio file handle to delete.
1864 */
1865int DrvAudioHlpFileDelete(PPDMAUDIOFILE pFile)
1866{
1867 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
1868
1869 int rc = RTFileDelete(pFile->szName);
1870 if (RT_SUCCESS(rc))
1871 {
1872 LogRel2(("Audio: Deleted file '%s'\n", pFile->szName));
1873 }
1874 else if (rc == VERR_FILE_NOT_FOUND) /* Don't bitch if the file is not around (anymore). */
1875 rc = VINF_SUCCESS;
1876
1877 if (RT_FAILURE(rc))
1878 LogRel(("Audio: Failed deleting file '%s', rc=%Rrc\n", pFile->szName, rc));
1879
1880 return rc;
1881}
1882
1883/**
1884 * Returns the raw audio data size of an audio file.
1885 *
1886 * Note: This does *not* include file headers and other data which does
1887 * not belong to the actual PCM audio data.
1888 *
1889 * @returns Size (in bytes) of the raw PCM audio data.
1890 * @param pFile Audio file handle to retrieve the audio data size for.
1891 */
1892size_t DrvAudioHlpFileGetDataSize(PPDMAUDIOFILE pFile)
1893{
1894 AssertPtrReturn(pFile, 0);
1895
1896 size_t cbSize = 0;
1897
1898 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)
1899 {
1900 cbSize = RTFileTell(pFile->hFile);
1901 }
1902 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)
1903 {
1904 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
1905 if (pData) /* The .WAV file data only is valid when a file actually has been created. */
1906 cbSize = pData->Hdr.u32Size2;
1907 }
1908
1909 return cbSize;
1910}
1911
1912/**
1913 * Returns whether the given audio file is open and in use or not.
1914 *
1915 * @return bool True if open, false if not.
1916 * @param pFile Audio file handle to check open status for.
1917 */
1918bool DrvAudioHlpFileIsOpen(PPDMAUDIOFILE pFile)
1919{
1920 if (!pFile)
1921 return false;
1922
1923 return RTFileIsValid(pFile->hFile);
1924}
1925
1926/**
1927 * Write PCM data to a wave (.WAV) file.
1928 *
1929 * @returns IPRT status code.
1930 * @param pFile Audio file handle to write PCM data to.
1931 * @param pvBuf Audio data to write.
1932 * @param cbBuf Size (in bytes) of audio data to write.
1933 * @param fFlags Additional write flags. Not being used at the moment and must be 0.
1934 */
1935int DrvAudioHlpFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags)
1936{
1937 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
1938 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1939
1940 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /** @todo fFlags are currently not implemented. */
1941
1942 if (!cbBuf)
1943 return VINF_SUCCESS;
1944
1945 AssertReturn(RTFileIsValid(pFile->hFile), VERR_WRONG_ORDER);
1946
1947 int rc;
1948
1949 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)
1950 {
1951 rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
1952 }
1953 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)
1954 {
1955 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
1956 AssertPtr(pData);
1957
1958 rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
1959 if (RT_SUCCESS(rc))
1960 {
1961 pData->Hdr.u32Size += (uint32_t)cbBuf;
1962 pData->Hdr.u32Size2 += (uint32_t)cbBuf;
1963 }
1964 }
1965 else
1966 rc = VERR_NOT_SUPPORTED;
1967
1968 return rc;
1969}
1970
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