Changeset 88028 in vbox for trunk/include/VBox/vmm
- Timestamp:
- Mar 8, 2021 7:31:22 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 143156
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/vmm/pdmaudioinline.h
r88027 r88028 1 1 /* $Id$ */ 2 2 /** @file 3 * Intermedia audio driver, common routines.4 * 5 * Th ese are also used in the drivers which are bound to Main, e.g. the VRDE6 * or the video audio recording drivers.3 * PDM - Audio Helpers, Inlined Code. (DEV,++) 4 * 5 * This is all inlined because it's too tedious to create a couple libraries to 6 * contain it all (same bad excuse as for intnetinline.h & pdmnetinline.h). 7 7 */ 8 8 … … 17 17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the 18 18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 19 */ 19 * 20 * The contents of this file may alternatively be used under the terms 21 * of the Common Development and Distribution License Version 1.0 22 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the 23 * VirtualBox OSE distribution, in which case the provisions of the 24 * CDDL are applicable instead of those of the GPL. 25 * 26 * You may elect to license modified versions of this file under the 27 * terms and conditions of either the GPL or the CDDL or both. 28 */ 29 30 #ifndef VBOX_INCLUDED_vmm_pdmaudioinline_h 31 #define VBOX_INCLUDED_vmm_pdmaudioinline_h 32 #ifndef RT_WITHOUT_PRAGMA_ONCE 33 # pragma once 34 #endif 20 35 21 36 … … 23 38 * Header Files * 24 39 *********************************************************************************************************************************/ 25 #include <iprt/alloc.h> 40 #include <VBox/err.h> 41 #include <VBox/log.h> 42 #include <VBox/vmm/pdmaudioifs.h> 43 44 #include <iprt/asm.h> 26 45 #include <iprt/asm-math.h> 27 46 #include <iprt/assert.h> 28 #include <iprt/dir.h> 29 #include <iprt/file.h> 47 #include <iprt/mem.h> 30 48 #include <iprt/string.h> 31 #include <iprt/uuid.h> 32 33 #define LOG_GROUP LOG_GROUP_DRV_AUDIO 34 #include <VBox/log.h> 35 36 #include <VBox/err.h> 37 #include <VBox/vmm/pdmdev.h> 38 #include <VBox/vmm/pdm.h> 39 #include <VBox/vmm/mm.h> 40 41 #include <ctype.h> 42 #include <stdlib.h> 43 44 #include "DrvAudio.h" 45 #include "AudioMixBuffer.h" 46 47 48 /********************************************************************************************************************************* 49 * Structures and Typedefs * 50 *********************************************************************************************************************************/ 51 /** 52 * Structure for building up a .WAV file header. 53 */ 54 typedef 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; 72 AssertCompileSize(AUDIOWAVFILEHDR, 11*4); 73 74 /** 75 * Structure for keeeping the internal .WAV file data 76 */ 77 typedef struct AUDIOWAVFILEDATA 78 { 79 /** The file header/footer. */ 80 AUDIOWAVFILEHDR Hdr; 81 } AUDIOWAVFILEDATA, *PAUDIOWAVFILEDATA; 82 83 84 85 86 /** 87 * Retrieves the matching PDMAUDIOFMT for the given bits + signing flag. 88 * 89 * @return Matching PDMAUDIOFMT value. 90 * @retval PDMAUDIOFMT_INVALID if unsupported @a cBits value. 91 * 92 * @param cBits The number of bits in the audio format. 93 * @param fSigned Whether the audio format is signed @c true or not. 94 */ 95 PDMAUDIOFMT DrvAudioAudFmtBitsToFormat(uint8_t cBits, bool fSigned) 96 { 97 if (fSigned) 98 { 99 switch (cBits) 100 { 101 case 8: return PDMAUDIOFMT_S8; 102 case 16: return PDMAUDIOFMT_S16; 103 case 32: return PDMAUDIOFMT_S32; 104 default: AssertMsgFailedReturn(("Bogus audio bits %RU8\n", cBits), PDMAUDIOFMT_INVALID); 105 } 106 } 107 else 108 { 109 switch (cBits) 110 { 111 case 8: return PDMAUDIOFMT_U8; 112 case 16: return PDMAUDIOFMT_U16; 113 case 32: return PDMAUDIOFMT_U32; 114 default: AssertMsgFailedReturn(("Bogus audio bits %RU8\n", cBits), PDMAUDIOFMT_INVALID); 115 } 116 } 117 } 118 119 /** 120 * Returns an unique file name for this given audio connector instance. 121 * 122 * @return Allocated file name. Must be free'd using RTStrFree(). 123 * @param uInstance Driver / device instance. 124 * @param pszPath Path name of the file to delete. The path must exist. 125 * @param pszSuffix File name suffix to use. 126 */ 127 char *DrvAudioDbgGetFileNameA(uint8_t uInstance, const char *pszPath, const char *pszSuffix) 128 { 129 char szFileName[64]; 130 RTStrPrintf(szFileName, sizeof(szFileName), "drvAudio%RU8-%s", uInstance, pszSuffix); 131 132 char szFilePath[RTPATH_MAX]; 133 int rc2 = RTStrCopy(szFilePath, sizeof(szFilePath), pszPath); 134 AssertRC(rc2); 135 rc2 = RTPathAppend(szFilePath, sizeof(szFilePath), szFileName); 136 AssertRC(rc2); 137 138 return RTStrDup(szFilePath); 139 } 140 141 /** 142 * Allocates an audio device. 143 * 144 * @returns Newly allocated audio device, or NULL if failed. 145 * @param cbData How much additional data (in bytes) should be allocated to provide 146 * a (backend) specific area to store additional data. 147 * Optional, can be 0. 148 */ 149 PPDMAUDIODEVICE DrvAudioHlpDeviceAlloc(size_t cbData) 150 { 151 PPDMAUDIODEVICE pDev = (PPDMAUDIODEVICE)RTMemAllocZ(sizeof(PDMAUDIODEVICE)); 152 if (!pDev) 153 return NULL; 154 155 if (cbData) 156 { 157 pDev->pvData = RTMemAllocZ(cbData); 158 if (!pDev->pvData) 159 { 160 RTMemFree(pDev); 161 return NULL; 162 } 163 } 164 165 pDev->cbData = cbData; 166 167 pDev->cMaxInputChannels = 0; 168 pDev->cMaxOutputChannels = 0; 169 170 return pDev; 171 } 172 173 /** 174 * Frees an audio device. 175 * 176 * @param pDev Device to free. 177 */ 178 void DrvAudioHlpDeviceFree(PPDMAUDIODEVICE pDev) 179 { 180 if (!pDev) 181 return; 182 183 Assert(pDev->cRefCount == 0); 184 185 if (pDev->pvData) 186 { 187 Assert(pDev->cbData); 188 189 RTMemFree(pDev->pvData); 190 pDev->pvData = NULL; 191 } 192 193 RTMemFree(pDev); 194 pDev = NULL; 195 } 196 197 /** 198 * Duplicates an audio device entry. 199 * 200 * @returns Duplicated audio device entry on success, or NULL on failure. 201 * @param pDev Audio device entry to duplicate. 202 * @param fCopyUserData Whether to also copy the user data portion or not. 203 */ 204 PPDMAUDIODEVICE DrvAudioHlpDeviceDup(const PPDMAUDIODEVICE pDev, bool fCopyUserData) 205 { 206 AssertPtrReturn(pDev, NULL); 207 208 PPDMAUDIODEVICE pDevDup = DrvAudioHlpDeviceAlloc(fCopyUserData ? pDev->cbData : 0); 209 if (pDevDup) 210 { 211 memcpy(pDevDup, pDev, sizeof(PDMAUDIODEVICE)); 212 213 if ( fCopyUserData 214 && pDevDup->cbData) 215 { 216 memcpy(pDevDup->pvData, pDev->pvData, pDevDup->cbData); 217 } 218 else 219 { 220 pDevDup->cbData = 0; 221 pDevDup->pvData = NULL; 222 } 223 } 224 225 return pDevDup; 226 } 227 228 /** 229 * Initializes an audio device enumeration structure. 230 * 231 * @returns IPRT status code. 232 * @param pDevEnm Device enumeration to initialize. 233 */ 234 int DrvAudioHlpDeviceEnumInit(PPDMAUDIODEVICEENUM pDevEnm) 235 { 236 AssertPtrReturn(pDevEnm, VERR_INVALID_POINTER); 237 238 RTListInit(&pDevEnm->lstDevices); 239 pDevEnm->cDevices = 0; 240 241 return VINF_SUCCESS; 242 } 243 244 /** 245 * Frees audio device enumeration data. 246 * 247 * @param pDevEnm Device enumeration to destroy. 248 */ 249 void DrvAudioHlpDeviceEnumFree(PPDMAUDIODEVICEENUM pDevEnm) 250 { 251 if (!pDevEnm) 252 return; 253 254 PPDMAUDIODEVICE pDev, pDevNext; 255 RTListForEachSafe(&pDevEnm->lstDevices, pDev, pDevNext, PDMAUDIODEVICE, Node) 256 { 257 RTListNodeRemove(&pDev->Node); 258 259 DrvAudioHlpDeviceFree(pDev); 260 261 pDevEnm->cDevices--; 262 } 263 264 /* Sanity. */ 265 Assert(RTListIsEmpty(&pDevEnm->lstDevices)); 266 Assert(pDevEnm->cDevices == 0); 267 } 268 269 /** 270 * Adds an audio device to a device enumeration. 271 * 272 * @return IPRT status code. 273 * @param pDevEnm Device enumeration to add device to. 274 * @param pDev Device to add. The pointer will be owned by the device enumeration then. 275 */ 276 int DrvAudioHlpDeviceEnumAdd(PPDMAUDIODEVICEENUM pDevEnm, PPDMAUDIODEVICE pDev) 277 { 278 AssertPtrReturn(pDevEnm, VERR_INVALID_POINTER); 279 AssertPtrReturn(pDev, VERR_INVALID_POINTER); 280 281 RTListAppend(&pDevEnm->lstDevices, &pDev->Node); 282 pDevEnm->cDevices++; 283 284 return VINF_SUCCESS; 285 } 286 287 /** 288 * Duplicates a device enumeration. 289 * 290 * @returns Duplicated device enumeration, or NULL on failure. 291 * Must be free'd with DrvAudioHlpDeviceEnumFree(). 292 * @param pDevEnm Device enumeration to duplicate. 293 */ 294 PPDMAUDIODEVICEENUM DrvAudioHlpDeviceEnumDup(const PPDMAUDIODEVICEENUM pDevEnm) 295 { 296 AssertPtrReturn(pDevEnm, NULL); 297 298 PPDMAUDIODEVICEENUM pDevEnmDup = (PPDMAUDIODEVICEENUM)RTMemAlloc(sizeof(PDMAUDIODEVICEENUM)); 299 if (!pDevEnmDup) 300 return NULL; 301 302 int rc2 = DrvAudioHlpDeviceEnumInit(pDevEnmDup); 303 AssertRC(rc2); 304 305 PPDMAUDIODEVICE pDev; 306 RTListForEach(&pDevEnm->lstDevices, pDev, PDMAUDIODEVICE, Node) 307 { 308 PPDMAUDIODEVICE pDevDup = DrvAudioHlpDeviceDup(pDev, true /* fCopyUserData */); 309 if (!pDevDup) 310 { 311 rc2 = VERR_NO_MEMORY; 312 break; 313 } 314 315 rc2 = DrvAudioHlpDeviceEnumAdd(pDevEnmDup, pDevDup); 316 if (RT_FAILURE(rc2)) 317 { 318 DrvAudioHlpDeviceFree(pDevDup); 319 break; 320 } 321 } 322 323 if (RT_FAILURE(rc2)) 324 { 325 DrvAudioHlpDeviceEnumFree(pDevEnmDup); 326 pDevEnmDup = NULL; 327 } 328 329 return pDevEnmDup; 330 } 331 332 /** 333 * Copies device enumeration entries from the source to the destination enumeration. 334 * 335 * @returns IPRT status code. 336 * @param pDstDevEnm Destination enumeration to store enumeration entries into. 337 * @param pSrcDevEnm Source enumeration to use. 338 * @param enmUsage Which entries to copy. Specify PDMAUDIODIR_DUPLEX to copy all entries. 339 * @param fCopyUserData Whether to also copy the user data portion or not. 340 */ 341 int DrvAudioHlpDeviceEnumCopyEx(PPDMAUDIODEVICEENUM pDstDevEnm, const PPDMAUDIODEVICEENUM pSrcDevEnm, 342 PDMAUDIODIR enmUsage, bool fCopyUserData) 343 { 344 AssertPtrReturn(pDstDevEnm, VERR_INVALID_POINTER); 345 AssertPtrReturn(pSrcDevEnm, VERR_INVALID_POINTER); 346 347 int rc = VINF_SUCCESS; 348 349 PPDMAUDIODEVICE pSrcDev; 350 RTListForEach(&pSrcDevEnm->lstDevices, pSrcDev, PDMAUDIODEVICE, Node) 351 { 352 if ( enmUsage != PDMAUDIODIR_DUPLEX 353 && enmUsage != pSrcDev->enmUsage) 354 { 355 continue; 356 } 357 358 PPDMAUDIODEVICE pDstDev = DrvAudioHlpDeviceDup(pSrcDev, fCopyUserData); 359 if (!pDstDev) 360 { 361 rc = VERR_NO_MEMORY; 362 break; 363 } 364 365 rc = DrvAudioHlpDeviceEnumAdd(pDstDevEnm, pDstDev); 366 if (RT_FAILURE(rc)) 367 break; 368 } 369 370 return rc; 371 } 372 373 /** 374 * Copies all device enumeration entries from the source to the destination enumeration. 375 * 376 * Note: Does *not* copy the user-specific data assigned to a device enumeration entry. 377 * To do so, use DrvAudioHlpDeviceEnumCopyEx(). 378 * 379 * @returns IPRT status code. 380 * @param pDstDevEnm Destination enumeration to store enumeration entries into. 381 * @param pSrcDevEnm Source enumeration to use. 382 */ 383 int DrvAudioHlpDeviceEnumCopy(PPDMAUDIODEVICEENUM pDstDevEnm, const PPDMAUDIODEVICEENUM pSrcDevEnm) 384 { 385 return DrvAudioHlpDeviceEnumCopyEx(pDstDevEnm, pSrcDevEnm, PDMAUDIODIR_DUPLEX, false /* fCopyUserData */); 386 } 387 388 /** 389 * Returns the default device of a given device enumeration. 390 * This assumes that only one default device per usage is set. 391 * 392 * @returns Default device if found, or NULL if none found. 393 * @param pDevEnm Device enumeration to get default device for. 394 * @param enmUsage Usage to get default device for. 395 */ 396 PPDMAUDIODEVICE DrvAudioHlpDeviceEnumGetDefaultDevice(const PPDMAUDIODEVICEENUM pDevEnm, PDMAUDIODIR enmUsage) 397 { 398 AssertPtrReturn(pDevEnm, NULL); 399 400 PPDMAUDIODEVICE pDev; 401 RTListForEach(&pDevEnm->lstDevices, pDev, PDMAUDIODEVICE, Node) 402 { 403 if (enmUsage != PDMAUDIODIR_DUPLEX) 404 { 405 if (enmUsage != pDev->enmUsage) /* Wrong usage? Skip. */ 406 continue; 407 } 408 409 if (pDev->fFlags & PDMAUDIODEV_FLAGS_DEFAULT) 410 return pDev; 411 } 412 413 return NULL; 414 } 415 416 /** 417 * Returns the number of enumerated devices of a given device enumeration. 418 * 419 * @returns Number of devices if found, or 0 if none found. 420 * @param pDevEnm Device enumeration to get default device for. 421 * @param enmUsage Usage to get default device for. 422 */ 423 uint16_t DrvAudioHlpDeviceEnumGetDeviceCount(const PPDMAUDIODEVICEENUM pDevEnm, PDMAUDIODIR enmUsage) 424 { 425 AssertPtrReturn(pDevEnm, 0); 426 427 if (enmUsage == PDMAUDIODIR_DUPLEX) 428 return pDevEnm->cDevices; 429 430 uint32_t cDevs = 0; 431 432 PPDMAUDIODEVICE pDev; 433 RTListForEach(&pDevEnm->lstDevices, pDev, PDMAUDIODEVICE, Node) 434 { 435 if (enmUsage == pDev->enmUsage) 436 cDevs++; 437 } 438 439 return cDevs; 440 } 441 442 /** 443 * Logs an audio device enumeration. 444 * 445 * @param pszDesc Logging description. 446 * @param pDevEnm Device enumeration to log. 447 */ 448 void DrvAudioHlpDeviceEnumPrint(const char *pszDesc, const PPDMAUDIODEVICEENUM pDevEnm) 449 { 450 AssertPtrReturnVoid(pszDesc); 451 AssertPtrReturnVoid(pDevEnm); 452 453 LogFunc(("%s: %RU16 devices\n", pszDesc, pDevEnm->cDevices)); 454 455 PPDMAUDIODEVICE pDev; 456 RTListForEach(&pDevEnm->lstDevices, pDev, PDMAUDIODEVICE, Node) 457 { 458 char *pszFlags = DrvAudioHlpAudDevFlagsToStrA(pDev->fFlags); 459 460 LogFunc(("Device '%s':\n", pDev->szName)); 461 LogFunc(("\tUsage = %s\n", PDMAudioDirGetName(pDev->enmUsage))); 462 LogFunc(("\tFlags = %s\n", pszFlags ? pszFlags : "<NONE>")); 463 LogFunc(("\tInput channels = %RU8\n", pDev->cMaxInputChannels)); 464 LogFunc(("\tOutput channels = %RU8\n", pDev->cMaxOutputChannels)); 465 LogFunc(("\tData = %p (%zu bytes)\n", pDev->pvData, pDev->cbData)); 466 467 if (pszFlags) 468 RTStrFree(pszFlags); 469 } 470 } 49 50 51 /* Fix later: */ 52 DECLINLINE(bool) PDMAudioPropsAreValid(PCPDMAUDIOPCMPROPS pProps); 53 DECLINLINE(bool) PDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2); 54 55 471 56 472 57 /** 473 58 * Gets the name of an audio direction enum value. 474 59 * 475 * @returns Pointer to read-only name string on success, " Unknown" if60 * @returns Pointer to read-only name string on success, "bad" if 476 61 * passed an invalid enum value. 477 62 * @param enmDir The audio direction value to name. 478 63 */ 479 const char *PDMAudioDirGetName(PDMAUDIODIR enmDir)64 DECLINLINE(const char *) PDMAudioDirGetName(PDMAUDIODIR enmDir) 480 65 { 481 66 switch (enmDir) … … 491 76 break; 492 77 } 493 AssertMsgFailedReturn(("Invalid audio direction %d\n", enmDir), " Unknown");494 } 495 496 /** 497 * Converts an audio mixer control to a string.498 * 499 * @returns Stringified audio mixer control or "Unknown", if not found.500 * @param enmMixerCtl Audio mixer control to convert.501 */ 502 const char *PDMAudioMixerCtlGetName(PDMAUDIOMIXERCTL enmMixerCtl)78 AssertMsgFailedReturn(("Invalid audio direction %d\n", enmDir), "bad"); 79 } 80 81 /** 82 * Gets the name of an audio mixer control enum value. 83 * 84 * @returns Pointer to read-only name, "bad" if invalid input. 85 * @param enmMixerCtl The audio mixer control value. 86 */ 87 DECLINLINE(const char *) PDMAudioMixerCtlGetName(PDMAUDIOMIXERCTL enmMixerCtl) 503 88 { 504 89 switch (enmMixerCtl) 505 90 { 91 case PDMAUDIOMIXERCTL_UNKNOWN: return "Unknown"; 506 92 case PDMAUDIOMIXERCTL_VOLUME_MASTER: return "Master Volume"; 507 93 case PDMAUDIOMIXERCTL_FRONT: return "Front"; … … 510 96 case PDMAUDIOMIXERCTL_LINE_IN: return "Line-In"; 511 97 case PDMAUDIOMIXERCTL_MIC_IN: return "Microphone-In"; 512 default: break; 513 } 514 515 AssertMsgFailed(("Invalid mixer control %ld\n", enmMixerCtl)); 516 return "Unknown"; 517 } 518 519 /** 520 * Converts an audio device flags to a string. 521 * 522 * @returns Stringified audio flags. Must be free'd with RTStrFree(). 523 * NULL if no flags set. 524 * @param fFlags Audio flags (PDMAUDIODEV_FLAGS_XXX) to convert. 525 */ 526 char *DrvAudioHlpAudDevFlagsToStrA(uint32_t fFlags) 527 { 528 #define APPEND_FLAG_TO_STR(_aFlag) \ 529 if (fFlags & PDMAUDIODEV_FLAGS_##_aFlag) \ 530 { \ 531 if (pszFlags) \ 532 { \ 533 rc2 = RTStrAAppend(&pszFlags, " "); \ 534 if (RT_FAILURE(rc2)) \ 535 break; \ 536 } \ 537 \ 538 rc2 = RTStrAAppend(&pszFlags, #_aFlag); \ 539 if (RT_FAILURE(rc2)) \ 540 break; \ 541 } \ 542 543 char *pszFlags = NULL; 544 int rc2 = VINF_SUCCESS; 545 546 do 547 { 548 APPEND_FLAG_TO_STR(DEFAULT); 549 APPEND_FLAG_TO_STR(HOTPLUG); 550 APPEND_FLAG_TO_STR(BUGGY); 551 APPEND_FLAG_TO_STR(IGNORE); 552 APPEND_FLAG_TO_STR(LOCKED); 553 APPEND_FLAG_TO_STR(DEAD); 554 555 } while (0); 556 557 if (!pszFlags) 558 rc2 = RTStrAAppend(&pszFlags, "NONE"); 559 560 if ( RT_FAILURE(rc2) 561 && pszFlags) 562 { 563 RTStrFree(pszFlags); 564 pszFlags = NULL; 565 } 566 567 #undef APPEND_FLAG_TO_STR 568 569 return pszFlags; 570 } 571 572 /** 573 * Converts a playback destination enumeration to a string. 574 * 575 * @returns Stringified playback destination, or "Unknown", if not found. 576 * @param enmPlaybackDst Playback destination to convert. 577 */ 578 const char *PDMAudioPlaybackDstGetName(const PDMAUDIOPLAYBACKDST enmPlaybackDst) 98 /* no default */ 99 case PDMAUDIOMIXERCTL_INVALID: 100 case PDMAUDIOMIXERCTL_32BIT_HACK: 101 break; 102 } 103 AssertMsgFailedReturn(("Invalid mixer control %ld\n", enmMixerCtl), "bad"); 104 } 105 106 /** 107 * Gets the name of a playback destination enum value. 108 * 109 * @returns Pointer to read-only name, "bad" if invalid input. 110 * @param enmPlaybackDst The playback destination value. 111 */ 112 DECLINLINE(const char *) PDMAudioPlaybackDstGetName(PDMAUDIOPLAYBACKDST enmPlaybackDst) 579 113 { 580 114 switch (enmPlaybackDst) … … 584 118 case PDMAUDIOPLAYBACKDST_CENTER_LFE: return "Center / LFE"; 585 119 case PDMAUDIOPLAYBACKDST_REAR: return "Rear"; 586 default: 120 /* no default */ 121 case PDMAUDIOPLAYBACKDST_INVALID: 122 case PDMAUDIOPLAYBACKDST_32BIT_HACK: 587 123 break; 588 124 } 589 590 AssertMsgFailed(("Invalid playback destination %ld\n", enmPlaybackDst)); 591 return "Unknown"; 592 } 593 594 /** 595 * Converts a recording source enumeration to a string. 596 * 597 * @returns Stringified recording source, or "Unknown", if not found. 598 * @param enmRecSrc Recording source to convert. 599 */ 600 const char *PDMAudioRecSrcGetName(const PDMAUDIORECSRC enmRecSrc) 125 AssertMsgFailedReturn(("Invalid playback destination %ld\n", enmPlaybackDst), "bad"); 126 } 127 128 /** 129 * Gets the name of a recording source enum value. 130 * 131 * @returns Pointer to read-only name, "bad" if invalid input. 132 * @param enmRecSrc The recording source value. 133 */ 134 DECLINLINE(const char *) PDMAudioRecSrcGetName(PDMAUDIORECSRC enmRecSrc) 601 135 { 602 136 switch (enmRecSrc) … … 609 143 case PDMAUDIORECSRC_LINE: return "Line In"; 610 144 case PDMAUDIORECSRC_PHONE: return "Phone"; 611 default: 145 /* no default */ 146 case PDMAUDIORECSRC_32BIT_HACK: 612 147 break; 613 148 } 614 615 AssertMsgFailed(("Invalid recording source %ld\n", enmRecSrc)); 616 return "Unknown"; 149 AssertMsgFailedReturn(("Invalid recording source %ld\n", enmRecSrc), "bad"); 617 150 } 618 151 … … 623 156 * @param enmFmt The audio format. 624 157 */ 625 boolPDMAudioFormatIsSigned(PDMAUDIOFMT enmFmt)158 DECLINLINE(bool) PDMAudioFormatIsSigned(PDMAUDIOFMT enmFmt) 626 159 { 627 160 switch (enmFmt) … … 651 184 * @param enmFmt The audio format. 652 185 */ 653 uint8_tPDMAudioFormatGetBits(PDMAUDIOFMT enmFmt)186 DECLINLINE(uint8_t) PDMAudioFormatGetBits(PDMAUDIOFMT enmFmt) 654 187 { 655 188 switch (enmFmt) … … 678 211 * Gets the name of an audio format enum value. 679 212 * 680 * @returns Pointer to read-only name on success, returns " Unknown" on if213 * @returns Pointer to read-only name on success, returns "bad" on if 681 214 * invalid enum value. 682 215 * @param enmFmt The audio format to name. 683 216 */ 684 const char *PDMAudioFormatGetName(PDMAUDIOFMT enmFmt)217 DECLINLINE(const char *) PDMAudioFormatGetName(PDMAUDIOFMT enmFmt) 685 218 { 686 219 switch (enmFmt) … … 697 230 break; 698 231 } 699 AssertMsgFailedReturn(("Bogus audio format %d\n", enmFmt), "Unknown"); 700 } 701 702 /** 703 * Converts a given string to an audio format. 704 * 705 * @returns Audio format for the given string, or PDMAUDIOFMT_INVALID if not found. 706 * @param pszFmt String to convert to an audio format. 707 */ 708 PDMAUDIOFMT DrvAudioHlpStrToAudFmt(const char *pszFmt) 709 { 710 AssertPtrReturn(pszFmt, PDMAUDIOFMT_INVALID); 711 712 if (!RTStrICmp(pszFmt, "u8")) 713 return PDMAUDIOFMT_U8; 714 if (!RTStrICmp(pszFmt, "u16")) 715 return PDMAUDIOFMT_U16; 716 if (!RTStrICmp(pszFmt, "u32")) 717 return PDMAUDIOFMT_U32; 718 if (!RTStrICmp(pszFmt, "s8")) 719 return PDMAUDIOFMT_S8; 720 if (!RTStrICmp(pszFmt, "s16")) 721 return PDMAUDIOFMT_S16; 722 if (!RTStrICmp(pszFmt, "s32")) 723 return PDMAUDIOFMT_S32; 724 725 AssertMsgFailed(("Invalid audio format '%s'\n", pszFmt)); 726 return PDMAUDIOFMT_INVALID; 727 } 728 729 #if 0 /* unused */ 730 /** 731 * Initializes a stream configuration with default values. 732 * 733 * @param pCfg The stream configuration structure to initialize. 734 */ 735 void PDMAudioStrmCfgInit(PPDMAUDIOSTREAMCFG pCfg) 736 { 737 AssertPtrReturnVoid(pCfg); 738 739 RT_ZERO(*pCfg); 740 741 pCfg->Backend.cFramesPreBuffering = UINT32_MAX; /* Explicitly set to "undefined". */ 742 } 743 #endif 232 AssertMsgFailedReturn(("Bogus audio format %d\n", enmFmt), "bad"); 233 } 744 234 745 235 /** … … 750 240 * @param pProps The PCM properties to use. 751 241 */ 752 intPDMAudioStrmCfgInitWithProps(PPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps)242 DECLINLINE(int) PDMAudioStrmCfgInitWithProps(PPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps) 753 243 { 754 244 AssertPtrReturn(pProps, VERR_INVALID_POINTER); … … 761 251 762 252 return VINF_SUCCESS; 763 }764 765 /**766 * Checks whether a given stream configuration is valid or not.767 *768 * @note See notes on DrvAudioHlpPcmPropsAreValid().769 *770 * Returns @c true if configuration is valid, @c false if not.771 * @param pCfg Stream configuration to check.772 */773 bool DrvAudioHlpStreamCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg)774 {775 AssertPtrReturn(pCfg, false);776 777 bool fValid = ( pCfg->enmDir == PDMAUDIODIR_IN778 || pCfg->enmDir == PDMAUDIODIR_OUT);779 780 fValid &= ( pCfg->enmLayout == PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED781 || pCfg->enmLayout == PDMAUDIOSTREAMLAYOUT_RAW);782 783 if (fValid)784 fValid = DrvAudioHlpPcmPropsAreValid(&pCfg->Props);785 786 return fValid;787 253 } 788 254 … … 794 260 * @param pProps The PCM properties to match with. 795 261 */ 796 boolPDMAudioStrmCfgMatchesProps(PCPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps)262 DECLINLINE(bool) PDMAudioStrmCfgMatchesProps(PCPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps) 797 263 { 798 264 AssertPtrReturn(pCfg, false); … … 805 271 * @param pCfg The stream configuration to free. 806 272 */ 807 voidPDMAudioStrmCfgFree(PPDMAUDIOSTREAMCFG pCfg)273 DECLINLINE(void) PDMAudioStrmCfgFree(PPDMAUDIOSTREAMCFG pCfg) 808 274 { 809 275 if (pCfg) 810 {811 276 RTMemFree(pCfg); 812 pCfg = NULL; 813 } 277 } 278 279 /** 280 * Checks whether the given stream configuration is valid or not. 281 * 282 * @returns true/false accordingly. 283 * @param pCfg Stream configuration to check. 284 * 285 * @remarks This just performs a generic check of value ranges. Further, it 286 * will assert if the input is invalid. 287 * 288 * @sa PDMAudioPropsAreValid 289 */ 290 DECLINLINE(bool) PDMAudioStrmCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg) 291 { 292 AssertPtrReturn(pCfg, false); 293 AssertMsgReturn(pCfg->enmDir >= PDMAUDIODIR_UNKNOWN && pCfg->enmDir <= PDMAUDIODIR_DUPLEX, 294 ("%d\n", pCfg->enmDir), false); 295 AssertMsgReturn(pCfg->enmLayout >= PDMAUDIOSTREAMLAYOUT_UNKNOWN && pCfg->enmLayout <= PDMAUDIOSTREAMLAYOUT_RAW, 296 ("%d\n", pCfg->enmLayout), false); 297 return PDMAudioPropsAreValid(&pCfg->Props); 814 298 } 815 299 … … 821 305 * @param pSrcCfg The source stream configuration. 822 306 */ 823 intPDMAudioStrmCfgCopy(PPDMAUDIOSTREAMCFG pDstCfg, PCPDMAUDIOSTREAMCFG pSrcCfg)307 DECLINLINE(int) PDMAudioStrmCfgCopy(PPDMAUDIOSTREAMCFG pDstCfg, PCPDMAUDIOSTREAMCFG pSrcCfg) 824 308 { 825 309 AssertPtrReturn(pDstCfg, VERR_INVALID_POINTER); 826 310 AssertPtrReturn(pSrcCfg, VERR_INVALID_POINTER); 827 311 828 #ifdef VBOX_STRICT 829 /** @todo r=bird: This is _bad_ as it makes strict builds behave different from 830 * release builds. The whole 'valid' concept is a bit inconsistent 831 * too, so it cannot carry over to PDM. */ 832 if (!DrvAudioHlpStreamCfgIsValid(pSrcCfg)) 833 { 834 AssertMsgFailed(("Stream config '%s' (%p) is invalid\n", pSrcCfg->szName, pSrcCfg)); 835 return VERR_INVALID_PARAMETER; 836 } 837 #endif 312 /* This used to be VBOX_STRICT only and return VERR_INVALID_PARAMETER, but 313 that's making release builds work differently from debug & strict builds, 314 which is a terrible idea: */ 315 Assert(PDMAudioStrmCfgIsValid(pSrcCfg)); 838 316 839 317 memcpy(pDstCfg, pSrcCfg, sizeof(PDMAUDIOSTREAMCFG)); … … 850 328 * @param pCfg The audio stream configuration to duplicate. 851 329 */ 852 PPDMAUDIOSTREAMCFGPDMAudioStrmCfgDup(PCPDMAUDIOSTREAMCFG pCfg)330 DECLINLINE(PPDMAUDIOSTREAMCFG) PDMAudioStrmCfgDup(PCPDMAUDIOSTREAMCFG pCfg) 853 331 { 854 332 AssertPtrReturn(pCfg, NULL); … … 871 349 * @param pCfg The stream configuration to log. 872 350 */ 873 voidPDMAudioStrmCfgLog(PCPDMAUDIOSTREAMCFG pCfg)351 DECLINLINE(void) PDMAudioStrmCfgLog(PCPDMAUDIOSTREAMCFG pCfg) 874 352 { 875 353 if (pCfg) … … 882 360 * 883 361 * @returns Pointer to read-only stream command name on success, 884 * " Unknown" if invalid command value.362 * "bad" if invalid command value. 885 363 * @param enmCmd The stream command to name. 886 364 */ 887 const char *PDMAudioStrmCmdGetName(PDMAUDIOSTREAMCMD enmCmd)365 DECLINLINE(const char *) PDMAudioStrmCmdGetName(PDMAUDIOSTREAMCMD enmCmd) 888 366 { 889 367 switch (enmCmd) … … 901 379 /* no default! */ 902 380 } 903 AssertMsgFailedReturn(("Invalid stream command %d\n", enmCmd), " Unknown");381 AssertMsgFailedReturn(("Invalid stream command %d\n", enmCmd), "bad"); 904 382 } 905 383 … … 910 388 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAMSTS_FLAGS_XXX. 911 389 */ 912 boolPDMAudioStrmStatusCanRead(PDMAUDIOSTREAMSTS fStatus)390 DECLINLINE(bool) PDMAudioStrmStatusCanRead(PDMAUDIOSTREAMSTS fStatus) 913 391 { 914 392 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false); … … 932 410 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAMSTS_FLAGS_XXX. 933 411 */ 934 boolPDMAudioStrmStatusCanWrite(PDMAUDIOSTREAMSTS fStatus)412 DECLINLINE(bool) PDMAudioStrmStatusCanWrite(PDMAUDIOSTREAMSTS fStatus) 935 413 { 936 414 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false); … … 956 434 * @param fStatus Stream status to evaluate, PDMAUDIOSTREAMSTS_FLAGS_XXX. 957 435 */ 958 boolPDMAudioStrmStatusIsReady(PDMAUDIOSTREAMSTS fStatus)436 DECLINLINE(bool) PDMAudioStrmStatusIsReady(PDMAUDIOSTREAMSTS fStatus) 959 437 { 960 438 AssertReturn(fStatus & PDMAUDIOSTREAMSTS_VALID_MASK, false); … … 970 448 } 971 449 972 /**973 * Calculates the audio bit rate of the given bits per sample, the Hz and the number974 * of audio channels.975 *976 * Divide the result by 8 to get the byte rate.977 *978 * @returns Bitrate.979 * @param cBits Number of bits per sample.980 * @param uHz Hz (Hertz) rate.981 * @param cChannels Number of audio channels.982 */983 uint32_t DrvAudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels)984 {985 return cBits * uHz * cChannels;986 }987 988 450 989 451 /********************************************************************************************************************************* … … 999 461 * @param pProps PCM properties to calculate bitrate for. 1000 462 */ 1001 uint32_tPDMAudioPropsGetBitrate(PCPDMAUDIOPCMPROPS pProps)463 DECLINLINE(uint32_t) PDMAudioPropsGetBitrate(PCPDMAUDIOPCMPROPS pProps) 1002 464 { 1003 465 return pProps->cbSample * pProps->cChannels * pProps->uHz * 8; … … 1011 473 * @param cb The size (in bytes) to round. 1012 474 */ 1013 uint32_tPDMAudioPropsFloorBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)475 DECLINLINE(uint32_t) PDMAudioPropsFloorBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) 1014 476 { 1015 477 AssertPtrReturn(pProps, 0); … … 1024 486 * @param cb The size (in bytes) to check. 1025 487 */ 1026 boolPDMAudioPropsIsSizeAligned(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)488 DECLINLINE(bool) PDMAudioPropsIsSizeAligned(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) 1027 489 { 1028 490 AssertPtrReturn(pProps, false); … … 1039 501 * @param cb The number of bytes to convert. 1040 502 */ 1041 uint32_tPDMAudioPropsBytesToFrames(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)503 DECLINLINE(uint32_t) PDMAudioPropsBytesToFrames(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) 1042 504 { 1043 505 AssertPtrReturn(pProps, 0); … … 1054 516 * @note Rounds up the result. 1055 517 */ 1056 uint64_tPDMAudioPropsBytesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)518 DECLINLINE(uint64_t) PDMAudioPropsBytesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) 1057 519 { 1058 520 AssertPtrReturn(pProps, 0); … … 1084 546 * @note Rounds up the result. 1085 547 */ 1086 uint64_tPDMAudioPropsBytesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)548 DECLINLINE(uint64_t) PDMAudioPropsBytesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) 1087 549 { 1088 550 AssertPtrReturn(pProps, 0); … … 1114 576 * @note Rounds up the result. 1115 577 */ 1116 uint64_tPDMAudioPropsBytesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cb)578 DECLINLINE(uint64_t) PDMAudioPropsBytesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) 1117 579 { 1118 580 AssertPtrReturn(pProps, 0); … … 1143 605 * @sa PDMAUDIOPCMPROPS_F2B 1144 606 */ 1145 uint32_tPDMAudioPropsFramesToBytes(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)607 DECLINLINE(uint32_t) PDMAudioPropsFramesToBytes(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) 1146 608 { 1147 609 AssertPtrReturn(pProps, 0); … … 1157 619 * @note No rounding here, result is floored. 1158 620 */ 1159 uint64_tPDMAudioPropsFramesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)621 DECLINLINE(uint64_t) PDMAudioPropsFramesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) 1160 622 { 1161 623 AssertPtrReturn(pProps, 0); … … 1176 638 * @note No rounding here, result is floored. 1177 639 */ 1178 uint64_tPDMAudioPropsFramesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)640 DECLINLINE(uint64_t) PDMAudioPropsFramesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) 1179 641 { 1180 642 AssertPtrReturn(pProps, 0); … … 1196 658 * @note The result is rounded rather than floored (hysterical raisins). 1197 659 */ 1198 uint32_tPDMAudioPropsMilliToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)660 DECLINLINE(uint32_t) PDMAudioPropsMilliToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs) 1199 661 { 1200 662 AssertPtrReturn(pProps, 0); … … 1222 684 * @note The result is rounded rather than floored (hysterical raisins). 1223 685 */ 1224 uint32_tPDMAudioPropsMilliToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs)686 DECLINLINE(uint32_t) PDMAudioPropsMilliToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs) 1225 687 { 1226 688 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsMilliToFrames(pProps, cMs)); … … 1236 698 * @note The result is rounded rather than floored (hysterical raisins). 1237 699 */ 1238 uint32_tPDMAudioPropsNanoToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)700 DECLINLINE(uint32_t) PDMAudioPropsNanoToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) 1239 701 { 1240 702 AssertPtrReturn(pProps, 0); … … 1262 724 * @note The result is rounded rather than floored (hysterical raisins). 1263 725 */ 1264 uint32_tPDMAudioPropsNanoToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs)726 DECLINLINE(uint32_t) PDMAudioPropsNanoToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) 1265 727 { 1266 728 return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs)); … … 1279 741 * uninitialized in some configurations. 1280 742 */ 1281 voidPDMAudioPropsClearBuffer(PCPDMAUDIOPCMPROPS pProps, void *pvBuf, size_t cbBuf, uint32_t cFrames)743 DECLINLINE(void) PDMAudioPropsClearBuffer(PCPDMAUDIOPCMPROPS pProps, void *pvBuf, size_t cbBuf, uint32_t cFrames) 1282 744 { 1283 745 /* … … 1342 804 * @param pProps2 The second set of properties to compare. 1343 805 */ 1344 boolPDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2)806 DECLINLINE(bool) PDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2) 1345 807 { 1346 808 AssertPtrReturn(pProps1, false); … … 1358 820 1359 821 /** 1360 * Checks whether given PCM properties are valid or not. 1361 * 1362 * @note This is more of a supported than valid check. There is code for 1363 * unsigned samples elsewhere (like DrvAudioHlpClearBuf()), but this 1364 * function will flag such properties as not valid. 1365 * 1366 * @todo r=bird: See note and explain properly. 1367 * 1368 * @returns @c true if the properties are valid, @c false if not. 1369 * @param pProps The PCM properties to check. 1370 */ 1371 bool DrvAudioHlpPcmPropsAreValid(PCPDMAUDIOPCMPROPS pProps) 822 * Checks whether the given PCM properties are valid or not. 823 * 824 * @returns true/false accordingly. 825 * @param pProps The PCM properties to check. 826 * 827 * @remarks This just performs a generic check of value ranges. Further, it 828 * will assert if the input is invalid. 829 * 830 * @sa PDMAudioStrmCfgIsValid 831 */ 832 DECLINLINE(bool) PDMAudioPropsAreValid(PCPDMAUDIOPCMPROPS pProps) 1372 833 { 1373 834 AssertPtrReturn(pProps, false); 1374 835 1375 /** @todo r=bird: This code is cannot make up its mind whether to return on 1376 * false, or whether to return at the end. (hint: just return 1377 * immediately, duh.) */ 1378 1379 /* Minimum 1 channel (mono), maximum 7.1 (= 8) channels. */ 1380 bool fValid = ( pProps->cChannels >= 1 1381 && pProps->cChannels <= 8); 1382 1383 if (fValid) 1384 { 1385 switch (pProps->cbSample) 1386 { 1387 case 1: /* 8 bit */ 1388 if (pProps->fSigned) 1389 fValid = false; 1390 break; 1391 case 2: /* 16 bit */ 1392 if (!pProps->fSigned) 1393 fValid = false; 1394 break; 1395 /** @todo Do we need support for 24 bit samples? */ 1396 case 4: /* 32 bit */ 1397 if (!pProps->fSigned) 1398 fValid = false; 1399 break; 1400 default: 1401 fValid = false; 1402 break; 1403 } 1404 } 1405 1406 if (!fValid) 1407 return false; 1408 1409 fValid &= pProps->uHz > 0; 1410 fValid &= pProps->cShift == PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pProps->cbSample, pProps->cChannels); 1411 fValid &= pProps->fSwapEndian == false; /** @todo Handling Big Endian audio data is not supported yet. */ 1412 1413 return fValid; 836 AssertReturn(pProps->cChannels != 0, false); 837 AssertMsgReturn(pProps->cbSample == 1 || pProps->cbSample == 2 || pProps->cbSample == 4, 838 ("%u\n", pProps->cbSample), false); 839 AssertMsgReturn(pProps->uHz >= 1000 && pProps->uHz < 1000000, ("%u\n", pProps->uHz), false); 840 AssertMsgReturn(pProps->cShift == PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pProps->cbSample, pProps->cChannels), 841 ("cShift=%u cbSample=%u cChannels=%u\n", pProps->cShift, pProps->cbSample, pProps->cChannels), 842 false); 843 return true; 1414 844 } 1415 845 … … 1421 851 * @sa PDMAUDIOPCMPROPS_F2B 1422 852 */ 1423 uint32_tPDMAudioPropsBytesPerFrame(PCPDMAUDIOPCMPROPS pProps)853 DECLINLINE(uint32_t) PDMAudioPropsBytesPerFrame(PCPDMAUDIOPCMPROPS pProps) 1424 854 { 1425 855 return PDMAUDIOPCMPROPS_F2B(pProps, 1 /*cFrames*/); … … 1431 861 * @param pProps Stream configuration to log. 1432 862 */ 1433 voidPDMAudioPropsLog(PCPDMAUDIOPCMPROPS pProps)863 DECLINLINE(void) PDMAudioPropsLog(PCPDMAUDIOPCMPROPS pProps) 1434 864 { 1435 865 AssertPtrReturnVoid(pProps); … … 1439 869 } 1440 870 1441 1442 /*********************************************************************************************************************************1443 * Audio File Helpers *1444 *********************************************************************************************************************************/1445 1446 /**1447 * Sanitizes the file name component so that unsupported characters1448 * will be replaced by an underscore ("_").1449 *1450 * @return IPRT status code.1451 * @param pszPath Path to sanitize.1452 * @param cbPath Size (in bytes) of path to sanitize.1453 */1454 int DrvAudioHlpFileNameSanitize(char *pszPath, size_t cbPath)1455 {1456 RT_NOREF(cbPath);1457 int rc = VINF_SUCCESS;1458 #ifdef RT_OS_WINDOWS1459 /* Filter out characters not allowed on Windows platforms, put in by1460 RTTimeSpecToString(). */1461 /** @todo Use something like RTPathSanitize() if available later some time. */1462 static RTUNICP const s_uszValidRangePairs[] =1463 {1464 ' ', ' ',1465 '(', ')',1466 '-', '.',1467 '0', '9',1468 'A', 'Z',1469 'a', 'z',1470 '_', '_',1471 0xa0, 0xd7af,1472 '\0'1473 };1474 ssize_t cReplaced = RTStrPurgeComplementSet(pszPath, s_uszValidRangePairs, '_' /* Replacement */);1475 if (cReplaced < 0)1476 rc = VERR_INVALID_UTF8_ENCODING;1477 #else1478 RT_NOREF(pszPath);1479 871 #endif 1480 return rc;1481 }1482 1483 /**1484 * Constructs an unique file name, based on the given path and the audio file type.1485 *1486 * @returns IPRT status code.1487 * @param pszFile Where to store the constructed file name.1488 * @param cchFile Size (in characters) of the file name buffer.1489 * @param pszPath Base path to use.1490 * If NULL or empty, the system's temporary directory will be used.1491 * @param pszName A name for better identifying the file.1492 * @param uInstance Device / driver instance which is using this file.1493 * @param enmType Audio file type to construct file name for.1494 * @param fFlags File naming flags, PDMAUDIOFILENAME_FLAGS_XXX.1495 */1496 int DrvAudioHlpFileNameGet(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName,1497 uint32_t uInstance, PDMAUDIOFILETYPE enmType, uint32_t fFlags)1498 {1499 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);1500 AssertReturn(cchFile, VERR_INVALID_PARAMETER);1501 /* pszPath can be NULL. */1502 AssertPtrReturn(pszName, VERR_INVALID_POINTER);1503 /** @todo Validate fFlags. */1504 1505 int rc;1506 1507 char *pszPathTmp = NULL;1508 1509 do1510 {1511 if ( pszPath == NULL1512 || !strlen(pszPath))1513 {1514 char szTemp[RTPATH_MAX];1515 rc = RTPathTemp(szTemp, sizeof(szTemp));1516 if (RT_SUCCESS(rc))1517 {1518 pszPathTmp = RTStrDup(szTemp);1519 }1520 else1521 break;1522 }1523 else1524 pszPathTmp = RTStrDup(pszPath);1525 1526 AssertPtrBreakStmt(pszPathTmp, rc = VERR_NO_MEMORY);1527 1528 char szFilePath[RTPATH_MAX];1529 rc = RTStrCopy(szFilePath, sizeof(szFilePath), pszPathTmp);1530 AssertRCBreak(rc);1531 1532 /* Create it when necessary. */1533 if (!RTDirExists(szFilePath))1534 {1535 rc = RTDirCreateFullPath(szFilePath, RTFS_UNIX_IRWXU);1536 if (RT_FAILURE(rc))1537 break;1538 }1539 1540 char szFileName[RTPATH_MAX];1541 szFileName[0] = '\0';1542 1543 if (fFlags & PDMAUDIOFILENAME_FLAGS_TS)1544 {1545 RTTIMESPEC time;1546 if (!RTTimeSpecToString(RTTimeNow(&time), szFileName, sizeof(szFileName)))1547 {1548 rc = VERR_BUFFER_OVERFLOW;1549 break;1550 }1551 1552 rc = DrvAudioHlpFileNameSanitize(szFileName, sizeof(szFileName));1553 if (RT_FAILURE(rc))1554 break;1555 1556 rc = RTStrCat(szFileName, sizeof(szFileName), "-");1557 if (RT_FAILURE(rc))1558 break;1559 }1560 1561 rc = RTStrCat(szFileName, sizeof(szFileName), pszName);1562 if (RT_FAILURE(rc))1563 break;1564 1565 rc = RTStrCat(szFileName, sizeof(szFileName), "-");1566 if (RT_FAILURE(rc))1567 break;1568 1569 char szInst[16];1570 RTStrPrintf2(szInst, sizeof(szInst), "%RU32", uInstance);1571 rc = RTStrCat(szFileName, sizeof(szFileName), szInst);1572 if (RT_FAILURE(rc))1573 break;1574 1575 switch (enmType)1576 {1577 case PDMAUDIOFILETYPE_RAW:1578 rc = RTStrCat(szFileName, sizeof(szFileName), ".pcm");1579 break;1580 1581 case PDMAUDIOFILETYPE_WAV:1582 rc = RTStrCat(szFileName, sizeof(szFileName), ".wav");1583 break;1584 1585 default:1586 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);1587 break;1588 }1589 1590 if (RT_FAILURE(rc))1591 break;1592 1593 rc = RTPathAppend(szFilePath, sizeof(szFilePath), szFileName);1594 if (RT_FAILURE(rc))1595 break;1596 1597 rc = RTStrCopy(pszFile, cchFile, szFilePath);1598 1599 } while (0);1600 1601 RTStrFree(pszPathTmp);1602 1603 LogFlowFuncLeaveRC(rc);1604 return rc;1605 }1606 1607 /**1608 * Creates an audio file.1609 *1610 * @returns IPRT status code.1611 * @param enmType Audio file type to open / create.1612 * @param pszFile File path of file to open or create.1613 * @param fFlags Audio file flags, PDMAUDIOFILE_FLAGS_XXX.1614 * @param ppFile Where to store the created audio file handle.1615 * Needs to be destroyed with DrvAudioHlpFileDestroy().1616 */1617 int DrvAudioHlpFileCreate(PDMAUDIOFILETYPE enmType, const char *pszFile, uint32_t fFlags, PPDMAUDIOFILE *ppFile)1618 {1619 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);1620 /** @todo Validate fFlags. */1621 1622 PPDMAUDIOFILE pFile = (PPDMAUDIOFILE)RTMemAlloc(sizeof(PDMAUDIOFILE));1623 if (!pFile)1624 return VERR_NO_MEMORY;1625 1626 int rc = VINF_SUCCESS;1627 1628 switch (enmType)1629 {1630 case PDMAUDIOFILETYPE_RAW:1631 case PDMAUDIOFILETYPE_WAV:1632 pFile->enmType = enmType;1633 break;1634 1635 default:1636 rc = VERR_INVALID_PARAMETER;1637 break;1638 }1639 1640 if (RT_SUCCESS(rc))1641 {1642 RTStrPrintf(pFile->szName, RT_ELEMENTS(pFile->szName), "%s", pszFile);1643 pFile->hFile = NIL_RTFILE;1644 pFile->fFlags = fFlags;1645 pFile->pvData = NULL;1646 pFile->cbData = 0;1647 }1648 1649 if (RT_FAILURE(rc))1650 {1651 RTMemFree(pFile);1652 pFile = NULL;1653 }1654 else1655 *ppFile = pFile;1656 1657 return rc;1658 }1659 1660 /**1661 * Destroys a formerly created audio file.1662 *1663 * @param pFile Audio file (object) to destroy.1664 */1665 void DrvAudioHlpFileDestroy(PPDMAUDIOFILE pFile)1666 {1667 if (!pFile)1668 return;1669 1670 DrvAudioHlpFileClose(pFile);1671 1672 RTMemFree(pFile);1673 pFile = NULL;1674 }1675 1676 /**1677 * Opens or creates an audio file.1678 *1679 * @returns IPRT status code.1680 * @param pFile Pointer to audio file handle to use.1681 * @param fOpen Open flags.1682 * Use PDMAUDIOFILE_DEFAULT_OPEN_FLAGS for the default open flags.1683 * @param pProps PCM properties to use.1684 */1685 int DrvAudioHlpFileOpen(PPDMAUDIOFILE pFile, uint32_t fOpen, PCPDMAUDIOPCMPROPS pProps)1686 {1687 AssertPtrReturn(pFile, VERR_INVALID_POINTER);1688 /** @todo Validate fOpen flags. */1689 AssertPtrReturn(pProps, VERR_INVALID_POINTER);1690 1691 int rc;1692 1693 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)1694 {1695 rc = RTFileOpen(&pFile->hFile, pFile->szName, fOpen);1696 }1697 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)1698 {1699 Assert(pProps->cChannels);1700 Assert(pProps->uHz);1701 Assert(pProps->cbSample);1702 1703 pFile->pvData = (PAUDIOWAVFILEDATA)RTMemAllocZ(sizeof(AUDIOWAVFILEDATA));1704 if (pFile->pvData)1705 {1706 pFile->cbData = sizeof(PAUDIOWAVFILEDATA);1707 1708 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;1709 AssertPtr(pData);1710 1711 /* Header. */1712 pData->Hdr.u32RIFF = AUDIO_MAKE_FOURCC('R','I','F','F');1713 pData->Hdr.u32Size = 36;1714 pData->Hdr.u32WAVE = AUDIO_MAKE_FOURCC('W','A','V','E');1715 1716 pData->Hdr.u32Fmt = AUDIO_MAKE_FOURCC('f','m','t',' ');1717 pData->Hdr.u32Size1 = 16; /* Means PCM. */1718 pData->Hdr.u16AudioFormat = 1; /* PCM, linear quantization. */1719 pData->Hdr.u16NumChannels = pProps->cChannels;1720 pData->Hdr.u32SampleRate = pProps->uHz;1721 pData->Hdr.u32ByteRate = PDMAudioPropsGetBitrate(pProps) / 8;1722 pData->Hdr.u16BlockAlign = pProps->cChannels * pProps->cbSample;1723 pData->Hdr.u16BitsPerSample = pProps->cbSample * 8;1724 1725 /* Data chunk. */1726 pData->Hdr.u32ID2 = AUDIO_MAKE_FOURCC('d','a','t','a');1727 pData->Hdr.u32Size2 = 0;1728 1729 rc = RTFileOpen(&pFile->hFile, pFile->szName, fOpen);1730 if (RT_SUCCESS(rc))1731 {1732 rc = RTFileWrite(pFile->hFile, &pData->Hdr, sizeof(pData->Hdr), NULL);1733 if (RT_FAILURE(rc))1734 {1735 RTFileClose(pFile->hFile);1736 pFile->hFile = NIL_RTFILE;1737 }1738 }1739 1740 if (RT_FAILURE(rc))1741 {1742 RTMemFree(pFile->pvData);1743 pFile->pvData = NULL;1744 pFile->cbData = 0;1745 }1746 }1747 else1748 rc = VERR_NO_MEMORY;1749 }1750 else1751 rc = VERR_INVALID_PARAMETER;1752 1753 if (RT_SUCCESS(rc))1754 {1755 LogRel2(("Audio: Opened file '%s'\n", pFile->szName));1756 }1757 else1758 LogRel(("Audio: Failed opening file '%s', rc=%Rrc\n", pFile->szName, rc));1759 1760 return rc;1761 }1762 1763 /**1764 * Closes an audio file.1765 *1766 * @returns IPRT status code.1767 * @param pFile Audio file handle to close.1768 */1769 int DrvAudioHlpFileClose(PPDMAUDIOFILE pFile)1770 {1771 if (!pFile)1772 return VINF_SUCCESS;1773 1774 size_t cbSize = DrvAudioHlpFileGetDataSize(pFile);1775 1776 int rc = VINF_SUCCESS;1777 1778 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)1779 {1780 if (RTFileIsValid(pFile->hFile))1781 rc = RTFileClose(pFile->hFile);1782 }1783 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)1784 {1785 if (RTFileIsValid(pFile->hFile))1786 {1787 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;1788 if (pData) /* The .WAV file data only is valid when a file actually has been created. */1789 {1790 /* Update the header with the current data size. */1791 RTFileWriteAt(pFile->hFile, 0, &pData->Hdr, sizeof(pData->Hdr), NULL);1792 }1793 1794 rc = RTFileClose(pFile->hFile);1795 }1796 1797 if (pFile->pvData)1798 {1799 RTMemFree(pFile->pvData);1800 pFile->pvData = NULL;1801 }1802 }1803 else1804 AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);1805 1806 if ( RT_SUCCESS(rc)1807 && !cbSize1808 && !(pFile->fFlags & PDMAUDIOFILE_FLAGS_KEEP_IF_EMPTY))1809 {1810 rc = DrvAudioHlpFileDelete(pFile);1811 }1812 1813 pFile->cbData = 0;1814 1815 if (RT_SUCCESS(rc))1816 {1817 pFile->hFile = NIL_RTFILE;1818 LogRel2(("Audio: Closed file '%s' (%zu bytes)\n", pFile->szName, cbSize));1819 }1820 else1821 LogRel(("Audio: Failed closing file '%s', rc=%Rrc\n", pFile->szName, rc));1822 1823 return rc;1824 }1825 1826 /**1827 * Deletes an audio file.1828 *1829 * @returns IPRT status code.1830 * @param pFile Audio file handle to delete.1831 */1832 int DrvAudioHlpFileDelete(PPDMAUDIOFILE pFile)1833 {1834 AssertPtrReturn(pFile, VERR_INVALID_POINTER);1835 1836 int rc = RTFileDelete(pFile->szName);1837 if (RT_SUCCESS(rc))1838 {1839 LogRel2(("Audio: Deleted file '%s'\n", pFile->szName));1840 }1841 else if (rc == VERR_FILE_NOT_FOUND) /* Don't bitch if the file is not around (anymore). */1842 rc = VINF_SUCCESS;1843 1844 if (RT_FAILURE(rc))1845 LogRel(("Audio: Failed deleting file '%s', rc=%Rrc\n", pFile->szName, rc));1846 1847 return rc;1848 }1849 1850 /**1851 * Returns the raw audio data size of an audio file.1852 *1853 * Note: This does *not* include file headers and other data which does1854 * not belong to the actual PCM audio data.1855 *1856 * @returns Size (in bytes) of the raw PCM audio data.1857 * @param pFile Audio file handle to retrieve the audio data size for.1858 */1859 size_t DrvAudioHlpFileGetDataSize(PPDMAUDIOFILE pFile)1860 {1861 AssertPtrReturn(pFile, 0);1862 1863 size_t cbSize = 0;1864 1865 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)1866 {1867 cbSize = RTFileTell(pFile->hFile);1868 }1869 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)1870 {1871 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;1872 if (pData) /* The .WAV file data only is valid when a file actually has been created. */1873 cbSize = pData->Hdr.u32Size2;1874 }1875 1876 return cbSize;1877 }1878 1879 /**1880 * Returns whether the given audio file is open and in use or not.1881 *1882 * @return bool True if open, false if not.1883 * @param pFile Audio file handle to check open status for.1884 */1885 bool DrvAudioHlpFileIsOpen(PPDMAUDIOFILE pFile)1886 {1887 if (!pFile)1888 return false;1889 1890 return RTFileIsValid(pFile->hFile);1891 }1892 1893 /**1894 * Write PCM data to a wave (.WAV) file.1895 *1896 * @returns IPRT status code.1897 * @param pFile Audio file handle to write PCM data to.1898 * @param pvBuf Audio data to write.1899 * @param cbBuf Size (in bytes) of audio data to write.1900 * @param fFlags Additional write flags. Not being used at the moment and must be 0.1901 */1902 int DrvAudioHlpFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags)1903 {1904 AssertPtrReturn(pFile, VERR_INVALID_POINTER);1905 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);1906 1907 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /** @todo fFlags are currently not implemented. */1908 1909 if (!cbBuf)1910 return VINF_SUCCESS;1911 1912 AssertReturn(RTFileIsValid(pFile->hFile), VERR_WRONG_ORDER);1913 1914 int rc;1915 1916 if (pFile->enmType == PDMAUDIOFILETYPE_RAW)1917 {1918 rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);1919 }1920 else if (pFile->enmType == PDMAUDIOFILETYPE_WAV)1921 {1922 PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;1923 AssertPtr(pData);1924 1925 rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);1926 if (RT_SUCCESS(rc))1927 {1928 pData->Hdr.u32Size += (uint32_t)cbBuf;1929 pData->Hdr.u32Size2 += (uint32_t)cbBuf;1930 }1931 }1932 else1933 rc = VERR_NOT_SUPPORTED;1934 1935 return rc;1936 }1937
Note:
See TracChangeset
for help on using the changeset viewer.