summaryrefslogtreecommitdiff
path: root/pjmedia/src/pjmedia-audiodev
diff options
context:
space:
mode:
authorLiong Sauw Ming <ming@teluu.com>2011-03-11 06:57:24 +0000
committerLiong Sauw Ming <ming@teluu.com>2011-03-11 06:57:24 +0000
commitc44da2d6d7f8a991cd8143f97acda117a4e0a422 (patch)
treee57adad451551e486fdbb8f4de0b2240978d091d /pjmedia/src/pjmedia-audiodev
parenta71c9ccfea1d7d9e7999037a8ee13820eb0e16e2 (diff)
Fixed #1204: Support for refreshing audio device list.
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3438 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia/src/pjmedia-audiodev')
-rw-r--r--pjmedia/src/pjmedia-audiodev/alsa_dev.c106
-rw-r--r--pjmedia/src/pjmedia-audiodev/audiodev.c19
-rw-r--r--pjmedia/src/pjmedia-audiodev/coreaudio_dev.c3
-rw-r--r--pjmedia/src/pjmedia-audiodev/legacy_dev.c11
-rw-r--r--pjmedia/src/pjmedia-audiodev/null_dev.c11
-rw-r--r--pjmedia/src/pjmedia-audiodev/pa_dev.c12
-rw-r--r--pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp11
-rw-r--r--pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp11
-rw-r--r--pjmedia/src/pjmedia-audiodev/symb_vas_dev.cpp11
-rw-r--r--pjmedia/src/pjmedia-audiodev/wmme_dev.c199
10 files changed, 355 insertions, 39 deletions
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; card<MAX_SOUND_CARDS; card++) {
- for (device=0; device<MAX_SOUND_DEVICES_PER_CARD; device++) {
- add_dev(af, card, device);
- }
- }
-
- /* 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);
+ pj_status_t status = alsa_factory_refresh(f);
+ if (PJ_SUCCESS != status)
+ return status;
- PJ_LOG(4,(THIS_FILE, "ALSA driver found %d devices", af->dev_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; i<aud_subsys.drv_cnt; ++i) {
+ struct driver *drv = &aud_subsys.drv[i];
+
+ if (drv->f && 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 <mmdeviceapi.h>
+#define INITGUID
+#include <Guiddef.h>
+#include <FunctionDiscoveryKeys_devpkey.h>
+
+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,
@@ -261,14 +383,31 @@ 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;
int i;
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;