Changeset 88455 in vbox for trunk/src/VBox/Devices
- Timestamp:
- Apr 10, 2021 11:51:12 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioOss.cpp
r88413 r88455 47 47 #endif 48 48 49 /** Makes DRVHOSTOSSAUDIO out of PDMIHOSTAUDIO. */50 #define PDMIHOSTAUDIO_2_DRVHOSTOSSAUDIO(pInterface) \51 ( (PDRVHOSTOSSAUDIO)((uintptr_t)pInterface - RT_UOFFSETOF(DRVHOSTOSSAUDIO, IHostAudio)) )52 53 49 54 50 /********************************************************************************************************************************* … … 62 58 { 63 59 /** Pointer to the driver instance structure. */ 64 PPDMDRVINS pDrvIns;60 PPDMDRVINS pDrvIns; 65 61 /** Pointer to host audio interface. */ 66 PDMIHOSTAUDIO IHostAudio;62 PDMIHOSTAUDIO IHostAudio; 67 63 /** Error count for not flooding the release log. 68 64 * UINT32_MAX for unlimited logging. */ 69 uint32_t cLogErrors; 70 } DRVHOSTOSSAUDIO, *PDRVHOSTOSSAUDIO; 71 65 uint32_t cLogErrors; 66 } DRVHOSTOSSAUDIO; 67 /** Pointer to the instance data for an OSS host audio driver. */ 68 typedef DRVHOSTOSSAUDIO *PDRVHOSTOSSAUDIO; 69 70 /** 71 * OSS audio stream configuration. 72 */ 72 73 typedef struct OSSAUDIOSTREAMCFG 73 74 { 74 PDMAUDIOPCMPROPS Props; 75 uint16_t cFragments; 76 uint32_t cbFragmentSize; 77 } OSSAUDIOSTREAMCFG, *POSSAUDIOSTREAMCFG; 78 75 PDMAUDIOPCMPROPS Props; 76 uint16_t cFragments; 77 /** The log2 of cbFragment. */ 78 uint16_t cbFragmentLog2; 79 uint32_t cbFragment; 80 } OSSAUDIOSTREAMCFG; 81 /** Pointer to an OSS audio stream configuration. */ 82 typedef OSSAUDIOSTREAMCFG *POSSAUDIOSTREAMCFG; 83 84 /** 85 * OSS audio stream. 86 */ 79 87 typedef struct OSSAUDIOSTREAM 80 88 { 89 /** The file descriptor. */ 90 int hFile; 91 /** Buffer alignment. */ 92 uint8_t uAlign; 93 /** Set if we're draining the stream (output only). */ 94 bool fDraining; 95 /** Internal stream byte offset. */ 96 uint64_t offInternal; 81 97 /** The stream's acquired configuration. */ 82 PPDMAUDIOSTREAMCFG pCfg; 83 /** Buffer alignment. */ 84 uint8_t uAlign; 85 int hFile; 86 int cFragments; 87 int cbFragmentSize; 88 int old_optr; 89 } OSSAUDIOSTREAM, *POSSAUDIOSTREAM; 90 91 typedef struct OSSAUDIOCFG 92 { 93 int nfrags; 94 int fragsize; 95 const char *devpath_out; 96 const char *devpath_in; 97 int debug; 98 } OSSAUDIOCFG, *POSSAUDIOCFG; 99 100 static OSSAUDIOCFG s_OSSConf = 101 { 102 4, 103 4096, 104 "/dev/dsp", 105 "/dev/dsp", 106 0 107 }; 108 109 110 /* http://www.df.lth.se/~john_e/gems/gem002d.html */ 111 static uint32_t popcount(uint32_t u) 112 { 113 u = ((u&0x55555555) + ((u>>1)&0x55555555)); 114 u = ((u&0x33333333) + ((u>>2)&0x33333333)); 115 u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); 116 u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); 117 u = ( u&0x0000ffff) + (u>>16); 118 return u; 119 } 120 121 122 static uint32_t lsbindex(uint32_t u) 123 { 124 return popcount((u & -u) - 1); 125 } 98 PDMAUDIOSTREAMCFG Cfg; 99 /** The acquired OSS configuration. */ 100 OSSAUDIOSTREAMCFG OssCfg; 101 /** Handle to the thread draining output streams. */ 102 RTTHREAD hThreadDrain; 103 104 } OSSAUDIOSTREAM; 105 /** Pointer to an OSS audio stream. */ 106 typedef OSSAUDIOSTREAM *POSSAUDIOSTREAM; 107 108 109 /********************************************************************************************************************************* 110 * Global Variables * 111 *********************************************************************************************************************************/ 112 /** The path to the output OSS device. */ 113 static char g_szPathOutputDev[] = "/dev/dsp"; 114 /** The path to the input OSS device. */ 115 static char g_szPathInputDev[] = "/dev/dsp"; 116 126 117 127 118 … … 320 311 */ 321 312 LogRel2(("OSS: Requested %RU16 %s fragments, %RU32 bytes each\n", 322 pOSSReq->cFragments, fInput ? "input" : "output", pOSSReq->cbFragment Size));323 324 int mmmmssss = (pOSSReq->cFragments << 16) | lsbindex(pOSSReq->cbFragmentSize);313 pOSSReq->cFragments, fInput ? "input" : "output", pOSSReq->cbFragment)); 314 315 int mmmmssss = (pOSSReq->cFragments << 16) | pOSSReq->cbFragmentLog2; 325 316 AssertLogRelMsgReturn(ioctl(hFile, SNDCTL_DSP_SETFRAGMENT, &mmmmssss) >= 0, 326 317 ("OSS: Failed to set %RU16 fragments to %RU32 bytes each: %s (%d)\n", 327 pOSSReq->cFragments, pOSSReq->cbFragment Size, strerror(errno), errno),318 pOSSReq->cFragments, pOSSReq->cbFragment, strerror(errno), errno), 328 319 RTErrConvertFromErrno(errno)); 329 320 … … 340 331 if (RT_SUCCESS(rc)) 341 332 { 342 pOSSAcq->cFragments = BufInfo.fragstotal; 343 pOSSAcq->cbFragmentSize = BufInfo.fragsize; 333 pOSSAcq->cFragments = BufInfo.fragstotal; 334 pOSSAcq->cbFragment = BufInfo.fragsize; 335 pOSSAcq->cbFragmentLog2 = ASMBitFirstSetU32(BufInfo.fragsize) - 1; 336 Assert(RT_BIT_32(pOSSAcq->cbFragmentLog2) == pOSSAcq->cbFragment); 344 337 345 338 LogRel2(("OSS: Got %RU16 %s fragments, %RU32 bytes each\n", 346 pOSSAcq->cFragments, fInput ? "input" : "output", pOSSAcq->cbFragment Size));339 pOSSAcq->cFragments, fInput ? "input" : "output", pOSSAcq->cbFragment)); 347 340 } 348 341 … … 363 356 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 364 357 358 pStreamOSS->hThreadDrain = NIL_RTTHREAD; 359 365 360 /* 366 361 * Open the device … … 368 363 int rc; 369 364 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 370 pStreamOSS->hFile = open( s_OSSConf.devpath_in, O_RDONLY | O_NONBLOCK);365 pStreamOSS->hFile = open(g_szPathInputDev, O_RDONLY | O_NONBLOCK); 371 366 else 372 pStreamOSS->hFile = open( s_OSSConf.devpath_out, O_WRONLY);367 pStreamOSS->hFile = open(g_szPathOutputDev, O_WRONLY); 373 368 if (pStreamOSS->hFile >= 0) 374 369 { … … 380 375 381 376 memcpy(&ReqOssCfg.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS)); 382 ReqOssCfg.cFragments = s_OSSConf.nfrags; 383 ReqOssCfg.cbFragmentSize = s_OSSConf.fragsize; 384 385 OSSAUDIOSTREAMCFG AcqOssCfg; 386 RT_ZERO(AcqOssCfg); 387 rc = ossStreamConfigure(pStreamOSS->hFile, pCfgReq->enmDir == PDMAUDIODIR_IN, &ReqOssCfg, &AcqOssCfg); 377 ReqOssCfg.cbFragmentLog2 = 12; 378 ReqOssCfg.cbFragment = RT_BIT_32(ReqOssCfg.cbFragmentLog2); 379 uint32_t const cbBuffer = PDMAudioPropsFramesToBytes(&pCfgReq->Props, pCfgReq->Backend.cFramesBufferSize); 380 ReqOssCfg.cFragments = cbBuffer >> ReqOssCfg.cbFragmentLog2; 381 AssertLogRelStmt(cbBuffer < ((uint32_t)0x7ffe << ReqOssCfg.cbFragmentLog2), ReqOssCfg.cFragments = 0x7ffe); 382 383 rc = ossStreamConfigure(pStreamOSS->hFile, pCfgReq->enmDir == PDMAUDIODIR_IN, &ReqOssCfg, &pStreamOSS->OssCfg); 388 384 if (RT_SUCCESS(rc)) 389 385 { 386 pStreamOSS->uAlign = 0; /** @todo r=bird: Where did the correct assignment of this go? */ 387 390 388 /* 391 389 * Complete the stream structure and fill in the pCfgAcq bits. 392 390 */ 393 if (( AcqOssCfg.cFragments * AcqOssCfg.cbFragmentSize) & pStreamOSS->uAlign)391 if ((pStreamOSS->OssCfg.cFragments * pStreamOSS->OssCfg.cbFragment) & pStreamOSS->uAlign) 394 392 LogRel(("OSS: Warning: Misaligned playback buffer: Size = %zu, Alignment = %u\n", 395 AcqOssCfg.cFragments * AcqOssCfg.cbFragmentSize, pStreamOSS->uAlign + 1)); 396 397 memcpy(&pCfgAcq->Props, &AcqOssCfg.Props, sizeof(PDMAUDIOPCMPROPS)); 398 pCfgAcq->Backend.cFramesPeriod = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, AcqOssCfg.cbFragmentSize); 399 pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering" */ 400 /** @todo Pre-buffering required? */ 393 pStreamOSS->OssCfg.cFragments * pStreamOSS->OssCfg.cbFragment, pStreamOSS->uAlign + 1)); 394 395 memcpy(&pCfgAcq->Props, &pStreamOSS->OssCfg.Props, sizeof(PDMAUDIOPCMPROPS)); 396 pCfgAcq->Backend.cFramesPeriod = PDMAudioPropsBytesToFrames(&pCfgAcq->Props, pStreamOSS->OssCfg.cbFragment); 397 pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * pStreamOSS->OssCfg.cFragments; 398 if (pCfgReq->enmDir == PDMAUDIODIR_OUT) 399 pCfgAcq->Backend.cFramesPreBuffering = (uint64_t)pCfgReq->Backend.cFramesPreBuffering 400 * pCfgAcq->Backend.cFramesBufferSize 401 / RT_MAX(pCfgReq->Backend.cFramesBufferSize, 1); 402 else 403 pCfgAcq->Backend.cFramesPreBuffering = 0; /** @todo is this sane? */ 401 404 402 405 /* 403 * Duplicatethe stream config and we're done!406 * Copy the stream config and we're done! 404 407 */ 405 pStreamOSS->pCfg = PDMAudioStrmCfgDup(pCfgAcq); 406 if (pStreamOSS->pCfg) 407 return VINF_SUCCESS; 408 409 rc = VERR_NO_MEMORY; 408 PDMAudioStrmCfgCopy(&pStreamOSS->Cfg, pCfgAcq); 409 return VINF_SUCCESS; 410 410 } 411 411 ossStreamClose(&pStreamOSS->hFile); … … 415 415 rc = RTErrConvertFromErrno(errno); 416 416 LogRel(("OSS: Failed to open '%s': %s (%d) / %Rrc\n", 417 pCfgReq->enmDir == PDMAUDIODIR_IN ? s_OSSConf.devpath_in : s_OSSConf.devpath_out, strerror(errno), errno, rc));417 pCfgReq->enmDir == PDMAUDIODIR_IN ? g_szPathInputDev : g_szPathOutputDev, strerror(errno), errno, rc)); 418 418 } 419 419 return rc; … … 431 431 432 432 ossStreamClose(&pStreamOSS->hFile); 433 PDMAudioStrmCfgFree(pStreamOSS->pCfg); 434 pStreamOSS->pCfg = NULL; 433 434 if (pStreamOSS->hThreadDrain != NIL_RTTHREAD) 435 { 436 int rc = RTThreadWait(pStreamOSS->hThreadDrain, 1, NULL); 437 AssertRC(rc); 438 pStreamOSS->hThreadDrain = NIL_RTTHREAD; 439 } 435 440 436 441 return VINF_SUCCESS; … … 438 443 439 444 440 static int ossControlStreamIn(/*PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd*/ void) 441 { 442 /** @todo Nothing to do here right now!? */ 445 /** 446 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamEnable} 447 */ 448 static DECLCALLBACK(int) drvHostOssAudioHA_StreamEnable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 449 { 450 RT_NOREF(pInterface); 451 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 452 453 pStreamOSS->fDraining = false; 454 455 int rc; 456 if (pStreamOSS->Cfg.enmDir == PDMAUDIODIR_IN) 457 rc = VINF_SUCCESS; /** @todo apparently nothing to do here? */ 458 else 459 { 460 int fMask = PCM_ENABLE_OUTPUT; 461 if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &fMask) >= 0) 462 rc = VINF_SUCCESS; 463 else 464 { 465 LogRel(("OSS: Failed to enable output stream: %s (%d)\n", strerror(errno), errno)); 466 rc = RTErrConvertFromErrno(errno); 467 } 468 } 469 470 LogFlowFunc(("returns %Rrc for '%s'\n", rc, pStreamOSS->Cfg.szName)); 471 return rc; 472 } 473 474 475 /** 476 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable} 477 */ 478 static DECLCALLBACK(int) drvHostOssAudioHA_StreamDisable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 479 { 480 RT_NOREF(pInterface); 481 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 482 483 int rc; 484 if (pStreamOSS->Cfg.enmDir == PDMAUDIODIR_IN) 485 rc = VINF_SUCCESS; /** @todo apparently nothing to do here? */ 486 else if (pStreamOSS->fDraining) 487 { 488 LogFlow(("Ignoring stream disable because we're draining...\n")); 489 rc = VINF_SUCCESS; /** @todo apparently nothing to do here? */ 490 } 491 else 492 { 493 /** @todo Official documentation says this isn't the right way to stop playback. 494 * It may work in some implementations but fail in all others... Suggest 495 * using SNDCTL_DSP_RESET / SNDCTL_DSP_HALT. */ 496 int fMask = 0; 497 if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &fMask) >= 0) 498 rc = VINF_SUCCESS; 499 else 500 { 501 LogRel(("OSS: Failed to enable output stream: %s (%d)\n", strerror(errno), errno)); 502 rc = RTErrConvertFromErrno(errno); 503 } 504 } 505 LogFlowFunc(("returns %Rrc for '%s'\n", rc, pStreamOSS->Cfg.szName)); 506 return rc; 507 } 508 509 510 /** 511 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamPause} 512 */ 513 static DECLCALLBACK(int) drvHostOssAudioHA_StreamPause(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 514 { 515 return drvHostOssAudioHA_StreamDisable(pInterface, pStream); 516 } 517 518 519 /** 520 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamResume} 521 */ 522 static DECLCALLBACK(int) drvHostOssAudioHA_StreamResume(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 523 { 524 return drvHostOssAudioHA_StreamEnable(pInterface, pStream); 525 } 526 527 528 /** 529 * @callback_method_impl{FNRTTHREAD, 530 * Thread for calling SNDCTL_DSP_SYNC (blocking) on an output stream.} 531 */ 532 static DECLCALLBACK(int) drvHostOssAudioDrainThread(RTTHREAD ThreadSelf, void *pvUser) 533 { 534 RT_NOREF(ThreadSelf); 535 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pvUser; 536 int rc; 537 538 /* Make it blocking (for Linux). */ 539 int fOrgFlags = fcntl(pStreamOSS->hFile, F_GETFL, 0); 540 LogFunc(("F_GETFL -> %#x\n", fOrgFlags)); 541 Assert(fOrgFlags != -1); 542 if (fOrgFlags != -1) 543 { 544 rc = fcntl(pStreamOSS->hFile, F_SETFL, fOrgFlags & ~O_NONBLOCK); 545 AssertStmt(rc != -1, fOrgFlags = -1); 546 } 547 548 /* Drain it. */ 549 LogFunc(("Calling SNDCTL_DSP_SYNC now...\n")); 550 rc = ioctl(pStreamOSS->hFile, SNDCTL_DSP_SYNC, NULL); 551 LogFunc(("SNDCTL_DSP_SYNC returned %d / errno=%d\n", rc, errno)); RT_NOREF(rc); 552 553 /* Re-enable non-blocking mode and disable it. */ 554 if (fOrgFlags != -1) 555 { 556 rc = fcntl(pStreamOSS->hFile, F_SETFL, fOrgFlags); 557 Assert(rc != -1); 558 559 int fMask = 0; 560 rc = ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &fMask); 561 Assert(rc >= 0); 562 563 pStreamOSS->fDraining = false; 564 LogFunc(("Restored non-block mode and cleared the trigger mask\n")); 565 } 443 566 444 567 return VINF_SUCCESS; … … 446 569 447 570 448 static int ossControlStreamOut(POSSAUDIOSTREAM pStreamOSS, PDMAUDIOSTREAMCMD enmStreamCmd) 449 { 450 int rc = VINF_SUCCESS; 451 452 switch (enmStreamCmd) 453 { 454 case PDMAUDIOSTREAMCMD_ENABLE: 455 case PDMAUDIOSTREAMCMD_RESUME: 456 { 457 int mask = PCM_ENABLE_OUTPUT; 458 if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0) 459 { 460 LogRel(("OSS: Failed to enable output stream: %s\n", strerror(errno))); 461 rc = RTErrConvertFromErrno(errno); 462 } 463 464 break; 465 } 466 467 case PDMAUDIOSTREAMCMD_DISABLE: 468 case PDMAUDIOSTREAMCMD_PAUSE: 469 { 470 int mask = 0; 471 if (ioctl(pStreamOSS->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0) 472 { 473 LogRel(("OSS: Failed to disable output stream: %s\n", strerror(errno))); 474 rc = RTErrConvertFromErrno(errno); 475 } 476 477 break; 478 } 479 480 default: 481 rc = VERR_NOT_SUPPORTED; 482 break; 483 } 484 485 return rc; 486 } 571 /** 572 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable} 573 */ 574 static DECLCALLBACK(int) drvHostOssAudioHA_StreamDrain(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 575 { 576 PDRVHOSTOSSAUDIO pThis = RT_FROM_MEMBER(pInterface, DRVHOSTOSSAUDIO, IHostAudio); 577 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 578 AssertReturn(pStreamOSS->Cfg.enmDir == PDMAUDIODIR_OUT, VERR_WRONG_ORDER); 579 580 pStreamOSS->fDraining = true; 581 582 /* 583 * Because the SNDCTL_DSP_SYNC call is blocking on real OSS, 584 * we kick off a thread to deal with it as we're probably on EMT 585 * and cannot block for extended periods. 586 */ 587 if (pStreamOSS->hThreadDrain != NIL_RTTHREAD) 588 { 589 int rc = RTThreadWait(pStreamOSS->hThreadDrain, 0, NULL); 590 if (RT_SUCCESS(rc)) 591 { 592 pStreamOSS->hThreadDrain = NIL_RTTHREAD; 593 LogFunc(("Cleaned up stale thread handle.\n")); 594 } 595 else 596 { 597 LogFunc(("Drain thread already running (%Rrc).\n", rc)); 598 AssertMsg(rc == VERR_TIMEOUT, ("%Rrc\n", rc)); 599 return rc == VERR_TIMEOUT ? VINF_SUCCESS : rc; 600 } 601 } 602 603 int rc = RTThreadCreateF(&pStreamOSS->hThreadDrain, drvHostOssAudioDrainThread, pStreamOSS, 0, 604 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "ossdrai%u", pThis->pDrvIns->iInstance); 605 LogFunc(("Started drain thread: %Rrc\n", rc)); 606 AssertRCReturn(rc, rc); 607 608 return VINF_SUCCESS; 609 } 610 487 611 488 612 … … 493 617 PDMAUDIOSTREAMCMD enmStreamCmd) 494 618 { 495 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 496 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 497 498 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 499 500 if (!pStreamOSS->pCfg) /* Not (yet) configured? Skip. */ 501 return VINF_SUCCESS; 502 503 int rc; 504 if (pStreamOSS->pCfg->enmDir == PDMAUDIODIR_IN) 505 rc = ossControlStreamIn(/*pInterface, pStream, enmStreamCmd*/); 506 else 507 rc = ossControlStreamOut(pStreamOSS, enmStreamCmd); 508 509 return rc; 619 /** @todo r=bird: I'd like to get rid of this pfnStreamControl method, 620 * replacing it with individual StreamXxxx methods. That would save us 621 * potentally huge switches and more easily see which drivers implement 622 * which operations (grep for pfnStreamXxxx). */ 623 switch (enmStreamCmd) 624 { 625 case PDMAUDIOSTREAMCMD_ENABLE: 626 return drvHostOssAudioHA_StreamEnable(pInterface, pStream); 627 case PDMAUDIOSTREAMCMD_DISABLE: 628 return drvHostOssAudioHA_StreamDisable(pInterface, pStream); 629 case PDMAUDIOSTREAMCMD_PAUSE: 630 return drvHostOssAudioHA_StreamPause(pInterface, pStream); 631 case PDMAUDIOSTREAMCMD_RESUME: 632 return drvHostOssAudioHA_StreamResume(pInterface, pStream); 633 case PDMAUDIOSTREAMCMD_DRAIN: 634 return drvHostOssAudioHA_StreamDrain(pInterface, pStream); 635 /** @todo the drain call for OSS is SNDCTL_DSP_SYNC, however in the non-ALSA 636 * implementation of OSS it is probably blocking. Also, it comes with 637 * caveats about clicks and silence... */ 638 case PDMAUDIOSTREAMCMD_END: 639 case PDMAUDIOSTREAMCMD_32BIT_HACK: 640 case PDMAUDIOSTREAMCMD_INVALID: 641 /* no default*/ 642 break; 643 } 644 return VERR_NOT_SUPPORTED; 510 645 } 511 646 … … 517 652 { 518 653 RT_NOREF(pInterface, pStream); 654 Log4Func(("returns UINT32_MAX\n")); 519 655 return UINT32_MAX; 520 656 } … … 526 662 static DECLCALLBACK(uint32_t) drvHostOssAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 527 663 { 664 RT_NOREF(pInterface); 528 665 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 529 666 AssertPtr(pStreamOSS); 530 RT_NOREF(pInterface);531 667 532 668 /* … … 551 687 #endif 552 688 553 return (uint32_t)(BufInfo.fragments * BufInfo.fragsize); 689 uint32_t cbRet = (uint32_t)(BufInfo.fragments * BufInfo.fragsize); 690 Log4Func(("returns %#x (%u)\n", cbRet, cbRet)); 691 return cbRet; 554 692 } 555 693 … … 571 709 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 572 710 { 711 RT_NOREF(pInterface); 573 712 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 574 713 AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER); 575 RT_NOREF(pInterface);576 714 577 715 /* 578 716 * Figure out now much to write. 579 717 */ 580 uint32_t cbToWrite;581 718 audio_buf_info BufInfo; 582 719 int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &BufInfo); … … 593 730 } 594 731 #endif 595 cbToWrite = (unsigned)(BufInfo.fragments * BufInfo.fragsize);732 uint32_t cbToWrite = (uint32_t)(BufInfo.fragments * BufInfo.fragsize); 596 733 cbToWrite = RT_MIN(cbToWrite, cbBuf); 734 Log3Func(("@%#RX64 cbBuf=%#x BufInfo: fragments=%#x fragstotal=%#x fragsize=%#x bytes=%#x %s cbToWrite=%#x\n", 735 pStreamOSS->offInternal, cbBuf, BufInfo.fragments, BufInfo.fragstotal, BufInfo.fragsize, BufInfo.bytes, 736 pStreamOSS->Cfg.szName, cbToWrite)); 597 737 598 738 /* … … 604 744 while (cbChunk > 0) 605 745 { 606 ssize_t cbWritten = write(pStreamOSS->hFile, &pbBuf[offChunk], RT_MIN(cbChunk, (unsigned)s_OSSConf.fragsize));607 if (cbWritten > =0)746 ssize_t cbWritten = write(pStreamOSS->hFile, &pbBuf[offChunk], RT_MIN(cbChunk, pStreamOSS->OssCfg.cbFragment)); 747 if (cbWritten > 0) 608 748 { 609 749 AssertLogRelMsg(!(cbWritten & pStreamOSS->uAlign), … … 613 753 offChunk += (uint32_t)cbWritten; 614 754 cbChunk -= (uint32_t)cbWritten; 755 pStreamOSS->offInternal += cbWritten; 756 } 757 else if (cbWritten == 0) 758 { 759 LogFunc(("@%#RX64 write(%#x) returned zeroed (previously wrote %#x bytes)!\n", 760 pStreamOSS->offInternal, RT_MIN(cbChunk, pStreamOSS->OssCfg.cbFragment), cbWritten)); 761 break; 615 762 } 616 763 else … … 621 768 } 622 769 623 *pcbWritten = cbToWrite;770 *pcbWritten = offChunk; 624 771 return VINF_SUCCESS; 625 772 } … … 630 777 */ 631 778 static DECLCALLBACK(int) drvHostOssAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 632 void *pvBuf, uint32_t uBufSize, uint32_t *puRead) 633 { 779 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead) 780 { 781 RT_NOREF(pInterface); 634 782 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 635 783 AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER); 636 RT_NOREF(pInterface); 637 638 639 size_t cbToRead = uBufSize; 640 LogFlowFunc(("cbToRead=%zi\n", cbToRead)); 641 784 Log3Func(("@%#RX64 cbBuf=%#x %s\n", pStreamOSS->offInternal, cbBuf, pStreamOSS->Cfg.szName)); 785 786 size_t cbToRead = cbBuf; 642 787 uint8_t * const pbDst = (uint8_t *)pvBuf; 643 788 size_t offWrite = 0; … … 651 796 cbToRead -= cbRead; 652 797 offWrite += cbRead; 798 pStreamOSS->offInternal += cbRead; 653 799 } 654 800 else … … 668 814 } 669 815 670 if (puRead) 671 *puRead = offWrite; 816 *pcbRead = offWrite; 672 817 return VINF_SUCCESS; 673 818 } … … 709 854 /* IHostAudio */ 710 855 pThis->IHostAudio.pfnGetConfig = drvHostOssAudioHA_GetConfig; 856 pThis->IHostAudio.pfnGetDevices = NULL; 711 857 pThis->IHostAudio.pfnGetStatus = drvHostOssAudioHA_GetStatus; 712 858 pThis->IHostAudio.pfnStreamCreate = drvHostOssAudioHA_StreamCreate; … … 718 864 pThis->IHostAudio.pfnStreamPlay = drvHostOssAudioHA_StreamPlay; 719 865 pThis->IHostAudio.pfnStreamCapture = drvHostOssAudioHA_StreamCapture; 720 pThis->IHostAudio.pfnGetDevices = NULL;721 866 pThis->IHostAudio.pfnStreamGetPending = NULL; 722 867
Note:
See TracChangeset
for help on using the changeset viewer.