VirtualBox

Changeset 34969 in vbox


Ignore:
Timestamp:
Dec 10, 2010 7:08:32 PM (14 years ago)
Author:
vboxsync
Message:

Audio filter: fixed dynamic switch between host and remote audio input.

Location:
trunk/src/VBox
Files:
2 edited

Legend:

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

    r34910 r34969  
    257257     * or the device itself is changed during the runtime. */
    258258    volatile uint32_t status;
     259
     260    /* the stream has been successfully initialized by host. */
     261    bool fHostOK;
    259262
    260263    /* Whether the input stream is used by the filter. */
     
    508511 ******************************************************************************/
    509512
    510 /* We need some forward declarations */
    511 static int filteraudio_run_in(HWVoiceIn *hw);
    512 static int filteraudio_read(SWVoiceIn *sw, void *buf, int size);
    513 static int filteraudio_ctl_in(HWVoiceIn *hw, int cmd, ...);
    514 static void filteraudio_fini_in(HWVoiceIn *hw);
    515 static int filteraudio_init_in(HWVoiceIn *hw, audsettings_t *as);
    516 
    517513/*
    518514 * Callback to feed audio input buffer. Samples format is be the same as
    519  * in the voice. The caller prepares stsample_t.
     515 * in the voice. The caller prepares st_sample_t.
    520516 *
    521517 * @param cbSamples Size of pvSamples array in bytes.
     
    595591    char *pcSrc;
    596592    st_sample_t *psDst;
    597 
    598     filterVoiceIn *pVoice = (filterVoiceIn *)((uint8_t *)phw + filter_conf.pDrv->voice_size_in);
     593    filterVoiceIn *pVoice;
     594
     595    if (!filter_conf.pDrv)
     596    {
     597        AssertFailed();
     598        return -1;
     599    }
     600
     601    pVoice = (filterVoiceIn *)((uint8_t *)phw + filter_conf.pDrv->voice_size_in);
    599602
    600603    if (!pVoice->fIntercepted)
     
    662665{
    663666    int rc = VINF_SUCCESS;
    664 
    665     filterVoiceIn *pVoice = (filterVoiceIn *)((uint8_t *)phw + filter_conf.pDrv->voice_size_in);
    666 
    667     if (!pVoice->fIntercepted)
    668     {
    669         /* Note: audio.c does not use variable parameters '...', so ok to forward only 'phw' and 'cmd'. */
    670         Log(("FilterAudio: [Input]: forwarding ctl_in for voice %p (hw %p)\n", pVoice, pVoice->phw));
    671         return filter_conf.pDrv->pcm_ops->ctl_in(phw, cmd);
    672     }
    673 
    674     Log(("FilterAudio: [Input]: ctl_in for voice %p (hw %p), cmd %d\n", pVoice, pVoice->phw, cmd));
    675 
    676     if (ASMAtomicReadU32(&pVoice->status) != CA_STATUS_INIT)
    677         return 0;
    678 
    679     switch (cmd)
    680     {
    681         case VOICE_ENABLE:
     667    filterVoiceIn *pVoice;
     668
     669    if (!filter_conf.pDrv)
     670    {
     671        AssertFailed();
     672        return -1;
     673    }
     674
     675    pVoice = (filterVoiceIn *)((uint8_t *)phw + filter_conf.pDrv->voice_size_in);
     676
     677    if (cmd == VOICE_ENABLE)
     678    {
     679        /* Decide who will provide input audio: filter or host driver. */
     680        if (!filter_input_intercepted())
    682681        {
    683             /* Only start the device if it is actually stopped */
    684             if (!pVoice->fIsRunning)
     682            if (!pVoice->fHostOK)
    685683            {
    686                 IORingBufferReset(pVoice->pBuf);
    687 
    688                 /* Sniffer will inform us on a second thread for new incoming audio data.
    689                  * Therefore register an callback function, which will process the new data.
    690                  * */
    691                 rc = filter_input_begin(&pVoice->pvInputCtx, fltRecordingCallback, pVoice, pVoice->phw, pVoice->phw->samples);
    692                 if (RT_SUCCESS(rc))
    693                 {
    694                     pVoice->fIsRunning = true;
    695                 }
    696             }
    697             if (RT_FAILURE(rc))
    698             {
    699                 LogRel(("FilterAudio: [Input] Failed to start recording (%Rrc)\n", rc));
     684                /* Host did not initialize the voice. */
     685                Log(("FilterAudio: [Input]: ctl_in ENABLE voice %p (hw %p) not available on host\n", pVoice, pVoice->phw));
    700686                return -1;
    701687            }
    702             break;
     688
     689            /* Note: audio.c does not use variable parameters '...', so ok to forward only 'phw' and 'cmd'. */
     690            Log(("FilterAudio: [Input]: forwarding ctl_in ENABLE for voice %p (hw %p)\n", pVoice, pVoice->phw));
     691            return filter_conf.pDrv->pcm_ops->ctl_in(phw, cmd);
    703692        }
    704         case VOICE_DISABLE:
     693
     694        /* The filter will use this voice. */
     695        Log(("FilterAudio: [Input]: ctl_in ENABLE for voice %p (hw %p), cmd %d\n", pVoice, pVoice->phw, cmd));
     696
     697        if (ASMAtomicReadU32(&pVoice->status) != CA_STATUS_INIT)
     698            return -1;
     699
     700        /* Only start the device if it is actually stopped */
     701        if (!pVoice->fIsRunning)
    705702        {
    706             /* Only stop the device if it is actually running */
    707             if (pVoice->fIsRunning)
     703            IORingBufferReset(pVoice->pBuf);
     704
     705            /* Sniffer will inform us on a second thread for new incoming audio data.
     706             * Therefore register an callback function, which will process the new data.
     707             * */
     708            rc = filter_input_begin(&pVoice->pvInputCtx, fltRecordingCallback, pVoice, pVoice->phw, pVoice->phw->samples);
     709            if (RT_SUCCESS(rc))
    708710            {
    709                 pVoice->fIsRunning = false;
    710                 /* Tell the sniffer to not to use this context anymore. */
    711                 filter_input_end(pVoice->pvInputCtx);
     711                pVoice->fIsRunning = true;
     712
     713                /* Remember that this voice is used by the filter. */
     714                pVoice->fIntercepted = true;
    712715            }
    713             break;
    714716        }
    715     }
     717        if (RT_FAILURE(rc))
     718        {
     719            LogRel(("FilterAudio: [Input] Failed to start recording (%Rrc)\n", rc));
     720            return -1;
     721        }
     722    }
     723    else if (cmd == VOICE_DISABLE)
     724    {
     725        if (ASMAtomicReadU32(&pVoice->status) != CA_STATUS_INIT)
     726            return -1;
     727
     728        /* Check if the voice has been intercepted. */
     729        if (!pVoice->fIntercepted)
     730        {
     731            /* Note: audio.c does not use variable parameters '...', so ok to forward only 'phw' and 'cmd'. */
     732            Log(("FilterAudio: [Input]: forwarding ctl_in DISABLE for voice %p (hw %p)\n", pVoice, pVoice->phw));
     733            return filter_conf.pDrv->pcm_ops->ctl_in(phw, cmd);
     734        }
     735
     736        /* The filter used this voice. */
     737        Log(("FilterAudio: [Input]: ctl_in DISABLE for voice %p (hw %p), cmd %d\n", pVoice, pVoice->phw, cmd));
     738
     739        /* Only stop the device if it is actually running */
     740        if (pVoice->fIsRunning)
     741        {
     742            pVoice->fIsRunning = false;
     743            /* Tell the sniffer to not to use this context anymore. */
     744            filter_input_end(pVoice->pvInputCtx);
     745        }
     746
     747        /* This voice is no longer used by the filter. */
     748        pVoice->fIntercepted = false;
     749    }
     750    else
     751    {
     752        return -1; /* Unknown command. */
     753    }
     754
    716755    return 0;
    717756}
     
    720759{
    721760    int ret = -1;
    722 
    723     filterVoiceIn *pVoice = (filterVoiceIn *)((uint8_t *)phw + filter_conf.pDrv->voice_size_in);
    724 
    725     /* Only pass voices, which are not intercepted. */
    726     if (!pVoice->fIntercepted)
    727     {
    728         Log(("FilterAudio: [Input]: forwarding fini_in for voice %p (hw %p)\n", pVoice, pVoice->phw));
    729         filter_conf.pDrv->pcm_ops->fini_in(phw);
     761    filterVoiceIn *pVoice;
     762
     763    if (!filter_conf.pDrv)
     764    {
     765        AssertFailed();
    730766        return;
    731767    }
     768
     769    pVoice = (filterVoiceIn *)((uint8_t *)phw + filter_conf.pDrv->voice_size_in);
     770
     771    /* Uninitialize both host and filter parts of the voice. */
     772    Log(("FilterAudio: [Input]: forwarding fini_in for voice %p (hw %p)\n", pVoice, pVoice->phw));
     773    filter_conf.pDrv->pcm_ops->fini_in(phw);
    732774
    733775    Log(("FilterAudio: [Input]: fini_in for voice %p (hw %p)\n", pVoice, pVoice->phw));
     
    736778        return;
    737779
    738     ret = filteraudio_ctl_in(phw, VOICE_DISABLE);
     780    /* If this voice is intercepted by filter, try to stop it. */
     781    if (pVoice->fIntercepted)
     782    {
     783        ret = filteraudio_ctl_in(phw, VOICE_DISABLE);
     784    }
     785    else
     786    {
     787        ret = 0;
     788    }
     789
    739790    if (RT_LIKELY(ret == 0))
    740791    {
     
    751802static int filteraudio_init_in(HWVoiceIn *phw, audsettings_t *as)
    752803{
    753     filterVoiceIn *pVoice = (filterVoiceIn *)((uint8_t *)phw + filter_conf.pDrv->voice_size_in);
    754 
    755     if (!filter_input_intercepted())
    756     {
    757         Log(("FilterAudio: [Input]: forwarding init_in for voice %p (hw %p)\n", pVoice, pVoice->phw));
    758         pVoice->fIntercepted = false;
    759         return filter_conf.pDrv->pcm_ops->init_in(phw, as);
    760     }
    761 
    762     Log(("FilterAudio: [Input]: init_in for voice %p (hw %p)\n", pVoice, pVoice->phw));
     804    int hostret = -1;
     805    filterVoiceIn *pVoice;
     806
     807    if (!filter_conf.pDrv)
     808    {
     809        AssertFailed();
     810        return -1;
     811    }
     812
     813    pVoice = (filterVoiceIn *)((uint8_t *)phw + filter_conf.pDrv->voice_size_in);
     814
     815    /* Initialize both host and filter parts of the voice. */
     816    Log(("FilterAudio: [Input]: forwarding init_in for voice %p (hw %p)\n", pVoice, pVoice->phw));
     817    hostret = filter_conf.pDrv->pcm_ops->init_in(phw, as);
     818
     819    Log(("FilterAudio: [Input]: init_in for voice %p (hw %p), hostret = %d\n", pVoice, pVoice->phw, hostret));
    763820
    764821    ASMAtomicWriteU32(&pVoice->status, CA_STATUS_UNINIT);
     
    767824    pVoice->rpos = 0;
    768825    pVoice->pBuf = NULL;
    769     /* Remember that this voice belongs to the filter. */
    770     pVoice->fIntercepted = true;
     826    pVoice->fHostOK = (hostret == 0);
     827    pVoice->fIntercepted = false;
    771828    pVoice->fIsRunning = false;
    772829    pVoice->pvInputCtx = NULL;
    773830
    774     /* The ring buffer must be big enough to hold specified number of samples.
    775      * A sample includes all channels.
    776      */
    777     pVoice->phw->samples = 2048;
    778 
    779     /* Initialize the hardware info section with the audio settings */
    780     audio_pcm_init_info(&pVoice->phw->info, as);
     831    if (!pVoice->fHostOK)
     832    {
     833        /* Initialize required fields of the common part of the voice. */
     834        pVoice->phw->samples = 2048;
     835
     836        /* Initialize the hardware info section with the audio settings */
     837        audio_pcm_init_info(&pVoice->phw->info, as);
     838    }
    781839
    782840    ASMAtomicWriteU32(&pVoice->status, CA_STATUS_IN_INIT);
     
    794852
    795853    Log(("FilterAudio: [Input] HW samples: %d\n", pVoice->phw->samples));
    796 
    797854    return 0;
    798855}
     
    806863static void *filteraudio_audio_init(void)
    807864{
    808     return &filter_conf;
     865    /* This is not supposed to be called. */
     866    Log(("FilterAudio: Init\n"));
     867    AssertFailed();
     868    return NULL;
    809869}
    810870
    811871static void filteraudio_audio_fini(void *opaque)
    812872{
    813     NOREF(opaque);
     873    Log(("FilterAudio: Init fini %p\n", opaque));
     874    /* Forward to the host driver. */
     875    Assert(opaque == filter_conf.pDrvOpaque);
     876    if (filter_conf.pDrv)
     877    {
     878        filter_conf.pDrv->fini(opaque);
     879        filter_conf.pDrv = NULL;
     880    }
    814881}
    815882
  • trunk/src/VBox/Main/ConsoleVRDPServer.cpp

    r34959 r34969  
    863863        if (pPort)
    864864        {
    865              // @todo dynamic filter attach does not yet work pPort->pfnAudioInputIntercept(pPort, false);
     865             pPort->pfnAudioInputIntercept(pPort, false);
    866866        }
    867867        else
     
    920920                if (pPort)
    921921                {
    922                      // @todo dynamic filter attach does not yet work pPort->pfnAudioInputIntercept(pPort, true);
     922                     pPort->pfnAudioInputIntercept(pPort, true);
    923923                     if (ppvIntercept)
    924924                     {
     
    22692269                                            audioFormat,
    22702270                                            cSamples);
    2271             *ppvUserCtx = NULL; /* This is the ConsoleVRDP server context.
     2271            *ppvUserCtx = NULL; /* This is the ConsoleVRDPServer context.
    22722272                                 * Currently not used because only one client is allowed to
    22732273                                 * do audio input and the client id is saved by the ConsoleVRDPServer.
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