From c44da2d6d7f8a991cd8143f97acda117a4e0a422 Mon Sep 17 00:00:00 2001 From: Liong Sauw Ming Date: Fri, 11 Mar 2011 06:57:24 +0000 Subject: Fixed #1204: Support for refreshing audio device list. git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3438 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/src/pjmedia-audiodev/alsa_dev.c | 106 ++++++++++---- pjmedia/src/pjmedia-audiodev/audiodev.c | 19 +++ pjmedia/src/pjmedia-audiodev/coreaudio_dev.c | 3 +- pjmedia/src/pjmedia-audiodev/legacy_dev.c | 11 +- pjmedia/src/pjmedia-audiodev/null_dev.c | 11 +- pjmedia/src/pjmedia-audiodev/pa_dev.c | 12 +- pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp | 11 +- pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp | 11 +- pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp | 11 +- pjmedia/src/pjmedia-audiodev/wmme_dev.c | 199 +++++++++++++++++++++++++- 10 files changed, 355 insertions(+), 39 deletions(-) (limited to 'pjmedia/src/pjmedia-audiodev') diff --git a/pjmedia/src/pjmedia-audiodev/alsa_dev.c b/pjmedia/src/pjmedia-audiodev/alsa_dev.c index 90eca542..c2cc4e5e 100644 --- a/pjmedia/src/pjmedia-audiodev/alsa_dev.c +++ b/pjmedia/src/pjmedia-audiodev/alsa_dev.c @@ -57,6 +57,7 @@ */ static pj_status_t alsa_factory_init(pjmedia_aud_dev_factory *f); static pj_status_t alsa_factory_destroy(pjmedia_aud_dev_factory *f); +static pj_status_t alsa_factory_refresh(pjmedia_aud_dev_factory *f); static unsigned alsa_factory_get_dev_count(pjmedia_aud_dev_factory *f); static pj_status_t alsa_factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, @@ -92,6 +93,7 @@ struct alsa_factory pjmedia_aud_dev_factory base; pj_pool_factory *pf; pj_pool_t *pool; + pj_pool_t *base_pool; unsigned dev_cnt; pjmedia_aud_dev_info devs[MAX_DEVICES]; @@ -133,7 +135,8 @@ static pjmedia_aud_dev_factory_op alsa_factory_op = &alsa_factory_get_dev_count, &alsa_factory_get_dev_info, &alsa_factory_default_param, - &alsa_factory_create_stream + &alsa_factory_create_stream, + &alsa_factory_refresh }; static pjmedia_aud_stream_op alsa_stream_op = @@ -146,6 +149,20 @@ static pjmedia_aud_stream_op alsa_stream_op = &alsa_stream_destroy }; +static void null_alsa_error_handler (const char *file, + int line, + const char *function, + int err, + const char *fmt, + ...) +{ + PJ_UNUSED_ARG(file); + PJ_UNUSED_ARG(line); + PJ_UNUSED_ARG(function); + PJ_UNUSED_ARG(err); + PJ_UNUSED_ARG(fmt); +} + static void alsa_error_handler (const char *file, int line, const char *function, @@ -174,10 +191,9 @@ static void alsa_error_handler (const char *file, } -static pj_status_t add_dev (struct alsa_factory *af, int card, int device) +static pj_status_t add_dev (struct alsa_factory *af, const char *dev_name) { pjmedia_aud_dev_info *adi; - char dev_name[32]; snd_pcm_t* pcm; int pb_result, ca_result; @@ -186,8 +202,7 @@ static pj_status_t add_dev (struct alsa_factory *af, int card, int device) adi = &af->devs[af->dev_cnt]; - TRACE_((THIS_FILE, "add_dev (%d, %d): Enter", card, device)); - sprintf (dev_name, ALSA_DEVICE_NAME, card, device); + TRACE_((THIS_FILE, "add_dev (%s): Enter", dev_name)); /* Try to open the device in playback mode */ pb_result = snd_pcm_open (&pcm, dev_name, SND_PCM_STREAM_PLAYBACK, 0); @@ -245,10 +260,10 @@ pjmedia_aud_dev_factory* pjmedia_alsa_factory(pj_pool_factory *pf) struct alsa_factory *af; pj_pool_t *pool; - pool = pj_pool_create(pf, "alsa_aud", 256, 256, NULL); + pool = pj_pool_create(pf, "alsa_aud_base", 256, 256, NULL); af = PJ_POOL_ZALLOC_T(pool, struct alsa_factory); af->pf = pf; - af->pool = pool; + af->base_pool = pool; af->base.op = &alsa_factory_op; return &af->base; @@ -258,23 +273,11 @@ pjmedia_aud_dev_factory* pjmedia_alsa_factory(pj_pool_factory *pf) /* API: init factory */ static pj_status_t alsa_factory_init(pjmedia_aud_dev_factory *f) { - struct alsa_factory *af = (struct alsa_factory*)f; - int card, device; - - TRACE_((THIS_FILE, "pjmedia_snd_init: Enumerate sound devices")); - /* Enumerate sound devices */ - for (card=0; carddev_cnt)); + PJ_LOG(4,(THIS_FILE, "ALSA initialized")); return PJ_SUCCESS; } @@ -284,9 +287,12 @@ static pj_status_t alsa_factory_destroy(pjmedia_aud_dev_factory *f) { struct alsa_factory *af = (struct alsa_factory*)f; - if (af->pool) { - pj_pool_t *pool = af->pool; - af->pool = NULL; + if (af->pool) + pj_pool_release(af->pool); + + if (af->base_pool) { + pj_pool_t *pool = af->base_pool; + af->base_pool = NULL; pj_pool_release(pool); } @@ -297,6 +303,54 @@ static pj_status_t alsa_factory_destroy(pjmedia_aud_dev_factory *f) } +/* API: refresh the device list */ +static pj_status_t alsa_factory_refresh(pjmedia_aud_dev_factory *f) +{ + struct alsa_factory *af = (struct alsa_factory*)f; + char **hints, **n; + int err; + + TRACE_((THIS_FILE, "pjmedia_snd_init: Enumerate sound devices")); + + if (af->pool != NULL) { + pj_pool_release(af->pool); + af->pool = NULL; + } + + af->pool = pj_pool_create(af->pf, "alsa_aud", 256, 256, NULL); + af->dev_cnt = 0; + + /* Enumerate sound devices */ + err = snd_device_name_hint(-1, "pcm", (void***)&hints); + if (err != 0) + return PJMEDIA_EAUD_SYSERR; + + /* Set a null error handler prior to enumeration to suppress errors */ + snd_lib_error_set_handler(null_alsa_error_handler); + + n = hints; + while (*n != NULL) { + char *name = snd_device_name_get_hint(*n, "NAME"); + if (name != NULL && 0 != strcmp("null", name)) { + add_dev(af, name); + free(name); + } + n++; + } + + /* Install error handler after enumeration, otherwise we'll get many + * error messages about invalid card/device ID. + */ + snd_lib_error_set_handler(alsa_error_handler); + + err = snd_device_name_free_hint((void**)hints); + + PJ_LOG(4,(THIS_FILE, "ALSA driver found %d devices", af->dev_cnt)); + + return PJ_SUCCESS; +} + + /* API: get device count */ static unsigned alsa_factory_get_dev_count(pjmedia_aud_dev_factory *f) { diff --git a/pjmedia/src/pjmedia-audiodev/audiodev.c b/pjmedia/src/pjmedia-audiodev/audiodev.c index 2a5a8e67..b9d960fe 100644 --- a/pjmedia/src/pjmedia-audiodev/audiodev.c +++ b/pjmedia/src/pjmedia-audiodev/audiodev.c @@ -491,6 +491,25 @@ PJ_DEF(pj_status_t) pjmedia_aud_subsys_shutdown(void) return PJ_SUCCESS; } +/* API: Refresh the list of sound devices installed in the system. */ +PJ_DEF(pj_status_t) pjmedia_aud_dev_refresh(void) +{ + unsigned i; + + for (i=0; if && drv->f->op->refresh) { + pj_status_t status = drv->f->op->refresh(drv->f); + if (status != PJ_SUCCESS) { + PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device " + "list for %s", drv->name)); + } + } + } + return PJ_SUCCESS; +} + /* API: Get the number of sound devices installed in the system. */ PJ_DEF(unsigned) pjmedia_aud_dev_count(void) { diff --git a/pjmedia/src/pjmedia-audiodev/coreaudio_dev.c b/pjmedia/src/pjmedia-audiodev/coreaudio_dev.c index 2cebbb34..de320488 100644 --- a/pjmedia/src/pjmedia-audiodev/coreaudio_dev.c +++ b/pjmedia/src/pjmedia-audiodev/coreaudio_dev.c @@ -178,7 +178,8 @@ static pjmedia_aud_dev_factory_op factory_op = &ca_factory_get_dev_count, &ca_factory_get_dev_info, &ca_factory_default_param, - &ca_factory_create_stream + &ca_factory_create_stream, + &ca_factory_refresh }; static pjmedia_aud_stream_op stream_op = diff --git a/pjmedia/src/pjmedia-audiodev/legacy_dev.c b/pjmedia/src/pjmedia-audiodev/legacy_dev.c index 66fad9b0..a7680f1e 100644 --- a/pjmedia/src/pjmedia-audiodev/legacy_dev.c +++ b/pjmedia/src/pjmedia-audiodev/legacy_dev.c @@ -51,6 +51,7 @@ struct legacy_stream /* Prototypes */ static pj_status_t factory_init(pjmedia_aud_dev_factory *f); static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f); +static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f); static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f); static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, @@ -86,7 +87,8 @@ static pjmedia_aud_dev_factory_op factory_op = &factory_get_dev_count, &factory_get_dev_info, &factory_default_param, - &factory_create_stream + &factory_create_stream, + &factory_refresh }; static pjmedia_aud_stream_op stream_op = @@ -147,6 +149,13 @@ static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f) return status; } +/* API: refresh the list of devices */ +static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f) +{ + PJ_UNUSED_ARG(f); + return PJ_ENOTSUP; +} + /* API: get number of devices */ static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f) { diff --git a/pjmedia/src/pjmedia-audiodev/null_dev.c b/pjmedia/src/pjmedia-audiodev/null_dev.c index feb96d22..44ce6412 100644 --- a/pjmedia/src/pjmedia-audiodev/null_dev.c +++ b/pjmedia/src/pjmedia-audiodev/null_dev.c @@ -59,6 +59,7 @@ struct null_audio_stream /* Prototypes */ static pj_status_t null_factory_init(pjmedia_aud_dev_factory *f); static pj_status_t null_factory_destroy(pjmedia_aud_dev_factory *f); +static pj_status_t null_factory_refresh(pjmedia_aud_dev_factory *f); static unsigned null_factory_get_dev_count(pjmedia_aud_dev_factory *f); static pj_status_t null_factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, @@ -93,7 +94,8 @@ static pjmedia_aud_dev_factory_op factory_op = &null_factory_get_dev_count, &null_factory_get_dev_info, &null_factory_default_param, - &null_factory_create_stream + &null_factory_create_stream, + &null_factory_refresh }; static pjmedia_aud_stream_op stream_op = @@ -166,6 +168,13 @@ static pj_status_t null_factory_destroy(pjmedia_aud_dev_factory *f) return PJ_SUCCESS; } +/* API: refresh the list of devices */ +static pj_status_t null_factory_refresh(pjmedia_aud_dev_factory *f) +{ + PJ_UNUSED_ARG(f); + return PJ_SUCCESS; +} + /* API: get number of devices */ static unsigned null_factory_get_dev_count(pjmedia_aud_dev_factory *f) { diff --git a/pjmedia/src/pjmedia-audiodev/pa_dev.c b/pjmedia/src/pjmedia-audiodev/pa_dev.c index 1188b8ab..fb33a6aa 100644 --- a/pjmedia/src/pjmedia-audiodev/pa_dev.c +++ b/pjmedia/src/pjmedia-audiodev/pa_dev.c @@ -106,6 +106,7 @@ struct pa_aud_stream /* Factory prototypes */ static pj_status_t pa_init(pjmedia_aud_dev_factory *f); static pj_status_t pa_destroy(pjmedia_aud_dev_factory *f); +static pj_status_t pa_refresh(pjmedia_aud_dev_factory *f); static unsigned pa_get_dev_count(pjmedia_aud_dev_factory *f); static pj_status_t pa_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, @@ -141,7 +142,8 @@ static pjmedia_aud_dev_factory_op pa_op = &pa_get_dev_count, &pa_get_dev_info, &pa_default_param, - &pa_create_stream + &pa_create_stream, + &pa_refresh }; static pjmedia_aud_stream_op pa_strm_op = @@ -487,6 +489,14 @@ static pj_status_t pa_destroy(pjmedia_aud_dev_factory *f) } +/* API: Refresh the device list. */ +static pj_status_t pa_refresh(pjmedia_aud_dev_factory *f) +{ + PJ_UNUSED_ARG(f); + return PJ_ENOTSUP; +} + + /* API: Get device count. */ static unsigned pa_get_dev_count(pjmedia_aud_dev_factory *f) { diff --git a/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp b/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp index 80ca7c51..aeb5cb3b 100644 --- a/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp +++ b/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp @@ -120,6 +120,7 @@ struct aps_stream /* Prototypes */ static pj_status_t factory_init(pjmedia_aud_dev_factory *f); static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f); +static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f); static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f); static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, @@ -155,7 +156,8 @@ static pjmedia_aud_dev_factory_op factory_op = &factory_get_dev_count, &factory_get_dev_info, &factory_default_param, - &factory_create_stream + &factory_create_stream, + &factory_refresh }; static pjmedia_aud_stream_op stream_op = @@ -1444,6 +1446,13 @@ static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f) return PJ_SUCCESS; } +/* API: refresh the device list */ +static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f) +{ + PJ_UNUSED_ARG(f); + return PJ_ENOTSUP; +} + /* API: get number of devices */ static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f) { diff --git a/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp b/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp index 2df93836..0c9d5e28 100644 --- a/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp +++ b/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp @@ -85,6 +85,7 @@ struct mda_stream /* Prototypes */ static pj_status_t factory_init(pjmedia_aud_dev_factory *f); static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f); +static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f); static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f); static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, @@ -120,7 +121,8 @@ static pjmedia_aud_dev_factory_op factory_op = &factory_get_dev_count, &factory_get_dev_info, &factory_default_param, - &factory_create_stream + &factory_create_stream, + &factory_refresh }; static pjmedia_aud_stream_op stream_op = @@ -834,6 +836,13 @@ static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f) return PJ_SUCCESS; } +/* API: refresh the device list */ +static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f) +{ + PJ_UNUSED_ARG(f); + return PJ_ENOTSUP; +} + /* API: get number of devices */ static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f) { diff --git a/pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp b/pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp index 2f35a660..d58cef59 100644 --- a/pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp +++ b/pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp @@ -130,6 +130,7 @@ struct vas_stream /* Prototypes */ static pj_status_t factory_init(pjmedia_aud_dev_factory *f); static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f); +static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f); static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f); static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, @@ -165,7 +166,8 @@ static pjmedia_aud_dev_factory_op factory_op = &factory_get_dev_count, &factory_get_dev_info, &factory_default_param, - &factory_create_stream + &factory_create_stream, + &factory_refresh }; static pjmedia_aud_stream_op stream_op = @@ -1476,6 +1478,13 @@ static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f) return PJ_SUCCESS; } +/* API: refresh the device list */ +static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f) +{ + PJ_UNUSED_ARG(f); + return PJ_ENOTSUP; +} + /* API: get number of devices */ static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f) { diff --git a/pjmedia/src/pjmedia-audiodev/wmme_dev.c b/pjmedia/src/pjmedia-audiodev/wmme_dev.c index 4a577c78..095aead9 100644 --- a/pjmedia/src/pjmedia-audiodev/wmme_dev.c +++ b/pjmedia/src/pjmedia-audiodev/wmme_dev.c @@ -38,6 +38,16 @@ # pragma warning(pop) #endif +#ifndef PJMEDIA_WMME_DEV_USE_MMDEVICE_API +# define PJMEDIAWMME_DEV_USE_MMDEVICE_API \ + (defined(_WIN32_WINNT) && (_WIN32_WINNT>=0x0600)) +#endif + +#if PJMEDIA_WMME_DEV_USE_MMDEVICE_API != 0 +# define DRV_QUERYFUNCTIONINSTANCEID (DRV_RESERVED + 17) +# define DRV_QUERYFUNCTIONINSTANCEIDSIZE (DRV_RESERVED + 18) +#endif + /* mingw lacks WAVE_FORMAT_ALAW/MULAW */ #ifndef WAVE_FORMAT_ALAW # define WAVE_FORMAT_ALAW 0x0006 @@ -60,12 +70,14 @@ struct wmme_dev_info { pjmedia_aud_dev_info info; unsigned deviceId; + const wchar_t *endpointId; }; /* WMME factory */ struct wmme_factory { pjmedia_aud_dev_factory base; + pj_pool_t *base_pool; pj_pool_t *pool; pj_pool_factory *pf; @@ -121,6 +133,7 @@ struct wmme_stream /* Prototypes */ static pj_status_t factory_init(pjmedia_aud_dev_factory *f); static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f); +static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f); static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f); static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, unsigned index, @@ -156,7 +169,8 @@ static pjmedia_aud_dev_factory_op factory_op = &factory_get_dev_count, &factory_get_dev_info, &factory_default_param, - &factory_create_stream + &factory_create_stream, + &factory_refresh }; static pjmedia_aud_stream_op stream_op = @@ -181,15 +195,123 @@ pjmedia_aud_dev_factory* pjmedia_wmme_factory(pj_pool_factory *pf) struct wmme_factory *f; pj_pool_t *pool; - pool = pj_pool_create(pf, "WMME", 1000, 1000, NULL); + pool = pj_pool_create(pf, "WMME base", 1000, 1000, NULL); f = PJ_POOL_ZALLOC_T(pool, struct wmme_factory); f->pf = pf; - f->pool = pool; + f->base_pool = pool; f->base.op = &factory_op; return &f->base; } +/* Internal: Windows Vista and Windows 7 have their device + * names truncated when using the waveXXX api. The names + * should be acquired from the MMDevice APIs + */ +#if PJMEDIA_WMME_DEV_USE_MMDEVICE_API != 0 + +#define COBJMACROS +#include +#define INITGUID +#include +#include + +DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, + 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E); +DEFINE_GUID(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, + 0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6); + +static void get_dev_names(pjmedia_aud_dev_factory *f) +{ + struct wmme_factory *wf = (struct wmme_factory*)f; + HRESULT coinit = S_OK; + HRESULT hr = S_OK; + IMMDeviceEnumerator *pEnumerator = NULL; + IMMDeviceCollection *pDevices = NULL; + UINT cDevices = 0; + UINT nDevice = 0; + + coinit = CoInitializeEx(NULL, COINIT_MULTITHREADED); + if (coinit == RPC_E_CHANGED_MODE) + coinit = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (FAILED(coinit)) + goto on_error; + + hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, + CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, + (void**)&pEnumerator); + if (FAILED(hr)) + goto on_error; + hr = IMMDeviceEnumerator_EnumAudioEndpoints(pEnumerator, eAll, + DEVICE_STATE_ACTIVE, + &pDevices); + if (FAILED(hr)) + goto on_error; + hr = IMMDeviceCollection_GetCount(pDevices, &cDevices); + if (FAILED(hr)) + goto on_error; + + for (nDevice = 0; nDevice < cDevices; ++nDevice) { + IMMDevice *pDevice = NULL; + IPropertyStore *pProps = NULL; + LPWSTR pwszID = NULL; + PROPVARIANT varName; + unsigned i; + + PropVariantInit(&varName); + + hr = IMMDeviceCollection_Item(pDevices, nDevice, &pDevice); + if (FAILED(hr)) + goto cleanup; + hr = IMMDevice_GetId(pDevice, &pwszID); + if (FAILED(hr)) + goto cleanup; + hr = IMMDevice_OpenPropertyStore(pDevice, STGM_READ, &pProps); + if (FAILED(hr)) + goto cleanup; + hr = IPropertyStore_GetValue(pProps, &PKEY_Device_FriendlyName, + &varName); + if (FAILED(hr)) + goto cleanup; + + for (i = 0; i < wf->dev_count; ++i) { + if (0 == wcscmp(wf->dev_info[i].endpointId, pwszID)) { + wcstombs(wf->dev_info[i].info.name, varName.pwszVal, + sizeof(wf->dev_info[i].info.name)); + break; + } + } + + PropVariantClear(&varName); + + cleanup: + if (pProps) + IPropertyStore_Release(pProps); + if (pwszID) + CoTaskMemFree(pwszID); + if (pDevice) + hr = IMMDevice_Release(pDevice); + } + +on_error: + if (pDevices) + hr = IMMDeviceCollection_Release(pDevices); + + if (pEnumerator) + hr = IMMDeviceEnumerator_Release(pEnumerator); + + if (SUCCEEDED(coinit)) + CoUninitialize(); +} + +#else + +static void get_dev_names(pjmedia_aud_dev_factory *f) +{ + PJ_UNUSED_ARG(f); +} + +#endif /* Internal: build device info from WAVEINCAPS/WAVEOUTCAPS */ static void build_dev_info(UINT deviceId, struct wmme_dev_info *wdi, @@ -260,6 +382,17 @@ static void build_dev_info(UINT deviceId, struct wmme_dev_info *wdi, /* API: init factory */ static pj_status_t factory_init(pjmedia_aud_dev_factory *f) +{ + pj_status_t ret = factory_refresh(f); + if (ret != PJ_SUCCESS) + return ret; + + PJ_LOG(4, (THIS_FILE, "WMME initialized")); + return PJ_SUCCESS; +} + +/* API: refresh the device list */ +static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f) { struct wmme_factory *wf = (struct wmme_factory*)f; unsigned c; @@ -267,8 +400,14 @@ static pj_status_t factory_init(pjmedia_aud_dev_factory *f) int inputDeviceCount, outputDeviceCount, devCount=0; pj_bool_t waveMapperAdded = PJ_FALSE; + if (wf->pool != NULL) { + pj_pool_release(wf->pool); + wf->pool = NULL; + } + /* Enumerate sound devices */ wf->dev_count = 0; + wf->pool = pj_pool_create(wf->pf, "WMME", 1000, 1000, NULL); inputDeviceCount = waveInGetNumDevs(); devCount += inputDeviceCount; @@ -314,6 +453,7 @@ static pj_status_t factory_init(pjmedia_aud_dev_factory *f) if (mr == MMSYSERR_NOERROR) { build_dev_info(WAVE_MAPPER, &wf->dev_info[wf->dev_count], &wic, &woc); + wf->dev_info[wf->dev_count].endpointId = L""; ++wf->dev_count; waveMapperAdded = PJ_TRUE; } @@ -327,6 +467,7 @@ static pj_status_t factory_init(pjmedia_aud_dev_factory *f) UINT uDeviceID = (UINT)((i==-1) ? WAVE_MAPPER : i); WAVEINCAPS wic; MMRESULT mr; + DWORD cbEndpointId; pj_bzero(&wic, sizeof(WAVEINCAPS)); @@ -340,6 +481,27 @@ static pj_status_t factory_init(pjmedia_aud_dev_factory *f) build_dev_info(uDeviceID, &wf->dev_info[wf->dev_count], &wic, NULL); + +#if PJMEDIA_WMME_DEV_USE_MMDEVICE_API != 0 + /* Try to get the endpoint id of the audio device */ + wf->dev_info[wf->dev_count].endpointId = L""; + + mr = waveInMessage((HWAVEIN)IntToPtr(uDeviceID), + DRV_QUERYFUNCTIONINSTANCEIDSIZE, + (DWORD_PTR)&cbEndpointId, (DWORD_PTR)NULL); + if (mr == MMSYSERR_NOERROR) { + const wchar_t **epid = &wf->dev_info[wf->dev_count].endpointId; + *epid = (const wchar_t*) pj_pool_calloc(wf->pool, + cbEndpointId, 1); + mr = waveInMessage((HWAVEIN)IntToPtr(uDeviceID), + DRV_QUERYFUNCTIONINSTANCEID, + (DWORD_PTR)*epid, + cbEndpointId); + } +#else + PJ_UNUSED_ARG(cbEndpointId); +#endif + ++wf->dev_count; } } @@ -351,6 +513,7 @@ static pj_status_t factory_init(pjmedia_aud_dev_factory *f) UINT uDeviceID = (UINT)((i==-1) ? WAVE_MAPPER : i); WAVEOUTCAPS woc; MMRESULT mr; + DWORD cbEndpointId; pj_bzero(&woc, sizeof(WAVEOUTCAPS)); @@ -364,11 +527,34 @@ static pj_status_t factory_init(pjmedia_aud_dev_factory *f) build_dev_info(uDeviceID, &wf->dev_info[wf->dev_count], NULL, &woc); + +#if PJMEDIA_WMME_DEV_USE_MMDEVICE_API != 0 + /* Try to get the endpoint id of the audio device */ + wf->dev_info[wf->dev_count].endpointId = L""; + + mr = waveOutMessage((HWAVEOUT)IntToPtr(uDeviceID), + DRV_QUERYFUNCTIONINSTANCEIDSIZE, + (DWORD_PTR)&cbEndpointId, (DWORD_PTR)NULL); + if (mr == MMSYSERR_NOERROR) { + const wchar_t **epid = &wf->dev_info[wf->dev_count].endpointId; + *epid = (const wchar_t*)pj_pool_calloc(wf->pool, + cbEndpointId, 1); + mr = waveOutMessage((HWAVEOUT)IntToPtr(uDeviceID), + DRV_QUERYFUNCTIONINSTANCEID, + (DWORD_PTR)*epid, cbEndpointId); + } +#else + PJ_UNUSED_ARG(cbEndpointId); +#endif + ++wf->dev_count; } } - PJ_LOG(4, (THIS_FILE, "WMME initialized, found %d devices:", + /* On Windows Vista and Windows 7 get the full device names */ + get_dev_names(f); + + PJ_LOG(4, (THIS_FILE, "WMME found %d devices:", wf->dev_count)); for (c = 0; c < wf->dev_count; ++c) { PJ_LOG(4, (THIS_FILE, " dev_id %d: %s (in=%d, out=%d)", @@ -385,9 +571,10 @@ static pj_status_t factory_init(pjmedia_aud_dev_factory *f) static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f) { struct wmme_factory *wf = (struct wmme_factory*)f; - pj_pool_t *pool = wf->pool; + pj_pool_t *pool = wf->base_pool; - wf->pool = NULL; + pj_pool_release(wf->pool); + wf->base_pool = NULL; pj_pool_release(pool); return PJ_SUCCESS; -- cgit v1.2.3