Ignore:
Timestamp:
Mar 11, 2011 6:57:24 AM (13 years ago)
Author:
ming
Message:

Fixed #1204: Support for refreshing audio device list.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia-audiodev/wmme_dev.c

    r2941 r3438  
    3939#endif 
    4040 
     41#ifndef PJMEDIA_WMME_DEV_USE_MMDEVICE_API 
     42#   define PJMEDIAWMME_DEV_USE_MMDEVICE_API \ 
     43           (defined(_WIN32_WINNT) && (_WIN32_WINNT>=0x0600)) 
     44#endif 
     45 
     46#if PJMEDIA_WMME_DEV_USE_MMDEVICE_API != 0 
     47#   define DRV_QUERYFUNCTIONINSTANCEID     (DRV_RESERVED + 17) 
     48#   define DRV_QUERYFUNCTIONINSTANCEIDSIZE (DRV_RESERVED + 18) 
     49#endif 
     50 
    4151/* mingw lacks WAVE_FORMAT_ALAW/MULAW */ 
    4252#ifndef WAVE_FORMAT_ALAW 
     
    6171    pjmedia_aud_dev_info         info; 
    6272    unsigned                     deviceId; 
     73    const wchar_t               *endpointId; 
    6374}; 
    6475 
     
    6778{ 
    6879    pjmedia_aud_dev_factory      base; 
     80    pj_pool_t                   *base_pool; 
    6981    pj_pool_t                   *pool; 
    7082    pj_pool_factory             *pf; 
     
    122134static pj_status_t factory_init(pjmedia_aud_dev_factory *f); 
    123135static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f); 
     136static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f); 
    124137static unsigned    factory_get_dev_count(pjmedia_aud_dev_factory *f); 
    125138static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,  
     
    157170    &factory_get_dev_info, 
    158171    &factory_default_param, 
    159     &factory_create_stream 
     172    &factory_create_stream, 
     173    &factory_refresh 
    160174}; 
    161175 
     
    182196    pj_pool_t *pool; 
    183197 
    184     pool = pj_pool_create(pf, "WMME", 1000, 1000, NULL); 
     198    pool = pj_pool_create(pf, "WMME base", 1000, 1000, NULL); 
    185199    f = PJ_POOL_ZALLOC_T(pool, struct wmme_factory); 
    186200    f->pf = pf; 
    187     f->pool = pool; 
     201    f->base_pool = pool; 
    188202    f->base.op = &factory_op; 
    189203 
     
    191205} 
    192206 
     207/* Internal: Windows Vista and Windows 7 have their device 
     208 * names truncated when using the waveXXX api.  The names 
     209 * should be acquired from the MMDevice APIs 
     210 */ 
     211#if PJMEDIA_WMME_DEV_USE_MMDEVICE_API != 0 
     212 
     213#define COBJMACROS 
     214#include <mmdeviceapi.h> 
     215#define INITGUID 
     216#include <Guiddef.h> 
     217#include <FunctionDiscoveryKeys_devpkey.h> 
     218 
     219DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 
     220            0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E); 
     221DEFINE_GUID(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, 
     222            0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6); 
     223 
     224static void get_dev_names(pjmedia_aud_dev_factory *f) 
     225{ 
     226    struct wmme_factory *wf = (struct wmme_factory*)f; 
     227    HRESULT              coinit = S_OK; 
     228    HRESULT              hr = S_OK; 
     229    IMMDeviceEnumerator *pEnumerator = NULL; 
     230    IMMDeviceCollection *pDevices = NULL; 
     231    UINT                 cDevices = 0; 
     232    UINT                 nDevice = 0; 
     233 
     234    coinit = CoInitializeEx(NULL, COINIT_MULTITHREADED); 
     235    if (coinit == RPC_E_CHANGED_MODE) 
     236        coinit = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 
     237    if (FAILED(coinit)) 
     238        goto on_error; 
     239 
     240    hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, 
     241                          CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, 
     242                          (void**)&pEnumerator); 
     243    if (FAILED(hr)) 
     244        goto on_error; 
     245    hr = IMMDeviceEnumerator_EnumAudioEndpoints(pEnumerator, eAll, 
     246                                                DEVICE_STATE_ACTIVE, 
     247                                                &pDevices); 
     248    if (FAILED(hr)) 
     249        goto on_error; 
     250    hr = IMMDeviceCollection_GetCount(pDevices, &cDevices); 
     251    if (FAILED(hr)) 
     252        goto on_error; 
     253 
     254    for (nDevice = 0; nDevice < cDevices; ++nDevice) { 
     255        IMMDevice      *pDevice = NULL; 
     256        IPropertyStore *pProps = NULL; 
     257        LPWSTR          pwszID = NULL; 
     258        PROPVARIANT     varName; 
     259        unsigned        i; 
     260 
     261        PropVariantInit(&varName); 
     262 
     263        hr = IMMDeviceCollection_Item(pDevices, nDevice, &pDevice); 
     264        if (FAILED(hr)) 
     265            goto cleanup; 
     266        hr = IMMDevice_GetId(pDevice, &pwszID); 
     267        if (FAILED(hr)) 
     268            goto cleanup; 
     269        hr = IMMDevice_OpenPropertyStore(pDevice, STGM_READ, &pProps); 
     270        if (FAILED(hr)) 
     271            goto cleanup; 
     272        hr = IPropertyStore_GetValue(pProps, &PKEY_Device_FriendlyName, 
     273                                     &varName); 
     274        if (FAILED(hr)) 
     275            goto cleanup; 
     276 
     277        for (i = 0; i < wf->dev_count; ++i) { 
     278            if (0 == wcscmp(wf->dev_info[i].endpointId, pwszID)) { 
     279                wcstombs(wf->dev_info[i].info.name, varName.pwszVal, 
     280                         sizeof(wf->dev_info[i].info.name)); 
     281                break; 
     282            } 
     283        } 
     284 
     285        PropVariantClear(&varName); 
     286 
     287    cleanup: 
     288        if (pProps) 
     289            IPropertyStore_Release(pProps); 
     290        if (pwszID) 
     291            CoTaskMemFree(pwszID); 
     292        if (pDevice) 
     293            hr = IMMDevice_Release(pDevice); 
     294    } 
     295 
     296on_error: 
     297    if (pDevices) 
     298        hr = IMMDeviceCollection_Release(pDevices); 
     299 
     300    if (pEnumerator) 
     301        hr = IMMDeviceEnumerator_Release(pEnumerator); 
     302 
     303    if (SUCCEEDED(coinit)) 
     304        CoUninitialize(); 
     305} 
     306 
     307#else 
     308 
     309static void get_dev_names(pjmedia_aud_dev_factory *f) 
     310{ 
     311    PJ_UNUSED_ARG(f); 
     312} 
     313 
     314#endif 
    193315 
    194316/* Internal: build device info from WAVEINCAPS/WAVEOUTCAPS */ 
     
    262384static pj_status_t factory_init(pjmedia_aud_dev_factory *f) 
    263385{ 
     386    pj_status_t ret = factory_refresh(f); 
     387    if (ret != PJ_SUCCESS) 
     388        return ret; 
     389 
     390    PJ_LOG(4, (THIS_FILE, "WMME initialized")); 
     391    return PJ_SUCCESS; 
     392} 
     393 
     394/* API: refresh the device list */ 
     395static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f) 
     396{ 
    264397    struct wmme_factory *wf = (struct wmme_factory*)f; 
    265398    unsigned c; 
     
    268401    pj_bool_t waveMapperAdded = PJ_FALSE; 
    269402 
     403    if (wf->pool != NULL) { 
     404        pj_pool_release(wf->pool); 
     405        wf->pool = NULL; 
     406    } 
     407 
    270408    /* Enumerate sound devices */ 
    271409    wf->dev_count = 0; 
     410    wf->pool = pj_pool_create(wf->pf, "WMME", 1000, 1000, NULL); 
    272411 
    273412    inputDeviceCount = waveInGetNumDevs(); 
     
    315454                build_dev_info(WAVE_MAPPER, &wf->dev_info[wf->dev_count],  
    316455                               &wic, &woc); 
     456                wf->dev_info[wf->dev_count].endpointId = L""; 
    317457                ++wf->dev_count; 
    318458                waveMapperAdded = PJ_TRUE; 
     
    328468            WAVEINCAPS wic; 
    329469            MMRESULT mr; 
     470            DWORD cbEndpointId; 
    330471 
    331472            pj_bzero(&wic, sizeof(WAVEINCAPS)); 
     
    341482            build_dev_info(uDeviceID, &wf->dev_info[wf->dev_count],  
    342483                           &wic, NULL); 
     484 
     485#if PJMEDIA_WMME_DEV_USE_MMDEVICE_API != 0 
     486            /* Try to get the endpoint id of the audio device */ 
     487            wf->dev_info[wf->dev_count].endpointId = L""; 
     488 
     489            mr = waveInMessage((HWAVEIN)IntToPtr(uDeviceID), 
     490                               DRV_QUERYFUNCTIONINSTANCEIDSIZE, 
     491                               (DWORD_PTR)&cbEndpointId, (DWORD_PTR)NULL); 
     492            if (mr == MMSYSERR_NOERROR) { 
     493                const wchar_t **epid = &wf->dev_info[wf->dev_count].endpointId; 
     494                *epid = (const wchar_t*) pj_pool_calloc(wf->pool, 
     495                                                        cbEndpointId, 1); 
     496                mr = waveInMessage((HWAVEIN)IntToPtr(uDeviceID), 
     497                                   DRV_QUERYFUNCTIONINSTANCEID, 
     498                                   (DWORD_PTR)*epid, 
     499                                   cbEndpointId); 
     500            } 
     501#else 
     502            PJ_UNUSED_ARG(cbEndpointId); 
     503#endif 
     504 
    343505            ++wf->dev_count; 
    344506        } 
     
    352514            WAVEOUTCAPS woc; 
    353515            MMRESULT mr; 
     516            DWORD cbEndpointId; 
    354517 
    355518            pj_bzero(&woc, sizeof(WAVEOUTCAPS)); 
     
    365528            build_dev_info(uDeviceID, &wf->dev_info[wf->dev_count],  
    366529                           NULL, &woc); 
     530 
     531#if PJMEDIA_WMME_DEV_USE_MMDEVICE_API != 0 
     532            /* Try to get the endpoint id of the audio device */ 
     533            wf->dev_info[wf->dev_count].endpointId = L""; 
     534 
     535            mr = waveOutMessage((HWAVEOUT)IntToPtr(uDeviceID), 
     536                                DRV_QUERYFUNCTIONINSTANCEIDSIZE, 
     537                                (DWORD_PTR)&cbEndpointId, (DWORD_PTR)NULL); 
     538            if (mr == MMSYSERR_NOERROR) { 
     539                const wchar_t **epid = &wf->dev_info[wf->dev_count].endpointId; 
     540                *epid = (const wchar_t*)pj_pool_calloc(wf->pool, 
     541                                                       cbEndpointId, 1); 
     542                mr = waveOutMessage((HWAVEOUT)IntToPtr(uDeviceID), 
     543                                    DRV_QUERYFUNCTIONINSTANCEID, 
     544                                    (DWORD_PTR)*epid, cbEndpointId); 
     545            } 
     546#else 
     547            PJ_UNUSED_ARG(cbEndpointId); 
     548#endif 
     549 
    367550            ++wf->dev_count; 
    368551        } 
    369552    } 
    370553 
    371     PJ_LOG(4, (THIS_FILE, "WMME initialized, found %d devices:",  
     554    /* On Windows Vista and Windows 7 get the full device names */ 
     555    get_dev_names(f); 
     556 
     557    PJ_LOG(4, (THIS_FILE, "WMME found %d devices:", 
    372558               wf->dev_count)); 
    373559    for (c = 0; c < wf->dev_count; ++c) { 
     
    386572{ 
    387573    struct wmme_factory *wf = (struct wmme_factory*)f; 
    388     pj_pool_t *pool = wf->pool; 
    389  
    390     wf->pool = NULL; 
     574    pj_pool_t *pool = wf->base_pool; 
     575 
     576    pj_pool_release(wf->pool); 
     577    wf->base_pool = NULL; 
    391578    pj_pool_release(pool); 
    392579 
Note: See TracChangeset for help on using the changeset viewer.