VirtualBox

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

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

AudioHlp/AudioHlpStreamCfgIsValid: Don't be difficult about the enmLayout. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.0 KB
Line 
1/* $Id: AudioHlp.cpp 89062 2021-05-16 19:57:58Z 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 /* As stated elsewhere, the following is non-sense and must be eliminated. */
191 if ( pCfg->enmLayout == PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED
192 || pCfg->enmLayout == PDMAUDIOSTREAMLAYOUT_INTERLEAVED
193 || pCfg->enmLayout == PDMAUDIOSTREAMLAYOUT_RAW)
194 return AudioHlpPcmPropsAreValid(&pCfg->Props);
195 }
196 }
197 }
198 return false;
199}
200
201/**
202 * Calculates the audio bit rate of the given bits per sample, the Hz and the number
203 * of audio channels.
204 *
205 * Divide the result by 8 to get the byte rate.
206 *
207 * @returns Bitrate.
208 * @param cBits Number of bits per sample.
209 * @param uHz Hz (Hertz) rate.
210 * @param cChannels Number of audio channels.
211 */
212uint32_t AudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels)
213{
214 return cBits * uHz * cChannels;
215}
216
217
218/**
219 * Checks whether given PCM properties are valid or not.
220 *
221 * @note This is more of a supported than valid check. There is code for
222 * unsigned samples elsewhere (like DrvAudioHlpClearBuf()), but this
223 * function will flag such properties as not valid.
224 *
225 * @todo r=bird: See note and explain properly. Perhaps rename to
226 * AudioHlpPcmPropsAreValidAndSupported?
227 *
228 * @returns @c true if the properties are valid, @c false if not.
229 * @param pProps The PCM properties to check.
230 */
231bool AudioHlpPcmPropsAreValid(PCPDMAUDIOPCMPROPS pProps)
232{
233 AssertPtrReturn(pProps, false);
234 AssertReturn(PDMAudioPropsAreValid(pProps), false);
235
236 /* Minimum 1 channel (mono), maximum 7.1 (= 8) channels. */
237 if (PDMAudioPropsChannels(pProps) >= 1 && PDMAudioPropsChannels(pProps) <= 8)
238 {
239 switch (PDMAudioPropsSampleSize(pProps))
240 {
241 case 1: /* 8 bit */
242 if (PDMAudioPropsIsSigned(pProps))
243 return false;
244 break;
245 case 2: /* 16 bit */
246 if (!PDMAudioPropsIsSigned(pProps))
247 return false;
248 break;
249 /** @todo Do we need support for 24 bit samples? */
250 case 4: /* 32 bit */
251 if (!PDMAudioPropsIsSigned(pProps))
252 return false;
253 break;
254 case 8: /* 64-bit raw */
255 if ( !PDMAudioPropsIsSigned(pProps)
256 || !pProps->fRaw)
257 return false;
258 break;
259 default:
260 return false;
261 }
262
263 if (pProps->uHz > 0)
264 {
265 if (!pProps->fSwapEndian) /** @todo Handling Big Endian audio data is not supported yet. */
266 return true;
267 }
268 }
269 return false;
270}
271
272
273/*********************************************************************************************************************************
274* Audio File Helpers *
275*********************************************************************************************************************************/
276
277/**
278 * Sanitizes the file name component so that unsupported characters
279 * will be replaced by an underscore ("_").
280 *
281 * @returns VBox status code.
282 * @param pszPath Path to sanitize.
283 * @param cbPath Size (in bytes) of path to sanitize.
284 */
285int AudioHlpFileNameSanitize(char *pszPath, size_t cbPath)
286{
287 RT_NOREF(cbPath);
288 int rc = VINF_SUCCESS;
289#ifdef RT_OS_WINDOWS
290 /* Filter out characters not allowed on Windows platforms, put in by
291 RTTimeSpecToString(). */
292 /** @todo Use something like RTPathSanitize() if available later some time. */
293 static RTUNICP const s_uszValidRangePairs[] =
294 {
295 ' ', ' ',
296 '(', ')',
297 '-', '.',
298 '0', '9',
299 'A', 'Z',
300 'a', 'z',
301 '_', '_',
302 0xa0, 0xd7af,
303 '\0'
304 };
305 ssize_t cReplaced = RTStrPurgeComplementSet(pszPath, s_uszValidRangePairs, '_' /* Replacement */);
306 if (cReplaced < 0)
307 rc = VERR_INVALID_UTF8_ENCODING;
308#else
309 RT_NOREF(pszPath);
310#endif
311 return rc;
312}
313
314/**
315 * Constructs an unique file name, based on the given path and the audio file type.
316 *
317 * @returns VBox status code.
318 * @param pszFile Where to store the constructed file name.
319 * @param cchFile Size (in characters) of the file name buffer.
320 * @param pszPath Base path to use.
321 * If NULL or empty, the system's temporary directory will be used.
322 * @param pszName A name for better identifying the file.
323 * @param uInstance Device / driver instance which is using this file.
324 * @param enmType Audio file type to construct file name for.
325 * @param fFlags File naming flags, AUDIOHLPFILENAME_FLAGS_XXX.
326 */
327int AudioHlpFileNameGet(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName,
328 uint32_t uInstance, AUDIOHLPFILETYPE enmType, uint32_t fFlags)
329{
330 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
331 AssertReturn(cchFile, VERR_INVALID_PARAMETER);
332 /* pszPath can be NULL. */
333 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
334 /** @todo Validate fFlags. */
335
336 int rc;
337
338 char *pszPathTmp = NULL;
339
340 do
341 {
342 if ( pszPath == NULL
343 || !strlen(pszPath))
344 {
345 char szTemp[RTPATH_MAX];
346 rc = RTPathTemp(szTemp, sizeof(szTemp));
347 if (RT_SUCCESS(rc))
348 {
349 pszPathTmp = RTStrDup(szTemp);
350 }
351 else
352 break;
353 }
354 else
355 pszPathTmp = RTStrDup(pszPath);
356
357 AssertPtrBreakStmt(pszPathTmp, rc = VERR_NO_MEMORY);
358
359 char szFilePath[RTPATH_MAX];
360 rc = RTStrCopy(szFilePath, sizeof(szFilePath), pszPathTmp);
361 AssertRCBreak(rc);
362
363 /* Create it when necessary. */
364 if (!RTDirExists(szFilePath))
365 {
366 rc = RTDirCreateFullPath(szFilePath, RTFS_UNIX_IRWXU);
367 if (RT_FAILURE(rc))
368 break;
369 }
370
371 char szFileName[RTPATH_MAX];
372 szFileName[0] = '\0';
373
374 if (fFlags & AUDIOHLPFILENAME_FLAGS_TS)
375 {
376 RTTIMESPEC time;
377 if (!RTTimeSpecToString(RTTimeNow(&time), szFileName, sizeof(szFileName)))
378 {
379 rc = VERR_BUFFER_OVERFLOW;
380 break;
381 }
382
383 rc = AudioHlpFileNameSanitize(szFileName, sizeof(szFileName));
384 if (RT_FAILURE(rc))
385 break;
386
387 rc = RTStrCat(szFileName, sizeof(szFileName), "-");
388 if (RT_FAILURE(rc))
389 break;
390 }
391
392 rc = RTStrCat(szFileName, sizeof(szFileName), pszName);
393 if (RT_FAILURE(rc))
394 break;
395
396 rc = RTStrCat(szFileName, sizeof(szFileName), "-");
397 if (RT_FAILURE(rc))
398 break;
399
400 char szInst[16];
401 RTStrPrintf2(szInst, sizeof(szInst), "%RU32", uInstance);
402 rc = RTStrCat(szFileName, sizeof(szFileName), szInst);
403 if (RT_FAILURE(rc))
404 break;
405
406 switch (enmType)
407 {
408 case AUDIOHLPFILETYPE_RAW:
409 rc = RTStrCat(szFileName, sizeof(szFileName), ".pcm");
410 break;
411
412 case AUDIOHLPFILETYPE_WAV:
413 rc = RTStrCat(szFileName, sizeof(szFileName), ".wav");
414 break;
415
416 default:
417 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
418 break;
419 }
420
421 if (RT_FAILURE(rc))
422 break;
423
424 rc = RTPathAppend(szFilePath, sizeof(szFilePath), szFileName);
425 if (RT_FAILURE(rc))
426 break;
427
428 rc = RTStrCopy(pszFile, cchFile, szFilePath);
429
430 } while (0);
431
432 RTStrFree(pszPathTmp);
433
434 LogFlowFuncLeaveRC(rc);
435 return rc;
436}
437
438/**
439 * Creates an audio file.
440 *
441 * @returns VBox status code.
442 * @param enmType Audio file type to open / create.
443 * @param pszFile File path of file to open or create.
444 * @param fFlags Audio file flags, AUDIOHLPFILE_FLAGS_XXX.
445 * @param ppFile Where to store the created audio file handle.
446 * Needs to be destroyed with AudioHlpFileDestroy().
447 */
448int AudioHlpFileCreate(AUDIOHLPFILETYPE enmType, const char *pszFile, uint32_t fFlags, PAUDIOHLPFILE *ppFile)
449{
450 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
451 /** @todo Validate fFlags. */
452
453 PAUDIOHLPFILE pFile = (PAUDIOHLPFILE)RTMemAlloc(sizeof(AUDIOHLPFILE));
454 if (!pFile)
455 return VERR_NO_MEMORY;
456
457 int rc = VINF_SUCCESS;
458
459 switch (enmType)
460 {
461 case AUDIOHLPFILETYPE_RAW:
462 case AUDIOHLPFILETYPE_WAV:
463 pFile->enmType = enmType;
464 break;
465
466 default:
467 rc = VERR_INVALID_PARAMETER;
468 break;
469 }
470
471 if (RT_SUCCESS(rc))
472 {
473 RTStrPrintf(pFile->szName, RT_ELEMENTS(pFile->szName), "%s", pszFile);
474 pFile->hFile = NIL_RTFILE;
475 pFile->fFlags = fFlags;
476 pFile->pvData = NULL;
477 pFile->cbData = 0;
478 }
479
480 if (RT_FAILURE(rc))
481 {
482 RTMemFree(pFile);
483 pFile = NULL;
484 }
485 else
486 *ppFile = pFile;
487
488 return rc;
489}
490
491/**
492 * Destroys a formerly created audio file.
493 *
494 * @param pFile Audio file (object) to destroy.
495 */
496void AudioHlpFileDestroy(PAUDIOHLPFILE pFile)
497{
498 if (!pFile)
499 return;
500
501 AudioHlpFileClose(pFile);
502
503 RTMemFree(pFile);
504 pFile = NULL;
505}
506
507/**
508 * Opens or creates an audio file.
509 *
510 * @returns VBox status code.
511 * @param pFile Pointer to audio file handle to use.
512 * @param fOpen Open flags.
513 * Use AUDIOHLPFILE_DEFAULT_OPEN_FLAGS for the default open flags.
514 * @param pProps PCM properties to use.
515 */
516int AudioHlpFileOpen(PAUDIOHLPFILE pFile, uint32_t fOpen, PCPDMAUDIOPCMPROPS pProps)
517{
518 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
519 /** @todo Validate fOpen flags. */
520 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
521 Assert(PDMAudioPropsAreValid(pProps));
522
523 int rc;
524
525 if (pFile->enmType == AUDIOHLPFILETYPE_RAW)
526 {
527 rc = RTFileOpen(&pFile->hFile, pFile->szName, fOpen);
528 }
529 else if (pFile->enmType == AUDIOHLPFILETYPE_WAV)
530 {
531 pFile->pvData = (PAUDIOWAVFILEDATA)RTMemAllocZ(sizeof(AUDIOWAVFILEDATA));
532 if (pFile->pvData)
533 {
534 pFile->cbData = sizeof(PAUDIOWAVFILEDATA);
535
536 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
537 AssertPtr(pData);
538
539 /* Header. */
540 pData->Hdr.u32RIFF = AUDIO_MAKE_FOURCC('R','I','F','F');
541 pData->Hdr.u32Size = 36;
542 pData->Hdr.u32WAVE = AUDIO_MAKE_FOURCC('W','A','V','E');
543
544 pData->Hdr.u32Fmt = AUDIO_MAKE_FOURCC('f','m','t',' ');
545 pData->Hdr.u32Size1 = 16; /* Means PCM. */
546 pData->Hdr.u16AudioFormat = 1; /* PCM, linear quantization. */
547 pData->Hdr.u16NumChannels = PDMAudioPropsChannels(pProps);
548 pData->Hdr.u32SampleRate = pProps->uHz;
549 pData->Hdr.u32ByteRate = PDMAudioPropsGetBitrate(pProps) / 8;
550 pData->Hdr.u16BlockAlign = PDMAudioPropsFrameSize(pProps);
551 pData->Hdr.u16BitsPerSample = PDMAudioPropsSampleBits(pProps);
552
553 /* Data chunk. */
554 pData->Hdr.u32ID2 = AUDIO_MAKE_FOURCC('d','a','t','a');
555 pData->Hdr.u32Size2 = 0;
556
557 rc = RTFileOpen(&pFile->hFile, pFile->szName, fOpen);
558 if (RT_SUCCESS(rc))
559 {
560 rc = RTFileWrite(pFile->hFile, &pData->Hdr, sizeof(pData->Hdr), NULL);
561 if (RT_FAILURE(rc))
562 {
563 RTFileClose(pFile->hFile);
564 pFile->hFile = NIL_RTFILE;
565 }
566 }
567
568 if (RT_FAILURE(rc))
569 {
570 RTMemFree(pFile->pvData);
571 pFile->pvData = NULL;
572 pFile->cbData = 0;
573 }
574 }
575 else
576 rc = VERR_NO_MEMORY;
577 }
578 else
579 rc = VERR_INVALID_PARAMETER;
580
581 if (RT_SUCCESS(rc))
582 LogRel2(("Audio: Opened file '%s'\n", pFile->szName));
583 else
584 LogRel(("Audio: Failed opening file '%s', rc=%Rrc\n", pFile->szName, rc));
585
586 return rc;
587}
588
589/**
590 * Creates a debug file structure and opens a file for it, extended version.
591 *
592 * @returns VBox status code.
593 * @param ppFile Where to return the debug file instance on success.
594 * @param enmType The file type.
595 * @param pszDir The directory to open the file in.
596 * @param pszName The base filename.
597 * @param iInstance The device/driver instance.
598 * @param fFilename AUDIOHLPFILENAME_FLAGS_XXX.
599 * @param fCreate AUDIOHLPFILE_FLAGS_XXX.
600 * @param pProps PCM audio properties for the file.
601 * @param fOpen RTFILE_O_XXX or AUDIOHLPFILE_DEFAULT_OPEN_FLAGS.
602 */
603int AudioHlpFileCreateAndOpenEx(PAUDIOHLPFILE *ppFile, AUDIOHLPFILETYPE enmType, const char *pszDir, const char *pszName,
604 uint32_t iInstance, uint32_t fFilename, uint32_t fCreate,
605 PCPDMAUDIOPCMPROPS pProps, uint64_t fOpen)
606{
607 char szFile[RTPATH_MAX];
608 int rc = AudioHlpFileNameGet(szFile, sizeof(szFile), pszDir, pszName, iInstance, enmType, fFilename);
609 if (RT_SUCCESS(rc))
610 {
611 PAUDIOHLPFILE pFile = NULL;
612 rc = AudioHlpFileCreate(enmType, szFile, fCreate, &pFile);
613 if (RT_SUCCESS(rc))
614 {
615 rc = AudioHlpFileOpen(pFile, fOpen, pProps);
616 if (RT_SUCCESS(rc))
617 {
618 *ppFile = pFile;
619 return rc;
620 }
621 AudioHlpFileDestroy(pFile);
622 }
623 }
624 *ppFile = NULL;
625 return rc;
626}
627
628/**
629 * Creates a debug wav-file structure and opens a file for it, default flags.
630 *
631 * @returns VBox status code.
632 * @param ppFile Where to return the debug file instance on success.
633 * @param pszDir The directory to open the file in.
634 * @param pszName The base filename.
635 * @param iInstance The device/driver instance.
636 * @param pProps PCM audio properties for the file.
637 */
638int AudioHlpFileCreateAndOpen(PAUDIOHLPFILE *ppFile, const char *pszDir, const char *pszName,
639 uint32_t iInstance, PCPDMAUDIOPCMPROPS pProps)
640{
641 return AudioHlpFileCreateAndOpenEx(ppFile, AUDIOHLPFILETYPE_WAV, pszDir, pszName, iInstance,
642 AUDIOHLPFILENAME_FLAGS_NONE, AUDIOHLPFILE_FLAGS_NONE,
643 pProps, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS);
644}
645
646
647/**
648 * Closes an audio file.
649 *
650 * @returns VBox status code.
651 * @param pFile Audio file handle to close.
652 */
653int AudioHlpFileClose(PAUDIOHLPFILE pFile)
654{
655 if (!pFile)
656 return VINF_SUCCESS;
657
658 size_t cbSize = AudioHlpFileGetDataSize(pFile);
659
660 int rc = VINF_SUCCESS;
661
662 if (pFile->enmType == AUDIOHLPFILETYPE_RAW)
663 {
664 if (RTFileIsValid(pFile->hFile))
665 rc = RTFileClose(pFile->hFile);
666 }
667 else if (pFile->enmType == AUDIOHLPFILETYPE_WAV)
668 {
669 if (RTFileIsValid(pFile->hFile))
670 {
671 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
672 if (pData) /* The .WAV file data only is valid when a file actually has been created. */
673 {
674 /* Update the header with the current data size. */
675 RTFileWriteAt(pFile->hFile, 0, &pData->Hdr, sizeof(pData->Hdr), NULL);
676 }
677
678 rc = RTFileClose(pFile->hFile);
679 }
680
681 if (pFile->pvData)
682 {
683 RTMemFree(pFile->pvData);
684 pFile->pvData = NULL;
685 }
686 }
687 else
688 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
689
690 if ( RT_SUCCESS(rc)
691 && !cbSize
692 && !(pFile->fFlags & AUDIOHLPFILE_FLAGS_KEEP_IF_EMPTY))
693 {
694 rc = AudioHlpFileDelete(pFile);
695 }
696
697 pFile->cbData = 0;
698
699 if (RT_SUCCESS(rc))
700 {
701 pFile->hFile = NIL_RTFILE;
702 LogRel2(("Audio: Closed file '%s' (%zu bytes)\n", pFile->szName, cbSize));
703 }
704 else
705 LogRel(("Audio: Failed closing file '%s', rc=%Rrc\n", pFile->szName, rc));
706
707 return rc;
708}
709
710/**
711 * Deletes an audio file.
712 *
713 * @returns VBox status code.
714 * @param pFile Audio file handle to delete.
715 */
716int AudioHlpFileDelete(PAUDIOHLPFILE pFile)
717{
718 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
719
720 int rc = RTFileDelete(pFile->szName);
721 if (RT_SUCCESS(rc))
722 {
723 LogRel2(("Audio: Deleted file '%s'\n", pFile->szName));
724 }
725 else if (rc == VERR_FILE_NOT_FOUND) /* Don't bitch if the file is not around (anymore). */
726 rc = VINF_SUCCESS;
727
728 if (RT_FAILURE(rc))
729 LogRel(("Audio: Failed deleting file '%s', rc=%Rrc\n", pFile->szName, rc));
730
731 return rc;
732}
733
734/**
735 * Returns the raw audio data size of an audio file.
736 *
737 * Note: This does *not* include file headers and other data which does
738 * not belong to the actual PCM audio data.
739 *
740 * @returns Size (in bytes) of the raw PCM audio data.
741 * @param pFile Audio file handle to retrieve the audio data size for.
742 */
743size_t AudioHlpFileGetDataSize(PAUDIOHLPFILE pFile)
744{
745 AssertPtrReturn(pFile, 0);
746
747 size_t cbSize = 0;
748
749 if (pFile->enmType == AUDIOHLPFILETYPE_RAW)
750 {
751 cbSize = RTFileTell(pFile->hFile);
752 }
753 else if (pFile->enmType == AUDIOHLPFILETYPE_WAV)
754 {
755 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
756 if (pData) /* The .WAV file data only is valid when a file actually has been created. */
757 cbSize = pData->Hdr.u32Size2;
758 }
759
760 return cbSize;
761}
762
763/**
764 * Returns whether the given audio file is open and in use or not.
765 *
766 * @return bool True if open, false if not.
767 * @param pFile Audio file handle to check open status for.
768 */
769bool AudioHlpFileIsOpen(PAUDIOHLPFILE pFile)
770{
771 if (!pFile)
772 return false;
773
774 return RTFileIsValid(pFile->hFile);
775}
776
777/**
778 * Write PCM data to a wave (.WAV) file.
779 *
780 * @returns VBox status code.
781 * @param pFile Audio file handle to write PCM data to.
782 * @param pvBuf Audio data to write.
783 * @param cbBuf Size (in bytes) of audio data to write.
784 * @param fFlags Additional write flags. Not being used at the moment and must be 0.
785 */
786int AudioHlpFileWrite(PAUDIOHLPFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags)
787{
788 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
789 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
790
791 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /** @todo fFlags are currently not implemented. */
792
793 if (!cbBuf)
794 return VINF_SUCCESS;
795
796 AssertReturn(RTFileIsValid(pFile->hFile), VERR_WRONG_ORDER);
797
798 int rc;
799
800 if (pFile->enmType == AUDIOHLPFILETYPE_RAW)
801 {
802 rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
803 }
804 else if (pFile->enmType == AUDIOHLPFILETYPE_WAV)
805 {
806 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
807 AssertPtr(pData);
808
809 rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
810 if (RT_SUCCESS(rc))
811 {
812 pData->Hdr.u32Size += (uint32_t)cbBuf;
813 pData->Hdr.u32Size2 += (uint32_t)cbBuf;
814 }
815 }
816 else
817 rc = VERR_NOT_SUPPORTED;
818
819 return rc;
820}
821
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