Changeset 88289 in vbox for trunk/src/VBox/Devices/Audio/DrvHostAudioOss.cpp
- Timestamp:
- Mar 25, 2021 11:29:10 AM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostAudioOss.cpp
r88288 r88289 122 122 static uint32_t lsbindex(uint32_t u) 123 123 { 124 return popcount ((u&-u)-1);124 return popcount((u & -u) - 1); 125 125 } 126 126 … … 170 170 if (close(*phFile)) 171 171 { 172 LogRel(("OSS: Closing stream failed: %s\n", strerror(errno)));173 rc = VERR_GENERAL_FAILURE; /** @todo */172 rc = RTErrConvertFromErrno(errno); 173 LogRel(("OSS: Closing stream failed: %s / %Rrc\n", strerror(errno), rc)); 174 174 } 175 175 else … … 180 180 181 181 return rc; 182 } 183 184 185 /** 186 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit} 187 */ 188 static DECLCALLBACK(int) drvHostOssAudioHA_Init(PPDMIHOSTAUDIO pInterface) 189 { 190 RT_NOREF(pInterface); 191 192 return VINF_SUCCESS; 193 } 194 195 196 /** 197 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown} 198 */ 199 static DECLCALLBACK(void) drvHostOssAudioHA_Shutdown(PPDMIHOSTAUDIO pInterface) 200 { 201 RT_NOREF(pInterface); 202 } 203 204 205 /** 206 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig} 207 */ 208 static DECLCALLBACK(int) drvHostOssAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg) 209 { 210 RT_NOREF(pInterface); 211 212 RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "OSS"); 213 214 pBackendCfg->cbStreamIn = sizeof(OSSAUDIOSTREAM); 215 pBackendCfg->cbStreamOut = sizeof(OSSAUDIOSTREAM); 216 217 int hFile = open("/dev/dsp", O_WRONLY | O_NONBLOCK, 0); 218 if (hFile == -1) 219 { 220 /* Try opening the mixing device instead. */ 221 hFile = open("/dev/mixer", O_RDONLY | O_NONBLOCK, 0); 222 } 223 if (hFile != -1) 224 { 225 int ossVer = -1; 226 int err = ioctl(hFile, OSS_GETVERSION, &ossVer); 227 if (err == 0) 228 { 229 LogRel2(("OSS: Using version: %d\n", ossVer)); 230 #ifdef VBOX_WITH_AUDIO_OSS_SYSINFO 231 oss_sysinfo ossInfo; 232 RT_ZERO(ossInfo); 233 err = ioctl(hFile, OSS_SYSINFO, &ossInfo); 234 if (err == 0) 235 { 236 LogRel2(("OSS: Number of DSPs: %d\n", ossInfo.numaudios)); 237 LogRel2(("OSS: Number of mixers: %d\n", ossInfo.nummixers)); 238 239 int cDev = ossInfo.nummixers; 240 if (!cDev) 241 cDev = ossInfo.numaudios; 242 243 pBackendCfg->cMaxStreamsIn = UINT32_MAX; 244 pBackendCfg->cMaxStreamsOut = UINT32_MAX; 245 } 246 else 247 #endif 248 { 249 /* Since we cannot query anything, assume that we have at least 250 * one input and one output if we found "/dev/dsp" or "/dev/mixer". */ 251 252 pBackendCfg->cMaxStreamsIn = UINT32_MAX; 253 pBackendCfg->cMaxStreamsOut = UINT32_MAX; 254 } 255 } 256 else 257 LogRel(("OSS: Unable to determine installed version: %s (%d)\n", strerror(err), err)); 258 close(hFile); 259 } 260 else 261 LogRel(("OSS: No devices found, audio is not available\n")); 262 263 return VINF_SUCCESS; 264 } 265 266 267 268 269 /** 270 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus} 271 */ 272 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostOssAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir) 273 { 274 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN); 275 RT_NOREF(enmDir); 276 277 return PDMAUDIOBACKENDSTS_RUNNING; 182 278 } 183 279 … … 293 389 294 390 391 static int ossCreateStreamIn(POSSAUDIOSTREAM pStreamOSS, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 392 { 393 int rc; 394 395 int hFile = -1; 396 397 do 398 { 399 OSSAUDIOSTREAMCFG ossReq; 400 memcpy(&ossReq.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS)); 401 402 ossReq.cFragments = s_OSSConf.nfrags; 403 ossReq.cbFragmentSize = s_OSSConf.fragsize; 404 405 OSSAUDIOSTREAMCFG ossAcq; 406 RT_ZERO(ossAcq); 407 408 rc = ossStreamOpen(s_OSSConf.devpath_in, O_RDONLY | O_NONBLOCK, &ossReq, &ossAcq, &hFile); 409 if (RT_SUCCESS(rc)) 410 { 411 memcpy(&pCfgAcq->Props, &ossAcq.Props, sizeof(PDMAUDIOPCMPROPS)); 412 413 if (ossAcq.cFragments * ossAcq.cbFragmentSize & pStreamOSS->uAlign) 414 { 415 LogRel(("OSS: Warning: Misaligned capturing buffer: Size = %zu, Alignment = %u\n", 416 ossAcq.cFragments * ossAcq.cbFragmentSize, pStreamOSS->uAlign + 1)); 417 } 418 419 if (RT_SUCCESS(rc)) 420 { 421 pStreamOSS->hFile = hFile; 422 423 pCfgAcq->Backend.cFramesPeriod = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, ossAcq.cbFragmentSize); 424 pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering". */ 425 /** @todo Pre-buffering required? */ 426 } 427 } 428 429 } while (0); 430 431 if (RT_FAILURE(rc)) 432 ossStreamClose(&hFile); 433 434 LogFlowFuncLeaveRC(rc); 435 return rc; 436 } 437 438 439 static int ossCreateStreamOut(POSSAUDIOSTREAM pStreamOSS, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 440 { 441 OSSAUDIOSTREAMCFG reqStream; 442 RT_ZERO(reqStream); 443 444 memcpy(&reqStream.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS)); 445 reqStream.cFragments = s_OSSConf.nfrags; 446 reqStream.cbFragmentSize = s_OSSConf.fragsize; 447 448 OSSAUDIOSTREAMCFG obtStream; 449 RT_ZERO(obtStream); 450 451 int hFile = -1; 452 int rc = ossStreamOpen(s_OSSConf.devpath_out, O_WRONLY, &reqStream, &obtStream, &hFile); 453 if (RT_SUCCESS(rc)) 454 { 455 memcpy(&pCfgAcq->Props, &obtStream.Props, sizeof(PDMAUDIOPCMPROPS)); 456 457 if ((obtStream.cFragments * obtStream.cbFragmentSize) & pStreamOSS->uAlign) 458 LogRel(("OSS: Warning: Misaligned playback buffer: Size = %zu, Alignment = %u\n", 459 obtStream.cFragments * obtStream.cbFragmentSize, pStreamOSS->uAlign + 1)); 460 461 pStreamOSS->hFile = hFile; 462 463 pCfgAcq->Backend.cFramesPeriod = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, obtStream.cbFragmentSize); 464 pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering" */ 465 466 } 467 468 LogFlowFuncLeaveRC(rc); 469 return rc; 470 } 471 472 473 /** 474 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate} 475 */ 476 static DECLCALLBACK(int) drvHostOssAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 477 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq) 478 { 479 AssertPtr(pInterface); 480 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 481 AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER); 482 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER); 483 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER); 484 485 pStreamOSS->pCfg = PDMAudioStrmCfgDup(pCfgAcq); 486 AssertReturn(pStreamOSS->pCfg, VERR_NO_MEMORY); 487 488 int rc; 489 if (pCfgReq->enmDir == PDMAUDIODIR_IN) 490 rc = ossCreateStreamIn( pStreamOSS, pCfgReq, pCfgAcq); 491 else 492 rc = ossCreateStreamOut(pStreamOSS, pCfgReq, pCfgAcq); 493 494 if (RT_FAILURE(rc)) 495 { 496 PDMAudioStrmCfgFree(pStreamOSS->pCfg); 497 pStreamOSS->pCfg = NULL; 498 } 499 return rc; 500 } 501 502 503 /** 504 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy} 505 */ 506 static DECLCALLBACK(int) drvHostOssAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 507 { 508 RT_NOREF(pInterface); 509 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 510 AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER); 511 512 ossStreamClose(&pStreamOSS->hFile); 513 PDMAudioStrmCfgFree(pStreamOSS->pCfg); 514 pStreamOSS->pCfg = NULL; 515 516 return VINF_SUCCESS; 517 } 518 519 295 520 static int ossControlStreamIn(/*PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd*/ void) 296 521 { … … 345 570 346 571 /** 347 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit} 348 */ 349 static DECLCALLBACK(int) drvHostOssAudioHA_Init(PPDMIHOSTAUDIO pInterface) 350 { 572 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl} 573 */ 574 static DECLCALLBACK(int) drvHostOssAudioHA_StreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 575 PDMAUDIOSTREAMCMD enmStreamCmd) 576 { 577 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 578 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 579 580 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 581 582 if (!pStreamOSS->pCfg) /* Not (yet) configured? Skip. */ 583 return VINF_SUCCESS; 584 585 int rc; 586 if (pStreamOSS->pCfg->enmDir == PDMAUDIODIR_IN) 587 rc = ossControlStreamIn(/*pInterface, pStream, enmStreamCmd*/); 588 else 589 rc = ossControlStreamOut(pStreamOSS, enmStreamCmd); 590 591 return rc; 592 } 593 594 595 /** 596 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable} 597 */ 598 static DECLCALLBACK(uint32_t) drvHostOssAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 599 { 600 RT_NOREF(pInterface, pStream); 601 return UINT32_MAX; 602 } 603 604 605 /** 606 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable} 607 */ 608 static DECLCALLBACK(uint32_t) drvHostOssAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 609 { 610 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 611 AssertPtr(pStreamOSS); 351 612 RT_NOREF(pInterface); 352 613 614 /* 615 * Note! This logic was found in StreamPlay and corrected a little. 616 * 617 * The logic here must match what StreamPlay does. 618 */ 619 audio_buf_info abinfo = { 0, 0, 0, 0 }; 620 int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo); 621 AssertMsgReturn(rc2 >= 0, ("SNDCTL_DSP_GETOSPACE failed: %s (%d)\n", strerror(errno), errno), 0); 622 623 #if 0 /** @todo we could return abinfo.bytes here iff StreamPlay didn't use the fragmented approach */ 624 /** @todo r=bird: WTF do we make a fuss over abinfo.bytes for when we don't even use it?!? */ 625 AssertLogRelMsgReturn(abinfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", abinfo.bytes), VERR_INTERNAL_ERROR_3); 626 if ((unsigned)abinfo.bytes > cbBuf) 627 { 628 LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", abinfo.bytes, cbBuf, cbBuf)); 629 abinfo.bytes = cbBuf; 630 /* Keep going. */ 631 } 632 #endif 633 634 return (uint32_t)(abinfo.fragments * abinfo.fragsize); 635 } 636 637 638 /** 639 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus} 640 */ 641 static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostOssAudioHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 642 { 643 RT_NOREF(pInterface, pStream); 644 return PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED | PDMAUDIOSTREAMSTS_FLAGS_ENABLED; 645 } 646 647 648 /** 649 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate} 650 */ 651 static DECLCALLBACK(int) drvHostOssAudioHA_StreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream) 652 { 653 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 654 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 655 656 LogFlowFuncEnter(); 657 658 /* Nothing to do here for OSS. */ 659 return VINF_SUCCESS; 660 } 661 662 663 /** 664 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay} 665 */ 666 static DECLCALLBACK(int) drvHostOssAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, 667 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten) 668 { 669 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream; 670 AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER); 671 RT_NOREF(pInterface); 672 673 /* 674 * Figure out now much to write. 675 */ 676 uint32_t cbToWrite; 677 audio_buf_info abinfo; 678 int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo); 679 AssertLogRelMsgReturn(rc2 >= 0, ("OSS: Failed to retrieve current playback buffer: %s (%d)\n", strerror(errno), errno), 680 RTErrConvertFromErrno(errno)); 681 682 #if 0 /** @todo r=bird: WTF do we make a fuss over abinfo.bytes for when we don't even use it?!? */ 683 AssertLogRelMsgReturn(abinfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", abinfo.bytes), VERR_INTERNAL_ERROR_3); 684 if ((unsigned)abinfo.bytes > cbBuf) 685 { 686 LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", abinfo.bytes, cbBuf, cbBuf)); 687 abinfo.bytes = cbBuf; 688 /* Keep going. */ 689 } 690 #endif 691 cbToWrite = (unsigned)(abinfo.fragments * abinfo.fragsize); 692 cbToWrite = RT_MIN(cbToWrite, cbBuf); 693 694 /* 695 * Write. 696 */ 697 uint8_t const *pbBuf = (uint8_t const *)pvBuf; 698 uint32_t cbChunk = cbToWrite; 699 uint32_t offChunk = 0; 700 while (cbChunk > 0) 701 { 702 ssize_t cbWritten = write(pStreamOSS->hFile, &pbBuf[offChunk], RT_MIN(cbChunk, (unsigned)s_OSSConf.fragsize)); 703 if (cbWritten >= 0) 704 { 705 AssertLogRelMsg(!(cbWritten & pStreamOSS->uAlign), 706 ("OSS: Misaligned write (written %#zx, alignment %#x)\n", cbWritten, pStreamOSS->uAlign)); 707 708 Assert((uint32_t)cbWritten <= cbChunk); 709 offChunk += (uint32_t)cbWritten; 710 cbChunk -= (uint32_t)cbWritten; 711 } 712 else 713 { 714 LogRel(("OSS: Failed writing output data: %s (%d)\n", strerror(errno), errno)); 715 return RTErrConvertFromErrno(errno); 716 } 717 } 718 719 *pcbWritten = cbToWrite; 353 720 return VINF_SUCCESS; 354 721 } … … 403 770 404 771 405 static int ossDestroyStreamIn(PPDMAUDIOBACKENDSTREAM pStream)406 {407 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;408 409 LogFlowFuncEnter();410 411 ossStreamClose(&pStreamOSS->hFile);412 413 return VINF_SUCCESS;414 }415 416 417 static int ossDestroyStreamOut(PPDMAUDIOBACKENDSTREAM pStream)418 {419 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;420 421 ossStreamClose(&pStreamOSS->hFile);422 423 return VINF_SUCCESS;424 }425 426 427 /**428 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}429 */430 static DECLCALLBACK(int) drvHostOssAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)431 {432 RT_NOREF(pInterface);433 434 RTStrPrintf2(pBackendCfg->szName, sizeof(pBackendCfg->szName), "OSS");435 436 pBackendCfg->cbStreamIn = sizeof(OSSAUDIOSTREAM);437 pBackendCfg->cbStreamOut = sizeof(OSSAUDIOSTREAM);438 439 int hFile = open("/dev/dsp", O_WRONLY | O_NONBLOCK, 0);440 if (hFile == -1)441 {442 /* Try opening the mixing device instead. */443 hFile = open("/dev/mixer", O_RDONLY | O_NONBLOCK, 0);444 }445 446 int ossVer = -1;447 448 #ifdef VBOX_WITH_AUDIO_OSS_SYSINFO449 oss_sysinfo ossInfo;450 RT_ZERO(ossInfo);451 #endif452 453 if (hFile != -1)454 {455 int err = ioctl(hFile, OSS_GETVERSION, &ossVer);456 if (err == 0)457 {458 LogRel2(("OSS: Using version: %d\n", ossVer));459 #ifdef VBOX_WITH_AUDIO_OSS_SYSINFO460 err = ioctl(hFile, OSS_SYSINFO, &ossInfo);461 if (err == 0)462 {463 LogRel2(("OSS: Number of DSPs: %d\n", ossInfo.numaudios));464 LogRel2(("OSS: Number of mixers: %d\n", ossInfo.nummixers));465 466 int cDev = ossInfo.nummixers;467 if (!cDev)468 cDev = ossInfo.numaudios;469 470 pBackendCfg->cMaxStreamsIn = UINT32_MAX;471 pBackendCfg->cMaxStreamsOut = UINT32_MAX;472 }473 else474 {475 #endif476 /* Since we cannot query anything, assume that we have at least477 * one input and one output if we found "/dev/dsp" or "/dev/mixer". */478 479 pBackendCfg->cMaxStreamsIn = UINT32_MAX;480 pBackendCfg->cMaxStreamsOut = UINT32_MAX;481 #ifdef VBOX_WITH_AUDIO_OSS_SYSINFO482 }483 #endif484 }485 else486 LogRel(("OSS: Unable to determine installed version: %s (%d)\n", strerror(err), err));487 }488 else489 LogRel(("OSS: No devices found, audio is not available\n"));490 491 if (hFile != -1)492 close(hFile);493 494 return VINF_SUCCESS;495 }496 497 498 static int ossCreateStreamIn(POSSAUDIOSTREAM pStreamOSS, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)499 {500 int rc;501 502 int hFile = -1;503 504 do505 {506 OSSAUDIOSTREAMCFG ossReq;507 memcpy(&ossReq.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS));508 509 ossReq.cFragments = s_OSSConf.nfrags;510 ossReq.cbFragmentSize = s_OSSConf.fragsize;511 512 OSSAUDIOSTREAMCFG ossAcq;513 RT_ZERO(ossAcq);514 515 rc = ossStreamOpen(s_OSSConf.devpath_in, O_RDONLY | O_NONBLOCK, &ossReq, &ossAcq, &hFile);516 if (RT_SUCCESS(rc))517 {518 memcpy(&pCfgAcq->Props, &ossAcq.Props, sizeof(PDMAUDIOPCMPROPS));519 520 if (ossAcq.cFragments * ossAcq.cbFragmentSize & pStreamOSS->uAlign)521 {522 LogRel(("OSS: Warning: Misaligned capturing buffer: Size = %zu, Alignment = %u\n",523 ossAcq.cFragments * ossAcq.cbFragmentSize, pStreamOSS->uAlign + 1));524 }525 526 if (RT_SUCCESS(rc))527 {528 pStreamOSS->hFile = hFile;529 530 pCfgAcq->Backend.cFramesPeriod = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, ossAcq.cbFragmentSize);531 pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering". */532 /** @todo Pre-buffering required? */533 }534 }535 536 } while (0);537 538 if (RT_FAILURE(rc))539 ossStreamClose(&hFile);540 541 LogFlowFuncLeaveRC(rc);542 return rc;543 }544 545 546 static int ossCreateStreamOut(POSSAUDIOSTREAM pStreamOSS, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)547 {548 OSSAUDIOSTREAMCFG reqStream;549 RT_ZERO(reqStream);550 551 memcpy(&reqStream.Props, &pCfgReq->Props, sizeof(PDMAUDIOPCMPROPS));552 reqStream.cFragments = s_OSSConf.nfrags;553 reqStream.cbFragmentSize = s_OSSConf.fragsize;554 555 OSSAUDIOSTREAMCFG obtStream;556 RT_ZERO(obtStream);557 558 int hFile = -1;559 int rc = ossStreamOpen(s_OSSConf.devpath_out, O_WRONLY, &reqStream, &obtStream, &hFile);560 if (RT_SUCCESS(rc))561 {562 memcpy(&pCfgAcq->Props, &obtStream.Props, sizeof(PDMAUDIOPCMPROPS));563 564 if ((obtStream.cFragments * obtStream.cbFragmentSize) & pStreamOSS->uAlign)565 LogRel(("OSS: Warning: Misaligned playback buffer: Size = %zu, Alignment = %u\n",566 obtStream.cFragments * obtStream.cbFragmentSize, pStreamOSS->uAlign + 1));567 568 pStreamOSS->hFile = hFile;569 570 pCfgAcq->Backend.cFramesPeriod = PDMAUDIOSTREAMCFG_B2F(pCfgAcq, obtStream.cbFragmentSize);571 pCfgAcq->Backend.cFramesBufferSize = pCfgAcq->Backend.cFramesPeriod * 2; /* Use "double buffering" */572 573 }574 575 LogFlowFuncLeaveRC(rc);576 return rc;577 }578 579 580 /**581 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}582 */583 static DECLCALLBACK(int) drvHostOssAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,584 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)585 {586 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;587 AssertPtrReturn(pStreamOSS, VERR_INVALID_POINTER);588 RT_NOREF(pInterface);589 590 /*591 * Figure out now much to write.592 */593 uint32_t cbToWrite;594 audio_buf_info abinfo;595 int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);596 AssertLogRelMsgReturn(rc2 >= 0, ("OSS: Failed to retrieve current playback buffer: %s (%d)\n", strerror(errno), errno),597 RTErrConvertFromErrno(errno));598 599 #if 0 /** @todo r=bird: WTF do we make a fuss over abinfo.bytes for when we don't even use it?!? */600 AssertLogRelMsgReturn(abinfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", abinfo.bytes), VERR_INTERNAL_ERROR_3);601 if ((unsigned)abinfo.bytes > cbBuf)602 {603 LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", abinfo.bytes, cbBuf, cbBuf));604 abinfo.bytes = cbBuf;605 /* Keep going. */606 }607 #endif608 cbToWrite = (unsigned)(abinfo.fragments * abinfo.fragsize);609 cbToWrite = RT_MIN(cbToWrite, cbBuf);610 611 /*612 * Write.613 */614 uint8_t const *pbBuf = (uint8_t const *)pvBuf;615 uint32_t cbChunk = cbToWrite;616 uint32_t offChunk = 0;617 while (cbChunk > 0)618 {619 ssize_t cbWritten = write(pStreamOSS->hFile, &pbBuf[offChunk], RT_MIN(cbChunk, (unsigned)s_OSSConf.fragsize));620 if (cbWritten >= 0)621 {622 AssertLogRelMsg(!(cbWritten & pStreamOSS->uAlign),623 ("OSS: Misaligned write (written %#zx, alignment %#x)\n", cbWritten, pStreamOSS->uAlign));624 625 Assert((uint32_t)cbWritten <= cbChunk);626 offChunk += (uint32_t)cbWritten;627 cbChunk -= (uint32_t)cbWritten;628 }629 else630 {631 LogRel(("OSS: Failed writing output data: %s (%d)\n", strerror(errno), errno));632 return RTErrConvertFromErrno(errno);633 }634 }635 636 *pcbWritten = cbToWrite;637 return VINF_SUCCESS;638 }639 640 641 /**642 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}643 */644 static DECLCALLBACK(void) drvHostOssAudioHA_Shutdown(PPDMIHOSTAUDIO pInterface)645 {646 RT_NOREF(pInterface);647 }648 649 650 /**651 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}652 */653 static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostOssAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)654 {655 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);656 RT_NOREF(enmDir);657 658 return PDMAUDIOBACKENDSTS_RUNNING;659 }660 661 662 /**663 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}664 */665 static DECLCALLBACK(int) drvHostOssAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,666 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)667 {668 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);669 AssertPtrReturn(pStream, VERR_INVALID_POINTER);670 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);671 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);672 673 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;674 675 int rc;676 if (pCfgReq->enmDir == PDMAUDIODIR_IN)677 rc = ossCreateStreamIn (pStreamOSS, pCfgReq, pCfgAcq);678 else679 rc = ossCreateStreamOut(pStreamOSS, pCfgReq, pCfgAcq);680 681 if (RT_SUCCESS(rc))682 {683 pStreamOSS->pCfg = PDMAudioStrmCfgDup(pCfgAcq);684 if (!pStreamOSS->pCfg)685 rc = VERR_NO_MEMORY;686 }687 688 return rc;689 }690 691 692 /**693 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}694 */695 static DECLCALLBACK(int) drvHostOssAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)696 {697 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);698 AssertPtrReturn(pStream, VERR_INVALID_POINTER);699 700 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;701 702 if (!pStreamOSS->pCfg) /* Not (yet) configured? Skip. */703 return VINF_SUCCESS;704 705 int rc;706 if (pStreamOSS->pCfg->enmDir == PDMAUDIODIR_IN)707 rc = ossDestroyStreamIn(pStream);708 else709 rc = ossDestroyStreamOut(pStream);710 711 if (RT_SUCCESS(rc))712 {713 PDMAudioStrmCfgFree(pStreamOSS->pCfg);714 pStreamOSS->pCfg = NULL;715 }716 717 return rc;718 }719 720 721 /**722 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}723 */724 static DECLCALLBACK(int) drvHostOssAudioHA_StreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,725 PDMAUDIOSTREAMCMD enmStreamCmd)726 {727 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);728 AssertPtrReturn(pStream, VERR_INVALID_POINTER);729 730 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;731 732 if (!pStreamOSS->pCfg) /* Not (yet) configured? Skip. */733 return VINF_SUCCESS;734 735 int rc;736 if (pStreamOSS->pCfg->enmDir == PDMAUDIODIR_IN)737 rc = ossControlStreamIn(/*pInterface, pStream, enmStreamCmd*/);738 else739 rc = ossControlStreamOut(pStreamOSS, enmStreamCmd);740 741 return rc;742 }743 744 745 /**746 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}747 */748 static DECLCALLBACK(int) drvHostOssAudioHA_StreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)749 {750 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);751 AssertPtrReturn(pStream, VERR_INVALID_POINTER);752 753 LogFlowFuncEnter();754 755 /* Nothing to do here for OSS. */756 return VINF_SUCCESS;757 }758 759 760 /**761 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}762 */763 static DECLCALLBACK(uint32_t) drvHostOssAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)764 {765 RT_NOREF(pInterface, pStream);766 return UINT32_MAX;767 }768 769 770 /**771 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}772 */773 static DECLCALLBACK(uint32_t) drvHostOssAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)774 {775 POSSAUDIOSTREAM pStreamOSS = (POSSAUDIOSTREAM)pStream;776 AssertPtr(pStreamOSS);777 RT_NOREF(pInterface);778 779 /*780 * Note! This logic was found in StreamPlay and corrected a little.781 *782 * The logic here must match what StreamPlay does.783 */784 audio_buf_info abinfo = { 0, 0, 0, 0 };785 int rc2 = ioctl(pStreamOSS->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);786 AssertMsgReturn(rc2 >= 0, ("SNDCTL_DSP_GETOSPACE failed: %s (%d)\n", strerror(errno), errno), 0);787 788 #if 0 /** @todo we could return abinfo.bytes here iff StreamPlay didn't use the fragmented approach */789 /** @todo r=bird: WTF do we make a fuss over abinfo.bytes for when we don't even use it?!? */790 AssertLogRelMsgReturn(abinfo.bytes >= 0, ("OSS: Warning: Invalid available size: %d\n", abinfo.bytes), VERR_INTERNAL_ERROR_3);791 if ((unsigned)abinfo.bytes > cbBuf)792 {793 LogRel2(("OSS: Warning: Too big output size (%d > %RU32), limiting to %RU32\n", abinfo.bytes, cbBuf, cbBuf));794 abinfo.bytes = cbBuf;795 /* Keep going. */796 }797 #endif798 799 return (uint32_t)(abinfo.fragments * abinfo.fragsize);800 }801 802 803 /**804 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}805 */806 static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostOssAudioHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)807 {808 RT_NOREF(pInterface, pStream);809 return PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED | PDMAUDIOSTREAMSTS_FLAGS_ENABLED;810 }811 772 812 773 /**
Note:
See TracChangeset
for help on using the changeset viewer.