VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp@ 62920

Last change on this file since 62920 was 62919, checked in by vboxsync, 9 years ago

Please use 'static const' on data that is constant, don't make the compiler recreated on the stack for each call.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.6 KB
Line 
1/* $Id: DrvAudioCommon.cpp 62919 2016-08-03 14:16:14Z vboxsync $ */
2/** @file
3 * Intermedia audio driver, common routines. These are also used
4 * in the drivers which are bound to Main, e.g. the VRDE or the
5 * video audio recording drivers.
6 */
7
8/*
9 * Copyright (C) 2006-2016 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 * This code is based on: audio_template.h from QEMU AUDIO subsystem.
21 *
22 * QEMU Audio subsystem header
23 *
24 * Copyright (c) 2005 Vassili Karpov (malc)
25 *
26 * Permission is hereby granted, free of charge, to any person obtaining a copy
27 * of this software and associated documentation files (the "Software"), to deal
28 * in the Software without restriction, including without limitation the rights
29 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30 * copies of the Software, and to permit persons to whom the Software is
31 * furnished to do so, subject to the following conditions:
32 *
33 * The above copyright notice and this permission notice shall be included in
34 * all copies or substantial portions of the Software.
35 *
36 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
39 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42 * THE SOFTWARE.
43 */
44#include <iprt/alloc.h>
45#include <iprt/asm-math.h>
46#include <iprt/assert.h>
47#include <iprt/dir.h>
48#include <iprt/file.h>
49#include <iprt/string.h>
50#include <iprt/uuid.h>
51
52#include <VBox/vmm/pdmdev.h>
53#include <VBox/vmm/pdm.h>
54#include <VBox/err.h>
55#include <VBox/vmm/mm.h>
56
57#include <ctype.h>
58#include <stdlib.h>
59
60#include "DrvAudio.h"
61#include "AudioMixBuffer.h"
62
63#pragma pack(1)
64/**
65 * Structure for building up a .WAV file header.
66 */
67typedef struct AUDIOWAVFILEHDR
68{
69 uint32_t u32RIFF;
70 uint32_t u32Size;
71 uint32_t u32WAVE;
72
73 uint32_t u32Fmt;
74 uint32_t u32Size1;
75 uint16_t u16AudioFormat;
76 uint16_t u16NumChannels;
77 uint32_t u32SampleRate;
78 uint32_t u32ByteRate;
79 uint16_t u16BlockAlign;
80 uint16_t u16BitsPerSample;
81
82 uint32_t u32ID2;
83 uint32_t u32Size2;
84} AUDIOWAVFILEHDR, *PAUDIOWAVFILEHDR;
85#pragma pack()
86
87/**
88 * Structure for keeeping the internal .WAV file data
89 */
90typedef struct AUDIOWAVFILEDATA
91{
92 /** The file header/footer. */
93 AUDIOWAVFILEHDR Hdr;
94} AUDIOWAVFILEDATA, *PAUDIOWAVFILEDATA;
95
96/**
97 * Retrieves the matching PDMAUDIOFMT for given bits + signing flag.
98 *
99 * @return IPRT status code.
100 * @return PDMAUDIOFMT Resulting audio format or PDMAUDIOFMT_INVALID if invalid.
101 * @param cBits Bits to retrieve audio format for.
102 * @param fSigned Signed flag for bits to retrieve audio format for.
103 */
104PDMAUDIOFMT DrvAudioAudFmtBitsToAudFmt(uint8_t cBits, bool fSigned)
105{
106 if (fSigned)
107 {
108 switch (cBits)
109 {
110 case 8: return PDMAUDIOFMT_S8;
111 case 16: return PDMAUDIOFMT_S16;
112 case 32: return PDMAUDIOFMT_S32;
113 default: break;
114 }
115 }
116 else
117 {
118 switch (cBits)
119 {
120 case 8: return PDMAUDIOFMT_U8;
121 case 16: return PDMAUDIOFMT_U16;
122 case 32: return PDMAUDIOFMT_U32;
123 default: break;
124 }
125 }
126
127 AssertMsgFailed(("Bogus audio bits %RU8\n", cBits));
128 return PDMAUDIOFMT_INVALID;
129}
130
131/**
132 * Clears a sample buffer by the given amount of audio samples.
133 *
134 * @return IPRT status code.
135 * @param pPCMProps PCM properties to use for the buffer to clear.
136 * @param pvBuf Buffer to clear.
137 * @param cbBuf Size (in bytes) of the buffer.
138 * @param cSamples Number of audio samples to clear in the buffer.
139 */
140void DrvAudioHlpClearBuf(PPDMPCMPROPS pPCMProps, void *pvBuf, size_t cbBuf, uint32_t cSamples)
141{
142 AssertPtrReturnVoid(pPCMProps);
143 AssertPtrReturnVoid(pvBuf);
144
145 if (!cbBuf || !cSamples)
146 return;
147
148 Log2Func(("pPCMInfo=%p, pvBuf=%p, cSamples=%RU32, fSigned=%RTbool, cBits=%RU8, cShift=%RU8\n",
149 pPCMProps, pvBuf, cSamples, pPCMProps->fSigned, pPCMProps->cBits, pPCMProps->cShift));
150
151 if (pPCMProps->fSigned)
152 {
153 memset(pvBuf, 0, cSamples << pPCMProps->cShift);
154 }
155 else
156 {
157 switch (pPCMProps->cBits)
158 {
159 case 8:
160 {
161 memset(pvBuf, 0x80, cSamples << pPCMProps->cShift);
162 break;
163 }
164
165 case 16:
166 {
167 uint16_t *p = (uint16_t *)pvBuf;
168 int shift = pPCMProps->cChannels - 1;
169 short s = INT16_MAX;
170
171 if (pPCMProps->fSwapEndian)
172 s = RT_BSWAP_U16(s);
173
174 for (unsigned i = 0; i < cSamples << shift; i++)
175 p[i] = s;
176
177 break;
178 }
179
180 case 32:
181 {
182 uint32_t *p = (uint32_t *)pvBuf;
183 int shift = pPCMProps->cChannels - 1;
184 int32_t s = INT32_MAX;
185
186 if (pPCMProps->fSwapEndian)
187 s = RT_BSWAP_U32(s);
188
189 for (unsigned i = 0; i < cSamples << shift; i++)
190 p[i] = s;
191
192 break;
193 }
194
195 default:
196 {
197 AssertMsgFailed(("Invalid bits: %RU8\n", pPCMProps->cBits));
198 break;
199 }
200 }
201 }
202}
203
204/**
205 * Converts a recording source enumeration to a string.
206 *
207 * @returns Stringified recording source, or "Unknown", if not found.
208 * @param enmRecSrc Recording source to convert.
209 */
210const char *DrvAudioHlpRecSrcToStr(PDMAUDIORECSOURCE enmRecSrc)
211{
212 switch (enmRecSrc)
213 {
214 case PDMAUDIORECSOURCE_UNKNOWN: return "Unknown";
215 case PDMAUDIORECSOURCE_MIC: return "Microphone In";
216 case PDMAUDIORECSOURCE_CD: return "CD";
217 case PDMAUDIORECSOURCE_VIDEO: return "Video";
218 case PDMAUDIORECSOURCE_AUX: return "AUX";
219 case PDMAUDIORECSOURCE_LINE: return "Line In";
220 case PDMAUDIORECSOURCE_PHONE: return "Phone";
221 default:
222 break;
223 }
224
225 AssertMsgFailed(("Invalid recording source %ld\n", enmRecSrc));
226 return "Unknown";
227}
228
229/**
230 * Returns wether the given audio format has signed bits or not.
231 *
232 * @return IPRT status code.
233 * @return bool @true for signed bits, @false for unsigned.
234 * @param enmFmt Audio format to retrieve value for.
235 */
236bool DrvAudioHlpAudFmtIsSigned(PDMAUDIOFMT enmFmt)
237{
238 switch (enmFmt)
239 {
240 case PDMAUDIOFMT_S8:
241 case PDMAUDIOFMT_S16:
242 case PDMAUDIOFMT_S32:
243 return true;
244
245 case PDMAUDIOFMT_U8:
246 case PDMAUDIOFMT_U16:
247 case PDMAUDIOFMT_U32:
248 return false;
249
250 default:
251 break;
252 }
253
254 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
255 return false;
256}
257
258/**
259 * Returns the bits of a given audio format.
260 *
261 * @return IPRT status code.
262 * @return uint8_t Bits of audio format.
263 * @param enmFmt Audio format to retrieve value for.
264 */
265uint8_t DrvAudioHlpAudFmtToBits(PDMAUDIOFMT enmFmt)
266{
267 switch (enmFmt)
268 {
269 case PDMAUDIOFMT_S8:
270 case PDMAUDIOFMT_U8:
271 return 8;
272
273 case PDMAUDIOFMT_U16:
274 case PDMAUDIOFMT_S16:
275 return 16;
276
277 case PDMAUDIOFMT_U32:
278 case PDMAUDIOFMT_S32:
279 return 32;
280
281 default:
282 break;
283 }
284
285 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
286 return 0;
287}
288
289/**
290 * Converts an audio format to a string.
291 *
292 * @returns Stringified audio format, or "Unknown", if not found.
293 * @param enmFmt Audio format to convert.
294 */
295const char *DrvAudioHlpAudFmtToStr(PDMAUDIOFMT enmFmt)
296{
297 switch (enmFmt)
298 {
299 case PDMAUDIOFMT_U8:
300 return "U8";
301
302 case PDMAUDIOFMT_U16:
303 return "U16";
304
305 case PDMAUDIOFMT_U32:
306 return "U32";
307
308 case PDMAUDIOFMT_S8:
309 return "S8";
310
311 case PDMAUDIOFMT_S16:
312 return "S16";
313
314 case PDMAUDIOFMT_S32:
315 return "S32";
316
317 default:
318 break;
319 }
320
321 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
322 return "Unknown";
323}
324
325/**
326 * Converts a given string to an audio format.
327 *
328 * @returns Audio format for the given string, or PDMAUDIOFMT_INVALID if not found.
329 * @param pszFmt String to convert to an audio format.
330 */
331PDMAUDIOFMT DrvAudioHlpStrToAudFmt(const char *pszFmt)
332{
333 AssertPtrReturn(pszFmt, PDMAUDIOFMT_INVALID);
334
335 if (!RTStrICmp(pszFmt, "u8"))
336 return PDMAUDIOFMT_U8;
337 else if (!RTStrICmp(pszFmt, "u16"))
338 return PDMAUDIOFMT_U16;
339 else if (!RTStrICmp(pszFmt, "u32"))
340 return PDMAUDIOFMT_U32;
341 else if (!RTStrICmp(pszFmt, "s8"))
342 return PDMAUDIOFMT_S8;
343 else if (!RTStrICmp(pszFmt, "s16"))
344 return PDMAUDIOFMT_S16;
345 else if (!RTStrICmp(pszFmt, "s32"))
346 return PDMAUDIOFMT_S32;
347
348 AssertMsgFailed(("Invalid audio format \"%s\"\n", pszFmt));
349 return PDMAUDIOFMT_INVALID;
350}
351
352/**
353 * Checks whether the given PCM properties are equal with the given
354 * stream configuration.
355 *
356 * @returns @true if equal, @false if not.
357 * @param pProps PCM properties to compare.
358 * @param pCfg Stream configuration to compare.
359 */
360bool DrvAudioHlpPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg)
361{
362 AssertPtrReturn(pProps, false);
363 AssertPtrReturn(pCfg, false);
364
365 int cBits = 8;
366 bool fSigned = false;
367
368 switch (pCfg->enmFormat)
369 {
370 case PDMAUDIOFMT_S8:
371 fSigned = true;
372 case PDMAUDIOFMT_U8:
373 break;
374
375 case PDMAUDIOFMT_S16:
376 fSigned = true;
377 case PDMAUDIOFMT_U16:
378 cBits = 16;
379 break;
380
381 case PDMAUDIOFMT_S32:
382 fSigned = true;
383 case PDMAUDIOFMT_U32:
384 cBits = 32;
385 break;
386
387 default:
388 AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
389 break;
390 }
391
392 bool fEqual = pProps->uHz == pCfg->uHz
393 && pProps->cChannels == pCfg->cChannels
394 && pProps->fSigned == fSigned
395 && pProps->cBits == cBits
396 && pProps->fSwapEndian == !(pCfg->enmEndianness == PDMAUDIOHOSTENDIANNESS);
397 return fEqual;
398}
399
400/**
401 * Checks whether two given PCM properties are equal.
402 *
403 * @returns @true if equal, @false if not.
404 * @param pProps1 First properties to compare.
405 * @param pProps2 Second properties to compare.
406 */
407bool DrvAudioHlpPCMPropsAreEqual(PPDMPCMPROPS pProps1, PPDMPCMPROPS pProps2)
408{
409 AssertPtrReturn(pProps1, false);
410 AssertPtrReturn(pProps2, false);
411
412 if (pProps1 == pProps2) /* If the pointers match, take a shortcut. */
413 return true;
414
415 return pProps1->uHz == pProps2->uHz
416 && pProps1->cChannels == pProps2->cChannels
417 && pProps1->fSigned == pProps2->fSigned
418 && pProps1->cBits == pProps2->cBits
419 && pProps1->fSwapEndian == pProps2->fSwapEndian;
420}
421
422/**
423 * Converts PCM properties to a audio stream configuration.
424 *
425 * @return IPRT status code.
426 * @param pPCMProps Pointer to PCM properties to convert.
427 * @param pCfg Pointer to audio stream configuration to store result into.
428 */
429int DrvAudioHlpPCMPropsToStreamCfg(PPDMPCMPROPS pPCMProps, PPDMAUDIOSTREAMCFG pCfg)
430{
431 AssertPtrReturn(pPCMProps, VERR_INVALID_POINTER);
432 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
433
434 pCfg->uHz = pPCMProps->uHz;
435 pCfg->cChannels = pPCMProps->cChannels;
436 pCfg->enmFormat = DrvAudioAudFmtBitsToAudFmt(pPCMProps->cBits, pPCMProps->fSigned);
437
438 /** @todo We assume little endian is the default for now. */
439 pCfg->enmEndianness = pPCMProps->fSwapEndian == false ? PDMAUDIOENDIANNESS_LITTLE : PDMAUDIOENDIANNESS_BIG;
440 return VINF_SUCCESS;
441}
442
443/**
444 * Checks whether a given stream configuration is valid or not.
445 *
446 * Returns @true if configuration is valid, @false if not.
447 * @param pCfg Stream configuration to check.
448 */
449bool DrvAudioHlpStreamCfgIsValid(PPDMAUDIOSTREAMCFG pCfg)
450{
451 bool fValid = ( pCfg->cChannels == 1
452 || pCfg->cChannels == 2); /* Either stereo (2) or mono (1), per stream. */
453
454 fValid |= ( pCfg->enmEndianness == PDMAUDIOENDIANNESS_LITTLE
455 || pCfg->enmEndianness == PDMAUDIOENDIANNESS_BIG);
456
457 fValid |= ( pCfg->enmDir == PDMAUDIODIR_IN
458 || pCfg->enmDir == PDMAUDIODIR_OUT);
459
460 if (fValid)
461 {
462 switch (pCfg->enmFormat)
463 {
464 case PDMAUDIOFMT_S8:
465 case PDMAUDIOFMT_U8:
466 case PDMAUDIOFMT_S16:
467 case PDMAUDIOFMT_U16:
468 case PDMAUDIOFMT_S32:
469 case PDMAUDIOFMT_U32:
470 break;
471 default:
472 fValid = false;
473 break;
474 }
475 }
476
477 fValid |= pCfg->uHz > 0;
478 /** @todo Check for defined frequencies supported. */
479
480 return fValid;
481}
482
483/**
484 * Converts an audio stream configuration to matching PCM properties.
485 *
486 * @return IPRT status code.
487 * @param pCfg Audio stream configuration to convert.
488 * @param pProps PCM properties to save result to.
489 */
490int DrvAudioHlpStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps)
491{
492 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
493 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
494
495 int rc = VINF_SUCCESS;
496
497 int cBits = 8, cShift = 0;
498 bool fSigned = false;
499
500 switch (pCfg->enmFormat)
501 {
502 case PDMAUDIOFMT_S8:
503 fSigned = true;
504 case PDMAUDIOFMT_U8:
505 break;
506
507 case PDMAUDIOFMT_S16:
508 fSigned = true;
509 case PDMAUDIOFMT_U16:
510 cBits = 16;
511 cShift = 1;
512 break;
513
514 case PDMAUDIOFMT_S32:
515 fSigned = true;
516 case PDMAUDIOFMT_U32:
517 cBits = 32;
518 cShift = 2;
519 break;
520
521 default:
522 AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
523 rc = VERR_NOT_SUPPORTED;
524 break;
525 }
526
527 if (RT_SUCCESS(rc))
528 {
529 pProps->uHz = pCfg->uHz;
530 pProps->cBits = cBits;
531 pProps->fSigned = fSigned;
532 pProps->cShift = (pCfg->cChannels == 2) + cShift;
533 pProps->cChannels = pCfg->cChannels;
534 pProps->uAlign = (1 << pProps->cShift) - 1;
535 pProps->fSwapEndian = pCfg->enmEndianness != PDMAUDIOHOSTENDIANNESS;
536 }
537
538 return rc;
539}
540
541/**
542 * Prints an audio stream configuration to the debug log.
543 *
544 * @param pCfg Stream configuration to log.
545 */
546void DrvAudioHlpStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg)
547{
548 AssertPtrReturnVoid(pCfg);
549
550 LogFlowFunc(("uHz=%RU32, cChannels=%RU8, enmFormat=", pCfg->uHz, pCfg->cChannels));
551
552 switch (pCfg->enmFormat)
553 {
554 case PDMAUDIOFMT_S8:
555 LogFlow(("S8"));
556 break;
557 case PDMAUDIOFMT_U8:
558 LogFlow(("U8"));
559 break;
560 case PDMAUDIOFMT_S16:
561 LogFlow(("S16"));
562 break;
563 case PDMAUDIOFMT_U16:
564 LogFlow(("U16"));
565 break;
566 case PDMAUDIOFMT_S32:
567 LogFlow(("S32"));
568 break;
569 case PDMAUDIOFMT_U32:
570 LogFlow(("U32"));
571 break;
572 default:
573 LogFlow(("invalid(%d)", pCfg->enmFormat));
574 break;
575 }
576
577 LogFlow((", endianness="));
578 switch (pCfg->enmEndianness)
579 {
580 case PDMAUDIOENDIANNESS_LITTLE:
581 LogFlow(("little\n"));
582 break;
583 case PDMAUDIOENDIANNESS_BIG:
584 LogFlow(("big\n"));
585 break;
586 default:
587 LogFlow(("invalid\n"));
588 break;
589 }
590}
591
592/**
593 * Calculates the audio bit rate of the given bits per sample, the Hz and the number
594 * of audio channels.
595 *
596 * Divide the result by 8 to get the byte rate.
597 *
598 * @returns The calculated bit rate.
599 * @param cBits Number of bits per sample.
600 * @param uHz Hz (Hertz) rate.
601 * @param cChannels Number of audio channels.
602 */
603uint32_t DrvAudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels)
604{
605 return (cBits * uHz * cChannels);
606}
607
608/**
609 * Calculates the audio bit rate out of a given audio stream configuration.
610 *
611 * Divide the result by 8 to get the byte rate.
612 *
613 * @returns The calculated bit rate.
614 * @param pCfg Audio stream configuration to calculate bit rate for.
615 *
616 * @remark
617 */
618uint32_t DrvAudioHlpCalcBitrate(PPDMAUDIOSTREAMCFG pCfg)
619{
620 return DrvAudioHlpCalcBitrate(DrvAudioHlpAudFmtToBits(pCfg->enmFormat), pCfg->uHz, pCfg->cChannels);
621}
622
623/**
624 * Sanitizes the file name component so that unsupported characters
625 * will be replaced by an underscore ("_").
626 *
627 * @return IPRT status code.
628 * @param pszPath Path to sanitize.
629 * @param cbPath Size (in bytes) of path to sanitize.
630 */
631int DrvAudioHlpSanitizeFileName(char *pszPath, size_t cbPath)
632{
633 int rc = VINF_SUCCESS;
634#ifdef RT_OS_WINDOWS
635 /* Filter out characters not allowed on Windows platforms, put in by
636 RTTimeSpecToString(). */
637 /** @todo Use something like RTPathSanitize() if available later some time. */
638 static RTUNICP const s_uszValidRangePairs[] =
639 {
640 ' ', ' ',
641 '(', ')',
642 '-', '.',
643 '0', '9',
644 'A', 'Z',
645 'a', 'z',
646 '_', '_',
647 0xa0, 0xd7af,
648 '\0'
649 };
650 ssize_t cReplaced = RTStrPurgeComplementSet(pszPath, s_uszValidRangePairs, '_' /* Replacement */);
651 if (cReplaced < 0)
652 rc = VERR_INVALID_UTF8_ENCODING;
653#else
654 RT_NOREF()
655#endif
656 return rc;
657}
658
659/**
660 * Constructs an unique file name, based on the given path and the audio file type.
661 *
662 * @returns IPRT status code.
663 * @param pszFile Where to store the constructed file name.
664 * @param cchFile Size (in characters) of the file name buffer.
665 * @param pszPath Base path to use.
666 * @param pszName A name for better identifying the file. Optional.
667 * @param enmType Audio file type to construct file name for.
668 */
669int DrvAudioHlpGetFileName(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName, PDMAUDIOFILETYPE enmType)
670{
671 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
672 AssertReturn(cchFile, VERR_INVALID_PARAMETER);
673 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
674 /* pszName is optional. */
675
676 int rc;
677
678 do
679 {
680 char szFilePath[RTPATH_MAX];
681 size_t cchFilePath = RTStrPrintf(szFilePath, sizeof(szFilePath), "%s", pszPath);
682
683 /* Create it when necessary. */
684 if (!RTDirExists(szFilePath))
685 {
686 rc = RTDirCreateFullPath(szFilePath, RTFS_UNIX_IRWXU);
687 if (RT_FAILURE(rc))
688 break;
689 }
690
691 /* The actually drop directory consist of the current time stamp and a
692 * unique number when necessary. */
693 char pszTime[64];
694 RTTIMESPEC time;
695 if (!RTTimeSpecToString(RTTimeNow(&time), pszTime, sizeof(pszTime)))
696 {
697 rc = VERR_BUFFER_OVERFLOW;
698 break;
699 }
700
701 rc = DrvAudioHlpSanitizeFileName(pszTime, sizeof(pszTime));
702 if (RT_FAILURE(rc))
703 break;
704
705 rc = RTPathAppend(szFilePath, sizeof(szFilePath), pszTime);
706 if (RT_FAILURE(rc))
707 break;
708
709 if (pszName) /* Optional name given? */
710 {
711 rc = RTStrCat(szFilePath, sizeof(szFilePath), "-");
712 if (RT_FAILURE(rc))
713 break;
714
715 rc = RTStrCat(szFilePath, sizeof(szFilePath), pszName);
716 if (RT_FAILURE(rc))
717 break;
718 }
719
720 switch (enmType)
721 {
722 case PDMAUDIOFILETYPE_WAV:
723 rc = RTStrCat(szFilePath, sizeof(szFilePath), ".wav");
724 break;
725
726 default:
727 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
728 }
729
730 if (RT_FAILURE(rc))
731 break;
732
733 RTStrPrintf(pszFile, cchFile, "%s", szFilePath);
734
735 } while (0);
736
737 LogFlowFuncLeaveRC(rc);
738 return rc;
739}
740
741/**
742 * Opens or creates a wave (.WAV) file.
743 *
744 * @returns IPRT status code.
745 * @param pFile Pointer to audio file handle to use.
746 * @param pszFile File path of file to open or create.
747 * @param fOpen Open flags.
748 * @param pProps PCM properties to use.
749 * @param fFlags Audio file flags.
750 */
751int DrvAudioHlpWAVFileOpen(PPDMAUDIOFILE pFile, const char *pszFile, uint32_t fOpen, PPDMPCMPROPS pProps,
752 PDMAUDIOFILEFLAGS fFlags)
753{
754 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
755 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
756 /** @todo Validate fOpen flags. */
757 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
758 /** @todo Validate fFlags flags. */
759
760 Assert(pProps->cChannels);
761 Assert(pProps->uHz);
762 Assert(pProps->cBits);
763
764 pFile->pvData = (PAUDIOWAVFILEDATA)RTMemAllocZ(sizeof(AUDIOWAVFILEDATA));
765 if (!pFile->pvData)
766 return VERR_NO_MEMORY;
767 pFile->cbData = sizeof(PAUDIOWAVFILEDATA);
768
769 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
770 AssertPtr(pData);
771
772 /* Header. */
773 pData->Hdr.u32RIFF = AUDIO_MAKE_FOURCC('R','I','F','F');
774 pData->Hdr.u32Size = 36;
775 pData->Hdr.u32WAVE = AUDIO_MAKE_FOURCC('W','A','V','E');
776
777 pData->Hdr.u32Fmt = AUDIO_MAKE_FOURCC('f','m','t',' ');
778 pData->Hdr.u32Size1 = 16; /* Means PCM. */
779 pData->Hdr.u16AudioFormat = 1; /* PCM, linear quantization. */
780 pData->Hdr.u16NumChannels = pProps->cChannels;
781 pData->Hdr.u32SampleRate = pProps->uHz;
782 pData->Hdr.u32ByteRate = DrvAudioHlpCalcBitrate(pProps->cBits, pProps->uHz, pProps->cChannels) / 8;
783 pData->Hdr.u16BlockAlign = pProps->cChannels * pProps->cBits / 8;
784 pData->Hdr.u16BitsPerSample = pProps->cBits;
785
786 /* Data chunk. */
787 pData->Hdr.u32ID2 = AUDIO_MAKE_FOURCC('d','a','t','a');
788 pData->Hdr.u32Size2 = 0;
789
790 int rc = RTFileOpen(&pFile->hFile, pszFile, fOpen);
791 if (RT_SUCCESS(rc))
792 {
793 rc = RTFileWrite(pFile->hFile, &pData->Hdr, sizeof(pData->Hdr), NULL);
794 if (RT_FAILURE(rc))
795 {
796 RTFileClose(pFile->hFile);
797 pFile->hFile = NIL_RTFILE;
798 }
799 }
800
801 if (RT_SUCCESS(rc))
802 {
803 pFile->enmType = PDMAUDIOFILETYPE_WAV;
804
805 RTStrPrintf(pFile->szName, RT_ELEMENTS(pFile->szName), "%s", pszFile);
806 }
807 else
808 {
809 RTMemFree(pFile->pvData);
810 pFile->pvData = NULL;
811 pFile->cbData = 0;
812 }
813
814 return rc;
815}
816
817/**
818 * Closes a wave (.WAV) audio file.
819 *
820 * @returns IPRT status code.
821 * @param pFile Audio file handle to close.
822 */
823int DrvAudioHlpWAVFileClose(PPDMAUDIOFILE pFile)
824{
825 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
826
827 Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
828
829 if (pFile->hFile != NIL_RTFILE)
830 {
831 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
832 AssertPtr(pData);
833
834 /* Update the header with the current data size. */
835 RTFileWriteAt(pFile->hFile, 0, &pData->Hdr, sizeof(pData->Hdr), NULL);
836
837 RTFileClose(pFile->hFile);
838 pFile->hFile = NIL_RTFILE;
839 }
840
841 if (pFile->pvData)
842 {
843 RTMemFree(pFile->pvData);
844 pFile->pvData = NULL;
845 }
846
847 pFile->cbData = 0;
848 pFile->enmType = PDMAUDIOFILETYPE_UNKNOWN;
849
850 return VINF_SUCCESS;
851}
852
853/**
854 * Returns the raw PCM audio data size of a wave file.
855 * This does *not* include file headers and other data which does
856 * not belong to the actual PCM audio data.
857 *
858 * @returns Size (in bytes) of the raw PCM audio data.
859 * @param pFile Audio file handle to retrieve the audio data size for.
860 */
861size_t DrvAudioHlpWAVFileGetDataSize(PPDMAUDIOFILE pFile)
862{
863 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
864
865 Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
866
867 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
868 AssertPtr(pData);
869
870 return pData->Hdr.u32Size2;
871}
872
873/**
874 * Write PCM data to a wave (.WAV) file.
875 *
876 * @returns IPRT status code.
877 * @param pFile Audio file handle to write PCM data to.
878 * @param pvBuf Audio data to write.
879 * @param cbBuf Size (in bytes) of audio data to write.
880 * @param fFlags Additional write flags. Not being used at the moment and must be 0.
881 *
882 * @remark
883 */
884int DrvAudioHlpWAVFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags)
885{
886 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
887 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
888
889 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /** @todo fFlags are currently not implemented. */
890
891 Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
892
893 if (!cbBuf)
894 return VINF_SUCCESS;
895
896 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
897 AssertPtr(pData);
898
899 int rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
900 if (RT_SUCCESS(rc))
901 {
902 pData->Hdr.u32Size += (uint32_t)cbBuf;
903 pData->Hdr.u32Size2 += (uint32_t)cbBuf;
904 }
905
906 return rc;
907}
908
Note: See TracBrowser for help on using the repository browser.

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