VirtualBox

Changeset 88492 in vbox


Ignore:
Timestamp:
Apr 13, 2021 11:12:25 AM (3 years ago)
Author:
vboxsync
Message:

DrvHostAudioPulseAudio: Cleaning up the stream control bits. The 'disable' orequest now does not drain the buffer, but leaves that to the 'drain' request. bugref:9890

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DrvHostAudioPulseAudio.cpp

    r88487 r88492  
    11201120
    11211121        pa_stream_disconnect(pStreamPA->pStream);
     1122
    11221123        pa_stream_unref(pStreamPA->pStream);
    1123 
    11241124        pStreamPA->pStream = NULL;
    11251125
     
    11391139    PPULSEAUDIOSTREAM pStreamPA = (PPULSEAUDIOSTREAM)pvUser;
    11401140    AssertPtrReturnVoid(pStreamPA);
     1141    LogFlowFunc(("fSuccess=%d\n", fSuccess));
    11411142
    11421143    pStreamPA->fOpSuccess = fSuccess;
     
    11541155
    11551156
    1156 static int drvHostAudioPaStreamControlOut(PDRVHOSTPULSEAUDIO pThis, PPULSEAUDIOSTREAM pStreamPA, PDMAUDIOSTREAMCMD enmStreamCmd)
    1157 {
     1157/**
     1158 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamEnable}
     1159 */
     1160static DECLCALLBACK(int) drvHostAudioPaHA_StreamEnable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     1161{
     1162    PDRVHOSTPULSEAUDIO pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTPULSEAUDIO, IHostAudio);
     1163    PPULSEAUDIOSTREAM  pStreamPA = (PPULSEAUDIOSTREAM)pStream;
     1164    LogFlowFunc(("\n"));
     1165
     1166    pa_threaded_mainloop_lock(pThis->pMainLoop);
     1167
     1168    /* Cancel and dispose of pending drain.  We'll unconditionally uncork
     1169       the stream even if we cancelled a drain, I hope that will work...  */
     1170    if (pStreamPA->pDrainOp)
     1171    {
     1172        pa_operation_state_t const enmOpState = pa_operation_get_state(pStreamPA->pDrainOp);
     1173        if (enmOpState != PA_OPERATION_RUNNING)
     1174        {
     1175            pa_operation_cancel(pStreamPA->pDrainOp);
     1176            LogFlowFunc(("cancelled drain (%d)\n", pa_operation_get_state(pStreamPA->pDrainOp)));
     1177        }
     1178        pa_operation_unref(pStreamPA->pDrainOp);
     1179        pStreamPA->pDrainOp = NULL;
     1180    }
     1181
     1182    /*
     1183     * Uncork (start or resume play/capture) the stream.
     1184     */
     1185/** @todo do this asynchronously as the caller is usually an EMT which cannot
     1186 *        wait on a potentally missing-in-action audio daemon. */
     1187    int rc = drvHostAudioPaWaitFor(pThis, pa_stream_cork(pStreamPA->pStream, 0 /* Uncork */,
     1188                                                         drvHostAudioPaStreamSuccessCallback, pStreamPA));
     1189
     1190    pa_threaded_mainloop_unlock(pThis->pMainLoop);
     1191    LogFlowFunc(("returns %Rrc\n", rc));
     1192    return rc;
     1193}
     1194
     1195
     1196/**
     1197 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable}
     1198 */
     1199static DECLCALLBACK(int) drvHostAudioPaHA_StreamDisable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     1200{
     1201    PDRVHOSTPULSEAUDIO pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTPULSEAUDIO, IHostAudio);
     1202    PPULSEAUDIOSTREAM  pStreamPA = (PPULSEAUDIOSTREAM)pStream;
     1203    LogFlowFunc(("\n"));
     1204
     1205    pa_threaded_mainloop_lock(pThis->pMainLoop);
     1206
     1207    /*
     1208     * Do some direction specific cleanups before we cork the stream.
     1209     */
     1210    bool fCorkIt = true;
     1211    if (pStreamPA->Cfg.enmDir == PDMAUDIODIR_IN)
     1212    {
     1213        /* Input - drop the peek buffer. */
     1214        if (pStreamPA->pu8PeekBuf) /* Do we need to drop the peek buffer?*/
     1215        {
     1216            pa_stream_drop(pStreamPA->pStream);
     1217            pStreamPA->pu8PeekBuf = NULL;
     1218        }
     1219    }
     1220    else
     1221    {
     1222        /* Output - Ignore request if we've got a running drain. */
     1223        fCorkIt = !pStreamPA->pDrainOp
     1224                || pa_operation_get_state(pStreamPA->pDrainOp) != PA_OPERATION_RUNNING;
     1225    }
     1226
     1227    /*
     1228     * Cork (pause) the stream.
     1229     */
    11581230    int rc = VINF_SUCCESS;
    1159 
    1160     switch (enmStreamCmd)
    1161     {
    1162         case PDMAUDIOSTREAMCMD_ENABLE:
    1163         case PDMAUDIOSTREAMCMD_RESUME:
    1164         {
    1165             pa_threaded_mainloop_lock(pThis->pMainLoop);
    1166 
    1167             if (   pStreamPA->pDrainOp
    1168                 && pa_operation_get_state(pStreamPA->pDrainOp) != PA_OPERATION_DONE)
    1169             {
    1170                 pa_operation_cancel(pStreamPA->pDrainOp);
    1171                 pa_operation_unref(pStreamPA->pDrainOp);
    1172 
    1173                 pStreamPA->pDrainOp = NULL;
    1174             }
    1175             else
    1176             {
    1177                 /* Uncork (resume) stream. */
    1178                 rc = drvHostAudioPaWaitFor(pThis, pa_stream_cork(pStreamPA->pStream, 0 /* Uncork */, drvHostAudioPaStreamSuccessCallback, pStreamPA));
    1179             }
    1180 
    1181             pa_threaded_mainloop_unlock(pThis->pMainLoop);
    1182             break;
    1183         }
    1184 
    1185         case PDMAUDIOSTREAMCMD_DISABLE:
    1186         case PDMAUDIOSTREAMCMD_PAUSE:
    1187         {
    1188             /* Pause audio output (the Pause bit of the AC97 x_CR register is set).
    1189              * Note that we must return immediately from here! */
    1190             pa_threaded_mainloop_lock(pThis->pMainLoop);
    1191             if (!pStreamPA->pDrainOp)
    1192             {
    1193                 rc = drvHostAudioPaWaitFor(pThis, pa_stream_trigger(pStreamPA->pStream, drvHostAudioPaStreamSuccessCallback, pStreamPA));
    1194                 if (RT_SUCCESS(rc))
    1195                     pStreamPA->pDrainOp = pa_stream_drain(pStreamPA->pStream, drvHostAudioPaStreamDrainCompletionCallback, pStreamPA);
    1196             }
    1197             pa_threaded_mainloop_unlock(pThis->pMainLoop);
    1198             break;
    1199         }
    1200 
    1201         default:
    1202             rc = VERR_NOT_SUPPORTED;
    1203             break;
    1204     }
    1205 
    1206     LogFlowFuncLeaveRC(rc);
     1231    if (fCorkIt)
     1232    {
     1233        LogFlowFunc(("Corking '%s'...\n", pStreamPA->Cfg.szName));
     1234/** @todo do this asynchronously as the caller is usually an EMT which cannot
     1235 *        wait on a potentally missing-in-action audio daemon. */
     1236        rc = drvHostAudioPaWaitFor(pThis, pa_stream_cork(pStreamPA->pStream, 1 /* cork it */,
     1237                                                         drvHostAudioPaStreamSuccessCallback, pStreamPA));
     1238    }
     1239    else
     1240        LogFlowFunc(("Stream '%s' is already draining, skipping corking.\n", pStreamPA->Cfg.szName));
     1241
     1242    pa_threaded_mainloop_unlock(pThis->pMainLoop);
     1243    LogFlowFunc(("returns %Rrc\n", rc));
    12071244    return rc;
    12081245}
    12091246
    12101247
    1211 static int drvHostAudioPaStreamControlIn(PDRVHOSTPULSEAUDIO pThis, PPULSEAUDIOSTREAM pStreamPA, PDMAUDIOSTREAMCMD enmStreamCmd)
    1212 {
     1248/**
     1249 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamPause}
     1250 */
     1251static DECLCALLBACK(int) drvHostAudioPaHA_StreamPause(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     1252{
     1253    /* Same as disable. */
     1254    return drvHostAudioPaHA_StreamDisable(pInterface, pStream);
     1255}
     1256
     1257
     1258/**
     1259 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamResume}
     1260 */
     1261static DECLCALLBACK(int) drvHostAudioPaHA_StreamResume(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     1262{
     1263    /* Same as enable. */
     1264    return drvHostAudioPaHA_StreamEnable(pInterface, pStream);
     1265}
     1266
     1267
     1268/**
     1269 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamDrain}
     1270 */
     1271static DECLCALLBACK(int) drvHostAudioPaHA_StreamDrain(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
     1272{
     1273    PDRVHOSTPULSEAUDIO pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTPULSEAUDIO, IHostAudio);
     1274    PPULSEAUDIOSTREAM  pStreamPA = (PPULSEAUDIOSTREAM)pStream;
     1275    AssertReturn(pStreamPA->Cfg.enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
     1276    LogFlowFunc(("\n"));
     1277
     1278    pa_threaded_mainloop_lock(pThis->pMainLoop);
     1279
     1280    /*
     1281     * We must make sure any pre-buffered stuff is played before we drain
     1282     * the stream.  Also, there might already be a drain request around,
     1283     * in case we're called multiple times.  Re-issue the drain if the old
     1284     * one has completed just to be sure.
     1285     */
    12131286    int rc = VINF_SUCCESS;
    1214 
    1215     LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
    1216 
    1217     switch (enmStreamCmd)
    1218     {
    1219         case PDMAUDIOSTREAMCMD_ENABLE:
    1220         case PDMAUDIOSTREAMCMD_RESUME:
    1221         {
    1222             pa_threaded_mainloop_lock(pThis->pMainLoop);
    1223             rc = drvHostAudioPaWaitFor(pThis, pa_stream_cork(pStreamPA->pStream, 0 /* Play / resume */, drvHostAudioPaStreamSuccessCallback, pStreamPA));
    1224             pa_threaded_mainloop_unlock(pThis->pMainLoop);
    1225             break;
    1226         }
    1227 
    1228         case PDMAUDIOSTREAMCMD_DISABLE:
    1229         case PDMAUDIOSTREAMCMD_PAUSE:
    1230         {
    1231             pa_threaded_mainloop_lock(pThis->pMainLoop);
    1232             if (pStreamPA->pu8PeekBuf) /* Do we need to drop the peek buffer?*/
    1233             {
    1234                 pa_stream_drop(pStreamPA->pStream);
    1235                 pStreamPA->pu8PeekBuf = NULL;
    1236             }
    1237 
    1238             rc = drvHostAudioPaWaitFor(pThis, pa_stream_cork(pStreamPA->pStream, 1 /* Stop / pause */, drvHostAudioPaStreamSuccessCallback, pStreamPA));
    1239             pa_threaded_mainloop_unlock(pThis->pMainLoop);
    1240             break;
    1241         }
    1242 
    1243         default:
    1244             rc = VERR_NOT_SUPPORTED;
    1245             break;
    1246     }
    1247 
     1287    if (!pStreamPA->pDrainOp)
     1288    {
     1289        LogFlowFunc(("pa_stream_trigger...\n"));
     1290        rc = drvHostAudioPaWaitFor(pThis, pa_stream_trigger(pStreamPA->pStream,
     1291                                                            drvHostAudioPaStreamSuccessCallback, pStreamPA));
     1292    }
     1293    else if (   pStreamPA->pDrainOp
     1294             && pa_operation_get_state(pStreamPA->pDrainOp) != PA_OPERATION_RUNNING)
     1295    {
     1296        pa_operation_unref(pStreamPA->pDrainOp);
     1297        pStreamPA->pDrainOp = NULL;
     1298    }
     1299
     1300    if (!pStreamPA->pDrainOp && RT_SUCCESS(rc))
     1301    {
     1302        pStreamPA->pDrainOp = pa_stream_drain(pStreamPA->pStream, drvHostAudioPaStreamDrainCompletionCallback, pStreamPA);
     1303        if (pStreamPA->pDrainOp)
     1304            LogFlowFunc(("Started drain operation %p of %s\n", pStreamPA->pDrainOp, pStreamPA->Cfg.szName));
     1305        else
     1306            LogFunc(("pa_stream_drain failed on '%s': %s (%d)\n", pStreamPA->Cfg.szName,
     1307                     pa_strerror(pa_context_errno(pThis->pContext)), pa_context_errno(pThis->pContext) ));
     1308    }
     1309    else if (RT_SUCCESS(rc))
     1310        LogFlowFunc(("Already draining (%p) ...\n", pStreamPA->pDrainOp));
     1311    else
     1312        LogFunc(("pa_stream_trigger + wait failed: %Rrc\n", rc));
     1313
     1314    pa_threaded_mainloop_unlock(pThis->pMainLoop);
     1315    LogFlowFunc(("returns %Rrc\n", rc));
    12481316    return rc;
    12491317}
     
    12561324                                                        PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
    12571325{
    1258     PDRVHOSTPULSEAUDIO pThis     = RT_FROM_MEMBER(pInterface, DRVHOSTPULSEAUDIO, IHostAudio);
    1259     PPULSEAUDIOSTREAM  pStreamPA = (PPULSEAUDIOSTREAM)pStream;
    1260     AssertPtrReturn(pStreamPA, VERR_INVALID_POINTER);
    1261 
    1262     int rc;
    1263     if (pStreamPA->Cfg.enmDir == PDMAUDIODIR_IN)
    1264         rc = drvHostAudioPaStreamControlIn (pThis, pStreamPA, enmStreamCmd);
    1265     else if (pStreamPA->Cfg.enmDir == PDMAUDIODIR_OUT)
    1266         rc = drvHostAudioPaStreamControlOut(pThis, pStreamPA, enmStreamCmd);
    1267     else
    1268         AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
    1269 
    1270     return rc;
     1326    /** @todo r=bird: I'd like to get rid of this pfnStreamControl method,
     1327     *        replacing it with individual StreamXxxx methods.  That would save us
     1328     *        potentally huge switches and more easily see which drivers implement
     1329     *        which operations (grep for pfnStreamXxxx). */
     1330    switch (enmStreamCmd)
     1331    {
     1332        case PDMAUDIOSTREAMCMD_ENABLE:
     1333            return drvHostAudioPaHA_StreamEnable(pInterface, pStream);
     1334        case PDMAUDIOSTREAMCMD_DISABLE:
     1335            return drvHostAudioPaHA_StreamDisable(pInterface, pStream);
     1336        case PDMAUDIOSTREAMCMD_PAUSE:
     1337            return drvHostAudioPaHA_StreamPause(pInterface, pStream);
     1338        case PDMAUDIOSTREAMCMD_RESUME:
     1339            return drvHostAudioPaHA_StreamResume(pInterface, pStream);
     1340        case PDMAUDIOSTREAMCMD_DRAIN:
     1341            return drvHostAudioPaHA_StreamDrain(pInterface, pStream);
     1342
     1343        case PDMAUDIOSTREAMCMD_END:
     1344        case PDMAUDIOSTREAMCMD_32BIT_HACK:
     1345        case PDMAUDIOSTREAMCMD_INVALID:
     1346            /* no default*/
     1347            break;
     1348    }
     1349    return VERR_NOT_SUPPORTED;
    12711350}
    12721351
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