VirtualBox

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

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

Audio: Removed unused PDMAUDIOFMT type and associated translators. bugref:9890

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