Changeset 67951 in vbox
- Timestamp:
- Jul 13, 2017 10:23:33 AM (8 years ago)
- Location:
- trunk/src/VBox/Devices/Audio
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
r67909 r67951 45 45 *********************************************************************************************************************************/ 46 46 #define VBOX_PULSEAUDIO_MAX_LOG_REL_ERRORS 32 /** @todo Make this configurable thru driver options. */ 47 48 /* Whether to use PulseAudio's asynchronous handling or not. */ 49 //#define PULSEAUDIO_ASYNC /** @todo Make this configurable thru driver options. */ 47 50 48 51 #ifndef PA_STREAM_NOFLAGS … … 117 120 size_t offPeekBuf; 118 121 pa_operation *pDrainOp; 122 /** Number of occurred audio data underflows. */ 123 uint32_t cUnderflows; 124 /** Current latency (in us). */ 125 uint64_t curLatencyUs; 126 /** Start time stamp (in us) of stream playback / recording. */ 127 pa_usec_t tsStartUs; 119 128 } PULSEAUDIOSTREAM, *PPULSEAUDIOSTREAM; 120 129 … … 177 186 static int paEnumerate(PDRVHOSTPULSEAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum); 178 187 static int paError(PDRVHOSTPULSEAUDIO pThis, const char *szMsg); 188 static void paStreamCbUnderflow(pa_stream *pStream, void *pvContext); 189 #ifdef PULSEAUDIO_ASYNC 190 static void paStreamCbReqWrite(pa_stream *pStream, size_t cbLen, void *pvContext); 191 #endif 179 192 static void paStreamCbSuccess(pa_stream *pStream, int fSuccess, void *pvContext); 180 181 193 182 194 … … 390 402 391 403 404 #ifdef PULSEAUDIO_ASYNC 405 static void paStreamCbReqWrite(pa_stream *pStream, size_t cbLen, void *pvContext) 406 { 407 RT_NOREF(cbLen, pvContext); 408 409 PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pvContext; 410 AssertPtrReturnVoid(pStrm); 411 412 pa_usec_t usec = 0; 413 int neg = 0; 414 pa_stream_get_latency(pStream, &usec, &neg); 415 416 Log2Func(("Requested %zu bytes -- Current latency is %RU64ms\n", cbLen, usec / 1000)); 417 } 418 #endif /* PULSEAUDIO_ASYNC */ 419 420 421 static void paStreamCbUnderflow(pa_stream *pStream, void *pvContext) 422 { 423 PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pvContext; 424 AssertPtrReturnVoid(pStrm); 425 426 pStrm->cUnderflows++; 427 428 Log2Func(("Warning: Hit underflow #%RU32\n", pStrm->cUnderflows)); 429 430 if ( pStrm->cUnderflows >= 6 /** @todo Make this check configurable. */ 431 && pStrm->curLatencyUs < 2000000 /* 2s */) 432 { 433 pStrm->curLatencyUs = (pStrm->curLatencyUs * 3) / 2; 434 LogFunc(("Latency increased to %RU64ms\n", pStrm->curLatencyUs / 1000)); 435 436 pStrm->BufAttr.maxlength = pa_usec_to_bytes(pStrm->curLatencyUs, &pStrm->SampleSpec); 437 pStrm->BufAttr.tlength = pa_usec_to_bytes(pStrm->curLatencyUs, &pStrm->SampleSpec); 438 439 pa_stream_set_buffer_attr(pStream, &pStrm->BufAttr, NULL, NULL); 440 441 pStrm->cUnderflows = 0; 442 } 443 444 #ifdef LOG_ENABLED 445 pa_usec_t curLatencyUs = 0; 446 pa_stream_get_latency(pStream, &curLatencyUs, NULL /* Neg */); 447 448 const pa_timing_info *pTInfo = pa_stream_get_timing_info(pStream); 449 const pa_sample_spec *pSpec = pa_stream_get_sample_spec(pStream); 450 451 pa_usec_t curPosWritesUs = pa_bytes_to_usec(pTInfo->write_index, pSpec); 452 pa_usec_t curTsUs = pa_rtclock_now() - pStrm->tsStartUs; 453 454 Log2Func(("curPosWrite=%RU64ms, curTs=%RU64ms, curDelta=%RI64ms, curLatency=%RU64ms\n", 455 curPosWritesUs / 1000, curTsUs / 1000, (((int64_t)curPosWritesUs - (int64_t)curTsUs) / 1000), curLatencyUs / 1000)); 456 #endif 457 } 458 459 392 460 static void paStreamCbSuccess(pa_stream *pStream, int fSuccess, void *pvUser) 393 461 { … … 406 474 407 475 408 static int paStreamOpen(PDRVHOSTPULSEAUDIO pThis, bool fIn, const char *pszName, 409 pa_sample_spec *pSampleSpec, pa_buffer_attr *pBufAttr, 410 pa_stream **ppStream) 411 { 412 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 413 AssertPtrReturn(pszName, VERR_INVALID_POINTER); 414 AssertPtrReturn(pSampleSpec, VERR_INVALID_POINTER); 415 AssertPtrReturn(pBufAttr, VERR_INVALID_POINTER); 416 AssertPtrReturn(ppStream, VERR_INVALID_POINTER); 417 418 if (!pa_sample_spec_valid(pSampleSpec)) 419 { 420 LogRel(("PulseAudio: Unsupported sample specification for stream '%s'\n", 421 pszName)); 422 return VERR_NOT_SUPPORTED; 423 } 476 static int paStreamOpen(PDRVHOSTPULSEAUDIO pThis, PPULSEAUDIOSTREAM pStreamPA, bool fIn, const char *pszName) 477 { 478 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 479 AssertPtrReturn(pStreamPA, VERR_INVALID_POINTER); 480 AssertPtrReturn(pszName, VERR_INVALID_POINTER); 424 481 425 482 int rc = VINF_SUCCESS; 426 483 427 484 pa_stream *pStream = NULL; 428 uint32_t flags = PA_STREAM_NOFLAGS; 429 430 LogFunc(("Opening '%s', rate=%dHz, channels=%d, format=%s\n", 431 pszName, pSampleSpec->rate, pSampleSpec->channels, 432 pa_sample_format_to_string(pSampleSpec->format))); 485 uint32_t flags = PA_STREAM_NOFLAGS; 433 486 434 487 pa_threaded_mainloop_lock(pThis->pMainLoop); … … 436 489 do 437 490 { 491 pa_sample_spec *pSampleSpec = &pStreamPA->SampleSpec; 492 493 LogFunc(("Opening '%s', rate=%dHz, channels=%d, format=%s\n", 494 pszName, pSampleSpec->rate, pSampleSpec->channels, 495 pa_sample_format_to_string(pSampleSpec->format))); 496 497 if (!pa_sample_spec_valid(pSampleSpec)) 498 { 499 LogRel(("PulseAudio: Unsupported sample specification for stream '%s'\n", pszName)); 500 rc = VERR_NOT_SUPPORTED; 501 break; 502 } 503 504 pa_buffer_attr *pBufAttr = &pStreamPA->BufAttr; 505 438 506 /** @todo r=andy Use pa_stream_new_with_proplist instead. */ 439 if (!(pStream = pa_stream_new(pThis->pContext, pszName, pSampleSpec, 440 NULL /* pa_channel_map */))) 507 if (!(pStream = pa_stream_new(pThis->pContext, pszName, pSampleSpec, NULL /* pa_channel_map */))) 441 508 { 442 509 LogRel(("PulseAudio: Could not create stream '%s'\n", pszName)); … … 445 512 } 446 513 447 pa_stream_set_state_callback(pStream, paStreamCbStateChanged, pThis); 514 #ifdef PULSEAUDIO_ASYNC 515 pa_stream_set_write_callback(pStream, paStreamCbReqWrite, pStreamPA); 516 #endif 517 pa_stream_set_underflow_callback(pStream, paStreamCbUnderflow, pStreamPA); 518 pa_stream_set_state_callback(pStream, paStreamCbStateChanged, pThis); 448 519 449 520 #if PA_API_VERSION >= 12 … … 451 522 flags |= PA_STREAM_ADJUST_LATENCY; 452 523 #endif 453 454 #if 0 455 /* Not applicable as we don't use pa_stream_get_latency() and pa_stream_get_time(). */ 524 /* For using pa_stream_get_latency() and pa_stream_get_time(). */ 456 525 flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE; 457 #endif 526 458 527 /* No input/output right away after the stream was started. */ 459 528 flags |= PA_STREAM_START_CORKED; … … 506 575 } 507 576 577 pStreamPA->tsStartUs = pa_rtclock_now(); 578 508 579 if (RT_FAILURE(rc)) 509 580 break; … … 513 584 memcpy(pBufAttr, pBufAttrObtained, sizeof(pa_buffer_attr)); 514 585 515 if (fIn) 516 LogFunc(("Obtained record buffer attributes: maxlength=%RU32, fragsize=%RU32\n", 517 pBufAttr->maxlength, pBufAttr->fragsize)); 518 else 519 LogFunc(("Obtained playback buffer attributes: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d\n", 520 pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq)); 586 LogFunc(("Obtained %s buffer attributes: tLength=%RU32, maxLength=%RU32, minReq=%RU32, fragSize=%RU32, preBuf=%RU32\n", 587 fIn ? "capture" : "playback", 588 pBufAttr->tlength, pBufAttr->maxlength, pBufAttr->minreq, pBufAttr->fragsize, pBufAttr->prebuf)); 589 590 pStreamPA->pStream = pStream; 521 591 522 592 } while (0); … … 533 603 pa_stream_unref(pStream); 534 604 } 535 else536 *ppStream = pStream;537 605 538 606 LogFlowFuncLeaveRC(rc); … … 662 730 pStreamPA->SampleSpec.channels = pCfgReq->Props.cChannels; 663 731 664 /* Note that setting maxlength to -1 does not work on PulseAudio servers 665 * older than 0.9.10. So use the suggested value of 3/2 of tlength */ 666 pStreamPA->BufAttr.tlength = (pa_bytes_per_second(&pStreamPA->SampleSpec) 667 * s_pulseCfg.buffer_msecs_out) / 1000; 668 pStreamPA->BufAttr.maxlength = (pStreamPA->BufAttr.tlength * 3) / 2; 669 pStreamPA->BufAttr.prebuf = -1; /* Same as tlength */ 670 pStreamPA->BufAttr.minreq = -1; 732 pStreamPA->curLatencyUs = 100 * 1000; /** 100ms latency by default. @todo Make this configurable. */ 733 734 const uint32_t mixsize = pa_usec_to_bytes(pStreamPA->curLatencyUs, &pStreamPA->SampleSpec); 735 736 pStreamPA->BufAttr.maxlength = mixsize * 4; 737 pStreamPA->BufAttr.tlength = mixsize; 738 pStreamPA->BufAttr.prebuf = mixsize * 2; 739 pStreamPA->BufAttr.minreq = mixsize; 740 741 LogFunc(("BufAttr tlength=%RU32, maxLength=%RU32, minReq=%RU32\n", 742 pStreamPA->BufAttr.tlength, pStreamPA->BufAttr.maxlength, pStreamPA->BufAttr.minreq)); 671 743 672 744 /* Note that the struct BufAttr is updated to the obtained values after this call! */ 673 int rc = paStreamOpen(pThis, false /* fIn */, "PulseAudio (Out)", 674 &pStreamPA->SampleSpec, &pStreamPA->BufAttr, &pStreamPA->pStream); 745 int rc = paStreamOpen(pThis, pStreamPA, false /* fIn */, "PulseAudio (Out)"); 675 746 if (RT_FAILURE(rc)) 676 747 return rc; … … 714 785 715 786 /* Note: Other members of BufAttr are ignored for record streams. */ 716 int rc = paStreamOpen(pThis, true /* fIn */, "PulseAudio (In)", &pStreamPA->SampleSpec, &pStreamPA->BufAttr, 717 &pStreamPA->pStream); 787 int rc = paStreamOpen(pThis, pStreamPA, true /* fIn */, "PulseAudio (In)"); 718 788 if (RT_FAILURE(rc)) 719 789 return rc; … … 1439 1509 { 1440 1510 size_t cbWritable = pa_stream_writable_size(pStreamPA->pStream); 1441 Log3Func(("cbWritable=%zu, cbMinReq=%RU32\n", cbWritable, pStreamPA->BufAttr.minreq)); 1442 1443 if (cbWritable >= pStreamPA->BufAttr.minreq) 1444 cbAvail = (uint32_t)cbWritable; 1511 1512 Log3Func(("cbWritable=%zu, maxLength=%RU32, minReq=%RU32\n", 1513 cbWritable, pStreamPA->BufAttr.maxlength, pStreamPA->BufAttr.minreq)); 1514 1515 /* Don't report more writable than the PA server can handle. */ 1516 if (cbWritable > pStreamPA->BufAttr.maxlength) 1517 cbWritable = pStreamPA->BufAttr.maxlength; 1518 1519 cbAvail = (uint32_t)cbWritable; 1445 1520 } 1446 1521 else -
trunk/src/VBox/Devices/Audio/pulse_mangling.h
r59987 r67951 6 6 7 7 /* 8 * Copyright (C) 2013-201 6Oracle Corporation8 * Copyright (C) 2013-2017 Oracle Corporation 9 9 * 10 10 * This file is part of VirtualBox Open Source Edition (OSE), as … … 30 30 #define pa_stream_unref PULSE_MANGLER(pa_stream_unref) 31 31 #define pa_stream_get_state PULSE_MANGLER(pa_stream_get_state) 32 #define pa_stream_get_latency PULSE_MANGLER(pa_stream_get_latency) 33 #define pa_stream_get_timing_info PULSE_MANGLER(pa_stream_get_timing_info) 34 #define pa_stream_set_buffer_attr PULSE_MANGLER(pa_stream_set_buffer_attr) 32 35 #define pa_stream_set_state_callback PULSE_MANGLER(pa_stream_set_state_callback) 36 #define pa_stream_set_underflow_callback PULSE_MANGLER(pa_stream_set_underflow_callback) 37 #define pa_stream_set_write_callback PULSE_MANGLER(pa_stream_set_write_callback) 33 38 #define pa_stream_flush PULSE_MANGLER(pa_stream_flush) 34 39 #define pa_stream_drain PULSE_MANGLER(pa_stream_drain) … … 60 65 #define pa_threaded_mainloop_lock PULSE_MANGLER(pa_threaded_mainloop_lock) 61 66 #define pa_bytes_per_second PULSE_MANGLER(pa_bytes_per_second) 67 #define pa_bytes_to_usec PULSE_MANGLER(pa_bytes_to_usec) 68 #define pa_usec_to_bytes PULSE_MANGLER(pa_usec_to_bytes) 69 #define pa_rtclock_now PULSE_MANGLER(pa_rtclock_now) 62 70 #define pa_frame_size PULSE_MANGLER(pa_frame_size) 63 71 #define pa_sample_format_to_string PULSE_MANGLER(pa_sample_format_to_string) -
trunk/src/VBox/Devices/Audio/pulse_stubs.c
r64631 r67951 5 5 6 6 /* 7 * Copyright (C) 2006-201 6Oracle Corporation7 * Copyright (C) 2006-2017 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 79 79 (pa_stream *p), 80 80 (p)) 81 PROXY_STUB (pa_stream_get_latency, int, 82 (pa_stream *s, pa_usec_t *r_usec, int *negative), 83 (s, r_usec, negative)) 84 PROXY_STUB (pa_stream_get_timing_info, pa_timing_info*, 85 (pa_stream *s), 86 (s)) 87 PROXY_STUB (pa_stream_set_buffer_attr, pa_operation *, 88 (pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata), 89 (s, attr, cb, userdata)) 81 90 PROXY_STUB_VOID(pa_stream_set_state_callback, 82 91 (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata), 92 (s, cb, userdata)) 93 PROXY_STUB_VOID(pa_stream_set_underflow_callback, 94 (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata), 95 (s, cb, userdata)) 96 PROXY_STUB_VOID(pa_stream_set_write_callback, 97 (pa_stream *s, pa_stream_request_cb_t cb, void *userdata), 83 98 (s, cb, userdata)) 84 99 PROXY_STUB (pa_stream_flush, pa_operation*, … … 111 126 (p)) 112 127 PROXY_STUB (pa_context_connect, int, 113 (pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api), 128 (pa_context *c, const char *server, pa_context_flags_t flags, 129 const pa_spawn_api *api), 114 130 (c, server, flags, api)) 115 131 PROXY_STUB_VOID(pa_context_disconnect, … … 170 186 (const pa_sample_spec *spec), 171 187 (spec)) 188 PROXY_STUB (pa_bytes_to_usec, pa_usec_t, 189 (uint64_t l, const pa_sample_spec *spec), 190 (l, spec)) 191 PROXY_STUB (pa_usec_to_bytes, size_t, 192 (pa_usec_t t, const pa_sample_spec *spec), 193 (t, spec)) 194 PROXY_STUB (pa_rtclock_now, pa_usec_t, 195 (void), 196 ()) 172 197 PROXY_STUB (pa_frame_size, size_t, 173 198 (const pa_sample_spec *spec), … … 216 241 ELEMENT(pa_stream_unref), 217 242 ELEMENT(pa_stream_get_state), 243 ELEMENT(pa_stream_get_latency), 244 ELEMENT(pa_stream_get_timing_info), 245 ELEMENT(pa_stream_set_buffer_attr), 218 246 ELEMENT(pa_stream_set_state_callback), 247 ELEMENT(pa_stream_set_underflow_callback), 248 ELEMENT(pa_stream_set_write_callback), 219 249 ELEMENT(pa_stream_flush), 220 250 ELEMENT(pa_stream_drain), … … 246 276 ELEMENT(pa_threaded_mainloop_lock), 247 277 ELEMENT(pa_bytes_per_second), 278 ELEMENT(pa_bytes_to_usec), 279 ELEMENT(pa_usec_to_bytes), 280 ELEMENT(pa_rtclock_now), 248 281 ELEMENT(pa_frame_size), 249 282 ELEMENT(pa_sample_format_to_string), … … 296 329 return rc; 297 330 } 331 -
trunk/src/VBox/Devices/Audio/pulse_stubs.h
r62517 r67951 5 5 6 6 /* 7 * Copyright (C) 2006-201 6Oracle Corporation7 * Copyright (C) 2006-2017 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as
Note:
See TracChangeset
for help on using the changeset viewer.