VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/AudioHlp.cpp@ 88288

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

Audio: Made sure PDMAUDIOPCMPROPS is initialized using a helper function or the initializer macro, and that vital changes are made using setting helper functions. There are now two derived fields (frame size and shift count) that must be maintained, so this was the sanest way of doing it. Added a raw flag to PDMAUDIOPCMPROPS for VRDE/VRDP, since it wants the raw mixer content and we need a way of expressing this (PDMAUDIOSTREAMLAYOUT isn't the right place). The mixer buffers now uses PDMAUDIOPCMPROPS rather than the weird 32-bit format contraption for picking conversion functions. Simplify the drvAudioStreamPlay code by eliminating the PDMAUDIOSTREAMLAYOUT_RAW special case. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.5 KB
Line 
1/* $Id: AudioHlp.cpp 88269 2021-03-24 11:45:54Z vboxsync $ */
2/** @file
3 * Audio helper routines.
4 *
5 * These are used with both drivers and devices.
6 */
7
8/*
9 * Copyright (C) 2006-2020 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#include <iprt/alloc.h>
25#include <iprt/asm-math.h>
26#include <iprt/assert.h>
27#include <iprt/dir.h>
28#include <iprt/file.h>
29#include <iprt/string.h>
30#include <iprt/uuid.h>
31
32#define LOG_GROUP LOG_GROUP_DRV_AUDIO
33#include <VBox/log.h>
34
35#include <VBox/err.h>
36#include <VBox/vmm/pdmdev.h>
37#include <VBox/vmm/pdm.h>
38#include <VBox/vmm/pdmaudioinline.h>
39#include <VBox/vmm/mm.h>
40
41#include <ctype.h>
42#include <stdlib.h>
43
44#include "AudioHlp.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#if 0 /* unused, no header prototypes */
86
87/**
88 * Retrieves the matching PDMAUDIOFMT for the given bits + signing flag.
89 *
90 * @return Matching PDMAUDIOFMT value.
91 * @retval PDMAUDIOFMT_INVALID if unsupported @a cBits value.
92 *
93 * @param cBits The number of bits in the audio format.
94 * @param fSigned Whether the audio format is signed @c true or not.
95 */
96PDMAUDIOFMT DrvAudioAudFmtBitsToFormat(uint8_t cBits, bool fSigned)
97{
98 if (fSigned)
99 {
100 switch (cBits)
101 {
102 case 8: return PDMAUDIOFMT_S8;
103 case 16: return PDMAUDIOFMT_S16;
104 case 32: return PDMAUDIOFMT_S32;
105 default: AssertMsgFailedReturn(("Bogus audio bits %RU8\n", cBits), PDMAUDIOFMT_INVALID);
106 }
107 }
108 else
109 {
110 switch (cBits)
111 {
112 case 8: return PDMAUDIOFMT_U8;
113 case 16: return PDMAUDIOFMT_U16;
114 case 32: return PDMAUDIOFMT_U32;
115 default: AssertMsgFailedReturn(("Bogus audio bits %RU8\n", cBits), PDMAUDIOFMT_INVALID);
116 }
117 }
118}
119
120/**
121 * Returns an unique file name for this given audio connector instance.
122 *
123 * @return Allocated file name. Must be free'd using RTStrFree().
124 * @param uInstance Driver / device instance.
125 * @param pszPath Path name of the file to delete. The path must exist.
126 * @param pszSuffix File name suffix to use.
127 */
128char *DrvAudioDbgGetFileNameA(uint8_t uInstance, const char *pszPath, const char *pszSuffix)
129{
130 char szFileName[64];
131 RTStrPrintf(szFileName, sizeof(szFileName), "drvAudio%RU8-%s", uInstance, pszSuffix);
132
133 char szFilePath[RTPATH_MAX];
134 int rc2 = RTStrCopy(szFilePath, sizeof(szFilePath), pszPath);
135 AssertRC(rc2);
136 rc2 = RTPathAppend(szFilePath, sizeof(szFilePath), szFileName);
137 AssertRC(rc2);
138
139 return RTStrDup(szFilePath);
140}
141
142#endif /* unused */
143
144/**
145 * Converts a given string to an audio format.
146 *
147 * @returns Audio format for the given string, or PDMAUDIOFMT_INVALID if not found.
148 * @param pszFmt String to convert to an audio format.
149 */
150PDMAUDIOFMT AudioHlpStrToAudFmt(const char *pszFmt)
151{
152 AssertPtrReturn(pszFmt, PDMAUDIOFMT_INVALID);
153
154 if (!RTStrICmp(pszFmt, "u8"))
155 return PDMAUDIOFMT_U8;
156 if (!RTStrICmp(pszFmt, "u16"))
157 return PDMAUDIOFMT_U16;
158 if (!RTStrICmp(pszFmt, "u32"))
159 return PDMAUDIOFMT_U32;
160 if (!RTStrICmp(pszFmt, "s8"))
161 return PDMAUDIOFMT_S8;
162 if (!RTStrICmp(pszFmt, "s16"))
163 return PDMAUDIOFMT_S16;
164 if (!RTStrICmp(pszFmt, "s32"))
165 return PDMAUDIOFMT_S32;
166
167 AssertMsgFailed(("Invalid audio format '%s'\n", pszFmt));
168 return PDMAUDIOFMT_INVALID;
169}
170
171/**
172 * Checks whether a given stream configuration is valid or not.
173 *
174 * @note See notes on AudioHlpPcmPropsAreValid().
175 *
176 * Returns @c true if configuration is valid, @c false if not.
177 * @param pCfg Stream configuration to check.
178 */
179bool AudioHlpStreamCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg)
180{
181 /* Ugly! HDA attach code calls us with uninitialized (all zero) config. */
182 if ( pCfg->enmLayout != PDMAUDIOSTREAMLAYOUT_INVALID
183 || PDMAudioPropsHz(&pCfg->Props) != 0)
184 {
185 if (PDMAudioStrmCfgIsValid(pCfg))
186 {
187 if ( pCfg->enmDir == PDMAUDIODIR_IN
188 || pCfg->enmDir == PDMAUDIODIR_OUT)
189 {
190 if ( pCfg->enmLayout == PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED
191 || pCfg->enmLayout == PDMAUDIOSTREAMLAYOUT_RAW)
192 return AudioHlpPcmPropsAreValid(&pCfg->Props);
193 }
194 }
195 }
196 return false;
197}
198
199/**
200 * Calculates the audio bit rate of the given bits per sample, the Hz and the number
201 * of audio channels.
202 *
203 * Divide the result by 8 to get the byte rate.
204 *
205 * @returns Bitrate.
206 * @param cBits Number of bits per sample.
207 * @param uHz Hz (Hertz) rate.
208 * @param cChannels Number of audio channels.
209 */
210uint32_t AudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels)
211{
212 return cBits * uHz * cChannels;
213}
214
215
216/**
217 * Checks whether given PCM properties are valid or not.
218 *
219 * @note This is more of a supported than valid check. There is code for
220 * unsigned samples elsewhere (like DrvAudioHlpClearBuf()), but this
221 * function will flag such properties as not valid.
222 *
223 * @todo r=bird: See note and explain properly. Perhaps rename to
224 * AudioHlpPcmPropsAreValidAndSupported?
225 *
226 * @returns @c true if the properties are valid, @c false if not.
227 * @param pProps The PCM properties to check.
228 */
229bool AudioHlpPcmPropsAreValid(PCPDMAUDIOPCMPROPS pProps)
230{
231 AssertPtrReturn(pProps, false);
232 AssertReturn(PDMAudioPropsAreValid(pProps), false);
233
234 /* Minimum 1 channel (mono), maximum 7.1 (= 8) channels. */
235 if (PDMAudioPropsChannels(pProps) >= 1 && PDMAudioPropsChannels(pProps) <= 8)
236 {
237 switch (PDMAudioPropsSampleSize(pProps))
238 {
239 case 1: /* 8 bit */
240 if (PDMAudioPropsIsSigned(pProps))
241 return false;
242 break;
243 case 2: /* 16 bit */
244 if (!PDMAudioPropsIsSigned(pProps))
245 return false;
246 break;
247 /** @todo Do we need support for 24 bit samples? */
248 case 4: /* 32 bit */
249 if (!PDMAudioPropsIsSigned(pProps))
250 return false;
251 break;
252 case 8: /* 64-bit raw */
253 if ( !PDMAudioPropsIsSigned(pProps)
254 || !pProps->fRaw)
255 return false;
256 break;
257 default:
258 return false;
259 }
260
261 if (pProps->uHz > 0)
262 {
263 if (!pProps->fSwapEndian) /** @todo Handling Big Endian audio data is not supported yet. */
264 return true;
265 }
266 }
267 return false;
268}
269
270
271/*********************************************************************************************************************************
272* Audio File Helpers *
273*********************************************************************************************************************************/
274
275/**
276 * Sanitizes the file name component so that unsupported characters
277 * will be replaced by an underscore ("_").
278 *
279 * @return IPRT status code.
280 * @param pszPath Path to sanitize.
281 * @param cbPath Size (in bytes) of path to sanitize.
282 */
283int AudioHlpFileNameSanitize(char *pszPath, size_t cbPath)
284{
285 RT_NOREF(cbPath);
286 int rc = VINF_SUCCESS;
287#ifdef RT_OS_WINDOWS
288 /* Filter out characters not allowed on Windows platforms, put in by
289 RTTimeSpecToString(). */
290 /** @todo Use something like RTPathSanitize() if available later some time. */
291 static RTUNICP const s_uszValidRangePairs[] =
292 {
293 ' ', ' ',
294 '(', ')',
295 '-', '.',
296 '0', '9',
297 'A', 'Z',
298 'a', 'z',
299 '_', '_',
300 0xa0, 0xd7af,
301 '\0'
302 };
303 ssize_t cReplaced = RTStrPurgeComplementSet(pszPath, s_uszValidRangePairs, '_' /* Replacement */);
304 if (cReplaced < 0)
305 rc = VERR_INVALID_UTF8_ENCODING;
306#else
307 RT_NOREF(pszPath);
308#endif
309 return rc;
310}
311
312/**
313 * Constructs an unique file name, based on the given path and the audio file type.
314 *
315 * @returns IPRT status code.
316 * @param pszFile Where to store the constructed file name.
317 * @param cchFile Size (in characters) of the file name buffer.
318 * @param pszPath Base path to use.
319 * If NULL or empty, the system's temporary directory will be used.
320 * @param pszName A name for better identifying the file.
321 * @param uInstance Device / driver instance which is using this file.
322 * @param enmType Audio file type to construct file name for.
323 * @param fFlags File naming flags, PDMAUDIOFILENAME_FLAGS_XXX.
324 */
325int AudioHlpFileNameGet(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName,
326 uint32_t uInstance, PDMAUDIOFILETYPE enmType, uint32_t fFlags)
327{
328 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
329 AssertReturn(cchFile, VERR_INVALID_PARAMETER);
330 /* pszPath can be NULL. */
331 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
332 /** @todo Validate fFlags. */
333
334 int rc;
335
336 char *pszPathTmp = NULL;
337
338 do
339 {
340 if ( pszPath == NULL
341 || !strlen(pszPath))
342 {
343 char szTemp[RTPATH_MAX];
344 rc = RTPathTemp(szTemp, sizeof(szTemp));
345 if (RT_SUCCESS(rc))
346 {
347 pszPathTmp = RTStrDup(szTemp);
348 }
349 else
350 break;
351 }
352 else
353 pszPathTmp = RTStrDup(pszPath);
354
355 AssertPtrBreakStmt(pszPathTmp, rc = VERR_NO_MEMORY);
356
357 char szFilePath[RTPATH_MAX];
358 rc = RTStrCopy(szFilePath, sizeof(szFilePath), pszPathTmp);
359 AssertRCBreak(rc);
360
361 /* Create it when necessary. */
362 if (!RTDirExists(szFilePath))
363 {
364 rc = RTDirCreateFullPath(szFilePath, RTFS_UNIX_IRWXU);
365 if (RT_FAILURE(rc))
366 break;
367 }
368
369 char szFileName[RTPATH_MAX];
370 szFileName[0] = '\0';
371
372 if (fFlags & PDMAUDIOFILENAME_FLAGS_TS)
373 {
374 RTTIMESPEC time;
375 if (!RTTimeSpecToString(RTTimeNow(&time), szFileName, sizeof(szFileName)))
376 {
377 rc = VERR_BUFFER_OVERFLOW;
378 break;
379 }
380
381 rc = AudioHlpFileNameSanitize(szFileName, sizeof(szFileName));
382 if (RT_FAILURE(rc))
383 break;
384
385 rc = RTStrCat(szFileName, sizeof(szFileName), "-");
386 if (RT_FAILURE(rc))
387 break;
388 }
389
390 rc = RTStrCat(szFileName, sizeof(szFileName), pszName);
391 if (RT_FAILURE(rc))
392 break;
393
394 rc = RTStrCat(szFileName, sizeof(szFileName), "-");
395 if (RT_FAILURE(rc))
396 break;
397
398 char szInst[16];
399 RTStrPrintf2(szInst, sizeof(szInst), "%RU32", uInstance);
400 rc = RTStrCat(szFileName, sizeof(szFileName), szInst);
401 if (RT_FAILURE(rc))
402 break;
403
404 switch (enmType)
405 {
406 case PDMAUDIOFILETYPE_RAW:
407 rc = RTStrCat(szFileName, sizeof(szFileName), ".pcm");
408 break;
409
410 case PDMAUDIOFILETYPE_WAV:
411 rc = RTStrCat(szFileName, sizeof(szFileName), ".wav");
412 break;
413
414 default:
415 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
416 break;
417 }
418
419 if (RT_FAILURE(rc))
420 break;
421
422 rc = RTPathAppend(szFilePath, sizeof(szFilePath), szFileName);
423 if (RT_FAILURE(rc))
424 break;
425
426 rc = RTStrCopy(pszFile, cchFile, szFilePath);
427
428 } while (0);
429
430 RTStrFree(pszPathTmp);
431
432 LogFlowFuncLeaveRC(rc);
433 return rc;
434}
435
436/**
437 * Creates an audio file.
438 *
439 * @returns IPRT status code.
440 * @param enmType Audio file type to open / create.
441 * @param pszFile File path of file to open or create.
442 * @param fFlags Audio file flags, PDMAUDIOFILE_FLAGS_XXX.
443 * @param ppFile Where to store the created audio file handle.
444 * Needs to be destroyed with AudioHlpFileDestroy().
445 */
446int AudioHlpFileCreate(PDMAUDIOFILETYPE enmType, const char *pszFile, uint32_t fFlags, PPDMAUDIOFILE *ppFile)
447{
448 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
449 /** @todo Validate fFlags. */
450
451 PPDMAUDIOFILE pFile = (PPDMAUDIOFILE)RTMemAlloc(sizeof(PDMAUDIOFILE));
452 if (!pFile)
453 return VERR_NO_MEMORY;
454
455 int rc = VINF_SUCCESS;
456
457 switch (enmType)
458 {
459 case PDMAUDIOFILETYPE_RAW:
460 case PDMAUDIOFILETYPE_WAV:
461 pFile->enmType = enmType;
462 break;
463
464 default:
465 rc = VERR_INVALID_PARAMETER;
466 break;
467 }
468
469 if (RT_SUCCESS(rc))
470 {
471 RTStrPrintf(pFile->szName, RT_ELEMENTS(pFile->szName), "%s", pszFile);
472 pFile->hFile = NIL_RTFILE;
473 pFile->fFlags = fFlags;
474 pFile->pvData = NULL;
475 pFile->cbData = 0;
476 }
477
478 if (RT_FAILURE(rc))
479 {
480 RTMemFree(pFile);
481 pFile = NULL;
482 }
483 else
484 *ppFile = pFile;
485
486 return rc;
487}
488
489/**
490 * Destroys a formerly created audio file.
491 *
492 * @param pFile Audio file (object) to destroy.
493 */
494void AudioHlpFileDestroy(PPDMAUDIOFILE pFile)
495{
496 if (!pFile)
497 return;
498
499 AudioHlpFileClose(pFile);
500
501 RTMemFree(pFile);
502 pFile = NULL;
503}
504
505/**
506 * Opens or creates an audio file.
507 *
508 * @returns IPRT status code.
509 * @param pFile Pointer to audio file handle to use.
510 * @param fOpen Open flags.
511 * Use PDMAUDIOFILE_DEFAULT_OPEN_FLAGS for the default open flags.
512 * @param pProps PCM properties to use.
513 */
514int AudioHlpFileOpen(PPDMAUDIOFILE pFile, uint32_t fOpen, PCPDMAUDIOPCMPROPS pProps)
515{
516 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
517 /** @todo Validate fOpen flags. */
518 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
519 Assert(PDMAudioPropsAreValid(pProps));
520
521 int rc;
522
523 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)
524 {
525 rc = RTFileOpen(&pFile->hFile, pFile->szName, fOpen);
526 }
527 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)
528 {
529 pFile->pvData = (PAUDIOWAVFILEDATA)RTMemAllocZ(sizeof(AUDIOWAVFILEDATA));
530 if (pFile->pvData)
531 {
532 pFile->cbData = sizeof(PAUDIOWAVFILEDATA);
533
534 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
535 AssertPtr(pData);
536
537 /* Header. */
538 pData->Hdr.u32RIFF = AUDIO_MAKE_FOURCC('R','I','F','F');
539 pData->Hdr.u32Size = 36;
540 pData->Hdr.u32WAVE = AUDIO_MAKE_FOURCC('W','A','V','E');
541
542 pData->Hdr.u32Fmt = AUDIO_MAKE_FOURCC('f','m','t',' ');
543 pData->Hdr.u32Size1 = 16; /* Means PCM. */
544 pData->Hdr.u16AudioFormat = 1; /* PCM, linear quantization. */
545 pData->Hdr.u16NumChannels = PDMAudioPropsChannels(pProps);
546 pData->Hdr.u32SampleRate = pProps->uHz;
547 pData->Hdr.u32ByteRate = PDMAudioPropsGetBitrate(pProps) / 8;
548 pData->Hdr.u16BlockAlign = PDMAudioPropsFrameSize(pProps);
549 pData->Hdr.u16BitsPerSample = PDMAudioPropsSampleBits(pProps);
550
551 /* Data chunk. */
552 pData->Hdr.u32ID2 = AUDIO_MAKE_FOURCC('d','a','t','a');
553 pData->Hdr.u32Size2 = 0;
554
555 rc = RTFileOpen(&pFile->hFile, pFile->szName, fOpen);
556 if (RT_SUCCESS(rc))
557 {
558 rc = RTFileWrite(pFile->hFile, &pData->Hdr, sizeof(pData->Hdr), NULL);
559 if (RT_FAILURE(rc))
560 {
561 RTFileClose(pFile->hFile);
562 pFile->hFile = NIL_RTFILE;
563 }
564 }
565
566 if (RT_FAILURE(rc))
567 {
568 RTMemFree(pFile->pvData);
569 pFile->pvData = NULL;
570 pFile->cbData = 0;
571 }
572 }
573 else
574 rc = VERR_NO_MEMORY;
575 }
576 else
577 rc = VERR_INVALID_PARAMETER;
578
579 if (RT_SUCCESS(rc))
580 LogRel2(("Audio: Opened file '%s'\n", pFile->szName));
581 else
582 LogRel(("Audio: Failed opening file '%s', rc=%Rrc\n", pFile->szName, rc));
583
584 return rc;
585}
586
587/**
588 * Closes an audio file.
589 *
590 * @returns IPRT status code.
591 * @param pFile Audio file handle to close.
592 */
593int AudioHlpFileClose(PPDMAUDIOFILE pFile)
594{
595 if (!pFile)
596 return VINF_SUCCESS;
597
598 size_t cbSize = AudioHlpFileGetDataSize(pFile);
599
600 int rc = VINF_SUCCESS;
601
602 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)
603 {
604 if (RTFileIsValid(pFile->hFile))
605 rc = RTFileClose(pFile->hFile);
606 }
607 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)
608 {
609 if (RTFileIsValid(pFile->hFile))
610 {
611 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
612 if (pData) /* The .WAV file data only is valid when a file actually has been created. */
613 {
614 /* Update the header with the current data size. */
615 RTFileWriteAt(pFile->hFile, 0, &pData->Hdr, sizeof(pData->Hdr), NULL);
616 }
617
618 rc = RTFileClose(pFile->hFile);
619 }
620
621 if (pFile->pvData)
622 {
623 RTMemFree(pFile->pvData);
624 pFile->pvData = NULL;
625 }
626 }
627 else
628 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
629
630 if ( RT_SUCCESS(rc)
631 && !cbSize
632 && !(pFile->fFlags & PDMAUDIOFILE_FLAGS_KEEP_IF_EMPTY))
633 {
634 rc = AudioHlpFileDelete(pFile);
635 }
636
637 pFile->cbData = 0;
638
639 if (RT_SUCCESS(rc))
640 {
641 pFile->hFile = NIL_RTFILE;
642 LogRel2(("Audio: Closed file '%s' (%zu bytes)\n", pFile->szName, cbSize));
643 }
644 else
645 LogRel(("Audio: Failed closing file '%s', rc=%Rrc\n", pFile->szName, rc));
646
647 return rc;
648}
649
650/**
651 * Deletes an audio file.
652 *
653 * @returns IPRT status code.
654 * @param pFile Audio file handle to delete.
655 */
656int AudioHlpFileDelete(PPDMAUDIOFILE pFile)
657{
658 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
659
660 int rc = RTFileDelete(pFile->szName);
661 if (RT_SUCCESS(rc))
662 {
663 LogRel2(("Audio: Deleted file '%s'\n", pFile->szName));
664 }
665 else if (rc == VERR_FILE_NOT_FOUND) /* Don't bitch if the file is not around (anymore). */
666 rc = VINF_SUCCESS;
667
668 if (RT_FAILURE(rc))
669 LogRel(("Audio: Failed deleting file '%s', rc=%Rrc\n", pFile->szName, rc));
670
671 return rc;
672}
673
674/**
675 * Returns the raw audio data size of an audio file.
676 *
677 * Note: This does *not* include file headers and other data which does
678 * not belong to the actual PCM audio data.
679 *
680 * @returns Size (in bytes) of the raw PCM audio data.
681 * @param pFile Audio file handle to retrieve the audio data size for.
682 */
683size_t AudioHlpFileGetDataSize(PPDMAUDIOFILE pFile)
684{
685 AssertPtrReturn(pFile, 0);
686
687 size_t cbSize = 0;
688
689 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)
690 {
691 cbSize = RTFileTell(pFile->hFile);
692 }
693 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)
694 {
695 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
696 if (pData) /* The .WAV file data only is valid when a file actually has been created. */
697 cbSize = pData->Hdr.u32Size2;
698 }
699
700 return cbSize;
701}
702
703/**
704 * Returns whether the given audio file is open and in use or not.
705 *
706 * @return bool True if open, false if not.
707 * @param pFile Audio file handle to check open status for.
708 */
709bool AudioHlpFileIsOpen(PPDMAUDIOFILE pFile)
710{
711 if (!pFile)
712 return false;
713
714 return RTFileIsValid(pFile->hFile);
715}
716
717/**
718 * Write PCM data to a wave (.WAV) file.
719 *
720 * @returns IPRT status code.
721 * @param pFile Audio file handle to write PCM data to.
722 * @param pvBuf Audio data to write.
723 * @param cbBuf Size (in bytes) of audio data to write.
724 * @param fFlags Additional write flags. Not being used at the moment and must be 0.
725 */
726int AudioHlpFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags)
727{
728 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
729 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
730
731 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /** @todo fFlags are currently not implemented. */
732
733 if (!cbBuf)
734 return VINF_SUCCESS;
735
736 AssertReturn(RTFileIsValid(pFile->hFile), VERR_WRONG_ORDER);
737
738 int rc;
739
740 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)
741 {
742 rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
743 }
744 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)
745 {
746 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
747 AssertPtr(pData);
748
749 rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
750 if (RT_SUCCESS(rc))
751 {
752 pData->Hdr.u32Size += (uint32_t)cbBuf;
753 pData->Hdr.u32Size2 += (uint32_t)cbBuf;
754 }
755 }
756 else
757 rc = VERR_NOT_SUPPORTED;
758
759 return rc;
760}
761
Note: See TracBrowser for help on using the repository browser.

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