VirtualBox

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

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

Audio: Moved PDMAUDIOFILE and associated stuff out of pdmaudioifs.h and into AudioHlp.h, renaming the typedefs & defines. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.8 KB
Line 
1/* $Id: AudioHlp.cpp 88357 2021-04-04 22:58:35Z 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 * @returns VBox 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 VBox 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, AUDIOHLPFILENAME_FLAGS_XXX.
324 */
325int AudioHlpFileNameGet(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName,
326 uint32_t uInstance, AUDIOHLPFILETYPE 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 & AUDIOHLPFILENAME_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 AUDIOHLPFILETYPE_RAW:
407 rc = RTStrCat(szFileName, sizeof(szFileName), ".pcm");
408 break;
409
410 case AUDIOHLPFILETYPE_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 VBox 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, AUDIOHLPFILE_FLAGS_XXX.
443 * @param ppFile Where to store the created audio file handle.
444 * Needs to be destroyed with AudioHlpFileDestroy().
445 */
446int AudioHlpFileCreate(AUDIOHLPFILETYPE enmType, const char *pszFile, uint32_t fFlags, PAUDIOHLPFILE *ppFile)
447{
448 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
449 /** @todo Validate fFlags. */
450
451 PAUDIOHLPFILE pFile = (PAUDIOHLPFILE)RTMemAlloc(sizeof(AUDIOHLPFILE));
452 if (!pFile)
453 return VERR_NO_MEMORY;
454
455 int rc = VINF_SUCCESS;
456
457 switch (enmType)
458 {
459 case AUDIOHLPFILETYPE_RAW:
460 case AUDIOHLPFILETYPE_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(PAUDIOHLPFILE 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 VBox status code.
509 * @param pFile Pointer to audio file handle to use.
510 * @param fOpen Open flags.
511 * Use AUDIOHLPFILE_DEFAULT_OPEN_FLAGS for the default open flags.
512 * @param pProps PCM properties to use.
513 */
514int AudioHlpFileOpen(PAUDIOHLPFILE 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 == AUDIOHLPFILETYPE_RAW)
524 {
525 rc = RTFileOpen(&pFile->hFile, pFile->szName, fOpen);
526 }
527 else if (pFile->enmType == AUDIOHLPFILETYPE_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 * Creates a debug file structure and opens a file for it, extended version.
589 *
590 * @returns VBox status code.
591 * @param ppFile Where to return the debug file instance on success.
592 * @param enmType The file type.
593 * @param pszDir The directory to open the file in.
594 * @param pszName The base filename.
595 * @param iInstance The device/driver instance.
596 * @param fFilename AUDIOHLPFILENAME_FLAGS_XXX.
597 * @param fCreate AUDIOHLPFILE_FLAGS_XXX.
598 * @param pProps PCM audio properties for the file.
599 * @param fOpen RTFILE_O_XXX or AUDIOHLPFILE_DEFAULT_OPEN_FLAGS.
600 */
601int AudioHlpFileCreateAndOpenEx(PAUDIOHLPFILE *ppFile, AUDIOHLPFILETYPE enmType, const char *pszDir, const char *pszName,
602 uint32_t iInstance, uint32_t fFilename, uint32_t fCreate,
603 PCPDMAUDIOPCMPROPS pProps, uint64_t fOpen)
604{
605 char szFile[RTPATH_MAX];
606 int rc = AudioHlpFileNameGet(szFile, sizeof(szFile), pszDir, pszName, iInstance, enmType, fFilename);
607 if (RT_SUCCESS(rc))
608 {
609 PAUDIOHLPFILE pFile = NULL;
610 rc = AudioHlpFileCreate(enmType, szFile, fCreate, &pFile);
611 if (RT_SUCCESS(rc))
612 {
613 rc = AudioHlpFileOpen(pFile, fOpen, pProps);
614 if (RT_SUCCESS(rc))
615 {
616 *ppFile = pFile;
617 return rc;
618 }
619 AudioHlpFileDestroy(pFile);
620 }
621 }
622 *ppFile = NULL;
623 return rc;
624}
625
626/**
627 * Creates a debug wav-file structure and opens a file for it, default flags.
628 *
629 * @returns VBox status code.
630 * @param ppFile Where to return the debug file instance on success.
631 * @param pszDir The directory to open the file in.
632 * @param pszName The base filename.
633 * @param iInstance The device/driver instance.
634 * @param pProps PCM audio properties for the file.
635 */
636int AudioHlpFileCreateAndOpen(PAUDIOHLPFILE *ppFile, const char *pszDir, const char *pszName,
637 uint32_t iInstance, PCPDMAUDIOPCMPROPS pProps)
638{
639 return AudioHlpFileCreateAndOpenEx(ppFile, AUDIOHLPFILETYPE_WAV, pszDir, pszName, iInstance,
640 AUDIOHLPFILENAME_FLAGS_NONE, AUDIOHLPFILE_FLAGS_NONE,
641 pProps, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS);
642}
643
644
645/**
646 * Closes an audio file.
647 *
648 * @returns VBox status code.
649 * @param pFile Audio file handle to close.
650 */
651int AudioHlpFileClose(PAUDIOHLPFILE pFile)
652{
653 if (!pFile)
654 return VINF_SUCCESS;
655
656 size_t cbSize = AudioHlpFileGetDataSize(pFile);
657
658 int rc = VINF_SUCCESS;
659
660 if (pFile->enmType == AUDIOHLPFILETYPE_RAW)
661 {
662 if (RTFileIsValid(pFile->hFile))
663 rc = RTFileClose(pFile->hFile);
664 }
665 else if (pFile->enmType == AUDIOHLPFILETYPE_WAV)
666 {
667 if (RTFileIsValid(pFile->hFile))
668 {
669 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
670 if (pData) /* The .WAV file data only is valid when a file actually has been created. */
671 {
672 /* Update the header with the current data size. */
673 RTFileWriteAt(pFile->hFile, 0, &pData->Hdr, sizeof(pData->Hdr), NULL);
674 }
675
676 rc = RTFileClose(pFile->hFile);
677 }
678
679 if (pFile->pvData)
680 {
681 RTMemFree(pFile->pvData);
682 pFile->pvData = NULL;
683 }
684 }
685 else
686 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
687
688 if ( RT_SUCCESS(rc)
689 && !cbSize
690 && !(pFile->fFlags & AUDIOHLPFILE_FLAGS_KEEP_IF_EMPTY))
691 {
692 rc = AudioHlpFileDelete(pFile);
693 }
694
695 pFile->cbData = 0;
696
697 if (RT_SUCCESS(rc))
698 {
699 pFile->hFile = NIL_RTFILE;
700 LogRel2(("Audio: Closed file '%s' (%zu bytes)\n", pFile->szName, cbSize));
701 }
702 else
703 LogRel(("Audio: Failed closing file '%s', rc=%Rrc\n", pFile->szName, rc));
704
705 return rc;
706}
707
708/**
709 * Deletes an audio file.
710 *
711 * @returns VBox status code.
712 * @param pFile Audio file handle to delete.
713 */
714int AudioHlpFileDelete(PAUDIOHLPFILE pFile)
715{
716 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
717
718 int rc = RTFileDelete(pFile->szName);
719 if (RT_SUCCESS(rc))
720 {
721 LogRel2(("Audio: Deleted file '%s'\n", pFile->szName));
722 }
723 else if (rc == VERR_FILE_NOT_FOUND) /* Don't bitch if the file is not around (anymore). */
724 rc = VINF_SUCCESS;
725
726 if (RT_FAILURE(rc))
727 LogRel(("Audio: Failed deleting file '%s', rc=%Rrc\n", pFile->szName, rc));
728
729 return rc;
730}
731
732/**
733 * Returns the raw audio data size of an audio file.
734 *
735 * Note: This does *not* include file headers and other data which does
736 * not belong to the actual PCM audio data.
737 *
738 * @returns Size (in bytes) of the raw PCM audio data.
739 * @param pFile Audio file handle to retrieve the audio data size for.
740 */
741size_t AudioHlpFileGetDataSize(PAUDIOHLPFILE pFile)
742{
743 AssertPtrReturn(pFile, 0);
744
745 size_t cbSize = 0;
746
747 if (pFile->enmType == AUDIOHLPFILETYPE_RAW)
748 {
749 cbSize = RTFileTell(pFile->hFile);
750 }
751 else if (pFile->enmType == AUDIOHLPFILETYPE_WAV)
752 {
753 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
754 if (pData) /* The .WAV file data only is valid when a file actually has been created. */
755 cbSize = pData->Hdr.u32Size2;
756 }
757
758 return cbSize;
759}
760
761/**
762 * Returns whether the given audio file is open and in use or not.
763 *
764 * @return bool True if open, false if not.
765 * @param pFile Audio file handle to check open status for.
766 */
767bool AudioHlpFileIsOpen(PAUDIOHLPFILE pFile)
768{
769 if (!pFile)
770 return false;
771
772 return RTFileIsValid(pFile->hFile);
773}
774
775/**
776 * Write PCM data to a wave (.WAV) file.
777 *
778 * @returns VBox status code.
779 * @param pFile Audio file handle to write PCM data to.
780 * @param pvBuf Audio data to write.
781 * @param cbBuf Size (in bytes) of audio data to write.
782 * @param fFlags Additional write flags. Not being used at the moment and must be 0.
783 */
784int AudioHlpFileWrite(PAUDIOHLPFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags)
785{
786 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
787 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
788
789 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /** @todo fFlags are currently not implemented. */
790
791 if (!cbBuf)
792 return VINF_SUCCESS;
793
794 AssertReturn(RTFileIsValid(pFile->hFile), VERR_WRONG_ORDER);
795
796 int rc;
797
798 if (pFile->enmType == AUDIOHLPFILETYPE_RAW)
799 {
800 rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
801 }
802 else if (pFile->enmType == AUDIOHLPFILETYPE_WAV)
803 {
804 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
805 AssertPtr(pData);
806
807 rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
808 if (RT_SUCCESS(rc))
809 {
810 pData->Hdr.u32Size += (uint32_t)cbBuf;
811 pData->Hdr.u32Size2 += (uint32_t)cbBuf;
812 }
813 }
814 else
815 rc = VERR_NOT_SUPPORTED;
816
817 return rc;
818}
819
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