VirtualBox

Changeset 34906 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Dec 9, 2010 4:29:49 PM (14 years ago)
Author:
vboxsync
Message:

Initial audio filter implementation, which is used for audio input via remote desktop server.

Location:
trunk/src/VBox
Files:
8 edited

Legend:

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

    r33400 r34906  
    15511551
    15521552    if (s->drv_opaque) {
     1553        /* Filter must be installed before initializing voices. */
     1554        drv = filteraudio_install(drv, s->drv_opaque);
    15531555        audio_init_nb_voices_out (s, drv);
    15541556        audio_init_nb_voices_in (s, drv);
  • trunk/src/VBox/Devices/Audio/audio_int.h

    r12977 r34906  
    314314                                    unsigned cSamples);
    315315
     316/*
     317 * Filter interface.
     318 */
     319typedef DECLCALLBACK(int) FNAUDIOINPUTCALLBACK(void* pvCtx, uint32_t cbSamples, const void *pvSamples);
     320typedef FNAUDIOINPUTCALLBACK *PFNAUDIOINPUTCALLBACK;
     321
     322int filter_output_intercepted(void);
     323int filter_output_begin(void **ppvOutputCtx, struct audio_pcm_info *pinfo, int samples);
     324void filter_output_end(void *pvOutputCtx);
     325
     326int filter_input_intercepted(void);
     327int filter_input_begin(void **ppvInputCtx, PFNAUDIOINPUTCALLBACK pfnCallback, void *pvCallback, HWVoiceIn *phw, int samples);
     328void filter_input_end(void *pvInputCtx);
     329
     330struct audio_driver *filteraudio_install(struct audio_driver *pDrv, void *pDrvOpaque);
     331
    316332#endif /* audio_int.h */
  • trunk/src/VBox/Devices/Audio/audiosniffer.c

    r32339 r34906  
    55
    66/*
    7  * Copyright (C) 2006-2007 Oracle Corporation
     7 * Copyright (C) 2006-2010 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2222
    2323#include <VBox/log.h>
     24#include <iprt/asm.h>
    2425#include <iprt/assert.h>
    2526#include <iprt/uuid.h>
     
    4041    /** Whether audio should reach the host driver too. */
    4142    bool fKeepHostAudio;
     43
     44    /** Whether audio input operations should be forwarded to the connector. */
     45    bool fInterceptAudioInput;
    4246
    4347    /** Pointer to device instance. */
     
    100104
    101105/*
    102  * Audio Sniffer PDM device.
    103  */
     106 * Filter interface.
     107 */
     108
     109/* Internal audio input context, which makes sure that:
     110 *   - the filter audio input callback is not called after the filter has issued filter_input_end;
     111 *   - maintains internal information and state of the audio stream.
     112 */
     113typedef struct SnifferInputCtx
     114{
     115    /* Whether the context is still in use by the filter or I'll check. */
     116    int32_t volatile cRefs;
     117
     118    /* The filter callback for incoming audio data. */
     119    PFNAUDIOINPUTCALLBACK pfnFilterCallback;
     120    void *pvFilterCallback;
     121
     122    /* Whether the stream has been ended by the filter. */
     123    bool fEndedByFilter;
     124
     125    /* Context pointer returned by pfnAudioInputBegin. */
     126    void *pvUserCtx;
     127
     128    /* Audio format used for recording. */
     129    HWVoiceIn *phw;
     130
     131    /* Number of bytes per frame (bitsPerSample * channels) of the actual input format. */
     132    uint32_t cBytesPerFrame;
     133
     134    /* Frequency of the actual audio format. */
     135    int iFreq;
     136
     137    /* Convertion from the actual input format to st_sample_t. */
     138    t_sample *conv;
     139
     140    /* If the actual format frequence differs from the requested format, this is not NULL. */
     141    void *rate;
     142
     143} SnifferInputCtx;
     144
     145/*
     146 * Filter audio output.
     147 */
     148
     149/* Whether the filter should intercept audio output. */
     150int filter_output_intercepted(void)
     151{
     152    return 0; /* @todo Not implemented yet.*/
     153}
     154
     155/* Filter informs that an audio output is starting. */
     156int filter_output_begin(void **ppvOutputCtx, struct audio_pcm_info *pinfo, int samples)
     157{
     158    return VERR_NOT_SUPPORTED; /* @todo Not implemented yet.*/
     159}
     160
     161/* Filter informs that the audio output has been stopped. */
     162void filter_output_end(void *pvOutputCtx)
     163{
     164    return; /* @todo Not implemented yet.*/
     165}
     166
     167/*
     168 * Filter audio input.
     169 */
     170
     171/* Whether the filter should intercept audio input. */
     172int filter_input_intercepted(void)
     173{
     174    if (!g_pData || !g_pData->pDrv)
     175    {
     176        return 0;
     177    }
     178
     179    return g_pData->fInterceptAudioInput;
     180}
     181
     182/* Filter informs that an audio input is starting. */
     183int filter_input_begin (void **ppvInputCtx, PFNAUDIOINPUTCALLBACK pfnCallback, void *pvCallback, HWVoiceIn *phw, int cSamples)
     184{
     185    int rc = VINF_SUCCESS;
     186
     187    SnifferInputCtx *pCtx = NULL;
     188
     189    if (!g_pData || !g_pData->pDrv)
     190    {
     191        return VERR_NOT_SUPPORTED;
     192    }
     193
     194    pCtx = (SnifferInputCtx *)RTMemAlloc(sizeof(SnifferInputCtx));
     195
     196    if (!pCtx)
     197    {
     198        return VERR_NO_MEMORY;
     199    }
     200
     201    pCtx->cRefs = 2; /* Context is used by both the filter and the user. */
     202    pCtx->pfnFilterCallback = pfnCallback;
     203    pCtx->pvFilterCallback = pvCallback;
     204    pCtx->fEndedByFilter = false;
     205    pCtx->pvUserCtx = NULL;
     206    pCtx->phw = phw;
     207    pCtx->cBytesPerFrame = 1;
     208    pCtx->iFreq = 0;
     209    pCtx->conv = NULL;
     210    pCtx->rate = NULL;
     211
     212    rc = g_pData->pDrv->pfnAudioInputBegin (g_pData->pDrv,
     213                                            &pCtx->pvUserCtx,      /* Returned by the pDrv. */
     214                                            pCtx,
     215                                            cSamples,              /* How many samples in one block is preferred. */
     216                                            phw->info.freq,        /* Required frequency. */
     217                                            phw->info.nchannels,   /* Number of audio channels. */
     218                                            phw->info.bits);       /* A sample size in one channel, samples are signed. */
     219
     220    if (RT_SUCCESS(rc))
     221    {
     222        *ppvInputCtx = pCtx;
     223    }
     224    else
     225    {
     226        RTMemFree(pCtx);
     227    }
     228
     229    Log(("input_begin rc = %Rrc\n", rc));
     230
     231    return rc;
     232}
     233
     234/* Filter informs that the audio input must be stopped. */
     235void filter_input_end(void *pvCtx)
     236{
     237    int32_t c;
     238
     239    SnifferInputCtx *pCtx = (SnifferInputCtx *)pvCtx;
     240
     241    void *pvUserCtx = pCtx->pvUserCtx;
     242
     243    pCtx->fEndedByFilter = true;
     244
     245    c = ASMAtomicDecU32(&pCtx->cRefs);
     246
     247    if (c == 0)
     248    {
     249        /* The caller will not use this context anymore. */
     250        if (pCtx->rate)
     251        {
     252            st_rate_stop (pCtx->rate);
     253        }
     254        RTMemFree(pCtx);
     255        pCtx = NULL;
     256    }
     257
     258    if (!g_pData || !g_pData->pDrv)
     259    {
     260        AssertFailed();
     261        return;
     262    }
     263
     264    g_pData->pDrv->pfnAudioInputEnd (g_pData->pDrv,
     265                                     pvUserCtx);
     266
     267    Log(("input_end\n"));
     268}
     269
     270
     271/*
     272 * Audio PDM device.
     273 */
     274static DECLCALLBACK(int) iface_AudioInputIntercept (PPDMIAUDIOSNIFFERPORT pInterface, bool fIntercept)
     275{
     276    AUDIOSNIFFERSTATE *pThis = RT_FROM_MEMBER(pInterface, AUDIOSNIFFERSTATE, IPort);
     277
     278    Assert(g_pData == pThis);
     279
     280    pThis->fInterceptAudioInput = fIntercept;
     281
     282    return VINF_SUCCESS;
     283}
     284
     285static DECLCALLBACK(int) iface_AudioInputEventBegin (PPDMIAUDIOSNIFFERPORT pInterface,
     286                                                     void *pvContext,
     287                                                     int iSampleHz,
     288                                                     int cChannels,
     289                                                     int cBits,
     290                                                     bool fUnsigned)
     291{
     292    int bitIdx;
     293
     294    AUDIOSNIFFERSTATE *pThis = RT_FROM_MEMBER(pInterface, AUDIOSNIFFERSTATE, IPort);
     295
     296    int rc = VINF_SUCCESS;
     297
     298    SnifferInputCtx *pCtx = (SnifferInputCtx *)pvContext;
     299
     300    Log(("FilterAudio: AudioInputEventBegin: %dHz,%dch,%dbits,%d ended %d\n",
     301         iSampleHz, cChannels, cBits, fUnsigned, pCtx->fEndedByFilter));
     302
     303    Assert(g_pData == pThis);
     304
     305    /* Prepare a format convertion for the actually used format. */
     306    pCtx->cBytesPerFrame = ((cBits + 7) / 8) * cChannels;
     307
     308    if (cBits == 16)
     309    {
     310        bitIdx = 1;
     311    }
     312    else if (cBits == 32)
     313    {
     314        bitIdx = 2;
     315    }
     316    else
     317    {
     318        bitIdx = 0;
     319    }
     320
     321    pCtx->conv = mixeng_conv[(cChannels == 2)? 1: 0] /* stereo */
     322                            [!fUnsigned]             /* sign */
     323                            [0]                      /* big endian */
     324                            [bitIdx];                /* bits */
     325
     326    if (iSampleHz && iSampleHz != pCtx->phw->info.freq)
     327    {
     328        pCtx->rate = st_rate_start (iSampleHz, pCtx->phw->info.freq);
     329        pCtx->iFreq = iSampleHz;
     330    }
     331
     332    return rc;
     333}
     334
     335static DECLCALLBACK(int) iface_AudioInputEventData (PPDMIAUDIOSNIFFERPORT pInterface,
     336                                                    void *pvContext,
     337                                                    const void *pvData,
     338                                                    uint32_t cbData)
     339{
     340    AUDIOSNIFFERSTATE *pThis = RT_FROM_MEMBER(pInterface, AUDIOSNIFFERSTATE, IPort);
     341
     342    int rc = VINF_SUCCESS;
     343
     344    SnifferInputCtx *pCtx = (SnifferInputCtx *)pvContext;
     345
     346    Log(("FilterAudio: AudioInputEventData: pvData %p. cbData %d, ended %d\n", pvData, cbData, pCtx->fEndedByFilter));
     347
     348    Assert(g_pData == pThis);
     349
     350    if (   !pCtx->fEndedByFilter
     351        && pCtx->conv)
     352    {
     353        /* Convert PCM samples to st_sample_t.
     354         * And then apply rate convertion if necessary.
     355         */
     356        /* @todo Optimization: allocate ps buffer once per context and reallocate if cbData changes. */
     357        uint32_t cs = cbData / pCtx->cBytesPerFrame;
     358        st_sample_t *ps = (st_sample_t *)RTMemAlloc(cs * sizeof(st_sample_t));
     359        if (ps)
     360        {
     361            void *pvSamplesRateDst = NULL;
     362
     363            void *pvSamples = NULL;
     364            uint32_t cbSamples = 0;
     365
     366            pCtx->conv(ps, pvData, cs, &nominal_volume);
     367
     368            if (pCtx->rate)
     369            {
     370                uint32_t csConverted = (cs * pCtx->phw->info.freq) / pCtx->iFreq;
     371                pvSamplesRateDst = RTMemAlloc(csConverted * sizeof(st_sample_t));
     372
     373                if (pvSamplesRateDst)
     374                {
     375                    int csSrc = cs;
     376                    int csDst = csConverted;
     377
     378                    st_rate_flow (pCtx->rate,
     379                                  ps, (st_sample_t *)pvSamplesRateDst,
     380                                  &csSrc, &csDst);
     381
     382                    pvSamples = pvSamplesRateDst;
     383                    cbSamples = csDst * sizeof(st_sample_t);
     384                }
     385                else
     386                {
     387                    rc = VERR_NO_MEMORY;
     388                }
     389            }
     390            else
     391            {
     392                pvSamples = ps;
     393                cbSamples = cs * sizeof(st_sample_t);
     394            }
     395
     396            if (cbSamples)
     397            {
     398                rc = pCtx->pfnFilterCallback(pCtx->pvFilterCallback, cbSamples, pvSamples);
     399            }
     400
     401            RTMemFree(pvSamplesRateDst);
     402            RTMemFree(ps);
     403        }
     404        else
     405        {
     406            rc = VERR_NO_MEMORY;
     407        }
     408    }
     409
     410    return rc;
     411}
     412
     413static DECLCALLBACK(void) iface_AudioInputEventEnd (PPDMIAUDIOSNIFFERPORT pInterface,
     414                                                    void *pvContext)
     415{
     416    int32_t c;
     417
     418    AUDIOSNIFFERSTATE *pThis = RT_FROM_MEMBER(pInterface, AUDIOSNIFFERSTATE, IPort);
     419
     420    SnifferInputCtx *pCtx = (SnifferInputCtx *)pvContext;
     421
     422    Log(("FilterAudio: AudioInputEventEnd: ended %d\n", pCtx->fEndedByFilter));
     423
     424    Assert(g_pData == pThis);
     425
     426    c = ASMAtomicDecU32(&pCtx->cRefs);
     427
     428    if (c == 0)
     429    {
     430        /* The caller will not use this context anymore. */
     431        if (pCtx->rate)
     432        {
     433            st_rate_stop (pCtx->rate);
     434        }
     435        RTMemFree(pCtx);
     436    }
     437}
     438
    104439
    105440static DECLCALLBACK(int) iface_Setup (PPDMIAUDIOSNIFFERPORT pInterface, bool fEnable, bool fKeepHostAudio)
     
    159494     * Validate configuration.
    160495     */
    161     if (!CFGMR3AreValuesValid(pCfgHandle, "\0"))
     496    if (!CFGMR3AreValuesValid(pCfgHandle, "InterceptAudioInput\0"))
    162497    {
    163498        return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
     
    170505    pThis->fKeepHostAudio = true;
    171506    pThis->pDrv = NULL;
     507    rc = CFGMR3QueryBoolDef(pCfgHandle, "InterceptAudioInput", &pThis->fInterceptAudioInput, false);
     508    if (RT_FAILURE(rc))
     509        return PDMDEV_SET_ERROR(pDevIns, rc,
     510                                N_("Configuration error: Failed to get the \"YieldOnLSRRead\" value"));
    172511
    173512    /*
     
    179518    /* Audio Sniffer port */
    180519    pThis->IPort.pfnSetup = iface_Setup;
     520    pThis->IPort.pfnAudioInputIntercept = iface_AudioInputIntercept;
     521    pThis->IPort.pfnAudioInputEventBegin = iface_AudioInputEventBegin;
     522    pThis->IPort.pfnAudioInputEventData = iface_AudioInputEventData;
     523    pThis->IPort.pfnAudioInputEventEnd = iface_AudioInputEventEnd;
    181524
    182525    /*
  • trunk/src/VBox/Devices/Makefile.kmk

    r34876 r34906  
    794794        Audio/mixeng.c \
    795795        Audio/noaudio.c \
     796        Audio/filteraudio.c \
    796797        Input/DrvKeyboardQueue.cpp \
    797798        Input/DrvMouseQueue.cpp \
  • trunk/src/VBox/Main/AudioSnifferInterface.cpp

    r33004 r34906  
    113113}
    114114
     115DECLCALLBACK(int) iface_AudioInputBegin (PPDMIAUDIOSNIFFERCONNECTOR pInterface,
     116                                         void **ppvUserCtx,
     117                                         void *pvContext,
     118                                         uint32_t cSamples,
     119                                         uint32_t iSampleHz,
     120                                         uint32_t cChannels,
     121                                         uint32_t cBits)
     122{
     123    PDRVAUDIOSNIFFER pDrv = PDMIAUDIOSNIFFERCONNECTOR_2_MAINAUDIOSNIFFER(pInterface);
     124
     125    return pDrv->pAudioSniffer->getParent()->consoleVRDPServer()->SendAudioInputBegin(ppvUserCtx,
     126                                                                                      pvContext,
     127                                                                                      cSamples,
     128                                                                                      iSampleHz,
     129                                                                                      cChannels,
     130                                                                                      cBits);
     131}
     132
     133DECLCALLBACK(void) iface_AudioInputEnd (PPDMIAUDIOSNIFFERCONNECTOR pInterface,
     134                                        void *pvUserCtx)
     135{
     136    PDRVAUDIOSNIFFER pDrv = PDMIAUDIOSNIFFERCONNECTOR_2_MAINAUDIOSNIFFER(pInterface);
     137
     138    pDrv->pAudioSniffer->getParent()->consoleVRDPServer()->SendAudioInputEnd(pvUserCtx);
     139}
     140
    115141
    116142/**
     
    175201    pThis->Connector.pfnAudioSamplesOut         = iface_AudioSamplesOut;
    176202    pThis->Connector.pfnAudioVolumeOut          = iface_AudioVolumeOut;
     203    pThis->Connector.pfnAudioInputBegin         = iface_AudioInputBegin;
     204    pThis->Connector.pfnAudioInputEnd           = iface_AudioInputEnd;
    177205
    178206    /*
  • trunk/src/VBox/Main/ConsoleVRDPServer.cpp

    r34574 r34906  
    2121#include "KeyboardImpl.h"
    2222#include "MouseImpl.h"
     23#include "AudioSnifferInterface.h"
    2324#ifdef VBOX_WITH_EXTPACK
    2425# include "ExtPackManagerImpl.h"
     
    510511PFNVRDECREATESERVER ConsoleVRDPServer::mpfnVRDECreateServer = NULL;
    511512
    512 VRDEENTRYPOINTS_1 *ConsoleVRDPServer::mpEntryPoints = NULL;
    513 
    514 VRDECALLBACKS_1 ConsoleVRDPServer::mCallbacks =
    515 {
    516     { VRDE_INTERFACE_VERSION_1, sizeof(VRDECALLBACKS_1) },
     513VRDEENTRYPOINTS_3 ConsoleVRDPServer::mEntryPoints; /* A copy of the server entry points. */
     514VRDEENTRYPOINTS_3 *ConsoleVRDPServer::mpEntryPoints = NULL;
     515
     516VRDECALLBACKS_3 ConsoleVRDPServer::mCallbacks =
     517{
     518    { VRDE_INTERFACE_VERSION_3, sizeof(VRDECALLBACKS_3) },
    517519    ConsoleVRDPServer::VRDPCallbackQueryProperty,
    518520    ConsoleVRDPServer::VRDPCallbackClientLogon,
     
    526528    ConsoleVRDPServer::VRDPCallbackFramebufferUnlock,
    527529    ConsoleVRDPServer::VRDPCallbackInput,
    528     ConsoleVRDPServer::VRDPCallbackVideoModeHint
     530    ConsoleVRDPServer::VRDPCallbackVideoModeHint,
     531    ConsoleVRDPServer::VRDECallbackAudioIn
    529532};
    530533
     
    851854
    852855    server->mConsole->VRDPClientDisconnect(u32ClientId, fu32Intercepted);
     856
     857    if (ASMAtomicReadU32(&server->mu32AudioInputClientId) == u32ClientId)
     858    {
     859        Log(("AUDIOIN: disconnected client %u\n", u32ClientId));
     860        ASMAtomicWriteU32(&server->mu32AudioInputClientId, 0);
     861
     862        PPDMIAUDIOSNIFFERPORT pPort = server->mConsole->getAudioSniffer()->getAudioSnifferPort();
     863        if (pPort)
     864        {
     865             // @todo dynamic filter attach does not yet work pPort->pfnAudioInputIntercept(pPort, false);
     866        }
     867        else
     868        {
     869            AssertFailed();
     870        }
     871    }
    853872}
    854873
     
    887906            }
    888907            rc = VINF_SUCCESS;
     908        } break;
     909
     910        case VRDE_CLIENT_INTERCEPT_AUDIO_INPUT:
     911        {
     912            /* This request is processed internally by the ConsoleVRDPServer.
     913             * Only one client is allowed to intercept audio input.
     914             */
     915            if (ASMAtomicCmpXchgU32(&server->mu32AudioInputClientId, u32ClientId, 0) == true)
     916            {
     917                Log(("AUDIOIN: connected client %u\n", u32ClientId));
     918
     919                PPDMIAUDIOSNIFFERPORT pPort = server->mConsole->getAudioSniffer()->getAudioSnifferPort();
     920                if (pPort)
     921                {
     922                     // @todo dynamic filter attach does not yet work pPort->pfnAudioInputIntercept(pPort, true);
     923                     if (ppvIntercept)
     924                     {
     925                         *ppvIntercept = server;
     926                     }
     927                }
     928                else
     929                {
     930                    AssertFailed();
     931                    ASMAtomicWriteU32(&server->mu32AudioInputClientId, 0);
     932                    rc = VERR_NOT_SUPPORTED;
     933                }
     934            }
     935            else
     936            {
     937                Log(("AUDIOIN: ignored client %u, active client %u\n", u32ClientId, server->mu32AudioInputClientId));
     938                rc = VERR_NOT_SUPPORTED;
     939            }
    889940        } break;
    890941
     
    11391190}
    11401191
     1192DECLCALLBACK(void) ConsoleVRDPServer::VRDECallbackAudioIn(void *pvCallback,
     1193                                                          void *pvCtx,
     1194                                                          uint32_t u32ClientId,
     1195                                                          uint32_t u32Event,
     1196                                                          const void *pvData,
     1197                                                          uint32_t cbData)
     1198{
     1199    ConsoleVRDPServer *server = static_cast<ConsoleVRDPServer*>(pvCallback);
     1200
     1201    PPDMIAUDIOSNIFFERPORT pPort = server->mConsole->getAudioSniffer()->getAudioSnifferPort();
     1202
     1203    switch (u32Event)
     1204    {
     1205        case VRDE_AUDIOIN_BEGIN:
     1206        {
     1207            const VRDEAUDIOINBEGIN *pParms = (const VRDEAUDIOINBEGIN *)pvData;
     1208
     1209            pPort->pfnAudioInputEventBegin (pPort, pvCtx,
     1210                                            VRDE_AUDIO_FMT_SAMPLE_FREQ(pParms->fmt),
     1211                                            VRDE_AUDIO_FMT_CHANNELS(pParms->fmt),
     1212                                            VRDE_AUDIO_FMT_BITS_PER_SAMPLE(pParms->fmt),
     1213                                            VRDE_AUDIO_FMT_SIGNED(pParms->fmt)
     1214                                           );
     1215        } break;
     1216
     1217        case VRDE_AUDIOIN_DATA:
     1218        {
     1219            pPort->pfnAudioInputEventData (pPort, pvCtx, pvData, cbData);
     1220        } break;
     1221
     1222        case VRDE_AUDIOIN_END:
     1223        {
     1224            pPort->pfnAudioInputEventEnd (pPort, pvCtx);
     1225        } break;
     1226
     1227        default:
     1228            return;
     1229    }
     1230}
     1231
     1232
    11411233ConsoleVRDPServer::ConsoleVRDPServer(Console *console)
    11421234{
     
    11591251
    11601252    mhServer = 0;
     1253    mServerInterfaceVersion = 0;
    11611254
    11621255    m_fGuestWantsAbsolute = false;
     
    11911284
    11921285    mAuthLibrary = 0;
     1286
     1287    mu32AudioInputClientId = 0;
    11931288}
    11941289
     
    12721367        if (RT_SUCCESS(vrc))
    12731368        {
    1274             vrc = mpfnVRDECreateServer(&mCallbacks.header, this, (VRDEINTERFACEHDR **)&mpEntryPoints, &mhServer);
     1369            VRDEENTRYPOINTS_3 *pEntryPoints3;
     1370            vrc = mpfnVRDECreateServer(&mCallbacks.header, this, (VRDEINTERFACEHDR **)&pEntryPoints3, &mhServer);
     1371
     1372            if (RT_SUCCESS(vrc))
     1373            {
     1374                mServerInterfaceVersion = 3;
     1375                mEntryPoints = *pEntryPoints3;
     1376                mpEntryPoints = &mEntryPoints;
     1377            }
     1378            else if (vrc == VERR_VERSION_MISMATCH)
     1379            {
     1380                /* An older version of VRDE is installed, try version 1. */
     1381                VRDEENTRYPOINTS_1 *pEntryPoints1;
     1382
     1383                VRDECALLBACKS_1 callbacks =
     1384                {
     1385                    { VRDE_INTERFACE_VERSION_1, sizeof(VRDECALLBACKS_1) },
     1386                    ConsoleVRDPServer::VRDPCallbackQueryProperty,
     1387                    ConsoleVRDPServer::VRDPCallbackClientLogon,
     1388                    ConsoleVRDPServer::VRDPCallbackClientConnect,
     1389                    ConsoleVRDPServer::VRDPCallbackClientDisconnect,
     1390                    ConsoleVRDPServer::VRDPCallbackIntercept,
     1391                    ConsoleVRDPServer::VRDPCallbackUSB,
     1392                    ConsoleVRDPServer::VRDPCallbackClipboard,
     1393                    ConsoleVRDPServer::VRDPCallbackFramebufferQuery,
     1394                    ConsoleVRDPServer::VRDPCallbackFramebufferLock,
     1395                    ConsoleVRDPServer::VRDPCallbackFramebufferUnlock,
     1396                    ConsoleVRDPServer::VRDPCallbackInput,
     1397                    ConsoleVRDPServer::VRDPCallbackVideoModeHint
     1398                };
     1399
     1400                vrc = mpfnVRDECreateServer(&callbacks.header, this, (VRDEINTERFACEHDR **)&pEntryPoints1, &mhServer);
     1401                if (RT_SUCCESS(vrc))
     1402                {
     1403                    LogRel(("VRDE: loaded an older version of the server.\n"));
     1404
     1405                    mServerInterfaceVersion = 3;
     1406                    mEntryPoints.header = pEntryPoints1->header;
     1407                    mEntryPoints.VRDEDestroy = pEntryPoints1->VRDEDestroy;
     1408                    mEntryPoints.VRDEEnableConnections = pEntryPoints1->VRDEEnableConnections;
     1409                    mEntryPoints.VRDEDisconnect = pEntryPoints1->VRDEDisconnect;
     1410                    mEntryPoints.VRDEResize = pEntryPoints1->VRDEResize;
     1411                    mEntryPoints.VRDEUpdate = pEntryPoints1->VRDEUpdate;
     1412                    mEntryPoints.VRDEColorPointer = pEntryPoints1->VRDEColorPointer;
     1413                    mEntryPoints.VRDEHidePointer = pEntryPoints1->VRDEHidePointer;
     1414                    mEntryPoints.VRDEAudioSamples = pEntryPoints1->VRDEAudioSamples;
     1415                    mEntryPoints.VRDEAudioVolume = pEntryPoints1->VRDEAudioVolume;
     1416                    mEntryPoints.VRDEUSBRequest = pEntryPoints1->VRDEUSBRequest;
     1417                    mEntryPoints.VRDEClipboard = pEntryPoints1->VRDEClipboard;
     1418                    mEntryPoints.VRDEQueryInfo = pEntryPoints1->VRDEQueryInfo;
     1419                    mEntryPoints.VRDERedirect = NULL;
     1420                    mEntryPoints.VRDEAudioInOpen = NULL;
     1421                    mEntryPoints.VRDEAudioInClose = NULL;
     1422                    mpEntryPoints = &mEntryPoints;
     1423                }
     1424            }
     1425
    12751426            if (RT_SUCCESS(vrc))
    12761427            {
     
    12821433            {
    12831434                if (vrc != VERR_NET_ADDRESS_IN_USE)
    1284                     LogRel(("VRDE: Could not start VRDP server rc = %Rrc\n", vrc));
     1435                    LogRel(("VRDE: Could not start the server rc = %Rrc\n", vrc));
    12851436                /* Don't unload the lib, because it prevents us trying again or
    12861437                   because there may be other users? */
     
    20982249    }
    20992250}
     2251
     2252/* @todo rc not needed? */
     2253int ConsoleVRDPServer::SendAudioInputBegin(void **ppvUserCtx,
     2254                                           void *pvContext,
     2255                                           uint32_t cSamples,
     2256                                           uint32_t iSampleHz,
     2257                                           uint32_t cChannels,
     2258                                           uint32_t cBits)
     2259{
     2260    if (mpEntryPoints && mhServer && mpEntryPoints->VRDEAudioInOpen)
     2261    {
     2262        uint32_t u32ClientId = ASMAtomicReadU32(&mu32AudioInputClientId);
     2263        if (u32ClientId != 0) /* 0 would mean broadcast to all clients. */
     2264        {
     2265            VRDEAUDIOFORMAT audioFormat = VRDE_AUDIO_FMT_MAKE(iSampleHz, cChannels, cBits, 0);
     2266            mpEntryPoints->VRDEAudioInOpen (mhServer,
     2267                                            pvContext,
     2268                                            u32ClientId,
     2269                                            audioFormat,
     2270                                            cSamples);
     2271            *ppvUserCtx = NULL; /* This is the ConsoleVRDP server context.
     2272                                 * Currently not used because only one client is allowed to
     2273                                 * do audio input and the client id is saved by the ConsoleVRDPServer.
     2274                                 */
     2275
     2276            return VINF_SUCCESS;
     2277        }
     2278    }
     2279    return VERR_NOT_SUPPORTED;
     2280}
     2281
     2282void ConsoleVRDPServer::SendAudioInputEnd(void *pvUserCtx)
     2283{
     2284    if (mpEntryPoints && mhServer && mpEntryPoints->VRDEAudioInClose)
     2285    {
     2286        uint32_t u32ClientId = ASMAtomicReadU32(&mu32AudioInputClientId);
     2287        if (u32ClientId != 0) /* 0 would mean broadcast to all clients. */
     2288        {
     2289            mpEntryPoints->VRDEAudioInClose(mhServer, u32ClientId);
     2290        }
     2291    }
     2292}
     2293
     2294
    21002295
    21012296void ConsoleVRDPServer::QueryInfo(uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
  • trunk/src/VBox/Main/include/ConsoleImpl.h

    r34587 r34906  
    168168    Display *getDisplay() const { return mDisplay; }
    169169    MachineDebugger *getMachineDebugger() const { return mDebugger; }
     170    AudioSniffer *getAudioSniffer() const { return mAudioSniffer; }
    170171
    171172    const ComPtr<IMachine> &machine() const { return mMachine; }
  • trunk/src/VBox/Main/include/ConsoleVRDPServer.h

    r34563 r34906  
    128128    void QueryInfo (uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const;
    129129
     130    int SendAudioInputBegin(void **ppvUserCtx,
     131                            void *pvContext,
     132                            uint32_t cSamples,
     133                            uint32_t iSampleHz,
     134                            uint32_t cChannels,
     135                            uint32_t cBits);
     136
     137    void SendAudioInputEnd(void *pvUserCtx);
     138
    130139private:
    131140    /* Note: This is not a ComObjPtr here, because the ConsoleVRDPServer object
     
    135144
    136145    HVRDESERVER mhServer;
     146    int mServerInterfaceVersion;
    137147
    138148    static int loadVRDPLibrary (const char *pszLibraryName);
     
    143153    static PFNVRDECREATESERVER mpfnVRDECreateServer;
    144154
    145     static VRDEENTRYPOINTS_1 *mpEntryPoints;
    146     static VRDECALLBACKS_1 mCallbacks;
     155    static VRDEENTRYPOINTS_3 mEntryPoints;
     156    static VRDEENTRYPOINTS_3 *mpEntryPoints;
     157    static VRDECALLBACKS_3 mCallbacks;
    147158
    148159    static DECLCALLBACK(int)  VRDPCallbackQueryProperty     (void *pvCallback, uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut);
     
    158169    static DECLCALLBACK(void) VRDPCallbackInput             (void *pvCallback, int type, const void *pvInput, unsigned cbInput);
    159170    static DECLCALLBACK(void) VRDPCallbackVideoModeHint     (void *pvCallback, unsigned cWidth, unsigned cHeight,  unsigned cBitsPerPixel, unsigned uScreenId);
     171    static DECLCALLBACK(void) VRDECallbackAudioIn           (void *pvCallback, void *pvCtx, uint32_t u32ClientId, uint32_t u32Event, const void *pvData, uint32_t cbData);
    160172
    161173    bool m_fGuestWantsAbsolute;
     
    212224    PAUTHENTRY2 mpfnAuthEntry2;
    213225    PAUTHENTRY3 mpfnAuthEntry3;
     226
     227    uint32_t volatile mu32AudioInputClientId;
    214228};
    215229
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