VirtualBox

Changeset 25678 in vbox


Ignore:
Timestamp:
Jan 7, 2010 8:18:05 AM (15 years ago)
Author:
vboxsync
Message:

Devices/pulseaudio: Several fixes from Arthur Taylor (thanks!), in particular for pcm_in though pcm_in currently untested plus some cleanup

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

Legend:

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

    r22647 r25678  
    7979                (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata),
    8080                (s, cb, userdata))
    81 PROXY_STUB     (pa_stream_flush, pa_operation*,
     81PROXY_STUB     (pa_stream_drain, pa_operation*,
    8282                (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
    8383                (s, cb, userdata))
     84PROXY_STUB     (pa_stream_trigger, pa_operation*,
     85                (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
     86                (s, cb, userdata))
    8487PROXY_STUB     (pa_stream_new, pa_stream*,
    8588                (pa_context *c, const char *name, const pa_sample_spec *ss,
     
    98101                (pa_stream *p),
    99102                (p))
    100 PROXY_STUB     (pa_stream_trigger, pa_operation*,
    101                 (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
    102                 (s, cb, userdata))
    103103PROXY_STUB     (pa_stream_writable_size, size_t,
    104104                (pa_stream *p),
     
    154154                (m))
    155155PROXY_STUB     (pa_bytes_per_second, size_t,
     156                (const pa_sample_spec *spec),
     157                (spec))
     158PROXY_STUB     (pa_frame_size, size_t,
    156159                (const pa_sample_spec *spec),
    157160                (spec))
     
    168171                (pa_operation *o),
    169172                (o))
     173PROXY_STUB     (pa_operation_get_state, pa_operation_state_t,
     174                (pa_operation *o),
     175                (o))
    170176PROXY_STUB     (pa_strerror, const char*,
    171177                (int error),
    172178                (error))
     179PROXY_STUB     (pa_stream_readable_size, size_t,
     180                (pa_stream *p),
     181                (p))
    173182
    174183
     
    191200    ELEMENT(pa_stream_get_state),
    192201    ELEMENT(pa_stream_set_state_callback),
    193     ELEMENT(pa_stream_flush),
     202    ELEMENT(pa_stream_drain),
     203    ELEMENT(pa_stream_trigger),
    194204    ELEMENT(pa_stream_new),
    195205    ELEMENT(pa_stream_get_buffer_attr),
     
    197207    ELEMENT(pa_stream_cork),
    198208    ELEMENT(pa_stream_drop),
    199     ELEMENT(pa_stream_trigger),
    200209    ELEMENT(pa_stream_writable_size),
    201210    ELEMENT(pa_context_connect),
     
    216225    ELEMENT(pa_threaded_mainloop_lock),
    217226    ELEMENT(pa_bytes_per_second),
     227    ELEMENT(pa_frame_size),
    218228    ELEMENT(pa_sample_format_to_string),
    219229    ELEMENT(pa_sample_spec_valid),
    220230    ELEMENT(pa_channel_map_init_auto),
    221231    ELEMENT(pa_operation_unref),
     232    ELEMENT(pa_operation_get_state),
    222233    ELEMENT(pa_strerror),
     234    ELEMENT(pa_stream_readable_size)
    223235};
    224236#undef ELEMENT
  • trunk/src/VBox/Devices/Audio/pulseaudio.c

    r22153 r25678  
    4949typedef struct PulseVoice
    5050{
    51     HWVoiceOut  hw;
    52     void       *pPCMBuf;
    53     pa_stream  *pStream;
    54     int         fOpSuccess;
    55     unsigned    cErrors;
     51    HWVoiceOut     hw;
     52    /** DAC buffer */
     53    void           *pPCMBuf;
     54    /** Pulse stream */
     55    pa_stream      *pStream;
     56    /** Pulse sample format and attribute specification */
     57    pa_sample_spec SampleSpec;
     58    /** Pulse playback and buffer metrics */
     59    pa_buffer_attr BufAttr;
     60    int            fOpSuccess;
     61    /** number of logged errors */
     62    unsigned       cErrors;
     63    const uint8_t  *pu8PeekBuf;
     64    size_t         cbPeekBuf;
     65    size_t         offPeekBuf;
    5666} PulseVoice;
    5767
     68/* The desired max buffer size in milliseconds. The desired latency will be
     69 * calculated to be 1/10 of the value */
    5870static struct
    5971{
     
    6476{
    6577    INIT_FIELD (.buffer_msecs_out = ) 100,
    66     INIT_FIELD (.buffer_msecs_in  = ) 100,
     78    INIT_FIELD (.buffer_msecs_in  = ) 300,
    6779};
    68 
    69 struct pulse_params_req
    70 {
    71     int                 freq;
    72     pa_sample_format_t  pa_format;
    73     int                 nchannels;
    74 };
    75 
    76 struct pulse_params_obt
    77 {
    78     int                 freq;
    79     pa_sample_format_t  pa_format;
    80     int                 nchannels;
    81     unsigned long       buffer_size;
    82 };
    83 
    84 static void pulse_check_fatal (PulseVoice *pulse, int rc)
    85 {
    86     if (rc == PA_ERR_CONNECTIONTERMINATED)
    87     {
    88         /* XXX runtime warning */
    89         LogRel(("Pulse: Audio input/output stopped!\n"));
    90         pulse->cErrors = MAX_LOG_REL_ERRORS;
    91     }
    92 }
    9380
    9481static pa_sample_format_t aud_to_pulsefmt (audfmt_e fmt)
     
    155142static void context_state_callback(pa_context *c, void *userdata)
    156143{
     144    PulseVoice *pPulse = (PulseVoice *)userdata;
    157145    switch (pa_context_get_state(c))
    158146    {
    159147        case PA_CONTEXT_READY:
    160148        case PA_CONTEXT_TERMINATED:
     149            pa_threaded_mainloop_signal(g_pMainLoop, 0);
     150            break;
     151
    161152        case PA_CONTEXT_FAILED:
     153            LogRel(("Pulse: Audio input/output stopped!\n"));
     154            pPulse->cErrors = MAX_LOG_REL_ERRORS;
    162155            pa_threaded_mainloop_signal(g_pMainLoop, 0);
    163156            break;
     157
    164158        default:
    165159            break;
     
    176170            pa_threaded_mainloop_signal(g_pMainLoop, 0);
    177171            break;
     172
    178173        default:
    179174            break;
     
    181176}
    182177
    183 static void stream_latency_update_callback(pa_stream *s, void *userdata)
    184 {
    185     pa_threaded_mainloop_signal(g_pMainLoop, 0);
    186 }
    187 
    188 static int pulse_open (int fIn, struct pulse_params_req *req,
    189                        struct pulse_params_obt *obt, pa_stream **ppStream)
    190 {
    191     pa_sample_spec        sspec;
    192     pa_channel_map        cmap;
     178static int pulse_open (int fIn, pa_stream **ppStream, pa_sample_spec *pSampleSpec,
     179                       pa_buffer_attr *pBufAttr)
     180{
     181    const pa_buffer_attr *pBufAttrObtained;
    193182    pa_stream            *pStream = NULL;
    194     pa_buffer_attr        bufAttr;
    195     const pa_buffer_attr *pBufAttr;
    196     const pa_sample_spec *pSampSpec;
    197     char                  achPCMName[64];
    198     pa_stream_flags_t     flags;
    199     int                   ms = fIn ? conf.buffer_msecs_in : conf.buffer_msecs_out;
     183    char                 achPCMName[64];
     184    pa_stream_flags_t    flags = 0;
    200185    const char           *stream_name = audio_get_stream_name();
    201186
     
    205190                fIn ? "pcm_in" : "pcm_out",
    206191                stream_name ? ")" : "");
    207     sspec.rate     = req->freq;
    208     sspec.channels = req->nchannels;
    209     sspec.format   = req->pa_format;
    210192
    211193    LogRel(("Pulse: open %s rate=%dHz channels=%d format=%s\n",
    212                 fIn ? "PCM_IN" : "PCM_OUT", req->freq, req->nchannels,
    213                 pa_sample_format_to_string(req->pa_format)));
    214 
    215     if (!pa_sample_spec_valid(&sspec))
     194                fIn ? "PCM_IN" : "PCM_OUT", pSampleSpec->rate, pSampleSpec->channels,
     195                pa_sample_format_to_string(pSampleSpec->format)));
     196
     197    if (!pa_sample_spec_valid(pSampleSpec))
    216198    {
    217199        LogRel(("Pulse: Unsupported sample specification\n"));
     
    219201    }
    220202
    221     pa_channel_map_init_auto(&cmap, sspec.channels, PA_CHANNEL_MAP_ALSA);
    222 
    223 #if 0
    224     pa_cvolume_reset(&volume, sspec.channels);
    225 #endif
    226 
    227203    pa_threaded_mainloop_lock(g_pMainLoop);
    228204
    229     if (!(pStream = pa_stream_new(g_pContext, achPCMName, &sspec, &cmap)))
     205    if (!(pStream = pa_stream_new(g_pContext, achPCMName, pSampleSpec, /*channel_map=*/NULL)))
    230206    {
    231207        LogRel(("Pulse: Cannot create stream %s\n", achPCMName));
     
    233209    }
    234210
    235     pSampSpec      = pa_stream_get_sample_spec(pStream);
    236     obt->pa_format = pSampSpec->format;
    237     obt->nchannels = pSampSpec->channels;
    238     obt->freq      = pSampSpec->rate;
    239 
    240211    pa_stream_set_state_callback(pStream, stream_state_callback, NULL);
    241     pa_stream_set_latency_update_callback(pStream, stream_latency_update_callback, NULL);
    242 
    243     memset(&bufAttr, 0, sizeof(bufAttr));
    244     bufAttr.tlength   = (pa_bytes_per_second(pSampSpec) * ms) / 1000;
    245     bufAttr.maxlength = (bufAttr.tlength*3) / 2;
    246     bufAttr.minreq    = pa_bytes_per_second(pSampSpec) / 100;    /* 10ms */
    247     bufAttr.prebuf    = bufAttr.tlength - bufAttr.minreq;
    248     bufAttr.fragsize  = pa_bytes_per_second(pSampSpec) / 100;    /* 10ms */
    249 
    250     flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
     212
     213#if PA_API_VERSION >= 12
     214    /* XXX */
     215    flags |= PA_STREAM_ADJUST_LATENCY;
     216#endif
     217
    251218    if (fIn)
    252219    {
    253         if (pa_stream_connect_record(pStream, /*dev=*/NULL, &bufAttr, flags) < 0)
    254         {
    255             LogRel(("Pulse: Cannot connect record stream : %s\n",
     220        LogRel(("Pulse: Requested record buffer attributes: maxlength=%d fragsize=%d\n",
     221                pBufAttr->maxlength, pBufAttr->fragsize));
     222#if 0
     223        /* not applicable as we don't use pa_stream_get_latency() and pa_stream_get_time() */
     224        flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
     225#endif
     226        if (pa_stream_connect_record(pStream, /*dev=*/NULL, pBufAttr, flags) < 0)
     227        {
     228            LogRel(("Pulse: Cannot connect record stream: %s\n",
    256229                    pa_strerror(pa_context_errno(g_pContext))));
    257230            goto disconnect_unlock_and_fail;
     
    260233    else
    261234    {
    262         if (pa_stream_connect_playback(pStream, /*dev=*/NULL, &bufAttr, flags,
    263                                        NULL, NULL) < 0)
     235        LogRel(("Pulse: Requested playback buffer attributes: maxlength=%d tlength=%d prebuf=%d minreq=%d\n",
     236                pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));
     237
     238        flags |= PA_STREAM_START_CORKED;
     239
     240        if (pa_stream_connect_playback(pStream, /*dev=*/NULL, pBufAttr, flags,
     241                                       /*cvolume=*/NULL, /*sync_stream=*/NULL) < 0)
    264242        {
    265243            LogRel(("Pulse: Cannot connect playback stream: %s\n",
     
    274252        pa_stream_state_t sstate;
    275253        pa_threaded_mainloop_wait(g_pMainLoop);
     254
    276255        sstate = pa_stream_get_state(pStream);
    277256        if (sstate == PA_STREAM_READY)
     
    284263    }
    285264
    286     pBufAttr = pa_stream_get_buffer_attr(pStream);
    287     obt->buffer_size = pBufAttr->maxlength;
     265    pBufAttrObtained = pa_stream_get_buffer_attr(pStream);
     266    memcpy(pBufAttr, pBufAttrObtained, sizeof(pa_buffer_attr));
     267
     268    LogRel(("Pulse: Obtained buffer attributes: tlength=%d maxlength=%d prebuf=%d minreq=%d fragsize=%d\n",
     269            pBufAttr->tlength, pBufAttr->maxlength, pBufAttr->prebuf, pBufAttr->minreq, pBufAttr->fragsize));
    288270
    289271    pa_threaded_mainloop_unlock(g_pMainLoop);
    290 
    291     LogRel(("Pulse: buffer settings: max=%d tlength=%d prebuf=%d minreq=%d\n",
    292             pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));
    293 
    294272    *ppStream = pStream;
    295273    return 0;
     
    311289static int pulse_init_out (HWVoiceOut *hw, audsettings_t *as)
    312290{
    313     PulseVoice *pulse = (PulseVoice *) hw;
    314     struct pulse_params_req req;
    315     struct pulse_params_obt obt;
    316     audfmt_e effective_fmt;
    317     int endianness;
     291    PulseVoice *pPulse = (PulseVoice *) hw;
    318292    audsettings_t obt_as;
    319 
    320     req.pa_format   = aud_to_pulsefmt (as->fmt);
    321     req.freq        = as->freq;
    322     req.nchannels   = as->nchannels;
    323 
    324     if (pulse_open (/*fIn=*/0, &req, &obt, &pulse->pStream))
     293    int cbBuf;
     294
     295    pPulse->SampleSpec.format   = aud_to_pulsefmt (as->fmt);
     296    pPulse->SampleSpec.rate     = as->freq;
     297    pPulse->SampleSpec.channels = as->nchannels;
     298
     299    /* Note that setting maxlength to -1 does not work for older PulseAudio libraries
     300     * (at least not for 0.9.10). So use the suggested value of 3/2 of tlength */
     301    pPulse->BufAttr.tlength     = (pa_bytes_per_second(&pPulse->SampleSpec)
     302                                  * conf.buffer_msecs_out) / 1000;
     303    pPulse->BufAttr.maxlength   = (pPulse->BufAttr.tlength * 3) / 2;
     304    pPulse->BufAttr.prebuf      = -1; /* Same as tlength */
     305    pPulse->BufAttr.minreq      = -1; /* Pulse should set something sensible for minreq on it's own */
     306
     307    /* Notice that the struct BufAttr is updated to the obtained values after this call */
     308    if (pulse_open (0, &pPulse->pStream, &pPulse->SampleSpec, &pPulse->BufAttr))
    325309        return -1;
    326310
    327     if (pulse_to_audfmt (obt.pa_format, &effective_fmt, &endianness))
    328     {
    329         LogRel(("Pulse: Cannot find audio format %d\n", obt.pa_format));
     311    if (pulse_to_audfmt (pPulse->SampleSpec.format, &obt_as.fmt, &obt_as.endianness))
     312    {
     313        LogRel(("Pulse: Cannot find audio format %d\n", pPulse->SampleSpec.format));
    330314        return -1;
    331315    }
    332316
    333     obt_as.freq       = obt.freq;
    334     obt_as.nchannels  = obt.nchannels;
    335     obt_as.fmt        = effective_fmt;
    336     obt_as.endianness = endianness;
     317    obt_as.freq       = pPulse->SampleSpec.rate;
     318    obt_as.nchannels  = pPulse->SampleSpec.channels;
    337319
    338320    audio_pcm_init_info (&hw->info, &obt_as);
    339     hw->samples = obt.buffer_size >> hw->info.shift;
    340 
    341     pulse->pPCMBuf = RTMemAllocZ(obt.buffer_size);
    342     if (!pulse->pPCMBuf)
    343     {
    344         LogRel(("Pulse: Could not allocate DAC buffer of %d bytes\n", obt.buffer_size));
     321    cbBuf = audio_MIN(pPulse->BufAttr.tlength * 2, pPulse->BufAttr.maxlength);
     322
     323    pPulse->pPCMBuf = RTMemAllocZ(cbBuf);
     324    if (!pPulse->pPCMBuf)
     325    {
     326        LogRel(("Pulse: Could not allocate DAC buffer of %d bytes\n", cbBuf));
    345327        return -1;
    346328    }
    347329
     330    /* Convert from bytes to frames (aka samples) */
     331    hw->samples = cbBuf >> hw->info.shift;
     332
    348333    return 0;
    349334}
     
    351336static void pulse_fini_out (HWVoiceOut *hw)
    352337{
    353     PulseVoice *pulse = (PulseVoice *)hw;
    354     if (pulse->pStream)
    355     {
    356         pa_stream_disconnect(pulse->pStream);
    357         pa_stream_unref(pulse->pStream);
    358         pulse->pStream = NULL;
    359     }
    360     if (pulse->pPCMBuf)
    361     {
    362         RTMemFree (pulse->pPCMBuf);
    363         pulse->pPCMBuf = NULL;
     338    PulseVoice *pPulse = (PulseVoice *)hw;
     339
     340    if (pPulse->pStream)
     341    {
     342        pa_threaded_mainloop_lock(g_pMainLoop);
     343        pa_stream_disconnect(pPulse->pStream);
     344        pa_stream_unref(pPulse->pStream);
     345        pa_threaded_mainloop_unlock(g_pMainLoop);
     346        pPulse->pStream = NULL;
     347    }
     348
     349    if (pPulse->pPCMBuf)
     350    {
     351        RTMemFree (pPulse->pPCMBuf);
     352        pPulse->pPCMBuf = NULL;
    364353    }
    365354}
     
    367356static int pulse_run_out (HWVoiceOut *hw)
    368357{
    369     PulseVoice *pulse = (PulseVoice *) hw;
    370     int          csLive, csDecr = 0, csSamples, csToWrite, csAvail;
    371     size_t       cbAvail, cbToWrite;
     358    PulseVoice  *pPulse = (PulseVoice *) hw;
     359    int          cFramesLive;
     360    int          cFramesWritten = 0;
     361    int          csSamples;
     362    int          cFramesToWrite;
     363    int          cFramesAvail;
     364    size_t       cbAvail;
     365    size_t       cbToWrite;
    372366    uint8_t     *pu8Dst;
    373367    st_sample_t *psSrc;
    374368
    375     csLive = audio_pcm_hw_get_live_out (hw);
    376     if (!csLive)
     369    cFramesLive = audio_pcm_hw_get_live_out (hw);
     370    if (!cFramesLive)
    377371        return 0;
    378372
    379373    pa_threaded_mainloop_lock(g_pMainLoop);
    380374
    381     cbAvail = pa_stream_writable_size (pulse->pStream);
     375    cbAvail = pa_stream_writable_size (pPulse->pStream);
    382376    if (cbAvail == (size_t)-1)
    383377    {
    384         if (pulse->cErrors < MAX_LOG_REL_ERRORS)
     378        if (pPulse->cErrors < MAX_LOG_REL_ERRORS)
    385379        {
    386380            int rc = pa_context_errno(g_pContext);
    387             pulse->cErrors++;
     381            pPulse->cErrors++;
    388382            LogRel(("Pulse: Failed to determine the writable size: %s\n",
    389383                     pa_strerror(rc)));
    390             pulse_check_fatal(pulse, rc);
    391384        }
    392385        goto unlock_and_exit;
    393386    }
    394387
    395     csAvail   = cbAvail >> hw->info.shift; /* bytes => samples */
    396     csDecr    = audio_MIN (csLive, csAvail);
    397     csSamples = csDecr;
     388    cFramesAvail   = cbAvail >> hw->info.shift; /* bytes => samples */
     389    cFramesWritten = audio_MIN (cFramesLive, cFramesAvail);
     390    csSamples      = cFramesWritten;
    398391
    399392    while (csSamples)
    400393    {
    401394        /* split request at the end of our samples buffer */
    402         csToWrite = audio_MIN (csSamples, hw->samples - hw->rpos);
    403         cbToWrite = csToWrite << hw->info.shift;
    404         psSrc     = hw->mix_buf + hw->rpos;
    405         pu8Dst    = advance (pulse->pPCMBuf, hw->rpos << hw->info.shift);
    406 
    407         hw->clip (pu8Dst, psSrc, csToWrite);
    408 
    409         if (pa_stream_write (pulse->pStream, pu8Dst, cbToWrite,
     395        cFramesToWrite = audio_MIN (csSamples, hw->samples - hw->rpos);
     396        cbToWrite      = cFramesToWrite << hw->info.shift;
     397        psSrc          = hw->mix_buf + hw->rpos;
     398        pu8Dst         = advance (pPulse->pPCMBuf, hw->rpos << hw->info.shift);
     399
     400        hw->clip (pu8Dst, psSrc, cFramesToWrite);
     401
     402        if (pa_stream_write (pPulse->pStream, pu8Dst, cbToWrite,
    410403                             /*cleanup_callback=*/NULL, 0, PA_SEEK_RELATIVE) < 0)
    411404        {
    412405            LogRel(("Pulse: Failed to write %d samples: %s\n",
    413                     csToWrite, pa_strerror(pa_context_errno(g_pContext))));
    414             break;
    415         }
    416         hw->rpos   = (hw->rpos + csToWrite) % hw->samples;
    417         csSamples -= csToWrite;
     406                    cFramesToWrite, pa_strerror(pa_context_errno(g_pContext))));
     407            break;
     408        }
     409        hw->rpos   = (hw->rpos + cFramesToWrite) % hw->samples;
     410        csSamples -= cFramesToWrite;
    418411    }
    419412
     
    421414    pa_threaded_mainloop_unlock(g_pMainLoop);
    422415
    423     return csDecr;
     416    return cFramesWritten;
    424417}
    425418
     
    431424static void stream_success_callback(pa_stream *pStream, int success, void *userdata)
    432425{
    433     PulseVoice *pulse = (PulseVoice *) userdata;
    434     pulse->fOpSuccess = success;
     426    PulseVoice *pPulse = (PulseVoice *) userdata;
     427    pPulse->fOpSuccess = success;
    435428    pa_threaded_mainloop_signal(g_pMainLoop, 0);
    436429}
     
    438431typedef enum
    439432{
    440     Unpause  = 0,
    441     Pause    = 1,
    442     Flush    = 2,
    443     Trigger  = 3
     433    Unpause,
     434    Pause,
     435    Trigger,
     436    Drain
    444437} pulse_cmd_t;
    445438
    446 static int pulse_ctrl (HWVoiceOut *hw, pulse_cmd_t cmd)
    447 {
    448     PulseVoice *pulse = (PulseVoice *) hw;
     439static int pulse_ctrl (PulseVoice *pPulse, pulse_cmd_t cmd)
     440{
    449441    pa_operation *op = NULL;
    450 
    451     if (!pulse->pStream)
     442    const char *cmd_str = cmd == Unpause ? "unpause" :
     443                          cmd == Pause   ? "pause"   :
     444                          cmd == Trigger ? "trigger" :
     445                          cmd == Drain   ? "drain"   : NULL;
     446
     447    if (!pPulse->pStream)
    452448        return 0;
     449
     450    LogRel(("Pulse: ctrl cmd=%s\n", cmd_str));
    453451
    454452    pa_threaded_mainloop_lock(g_pMainLoop);
     
    456454    {
    457455        case Pause:
    458             op = pa_stream_cork(pulse->pStream, 1, stream_success_callback, pulse);
     456            op = pa_stream_cork(pPulse->pStream, 1, stream_success_callback, pPulse);
    459457            break;
    460458        case Unpause:
    461             op = pa_stream_cork(pulse->pStream, 0, stream_success_callback, pulse);
    462             break;
    463         case Flush:
    464             op = pa_stream_flush(pulse->pStream, stream_success_callback, pulse);
     459            op = pa_stream_cork(pPulse->pStream, 0, stream_success_callback, pPulse);
     460            break;
     461        case Drain:
     462            op = pa_stream_drain(pPulse->pStream, stream_success_callback, pPulse);
    465463            break;
    466464        case Trigger:
    467             op = pa_stream_trigger(pulse->pStream, stream_success_callback, pulse);
     465            op = pa_stream_trigger(pPulse->pStream, stream_success_callback, pPulse);
    468466            break;
    469467        default:
     
    472470    if (!op)
    473471    {
    474         if (pulse->cErrors < MAX_LOG_REL_ERRORS)
     472        if (pPulse->cErrors < MAX_LOG_REL_ERRORS)
    475473        {
    476474            int rc = pa_context_errno(g_pContext);
    477             pulse->cErrors++;
    478             LogRel(("Pulse: Failed ctrl cmd=%d to stream: %s\n",
    479                     cmd, pa_strerror(pa_context_errno(g_pContext))));
    480             pulse_check_fatal(pulse, rc);
     475            pPulse->cErrors++;
     476            LogRel(("Pulse: Failed ctrl cmd=%s to stream: %s\n", cmd_str, pa_strerror(rc)));
    481477        }
    482478    }
    483479    else
     480    {
     481        while (pa_operation_get_state(op) == PA_OPERATION_RUNNING)
     482            pa_threaded_mainloop_wait(g_pMainLoop);
    484483        pa_operation_unref(op);
     484    }
    485485
    486486unlock_and_exit:
     
    494494    {
    495495        case VOICE_ENABLE:
    496             pulse_ctrl(hw, Unpause);
    497             pulse_ctrl(hw, Trigger);
    498             break;
     496            pulse_ctrl((PulseVoice *)hw, Unpause);
     497            break;
     498
    499499        case VOICE_DISABLE:
    500             pulse_ctrl(hw, Flush);
    501             break;
     500            pulse_ctrl((PulseVoice *)hw, Trigger);
     501            pulse_ctrl((PulseVoice *)hw, Drain);
     502            pulse_ctrl((PulseVoice *)hw, Pause);
     503            break;
     504
    502505        default:
    503506            return -1;
     
    508511static int pulse_init_in (HWVoiceIn *hw, audsettings_t *as)
    509512{
    510     PulseVoice *pulse = (PulseVoice *) hw;
    511     struct pulse_params_req req;
    512     struct pulse_params_obt obt;
    513     audfmt_e effective_fmt;
    514     int endianness;
     513    PulseVoice *pPulse = (PulseVoice *) hw;
    515514    audsettings_t obt_as;
    516515
    517     req.pa_format   = aud_to_pulsefmt (as->fmt);
    518     req.freq        = as->freq;
    519     req.nchannels   = as->nchannels;
    520 
    521     if (pulse_open (/*fIn=*/1, &req, &obt, &pulse->pStream))
     516    pPulse->SampleSpec.format   = aud_to_pulsefmt (as->fmt);
     517    pPulse->SampleSpec.rate     = as->freq;
     518    pPulse->SampleSpec.channels = as->nchannels;
     519
     520    /* XXX check these values */
     521    pPulse->BufAttr.fragsize    = (pa_bytes_per_second(&pPulse->SampleSpec)
     522                                  * conf.buffer_msecs_in) / 2000; /* one tenth */
     523    pPulse->BufAttr.maxlength   = (pa_bytes_per_second(&pPulse->SampleSpec)
     524                                  * conf.buffer_msecs_in) / 1000;
     525    /* Other memebers of pa_buffer_attr are ignored for record streams */
     526
     527    if (pulse_open (1, &pPulse->pStream, &pPulse->SampleSpec, &pPulse->BufAttr))
    522528        return -1;
    523529
    524     if (pulse_to_audfmt (obt.pa_format, &effective_fmt, &endianness))
    525     {
    526         LogRel(("Pulse: Cannot find audio format %d\n", obt.pa_format));
     530    if (pulse_to_audfmt (pPulse->SampleSpec.format, &obt_as.fmt, &obt_as.endianness))
     531    {
     532        LogRel(("Pulse: Cannot find audio format %d\n", pPulse->SampleSpec.format));
    527533        return -1;
    528534    }
    529535
    530     obt_as.freq       = obt.freq;
    531     obt_as.nchannels  = obt.nchannels;
    532     obt_as.fmt        = effective_fmt;
    533     obt_as.endianness = endianness;
    534 
     536    obt_as.freq       = pPulse->SampleSpec.rate;
     537    obt_as.nchannels  = pPulse->SampleSpec.channels;
    535538    audio_pcm_init_info (&hw->info, &obt_as);
    536 
    537     /* pcm_in: reserve twice as the maximum buffer length because of peek()/drop(). */
    538     hw->samples = 2 * (obt.buffer_size >> hw->info.shift);
    539 
    540     /* no buffer for input */
    541     pulse->pPCMBuf = NULL;
     539    hw->samples       = audio_MIN(pPulse->BufAttr.fragsize * 10, pPulse->BufAttr.maxlength)
     540                          >> hw->info.shift;
     541    pPulse->pu8PeekBuf = NULL;
    542542
    543543    return 0;
     
    546546static void pulse_fini_in (HWVoiceIn *hw)
    547547{
    548     PulseVoice *pulse = (PulseVoice *)hw;
    549     if (pulse->pStream)
    550     {
    551         pa_stream_disconnect(pulse->pStream);
    552         pa_stream_unref(pulse->pStream);
    553         pulse->pStream = NULL;
    554     }
    555     if (pulse->pPCMBuf)
    556     {
    557         RTMemFree (pulse->pPCMBuf);
    558         pulse->pPCMBuf = NULL;
     548    PulseVoice *pPulse = (PulseVoice *)hw;
     549
     550    if (pPulse->pStream)
     551    {
     552        pa_threaded_mainloop_lock(g_pMainLoop);
     553        pa_stream_disconnect(pPulse->pStream);
     554        pa_stream_unref(pPulse->pStream);
     555        pa_threaded_mainloop_unlock(g_pMainLoop);
     556        pPulse->pStream = NULL;
    559557    }
    560558}
     
    562560static int pulse_run_in (HWVoiceIn *hw)
    563561{
    564     PulseVoice *pulse = (PulseVoice *) hw;
    565     int    csDead, csDecr = 0, csSamples, csRead, csAvail;
    566     size_t cbAvail;
    567     const void  *pu8Src;
    568     st_sample_t *psDst;
    569 
    570     csDead = hw->samples - audio_pcm_hw_get_live_in (hw);
    571 
    572     if (!csDead)
    573         return 0; /* no buffer available */
    574 
     562    PulseVoice *pPulse = (PulseVoice *) hw;
     563    const int hwshift = hw->info.shift;
     564    int       cFramesRead = 0;    /* total frames which have been read this call */
     565    int       cFramesAvail;       /* total frames available from pulse at start of call */
     566    int       cFramesToRead;      /* the largest amount we want/can get this call */
     567    int       cFramesToPeek;      /* the largest amount we want/can get this peek */
     568
     569    /* We should only call pa_stream_readable_size() once and trust the first value */
    575570    pa_threaded_mainloop_lock(g_pMainLoop);
    576 
    577     if (pa_stream_peek(pulse->pStream, &pu8Src, &cbAvail) < 0)
    578     {
    579         LogRel(("Pulse: Peek failed: %s\n",
    580                 pa_strerror(pa_context_errno(g_pContext))));
    581         goto unlock_and_exit;
    582     }
    583     if (!pu8Src)
    584         goto unlock_and_exit;
    585 
    586     csAvail = cbAvail >> hw->info.shift;
    587     csDecr  = audio_MIN (csDead, csAvail);
    588 
    589     csSamples = csDecr;
    590 
    591     while (csSamples)
    592     {
    593         /* split request at the end of our samples buffer */
    594         psDst      = hw->conv_buf + hw->wpos;
    595         csRead     = audio_MIN (csSamples, hw->samples - hw->wpos);
    596         hw->conv (psDst, pu8Src, csRead, &nominal_volume);
    597         hw->wpos   = (hw->wpos + csRead) % hw->samples;
    598         csSamples -= csRead;
    599         pu8Src     = (const void*)((uint8_t*)pu8Src + (csRead << hw->info.shift));
    600     }
    601 
    602     pa_stream_drop(pulse->pStream);
    603 
    604 unlock_and_exit:
     571    cFramesAvail = pa_stream_readable_size(pPulse->pStream) >> hwshift;
    605572    pa_threaded_mainloop_unlock(g_pMainLoop);
    606573
    607     return csDecr;
     574    /* If the buffer was not dropped last call, add what remains */
     575    if (pPulse->pu8PeekBuf)
     576        cFramesAvail += (pPulse->cbPeekBuf - pPulse->offPeekBuf) >> hwshift;
     577
     578    cFramesToRead = audio_MIN(cFramesAvail, hw->samples - audio_pcm_hw_get_live_in(hw));
     579    for (; cFramesToRead; cFramesToRead -= cFramesToPeek)
     580    {
     581        /* If there is no data, do another peek */
     582        if (!pPulse->pu8PeekBuf)
     583        {
     584            pa_threaded_mainloop_lock(g_pMainLoop);
     585            pa_stream_peek(pPulse->pStream, (const void**)&pPulse->pu8PeekBuf, &pPulse->cbPeekBuf);
     586            pa_threaded_mainloop_unlock(g_pMainLoop);
     587            pPulse->offPeekBuf = 0;
     588            if (!pPulse->cbPeekBuf)
     589                break;
     590        }
     591
     592        cFramesToPeek = audio_MIN((signed)(  pPulse->cbPeekBuf
     593                                           - pPulse->offPeekBuf) >> hwshift,
     594                                  cFramesToRead);
     595
     596        /* Check for wrapping around the buffer end */
     597        if (hw->wpos + cFramesToPeek > hw->samples)
     598        {
     599            int cFramesDelta = hw->samples - hw->wpos;
     600
     601            hw->conv(hw->conv_buf + hw->wpos,
     602                     pPulse->pu8PeekBuf + pPulse->offPeekBuf,
     603                     cFramesDelta,
     604                     &nominal_volume);
     605
     606            hw->conv(hw->conv_buf,
     607                     pPulse->pu8PeekBuf + pPulse->offPeekBuf + (cFramesDelta << hwshift),
     608                     cFramesToPeek - cFramesDelta,
     609                     &nominal_volume);
     610        }
     611        else
     612        {
     613            hw->conv(hw->conv_buf + hw->wpos,
     614                     pPulse->pu8PeekBuf + pPulse->offPeekBuf,
     615                     cFramesToPeek,
     616                     &nominal_volume);
     617        }
     618
     619        cFramesRead += cFramesToPeek;
     620        hw->wpos = (hw->wpos + cFramesToPeek) % hw->samples;
     621        pPulse->offPeekBuf += cFramesToPeek << hwshift;
     622
     623        /* If the buffer is done, drop it */
     624        if (pPulse->offPeekBuf == pPulse->cbPeekBuf)
     625        {
     626            pa_threaded_mainloop_lock(g_pMainLoop);
     627            pa_stream_drop(pPulse->pStream);
     628            pa_threaded_mainloop_unlock(g_pMainLoop);
     629            pPulse->pu8PeekBuf = NULL;
     630        }
     631    }
     632
     633    return cFramesRead;
    608634}
    609635
     
    615641static int pulse_ctl_in (HWVoiceIn *hw, int cmd, ...)
    616642{
     643    PulseVoice *pPulse = (PulseVoice *)hw;
     644
     645    switch (cmd)
     646    {
     647        case VOICE_ENABLE:
     648            pulse_ctrl((PulseVoice *)hw, Unpause);
     649            break;
     650        case VOICE_DISABLE:
     651            if (pPulse->pu8PeekBuf)
     652            {
     653                pa_stream_drop(pPulse->pStream);
     654                pPulse->pu8PeekBuf = NULL;
     655            }
     656            pulse_ctrl((PulseVoice *)hw, Pause);
     657            break;
     658        default:
     659            return -1;
     660    }
    617661    return 0;
    618662}
     
    628672        return NULL;
    629673    }
     674
    630675    if (!(g_pMainLoop = pa_threaded_mainloop_new()))
    631676    {
     
    634679        goto fail;
    635680    }
     681
    636682    if (!(g_pContext = pa_context_new(pa_threaded_mainloop_get_api(g_pMainLoop), "VBox")))
    637683    {
     
    640686        goto fail;
    641687    }
     688
    642689    if (pa_threaded_mainloop_start(g_pMainLoop) < 0)
    643690    {
     
    689736        g_pContext = NULL;
    690737    }
     738
    691739    if (g_pMainLoop)
    692740    {
     
    694742        g_pMainLoop = NULL;
    695743    }
     744
    696745    return NULL;
    697746}
     
    701750    if (g_pMainLoop)
    702751        pa_threaded_mainloop_stop(g_pMainLoop);
     752
    703753    if (g_pContext)
    704754    {
     
    707757        g_pContext = NULL;
    708758    }
     759
    709760    if (g_pMainLoop)
    710761    {
     
    712763        g_pMainLoop = NULL;
    713764    }
     765
    714766    (void) opaque;
    715767}
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