VirtualBox

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

Last change on this file since 94993 was 94993, checked in by vboxsync, 2 years ago

Audio: Resolved @todos regarding PDMAudioPropsAreValid() / AudioHlpPcmPropsAreValid():

  • Renamed AudioHlpPcmPropsAreValid() -> AudioHlpPcmPropsAreValidAndSupported().
  • Don't assert when not supported or invalid (i.e. not set) but just return false. The caller now is responsible for asserting now, if needed.
  • Also added unsigned samples support to AudioHlpPcmPropsAreValidAndSupported().
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.3 KB
Line 
1/* $Id: AudioHlp.cpp 94993 2022-05-12 13:57: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-2022 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/assert.h>
25#include <iprt/dir.h>
26#include <iprt/file.h>
27#include <iprt/mem.h>
28#include <iprt/string.h>
29#include <iprt/uuid.h>
30#include <iprt/formats/riff.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
40#include "AudioHlp.h"
41
42
43/*********************************************************************************************************************************
44* Structures and Typedefs *
45*********************************************************************************************************************************/
46typedef struct AUDIOWAVEFILEHDR
47{
48 RTRIFFHDR Hdr;
49 RTRIFFWAVEFMTEXTCHUNK FmtExt;
50 RTRIFFCHUNK Data;
51} AUDIOWAVEFILEHDR;
52
53
54#if 0 /* unused, no header prototypes */
55
56/**
57 * Retrieves the matching PDMAUDIOFMT for the given bits + signing flag.
58 *
59 * @return Matching PDMAUDIOFMT value.
60 * @retval PDMAUDIOFMT_INVALID if unsupported @a cBits value.
61 *
62 * @param cBits The number of bits in the audio format.
63 * @param fSigned Whether the audio format is signed @c true or not.
64 */
65PDMAUDIOFMT DrvAudioAudFmtBitsToFormat(uint8_t cBits, bool fSigned)
66{
67 if (fSigned)
68 {
69 switch (cBits)
70 {
71 case 8: return PDMAUDIOFMT_S8;
72 case 16: return PDMAUDIOFMT_S16;
73 case 32: return PDMAUDIOFMT_S32;
74 default: AssertMsgFailedReturn(("Bogus audio bits %RU8\n", cBits), PDMAUDIOFMT_INVALID);
75 }
76 }
77 else
78 {
79 switch (cBits)
80 {
81 case 8: return PDMAUDIOFMT_U8;
82 case 16: return PDMAUDIOFMT_U16;
83 case 32: return PDMAUDIOFMT_U32;
84 default: AssertMsgFailedReturn(("Bogus audio bits %RU8\n", cBits), PDMAUDIOFMT_INVALID);
85 }
86 }
87}
88
89/**
90 * Returns an unique file name for this given audio connector instance.
91 *
92 * @return Allocated file name. Must be free'd using RTStrFree().
93 * @param uInstance Driver / device instance.
94 * @param pszPath Path name of the file to delete. The path must exist.
95 * @param pszSuffix File name suffix to use.
96 */
97char *DrvAudioDbgGetFileNameA(uint8_t uInstance, const char *pszPath, const char *pszSuffix)
98{
99 char szFileName[64];
100 RTStrPrintf(szFileName, sizeof(szFileName), "drvAudio%RU8-%s", uInstance, pszSuffix);
101
102 char szFilePath[RTPATH_MAX];
103 int rc2 = RTStrCopy(szFilePath, sizeof(szFilePath), pszPath);
104 AssertRC(rc2);
105 rc2 = RTPathAppend(szFilePath, sizeof(szFilePath), szFileName);
106 AssertRC(rc2);
107
108 return RTStrDup(szFilePath);
109}
110
111#endif /* unused */
112
113/**
114 * Checks whether a given stream configuration is valid or not.
115 *
116 * @note See notes on AudioHlpPcmPropsAreValid().
117 *
118 * Returns @c true if configuration is valid, @c false if not.
119 * @param pCfg Stream configuration to check.
120 */
121bool AudioHlpStreamCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg)
122{
123 /* Ugly! HDA attach code calls us with uninitialized (all zero) config. */
124 if (PDMAudioPropsHz(&pCfg->Props) != 0)
125 {
126 if (PDMAudioStrmCfgIsValid(pCfg))
127 {
128 if ( pCfg->enmDir == PDMAUDIODIR_IN
129 || pCfg->enmDir == PDMAUDIODIR_OUT)
130 return AudioHlpPcmPropsAreValidAndSupported(&pCfg->Props);
131 }
132 }
133 return false;
134}
135
136/**
137 * Calculates the audio bit rate of the given bits per sample, the Hz and the number
138 * of audio channels.
139 *
140 * Divide the result by 8 to get the byte rate.
141 *
142 * @returns Bitrate.
143 * @param cBits Number of bits per sample.
144 * @param uHz Hz (Hertz) rate.
145 * @param cChannels Number of audio channels.
146 */
147uint32_t AudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels)
148{
149 return cBits * uHz * cChannels;
150}
151
152
153/**
154 * Checks whether given PCM properties are valid *and* supported by the audio stack or not.
155 *
156 * @returns @c true if the properties are valid and supported, @c false if not.
157 * @param pProps The PCM properties to check.
158 *
159 * @note Use PDMAudioPropsAreValid() to just check the validation bits.
160 */
161bool AudioHlpPcmPropsAreValidAndSupported(PCPDMAUDIOPCMPROPS pProps)
162{
163 AssertPtrReturn(pProps, false);
164
165 if (!PDMAudioPropsAreValid(pProps))
166 return false;
167
168 /* Properties seem valid, now check if we actually support those. */
169 switch (PDMAudioPropsSampleSize(pProps))
170 {
171 case 1: /* 8 bit */
172 /* Signed / unsigned. */
173 break;
174 case 2: /* 16 bit */
175 /* Signed / unsigned. */
176 break;
177 /** @todo Do we need support for 24 bit samples? */
178 case 4: /* 32 bit */
179 /* Signed / unsigned. */
180 break;
181 case 8: /* 64-bit raw */
182 if ( !PDMAudioPropsIsSigned(pProps)
183 || !pProps->fRaw)
184 return false;
185 break;
186 default:
187 return false;
188 }
189
190 if (!pProps->fSwapEndian) /** @todo Handling Big Endian audio data is not supported yet. */
191 return true;
192 return false;
193}
194
195
196/*********************************************************************************************************************************
197* Audio File Helpers *
198*********************************************************************************************************************************/
199
200/**
201 * Constructs an unique file name, based on the given path and the audio file type.
202 *
203 * @returns VBox status code.
204 * @param pszDst Where to store the constructed file name.
205 * @param cbDst Size of the destination buffer (bytes; incl terminator).
206 * @param pszPath Base path to use. If NULL or empty, the user's
207 * temporary directory will be used.
208 * @param pszNameFmt A name for better identifying the file.
209 * @param va Arguments for @a pszNameFmt.
210 * @param uInstance Device / driver instance which is using this file.
211 * @param enmType Audio file type to construct file name for.
212 * @param fFlags File naming flags, AUDIOHLPFILENAME_FLAGS_XXX.
213 * @param chTweak Retry tweak character.
214 */
215static int audioHlpConstructPathWorker(char *pszDst, size_t cbDst, const char *pszPath, const char *pszNameFmt, va_list va,
216 uint32_t uInstance, AUDIOHLPFILETYPE enmType, uint32_t fFlags, char chTweak)
217{
218 /*
219 * Validate input.
220 */
221 AssertPtrNullReturn(pszPath, VERR_INVALID_POINTER);
222 AssertPtrReturn(pszNameFmt, VERR_INVALID_POINTER);
223 AssertReturn(!(fFlags & ~AUDIOHLPFILENAME_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
224
225 /* Validate the type and translate it into a suffix. */
226 const char *pszSuffix = NULL;
227 switch (enmType)
228 {
229 case AUDIOHLPFILETYPE_RAW: pszSuffix = ".pcm"; break;
230 case AUDIOHLPFILETYPE_WAV: pszSuffix = ".wav"; break;
231 case AUDIOHLPFILETYPE_INVALID:
232 case AUDIOHLPFILETYPE_32BIT_HACK:
233 break; /* no default */
234 }
235 AssertMsgReturn(pszSuffix, ("enmType=%d\n", enmType), VERR_INVALID_PARAMETER);
236
237 /*
238 * The directory. Make sure it exists and ends with a path separator.
239 */
240 int rc;
241 if (!pszPath || !*pszPath)
242 rc = RTPathTemp(pszDst, cbDst);
243 else
244 {
245 AssertPtrReturn(pszDst, VERR_INVALID_POINTER);
246 rc = RTStrCopy(pszDst, cbDst, pszPath);
247 }
248 AssertRCReturn(rc, rc);
249
250 if (!RTDirExists(pszDst))
251 {
252 rc = RTDirCreateFullPath(pszDst, RTFS_UNIX_IRWXU);
253 AssertRCReturn(rc, rc);
254 }
255
256 size_t offDst = RTPathEnsureTrailingSeparator(pszDst, cbDst);
257 AssertReturn(offDst > 0, VERR_BUFFER_OVERFLOW);
258 Assert(offDst < cbDst);
259
260 /*
261 * The filename.
262 */
263 /* Start with a ISO timestamp w/ colons replaced by dashes if requested. */
264 if (fFlags & AUDIOHLPFILENAME_FLAGS_TS)
265 {
266 RTTIMESPEC NowTimeSpec;
267 RTTIME NowUtc;
268 AssertReturn(RTTimeToString(RTTimeExplode(&NowUtc, RTTimeNow(&NowTimeSpec)), &pszDst[offDst], cbDst - offDst),
269 VERR_BUFFER_OVERFLOW);
270
271 /* Change the two colons in the time part to dashes. */
272 char *pchColon = &pszDst[offDst];
273 while ((pchColon = strchr(pchColon, ':')) != NULL)
274 *pchColon++ = '-';
275
276 offDst += strlen(&pszDst[offDst]);
277 Assert(pszDst[offDst - 1] == 'Z');
278
279 /* Append a dash to separate the timestamp from the name. */
280 AssertReturn(offDst + 2 <= cbDst, VERR_BUFFER_OVERFLOW);
281 pszDst[offDst++] = '-';
282 pszDst[offDst] = '\0';
283 }
284
285 /* Append the filename, instance, retry-tweak and suffix. */
286 va_list vaCopy;
287 va_copy(vaCopy, va);
288 ssize_t cchTail;
289 if (chTweak == '\0')
290 cchTail = RTStrPrintf2(&pszDst[offDst], cbDst - offDst, "%N-%u%s", pszNameFmt, &vaCopy, uInstance, pszSuffix);
291 else
292 cchTail = RTStrPrintf2(&pszDst[offDst], cbDst - offDst, "%N-%u%c%s", pszNameFmt, &vaCopy, uInstance, chTweak, pszSuffix);
293 va_end(vaCopy);
294 AssertReturn(cchTail > 0, VERR_BUFFER_OVERFLOW);
295
296 return VINF_SUCCESS;
297}
298
299
300/**
301 * Worker for AudioHlpFileCreateF and AudioHlpFileCreateAndOpenEx that allocates
302 * and initializes a AUDIOHLPFILE instance.
303 */
304static int audioHlpFileCreateWorker(PAUDIOHLPFILE *ppFile, uint32_t fFlags, AUDIOHLPFILETYPE enmType, const char *pszPath)
305{
306 AssertReturn(!(fFlags & ~AUDIOHLPFILE_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
307
308 size_t const cbPath = strlen(pszPath) + 1;
309 PAUDIOHLPFILE pFile = (PAUDIOHLPFILE)RTMemAllocVar(RT_UOFFSETOF_DYN(AUDIOHLPFILE, szName[cbPath]));
310 AssertPtrReturn(pFile, VERR_NO_MEMORY);
311
312 pFile->enmType = enmType;
313 pFile->fFlags = fFlags;
314 pFile->cbWaveData = 0;
315 pFile->hFile = NIL_RTFILE;
316 memcpy(pFile->szName, pszPath, cbPath);
317
318 *ppFile = pFile;
319 return VINF_SUCCESS;
320}
321
322
323/**
324 * Creates an instance of AUDIOHLPFILE with the given filename and type.
325 *
326 * @note This does <b>NOT</b> create the file, see AudioHlpFileOpen for that.
327 *
328 * @returns VBox status code.
329 * @param ppFile Where to return the pointer to the audio debug file
330 * instance on success.
331 * @param fFlags AUDIOHLPFILE_FLAGS_XXX.
332 * @param enmType The audio file type to produce.
333 * @param pszPath The directory path. The temporary directory will be
334 * used if NULL or empty.
335 * @param fFilename AUDIOHLPFILENAME_FLAGS_XXX.
336 * @param uInstance The instance number (will be appended to the filename
337 * with a dash inbetween).
338 * @param pszNameFmt The filename format string.
339 * @param ... Arguments to the filename format string.
340 */
341int AudioHlpFileCreateF(PAUDIOHLPFILE *ppFile, uint32_t fFlags, AUDIOHLPFILETYPE enmType,
342 const char *pszPath, uint32_t fFilename, uint32_t uInstance, const char *pszNameFmt, ...)
343{
344 *ppFile = NULL;
345
346 /*
347 * Construct the filename first.
348 */
349 char szPath[RTPATH_MAX];
350 va_list va;
351 va_start(va, pszNameFmt);
352 int rc = audioHlpConstructPathWorker(szPath, sizeof(szPath), pszPath, pszNameFmt, va, uInstance, enmType, fFilename, '\0');
353 va_end(va);
354 AssertRCReturn(rc, rc);
355
356 /*
357 * Allocate and initializes a debug file instance with that filename path.
358 */
359 return audioHlpFileCreateWorker(ppFile, fFlags, enmType, szPath);
360}
361
362
363/**
364 * Destroys a formerly created audio file.
365 *
366 * @param pFile Audio file (object) to destroy.
367 */
368void AudioHlpFileDestroy(PAUDIOHLPFILE pFile)
369{
370 if (pFile)
371 {
372 AudioHlpFileClose(pFile);
373 RTMemFree(pFile);
374 }
375}
376
377
378/**
379 * Opens or creates an audio file.
380 *
381 * @returns VBox status code.
382 * @param pFile Pointer to audio file handle to use.
383 * @param fOpen Open flags.
384 * Use AUDIOHLPFILE_DEFAULT_OPEN_FLAGS for the default open flags.
385 * @param pProps PCM properties to use.
386 */
387int AudioHlpFileOpen(PAUDIOHLPFILE pFile, uint64_t fOpen, PCPDMAUDIOPCMPROPS pProps)
388{
389 int rc;
390
391 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
392 /** @todo Validate fOpen flags. */
393 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
394 Assert(PDMAudioPropsAreValid(pProps));
395
396 /*
397 * Raw files just needs to be opened.
398 */
399 if (pFile->enmType == AUDIOHLPFILETYPE_RAW)
400 rc = RTFileOpen(&pFile->hFile, pFile->szName, fOpen);
401 /*
402 * Wave files needs a header to be constructed and we need to take note of where
403 * there are sizes to update later when closing the file.
404 */
405 else if (pFile->enmType == AUDIOHLPFILETYPE_WAV)
406 {
407 /* Construct the header. */
408 AUDIOWAVEFILEHDR FileHdr;
409 FileHdr.Hdr.uMagic = RTRIFFHDR_MAGIC;
410 FileHdr.Hdr.cbFile = 0; /* need to update this later */
411 FileHdr.Hdr.uFileType = RTRIFF_FILE_TYPE_WAVE;
412 FileHdr.FmtExt.Chunk.uMagic = RTRIFFWAVEFMT_MAGIC;
413 FileHdr.FmtExt.Chunk.cbChunk = sizeof(RTRIFFWAVEFMTEXTCHUNK) - sizeof(RTRIFFCHUNK);
414 FileHdr.FmtExt.Data.Core.uFormatTag = RTRIFFWAVEFMT_TAG_EXTENSIBLE;
415 FileHdr.FmtExt.Data.Core.cChannels = PDMAudioPropsChannels(pProps);
416 FileHdr.FmtExt.Data.Core.uHz = PDMAudioPropsHz(pProps);
417 FileHdr.FmtExt.Data.Core.cbRate = PDMAudioPropsFramesToBytes(pProps, PDMAudioPropsHz(pProps));
418 FileHdr.FmtExt.Data.Core.cbFrame = PDMAudioPropsFrameSize(pProps);
419 FileHdr.FmtExt.Data.Core.cBitsPerSample = PDMAudioPropsSampleBits(pProps);
420 FileHdr.FmtExt.Data.cbExtra = sizeof(FileHdr.FmtExt.Data) - sizeof(FileHdr.FmtExt.Data.Core);
421 FileHdr.FmtExt.Data.cValidBitsPerSample = PDMAudioPropsSampleBits(pProps);
422 FileHdr.FmtExt.Data.fChannelMask = 0;
423 for (uintptr_t idxCh = 0; idxCh < FileHdr.FmtExt.Data.Core.cChannels; idxCh++)
424 {
425 PDMAUDIOCHANNELID const idCh = (PDMAUDIOCHANNELID)pProps->aidChannels[idxCh];
426 AssertLogRelMsgReturn(idCh >= PDMAUDIOCHANNELID_FIRST_STANDARD && idCh < PDMAUDIOCHANNELID_END_STANDARD,
427 ("Invalid channel ID %d for channel #%u", idCh, idxCh), VERR_INVALID_PARAMETER);
428 AssertLogRelMsgReturn(!(FileHdr.FmtExt.Data.fChannelMask & RT_BIT_32(idCh - PDMAUDIOCHANNELID_FIRST_STANDARD)),
429 ("Channel #%u repeats channel ID %d", idxCh, idCh), VERR_INVALID_PARAMETER);
430 FileHdr.FmtExt.Data.fChannelMask |= RT_BIT_32(idCh - PDMAUDIOCHANNELID_FIRST_STANDARD);
431 }
432
433 RTUUID UuidTmp;
434 rc = RTUuidFromStr(&UuidTmp, RTRIFFWAVEFMTEXT_SUBTYPE_PCM);
435 AssertRCReturn(rc, rc);
436 FileHdr.FmtExt.Data.SubFormat = UuidTmp; /* (64-bit field maybe unaligned) */
437
438 FileHdr.Data.uMagic = RTRIFFWAVEDATACHUNK_MAGIC;
439 FileHdr.Data.cbChunk = 0; /* need to update this later */
440
441 /* Open the file and write out the header. */
442 rc = RTFileOpen(&pFile->hFile, pFile->szName, fOpen);
443 if (RT_SUCCESS(rc))
444 {
445 rc = RTFileWrite(pFile->hFile, &FileHdr, sizeof(FileHdr), NULL);
446 if (RT_FAILURE(rc))
447 {
448 RTFileClose(pFile->hFile);
449 pFile->hFile = NIL_RTFILE;
450 }
451 }
452 }
453 else
454 AssertFailedStmt(rc = VERR_INTERNAL_ERROR_3);
455 if (RT_SUCCESS(rc))
456 {
457 pFile->cbWaveData = 0;
458 LogRel2(("Audio: Opened file '%s'\n", pFile->szName));
459 }
460 else
461 LogRel(("Audio: Failed opening file '%s': %Rrc\n", pFile->szName, rc));
462 return rc;
463}
464
465
466/**
467 * Creates a debug file structure and opens a file for it, extended version.
468 *
469 * @returns VBox status code.
470 * @param ppFile Where to return the debug file instance on success.
471 * @param enmType The file type.
472 * @param pszDir The directory to open the file in.
473 * @param iInstance The device/driver instance.
474 * @param fFilename AUDIOHLPFILENAME_FLAGS_XXX.
475 * @param fCreate AUDIOHLPFILE_FLAGS_XXX.
476 * @param pProps PCM audio properties for the file.
477 * @param fOpen RTFILE_O_XXX or AUDIOHLPFILE_DEFAULT_OPEN_FLAGS.
478 * @param pszNameFmt The base filename.
479 * @param ... Filename format arguments.
480 */
481int AudioHlpFileCreateAndOpenEx(PAUDIOHLPFILE *ppFile, AUDIOHLPFILETYPE enmType, const char *pszDir,
482 uint32_t iInstance, uint32_t fFilename, uint32_t fCreate,
483 PCPDMAUDIOPCMPROPS pProps, uint64_t fOpen, const char *pszNameFmt, ...)
484{
485 *ppFile = NULL;
486
487 for (uint32_t iTry = 0; ; iTry++)
488 {
489 /* Format the path to the filename. */
490 char szFile[RTPATH_MAX];
491 va_list va;
492 va_start(va, pszNameFmt);
493 int rc = audioHlpConstructPathWorker(szFile, sizeof(szFile), pszDir, pszNameFmt, va, iInstance, enmType, fFilename,
494 iTry == 0 ? '\0' : iTry + 'a');
495 va_end(va);
496 AssertRCReturn(rc, rc);
497
498 /* Create an debug audio file instance with the filename path. */
499 PAUDIOHLPFILE pFile = NULL;
500 rc = audioHlpFileCreateWorker(&pFile, fCreate, enmType, szFile);
501 AssertRCReturn(rc, rc);
502
503 /* Try open it. */
504 rc = AudioHlpFileOpen(pFile, fOpen, pProps);
505 if (RT_SUCCESS(rc))
506 {
507 *ppFile = pFile;
508 return rc;
509 }
510 AudioHlpFileDestroy(pFile);
511
512 AssertReturn(iTry < 16, rc);
513 }
514}
515
516
517/**
518 * Creates a debug wav-file structure and opens a file for it, default flags.
519 *
520 * @returns VBox status code.
521 * @param ppFile Where to return the debug file instance on success.
522 * @param pszDir The directory to open the file in.
523 * @param pszName The base filename.
524 * @param iInstance The device/driver instance.
525 * @param pProps PCM audio properties for the file.
526 */
527int AudioHlpFileCreateAndOpen(PAUDIOHLPFILE *ppFile, const char *pszDir, const char *pszName,
528 uint32_t iInstance, PCPDMAUDIOPCMPROPS pProps)
529{
530 return AudioHlpFileCreateAndOpenEx(ppFile, AUDIOHLPFILETYPE_WAV, pszDir, iInstance,
531 AUDIOHLPFILENAME_FLAGS_NONE, AUDIOHLPFILE_FLAGS_NONE,
532 pProps, AUDIOHLPFILE_DEFAULT_OPEN_FLAGS, "%s", pszName);
533}
534
535
536/**
537 * Closes an audio file.
538 *
539 * @returns VBox status code.
540 * @param pFile Audio file handle to close.
541 */
542int AudioHlpFileClose(PAUDIOHLPFILE pFile)
543{
544 if (!pFile || pFile->hFile == NIL_RTFILE)
545 return VINF_SUCCESS;
546
547 /*
548 * Wave files needs to update the data size and file size in the header.
549 */
550 if (pFile->enmType == AUDIOHLPFILETYPE_WAV)
551 {
552 uint32_t const cbFile = sizeof(AUDIOWAVEFILEHDR) - sizeof(RTRIFFCHUNK) + (uint32_t)pFile->cbWaveData;
553 uint32_t const cbData = (uint32_t)pFile->cbWaveData;
554
555 int rc2;
556 rc2 = RTFileWriteAt(pFile->hFile, RT_UOFFSETOF(AUDIOWAVEFILEHDR, Hdr.cbFile), &cbFile, sizeof(cbFile), NULL);
557 AssertRC(rc2);
558 rc2 = RTFileWriteAt(pFile->hFile, RT_UOFFSETOF(AUDIOWAVEFILEHDR, Data.cbChunk), &cbData, sizeof(cbData), NULL);
559 AssertRC(rc2);
560 }
561
562 /*
563 * Do the closing.
564 */
565 int rc = RTFileClose(pFile->hFile);
566 if (RT_SUCCESS(rc) || rc == VERR_INVALID_HANDLE)
567 pFile->hFile = NIL_RTFILE;
568
569 if (RT_SUCCESS(rc))
570 LogRel2(("Audio: Closed file '%s' (%'RU64 bytes PCM data)\n", pFile->szName, pFile->cbWaveData));
571 else
572 LogRel(("Audio: Failed closing file '%s': %Rrc\n", pFile->szName, rc));
573
574 /*
575 * Delete empty file if requested.
576 */
577 if ( !(pFile->fFlags & AUDIOHLPFILE_FLAGS_KEEP_IF_EMPTY)
578 && pFile->cbWaveData == 0
579 && RT_SUCCESS(rc))
580 AudioHlpFileDelete(pFile);
581
582 return rc;
583}
584
585
586/**
587 * Deletes an audio file.
588 *
589 * @returns VBox status code.
590 * @param pFile Audio file to delete.
591 */
592int AudioHlpFileDelete(PAUDIOHLPFILE pFile)
593{
594 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
595
596 int rc = RTFileDelete(pFile->szName);
597 if (RT_SUCCESS(rc))
598 LogRel2(("Audio: Deleted file '%s'\n", pFile->szName));
599 else if (rc == VERR_FILE_NOT_FOUND) /* Don't bitch if the file is not around anymore. */
600 rc = VINF_SUCCESS;
601
602 if (RT_FAILURE(rc))
603 LogRel(("Audio: Failed deleting file '%s', rc=%Rrc\n", pFile->szName, rc));
604
605 return rc;
606}
607
608
609/**
610 * Returns whether the given audio file is open and in use or not.
611 *
612 * @returns True if open, false if not.
613 * @param pFile Audio file to check open status for.
614 */
615bool AudioHlpFileIsOpen(PAUDIOHLPFILE pFile)
616{
617 if (!pFile || pFile->hFile == NIL_RTFILE)
618 return false;
619
620 return RTFileIsValid(pFile->hFile);
621}
622
623
624/**
625 * Write PCM data to a wave (.WAV) file.
626 *
627 * @returns VBox status code.
628 * @param pFile Audio file to write PCM data to.
629 * @param pvBuf Audio data to write.
630 * @param cbBuf Size (in bytes) of audio data to write.
631 */
632int AudioHlpFileWrite(PAUDIOHLPFILE pFile, const void *pvBuf, size_t cbBuf)
633{
634 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
635 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
636
637 if (!cbBuf)
638 return VINF_SUCCESS;
639
640 int rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
641 if (RT_SUCCESS(rc))
642 pFile->cbWaveData += cbBuf;
643
644 return rc;
645}
646
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