VirtualBox

Changeset 27105 in vbox


Ignore:
Timestamp:
Mar 5, 2010 3:36:32 PM (15 years ago)
Author:
vboxsync
Message:

pulse: drain the out stream before we disable the voice

Location:
trunk/src/VBox/Devices/Audio
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/pulse_stubs.c

    r26783 r27105  
    181181                (o))
    182182PROXY_STUB     (pa_operation_get_state, pa_operation_state_t,
     183                (pa_operation *o),
     184                (o))
     185PROXY_STUB_VOID(pa_operation_cancel,
    183186                (pa_operation *o),
    184187                (o))
     
    241244    ELEMENT(pa_operation_unref),
    242245    ELEMENT(pa_operation_get_state),
     246    ELEMENT(pa_operation_cancel),
    243247    ELEMENT(pa_strerror),
    244248    ELEMENT(pa_stream_readable_size)
  • trunk/src/VBox/Devices/Audio/pulseaudio.c

    r26783 r27105  
    7070    size_t         cbPeekBuf;
    7171    size_t         offPeekBuf;
     72    pa_operation   *pDrainOp;
    7273} PulseVoice;
    7374
     
    147148}
    148149
    149 static void context_state_callback(pa_context *c, void *userdata)
     150static void stream_success_callback(pa_stream *pStream, int fSuccess, void *userdata)
    150151{
    151152    PulseVoice *pPulse = (PulseVoice *)userdata;
    152     switch (pa_context_get_state(c))
     153    pPulse->fOpSuccess = fSuccess;
     154    if (!fSuccess)
     155    {
     156        if (pPulse->cErrors < MAX_LOG_REL_ERRORS)
     157        {
     158            int rc = pa_context_errno(g_pContext);
     159            pPulse->cErrors++;
     160            LogRel(("Pulse: Failed stream operation: %s\n", pa_strerror(rc)));
     161        }
     162    }
     163    pa_threaded_mainloop_signal(g_pMainLoop, 0);
     164}
     165
     166/**
     167 * Synchronously wait until an operation completed.
     168 */
     169static int pulse_wait_for_operation (pa_operation *op)
     170{
     171    if (op)
     172    {
     173        while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
     174            pa_threaded_mainloop_wait(g_pMainLoop);
     175        pa_operation_unref(op);
     176    }
     177
     178    return 1;
     179}
     180
     181/**
     182 * Context status changed.
     183 */
     184static void context_state_callback(pa_context *pContext, void *userdata)
     185{
     186    PulseVoice *pPulse = (PulseVoice *)userdata;
     187    switch (pa_context_get_state(pContext))
    153188    {
    154189        case PA_CONTEXT_READY:
     
    169204}
    170205
    171 static void stream_state_callback(pa_stream *s, void *userdata)
    172 {
    173     switch (pa_stream_get_state(s))
     206/**
     207 * Stream status changed.
     208 */
     209static void stream_state_callback(pa_stream *pStream, void *userdata)
     210{
     211    switch (pa_stream_get_state(pStream))
    174212    {
    175213        case PA_STREAM_READY:
     
    182220            break;
    183221    }
     222}
     223
     224/**
     225 * Callback called when our pa_stream_drain operation was completed.
     226 */
     227static void stream_drain_callback(pa_stream *pStream, int fSuccess, void *userdata)
     228{
     229    PulseVoice *pPulse = (PulseVoice *)userdata;
     230    pPulse->fOpSuccess = fSuccess;
     231    if (!fSuccess)
     232    {
     233        if (pPulse->cErrors < MAX_LOG_REL_ERRORS)
     234        {
     235            int rc = pa_context_errno(g_pContext);
     236            pPulse->cErrors++;
     237            LogRel(("Pulse: Failed stream operation: %s\n", pa_strerror(rc)));
     238        }
     239    }
     240    else
     241        pa_operation_unref(pa_stream_cork(pStream, 1, stream_success_callback, userdata));
     242
     243    pa_operation_unref(pPulse->pDrainOp);
     244    pPulse->pDrainOp = NULL;
    184245}
    185246
     
    229290#endif
    230291
     292    /* no input/output right away after the stream was started */
     293    flags |= PA_STREAM_START_CORKED;
     294
    231295    if (fIn)
    232296    {
     
    246310                pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));
    247311
    248         flags |= PA_STREAM_START_CORKED;
    249 
    250312        if (pa_stream_connect_playback(pStream, /*dev=*/NULL, pBufAttr, flags,
    251313                                       /*cvolume=*/NULL, /*sync_stream=*/NULL) < 0)
     
    310372    audsettings_t obt_as;
    311373    int cbBuf;
     374
     375    pPulse->pDrainOp            = NULL;
    312376
    313377    pPulse->SampleSpec.format   = aud_to_pulsefmt (as->fmt);
     
    440504}
    441505
    442 static void stream_success_callback(pa_stream *pStream, int success, void *userdata)
    443 {
    444     PulseVoice *pPulse = (PulseVoice *) userdata;
    445     pPulse->fOpSuccess = success;
    446     if (!success)
    447     {
    448         if (pPulse->cErrors < MAX_LOG_REL_ERRORS)
    449         {
    450             int rc = pa_context_errno(g_pContext);
    451             pPulse->cErrors++;
    452             LogRel(("Pulse: Failed stream operation: %s\n", pa_strerror(rc)));
    453         }
    454     }
    455     pa_threaded_mainloop_signal(g_pMainLoop, 0);
    456 }
    457 
    458 static int pulse_wait_for_operation (pa_operation *op)
    459 {
    460     if (op)
    461     {
    462         while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
    463             pa_threaded_mainloop_wait(g_pMainLoop);
    464         pa_operation_unref(op);
    465     }
    466 
    467     return 1;
    468 }
    469 
    470506static int pulse_ctl_out (HWVoiceOut *hw, int cmd, ...)
    471507{
     
    477513            /* Start audio output. */
    478514            pa_threaded_mainloop_lock(g_pMainLoop);
    479             pulse_wait_for_operation(pa_stream_cork(pPulse->pStream, 0,
    480                                                     stream_success_callback, pPulse));
     515            if (   pPulse->pDrainOp
     516                && pa_operation_get_state(pPulse->pDrainOp) != PA_OPERATION_DONE)
     517            {
     518                pa_operation_cancel(pPulse->pDrainOp);
     519                pa_operation_unref(pPulse->pDrainOp);
     520                pPulse->pDrainOp = NULL;
     521            }
     522            else
     523            {
     524                /* should return immediately */
     525                pulse_wait_for_operation(pa_stream_cork(pPulse->pStream, 0,
     526                                                        stream_success_callback, pPulse));
     527            }
    481528            pa_threaded_mainloop_unlock(g_pMainLoop);
    482529            break;
    483530
    484531        case VOICE_DISABLE:
    485             /* Pause audio output. Note that we must return immediately from here
    486              * so waiting until the buffers are flushed (trigger+drain) is not an
    487              * option! It could be sufficient to cork the audio stream (we are
    488              * called if the Pause bit of the AC97 x_CR register is set) but ALSA
    489              * uses snd_pcm_drop() dropping all pending frames so we do the same
    490              * here. */
     532            /* Pause audio output (the Pause bit of the AC97 x_CR register is set).
     533             * Note that we must return immediately from here! */
    491534            pa_threaded_mainloop_lock(g_pMainLoop);
    492             pulse_wait_for_operation(pa_stream_flush(pPulse->pStream,
    493                                                      stream_success_callback, pPulse));
    494             pulse_wait_for_operation(pa_stream_cork(pPulse->pStream, 1,
    495                                                     stream_success_callback, pPulse));
     535            if (!pPulse->pDrainOp)
     536            {
     537                /* should return immediately */
     538                pulse_wait_for_operation(pa_stream_trigger(pPulse->pStream,
     539                                                           stream_success_callback, pPulse));
     540                pPulse->pDrainOp = pa_stream_drain(pPulse->pStream,
     541                                                   stream_drain_callback, pPulse);
     542            }
    496543            pa_threaded_mainloop_unlock(g_pMainLoop);
    497544            break;
     
    653700        case VOICE_ENABLE:
    654701            pa_threaded_mainloop_lock(g_pMainLoop);
     702            /* should return immediately */
    655703            pulse_wait_for_operation(pa_stream_cork(pPulse->pStream, 0,
    656704                                                    stream_success_callback, pPulse));
     
    665713                pPulse->pu8PeekBuf = NULL;
    666714            }
     715            /* should return immediately */
    667716            pulse_wait_for_operation(pa_stream_cork(pPulse->pStream, 1,
    668717                                                    stream_success_callback, pPulse));
Note: See TracChangeset for help on using the changeset viewer.

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