VirtualBox

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

最後變更 在這個檔案從62581是 62581,由 vboxsync 提交於 9 年 前

Audio: Committed too much.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 22.2 KB
 
1/* $Id: DrvAudioCommon.cpp 62581 2016-07-27 09:57:41Z 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.alldomusa.eu.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
204const char *DrvAudioHlpRecSrcToStr(PDMAUDIORECSOURCE enmRecSrc)
205{
206 switch (enmRecSrc)
207 {
208 case PDMAUDIORECSOURCE_UNKNOWN: return "Unknown";
209 case PDMAUDIORECSOURCE_MIC: return "Microphone In";
210 case PDMAUDIORECSOURCE_CD: return "CD";
211 case PDMAUDIORECSOURCE_VIDEO: return "Video";
212 case PDMAUDIORECSOURCE_AUX: return "AUX";
213 case PDMAUDIORECSOURCE_LINE: return "Line In";
214 case PDMAUDIORECSOURCE_PHONE: return "Phone";
215 default:
216 break;
217 }
218
219 AssertMsgFailed(("Invalid recording source %ld\n", enmRecSrc));
220 return "Unknown";
221}
222
223/**
224 * Returns wether the given audio format has signed bits or not.
225 *
226 * @return IPRT status code.
227 * @return bool @true for signed bits, @false for unsigned.
228 * @param enmFmt Audio format to retrieve value for.
229 */
230bool DrvAudioHlpAudFmtIsSigned(PDMAUDIOFMT enmFmt)
231{
232 switch (enmFmt)
233 {
234 case PDMAUDIOFMT_S8:
235 case PDMAUDIOFMT_S16:
236 case PDMAUDIOFMT_S32:
237 return true;
238
239 case PDMAUDIOFMT_U8:
240 case PDMAUDIOFMT_U16:
241 case PDMAUDIOFMT_U32:
242 return false;
243
244 default:
245 break;
246 }
247
248 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
249 return false;
250}
251
252/**
253 * Returns the bits of a given audio format.
254 *
255 * @return IPRT status code.
256 * @return uint8_t Bits of audio format.
257 * @param enmFmt Audio format to retrieve value for.
258 */
259uint8_t DrvAudioHlpAudFmtToBits(PDMAUDIOFMT enmFmt)
260{
261 switch (enmFmt)
262 {
263 case PDMAUDIOFMT_S8:
264 case PDMAUDIOFMT_U8:
265 return 8;
266
267 case PDMAUDIOFMT_U16:
268 case PDMAUDIOFMT_S16:
269 return 16;
270
271 case PDMAUDIOFMT_U32:
272 case PDMAUDIOFMT_S32:
273 return 32;
274
275 default:
276 break;
277 }
278
279 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
280 return 0;
281}
282
283const char *DrvAudioHlpAudFmtToStr(PDMAUDIOFMT enmFmt)
284{
285 switch (enmFmt)
286 {
287 case PDMAUDIOFMT_U8:
288 return "U8";
289
290 case PDMAUDIOFMT_U16:
291 return "U16";
292
293 case PDMAUDIOFMT_U32:
294 return "U32";
295
296 case PDMAUDIOFMT_S8:
297 return "S8";
298
299 case PDMAUDIOFMT_S16:
300 return "S16";
301
302 case PDMAUDIOFMT_S32:
303 return "S32";
304
305 default:
306 break;
307 }
308
309 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
310 return "Invalid";
311}
312
313PDMAUDIOFMT DrvAudioHlpStrToAudFmt(const char *pszFmt)
314{
315 AssertPtrReturn(pszFmt, PDMAUDIOFMT_INVALID);
316
317 if (!RTStrICmp(pszFmt, "u8"))
318 return PDMAUDIOFMT_U8;
319 else if (!RTStrICmp(pszFmt, "u16"))
320 return PDMAUDIOFMT_U16;
321 else if (!RTStrICmp(pszFmt, "u32"))
322 return PDMAUDIOFMT_U32;
323 else if (!RTStrICmp(pszFmt, "s8"))
324 return PDMAUDIOFMT_S8;
325 else if (!RTStrICmp(pszFmt, "s16"))
326 return PDMAUDIOFMT_S16;
327 else if (!RTStrICmp(pszFmt, "s32"))
328 return PDMAUDIOFMT_S32;
329
330 AssertMsgFailed(("Invalid audio format \"%s\"\n", pszFmt));
331 return PDMAUDIOFMT_INVALID;
332}
333
334bool DrvAudioHlpPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg)
335{
336 AssertPtrReturn(pProps, false);
337 AssertPtrReturn(pCfg, false);
338
339 int cBits = 8;
340 bool fSigned = false;
341
342 switch (pCfg->enmFormat)
343 {
344 case PDMAUDIOFMT_S8:
345 fSigned = true;
346 case PDMAUDIOFMT_U8:
347 break;
348
349 case PDMAUDIOFMT_S16:
350 fSigned = true;
351 case PDMAUDIOFMT_U16:
352 cBits = 16;
353 break;
354
355 case PDMAUDIOFMT_S32:
356 fSigned = true;
357 case PDMAUDIOFMT_U32:
358 cBits = 32;
359 break;
360
361 default:
362 AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
363 break;
364 }
365
366 bool fEqual = pProps->uHz == pCfg->uHz
367 && pProps->cChannels == pCfg->cChannels
368 && pProps->fSigned == fSigned
369 && pProps->cBits == cBits
370 && pProps->fSwapEndian == !(pCfg->enmEndianness == PDMAUDIOHOSTENDIANNESS);
371 return fEqual;
372}
373
374bool DrvAudioHlpPCMPropsAreEqual(PPDMPCMPROPS pProps1, PPDMPCMPROPS pProps2)
375{
376 AssertPtrReturn(pProps1, false);
377 AssertPtrReturn(pProps2, false);
378
379 if (pProps1 == pProps2)
380 return true;
381
382 return pProps1->uHz == pProps2->uHz
383 && pProps1->cChannels == pProps2->cChannels
384 && pProps1->fSigned == pProps2->fSigned
385 && pProps1->cBits == pProps2->cBits
386 && pProps1->fSwapEndian == pProps2->fSwapEndian;
387}
388
389/**
390 * Converts PCM properties to a audio stream configuration.
391 *
392 * @return IPRT status code.
393 * @param pPCMProps Pointer to PCM properties to convert.
394 * @param pCfg Pointer to audio stream configuration to store result into.
395 */
396int DrvAudioHlpPCMPropsToStreamCfg(PPDMPCMPROPS pPCMProps, PPDMAUDIOSTREAMCFG pCfg)
397{
398 AssertPtrReturn(pPCMProps, VERR_INVALID_POINTER);
399 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
400
401 pCfg->uHz = pPCMProps->uHz;
402 pCfg->cChannels = pPCMProps->cChannels;
403 pCfg->enmFormat = DrvAudioAudFmtBitsToAudFmt(pPCMProps->cBits, pPCMProps->fSigned);
404
405 /** @todo We assume little endian is the default for now. */
406 pCfg->enmEndianness = pPCMProps->fSwapEndian == false ? PDMAUDIOENDIANNESS_LITTLE : PDMAUDIOENDIANNESS_BIG;
407 return VINF_SUCCESS;
408}
409
410bool DrvAudioHlpStreamCfgIsValid(PPDMAUDIOSTREAMCFG pCfg)
411{
412 bool fValid = ( pCfg->cChannels == 1
413 || pCfg->cChannels == 2); /* Either stereo (2) or mono (1), per stream. */
414
415 fValid |= ( pCfg->enmEndianness == PDMAUDIOENDIANNESS_LITTLE
416 || pCfg->enmEndianness == PDMAUDIOENDIANNESS_BIG);
417
418 fValid |= ( pCfg->enmDir == PDMAUDIODIR_IN
419 || pCfg->enmDir == PDMAUDIODIR_OUT);
420
421 if (fValid)
422 {
423 switch (pCfg->enmFormat)
424 {
425 case PDMAUDIOFMT_S8:
426 case PDMAUDIOFMT_U8:
427 case PDMAUDIOFMT_S16:
428 case PDMAUDIOFMT_U16:
429 case PDMAUDIOFMT_S32:
430 case PDMAUDIOFMT_U32:
431 break;
432 default:
433 fValid = false;
434 break;
435 }
436 }
437
438 fValid |= pCfg->uHz > 0;
439 /** @todo Check for defined frequencies supported. */
440
441 return fValid;
442}
443
444/**
445 * Converts an audio stream configuration to matching PCM properties.
446 *
447 * @return IPRT status code.
448 * @param pCfg Audio stream configuration to convert.
449 * @param pProps PCM properties to save result to.
450 */
451int DrvAudioHlpStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps)
452{
453 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
454 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
455
456 int rc = VINF_SUCCESS;
457
458 int cBits = 8, cShift = 0;
459 bool fSigned = false;
460
461 switch (pCfg->enmFormat)
462 {
463 case PDMAUDIOFMT_S8:
464 fSigned = true;
465 case PDMAUDIOFMT_U8:
466 break;
467
468 case PDMAUDIOFMT_S16:
469 fSigned = true;
470 case PDMAUDIOFMT_U16:
471 cBits = 16;
472 cShift = 1;
473 break;
474
475 case PDMAUDIOFMT_S32:
476 fSigned = true;
477 case PDMAUDIOFMT_U32:
478 cBits = 32;
479 cShift = 2;
480 break;
481
482 default:
483 AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
484 rc = VERR_NOT_SUPPORTED;
485 break;
486 }
487
488 if (RT_SUCCESS(rc))
489 {
490 pProps->uHz = pCfg->uHz;
491 pProps->cBits = cBits;
492 pProps->fSigned = fSigned;
493 pProps->cShift = (pCfg->cChannels == 2) + cShift;
494 pProps->cChannels = pCfg->cChannels;
495 pProps->uAlign = (1 << pProps->cShift) - 1;
496 pProps->fSwapEndian = pCfg->enmEndianness != PDMAUDIOHOSTENDIANNESS;
497 }
498
499 return rc;
500}
501
502void DrvAudioHlpStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg)
503{
504 AssertPtrReturnVoid(pCfg);
505
506 LogFlowFunc(("uHz=%RU32, cChannels=%RU8, enmFormat=", pCfg->uHz, pCfg->cChannels));
507
508 switch (pCfg->enmFormat)
509 {
510 case PDMAUDIOFMT_S8:
511 LogFlow(("S8"));
512 break;
513 case PDMAUDIOFMT_U8:
514 LogFlow(("U8"));
515 break;
516 case PDMAUDIOFMT_S16:
517 LogFlow(("S16"));
518 break;
519 case PDMAUDIOFMT_U16:
520 LogFlow(("U16"));
521 break;
522 case PDMAUDIOFMT_S32:
523 LogFlow(("S32"));
524 break;
525 case PDMAUDIOFMT_U32:
526 LogFlow(("U32"));
527 break;
528 default:
529 LogFlow(("invalid(%d)", pCfg->enmFormat));
530 break;
531 }
532
533 LogFlow((", endianness="));
534 switch (pCfg->enmEndianness)
535 {
536 case PDMAUDIOENDIANNESS_LITTLE:
537 LogFlow(("little\n"));
538 break;
539 case PDMAUDIOENDIANNESS_BIG:
540 LogFlow(("big\n"));
541 break;
542 default:
543 LogFlow(("invalid\n"));
544 break;
545 }
546}
547
548uint32_t DrvAudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels)
549{
550 return (cBits * uHz * cChannels);
551}
552
553uint32_t DrvAudioHlpCalcBitrate(PPDMAUDIOSTREAMCFG pCfg)
554{
555 return DrvAudioHlpCalcBitrate(DrvAudioHlpAudFmtToBits(pCfg->enmFormat), pCfg->uHz, pCfg->cChannels);
556}
557
558/**
559 * Sanitizes the file name component so that unsupported characters
560 * will be replaced by an underscore ("_").
561 *
562 * @return IPRT status code.
563 * @param pszPath Path to sanitize.
564 * @param cbPath Size (in bytes) of path to sanitize.
565 */
566int DrvAudioHlpSanitizeFileName(char *pszPath, size_t cbPath)
567{
568 int rc = VINF_SUCCESS;
569#ifdef RT_OS_WINDOWS
570 /* Filter out characters not allowed on Windows platforms, put in by
571 RTTimeSpecToString(). */
572 /** @todo Use something like RTPathSanitize() when available. Later. */
573 RTUNICP aCpSet[] =
574 { ' ', ' ', '(', ')', '-', '.', '0', '9', 'A', 'Z', 'a', 'z', '_', '_',
575 0xa0, 0xd7af, '\0' };
576 ssize_t cReplaced = RTStrPurgeComplementSet(pszPath, aCpSet, '_' /* Replacement */);
577 if (cReplaced < 0)
578 rc = VERR_INVALID_UTF8_ENCODING;
579#endif
580 return rc;
581}
582
583/**
584 * Constructs an unique file name, based on the given path and the audio file type.
585 *
586 * @returns IPRT status code.
587 * @param pszFile Where to store the constructed file name.
588 * @param cchFile Size (in characters) of the file name buffer.
589 * @param pszPath Base path to use.
590 * @param pszName A name for better identifying the file. Optional.
591 * @param enmType Audio file type to construct file name for.
592 */
593int DrvAudioHlpGetFileName(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName, PDMAUDIOFILETYPE enmType)
594{
595 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
596 AssertReturn(cchFile, VERR_INVALID_PARAMETER);
597 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
598 /* pszName is optional. */
599
600 int rc;
601
602 do
603 {
604 char szFilePath[RTPATH_MAX];
605 size_t cchFilePath = RTStrPrintf(szFilePath, sizeof(szFilePath), "%s", pszPath);
606
607 /* Create it when necessary. */
608 if (!RTDirExists(szFilePath))
609 {
610 rc = RTDirCreateFullPath(szFilePath, RTFS_UNIX_IRWXU);
611 if (RT_FAILURE(rc))
612 break;
613 }
614
615 /* The actually drop directory consist of the current time stamp and a
616 * unique number when necessary. */
617 char pszTime[64];
618 RTTIMESPEC time;
619 if (!RTTimeSpecToString(RTTimeNow(&time), pszTime, sizeof(pszTime)))
620 {
621 rc = VERR_BUFFER_OVERFLOW;
622 break;
623 }
624
625 rc = DrvAudioHlpSanitizeFileName(pszTime, sizeof(pszTime));
626 if (RT_FAILURE(rc))
627 break;
628
629 rc = RTPathAppend(szFilePath, sizeof(szFilePath), pszTime);
630 if (RT_FAILURE(rc))
631 break;
632
633 if (pszName) /* Optional name given? */
634 {
635 rc = RTStrCat(szFilePath, sizeof(szFilePath), "-");
636 if (RT_FAILURE(rc))
637 break;
638
639 rc = RTStrCat(szFilePath, sizeof(szFilePath), pszName);
640 if (RT_FAILURE(rc))
641 break;
642 }
643
644 switch (enmType)
645 {
646 case PDMAUDIOFILETYPE_WAV:
647 rc = RTStrCat(szFilePath, sizeof(szFilePath), ".wav");
648 break;
649
650 default:
651 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
652 }
653
654 if (RT_FAILURE(rc))
655 break;
656
657 RTStrPrintf(pszFile, cchFile, "%s", szFilePath);
658
659 } while (0);
660
661 LogFlowFuncLeaveRC(rc);
662 return rc;
663}
664
665int DrvAudioHlpWAVFileOpen(PPDMAUDIOFILE pFile, const char *pszFile, uint32_t fOpen, PPDMPCMPROPS pProps,
666 PDMAUDIOFILEFLAGS fFlags)
667{
668 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
669 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
670 /** @todo Validate fOpen flags. */
671 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
672 /** @todo Validate fFlags flags. */
673
674 Assert(pProps->cChannels);
675 Assert(pProps->uHz);
676 Assert(pProps->cBits);
677
678 pFile->pvData = (PAUDIOWAVFILEDATA)RTMemAllocZ(sizeof(AUDIOWAVFILEDATA));
679 if (!pFile->pvData)
680 return VERR_NO_MEMORY;
681 pFile->cbData = sizeof(PAUDIOWAVFILEDATA);
682
683 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
684 AssertPtr(pData);
685
686 /* Header. */
687 pData->Hdr.u32RIFF = AUDIO_MAKE_FOURCC('R','I','F','F');
688 pData->Hdr.u32Size = 36;
689 pData->Hdr.u32WAVE = AUDIO_MAKE_FOURCC('W','A','V','E');
690
691 pData->Hdr.u32Fmt = AUDIO_MAKE_FOURCC('f','m','t',' ');
692 pData->Hdr.u32Size1 = 16; /* Means PCM. */
693 pData->Hdr.u16AudioFormat = 1; /* PCM, linear quantization. */
694 pData->Hdr.u16NumChannels = pProps->cChannels;
695 pData->Hdr.u32SampleRate = pProps->uHz;
696 pData->Hdr.u32ByteRate = DrvAudioHlpCalcBitrate(pProps->cBits, pProps->uHz, pProps->cChannels) / 8;
697 pData->Hdr.u16BlockAlign = pProps->cChannels * pProps->cBits / 8;
698 pData->Hdr.u16BitsPerSample = pProps->cBits;
699
700 /* Data chunk. */
701 pData->Hdr.u32ID2 = AUDIO_MAKE_FOURCC('d','a','t','a');
702 pData->Hdr.u32Size2 = 0;
703
704 int rc = RTFileOpen(&pFile->hFile, pszFile, fOpen);
705 if (RT_SUCCESS(rc))
706 {
707 rc = RTFileWrite(pFile->hFile, &pData->Hdr, sizeof(pData->Hdr), NULL);
708 if (RT_FAILURE(rc))
709 {
710 RTFileClose(pFile->hFile);
711 pFile->hFile = NIL_RTFILE;
712 }
713 }
714
715 if (RT_SUCCESS(rc))
716 {
717 pFile->enmType = PDMAUDIOFILETYPE_WAV;
718
719 RTStrPrintf(pFile->szName, RT_ELEMENTS(pFile->szName), "%s", pszFile);
720 }
721 else
722 {
723 RTMemFree(pFile->pvData);
724 pFile->pvData = NULL;
725 pFile->cbData = 0;
726 }
727
728 return rc;
729}
730
731int DrvAudioHlpWAVFileClose(PPDMAUDIOFILE pFile)
732{
733 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
734
735 Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
736
737 if (pFile->hFile != NIL_RTFILE)
738 {
739 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
740 AssertPtr(pData);
741
742 /* Update the header with the current data size. */
743 RTFileWriteAt(pFile->hFile, 0, &pData->Hdr, sizeof(pData->Hdr), NULL);
744
745 RTFileClose(pFile->hFile);
746 pFile->hFile = NIL_RTFILE;
747 }
748
749 if (pFile->pvData)
750 {
751 RTMemFree(pFile->pvData);
752 pFile->pvData = NULL;
753 }
754
755 pFile->cbData = 0;
756 pFile->enmType = PDMAUDIOFILETYPE_UNKNOWN;
757
758 return VINF_SUCCESS;
759}
760
761size_t DrvAudioHlpWAVFileGetDataSize(PPDMAUDIOFILE pFile)
762{
763 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
764
765 Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
766
767 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
768 AssertPtr(pData);
769
770 return pData->Hdr.u32Size2;
771}
772
773int DrvAudioHlpWAVFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags)
774{
775 AssertPtrReturn(pFile, VERR_INVALID_POINTER);
776 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
777 /** @todo Validate fFlags. */
778
779 Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
780
781 if (!cbBuf)
782 return VINF_SUCCESS;
783
784 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
785 AssertPtr(pData);
786
787 int rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
788 if (RT_SUCCESS(rc))
789 {
790 pData->Hdr.u32Size += (uint32_t)cbBuf;
791 pData->Hdr.u32Size2 += (uint32_t)cbBuf;
792 }
793
794 return rc;
795}
796
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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