Ticket #734: error codes in audiodev

git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/aps-direct@2488 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/build.symbian/pjmedia_audiodev.mmp b/build.symbian/pjmedia_audiodev.mmp
index 0c952ba..ccabc2f 100644
--- a/build.symbian/pjmedia_audiodev.mmp
+++ b/build.symbian/pjmedia_audiodev.mmp
@@ -12,6 +12,7 @@
 MACRO		PJ_SYMBIAN=1
 
 SOURCE		audiodev.c
+SOURCE		errno.c
 SOURCE		symb_aps_dev.cpp
 SOURCE		symb_mda_dev.cpp
 
diff --git a/pjlib/include/pj/errno.h b/pjlib/include/pj/errno.h
index 59b21cf..07cdcf8 100644
--- a/pjlib/include/pj/errno.h
+++ b/pjlib/include/pj/errno.h
@@ -375,6 +375,7 @@
  *  - PJSIP_SIMPLE_ERRNO_START	(PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE*2)
  *  - PJLIB_UTIL_ERRNO_START	(PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE*3)
  *  - PJNATH_ERRNO_START	(PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE*4)
+ *  - PJMEDIA_AUDIODEV_ERRNO_START (PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE*5)
  */
 
 /* Internal */
diff --git a/pjmedia/build/pjmedia_audiodev.dsp b/pjmedia/build/pjmedia_audiodev.dsp
index 508228e..2557128 100644
--- a/pjmedia/build/pjmedia_audiodev.dsp
+++ b/pjmedia/build/pjmedia_audiodev.dsp
@@ -97,6 +97,10 @@
 # End Source File

 # Begin Source File

 

+SOURCE="..\src\pjmedia-audiodev\errno.c"

+# End Source File

+# Begin Source File

+

 SOURCE="..\src\pjmedia-audiodev\pa_dev.c"

 # End Source File

 # Begin Source File

@@ -133,6 +137,10 @@
 

 SOURCE="..\include\pjmedia-audiodev\config.h"

 # End Source File

+# Begin Source File

+

+SOURCE="..\include\pjmedia-audiodev\errno.h"

+# End Source File

 # End Group

 # End Target

 # End Project

diff --git a/pjmedia/include/pjmedia-audiodev/audiodev.h b/pjmedia/include/pjmedia-audiodev/audiodev.h
index 9e81ab5..c3c7479 100644
--- a/pjmedia/include/pjmedia-audiodev/audiodev.h
+++ b/pjmedia/include/pjmedia-audiodev/audiodev.h
@@ -25,6 +25,7 @@
  * @brief Audio device API.
  */
 #include <pjmedia-audiodev/config.h>
+#include <pjmedia-audiodev/errno.h>
 #include <pjmedia/port.h>
 #include <pj/pool.h>
 
@@ -601,30 +602,6 @@
 PJ_DECL(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm);
 
 
-/* Audio subsystem not initialized */
-#define PJMEDIA_EAUD_INIT	-1
-
-/* Invalid audio device */
-#define PJMEDIA_EAUD_INVDEV	-1
-
-/* Found no devices */
-#define PJMEDIA_EAUD_NODEV	-1
-
-/* Unable to find default device */
-#define PJMEDIA_EAUD_NODEFDEV	-1
-
-/* Device not ready */
-#define PJMEDIA_EAUD_NOTREADY	-1
-
-/* Invalid audio capability or audio capability not supported */
-#define PJMEDIA_EAUD_INVCAP	-1
-
-/* Unknown system error */
-#define PJMEDIA_EAUD_SYSERR	-1
-
-/* Bad or invalid format */
-#define PJMEDIA_EAUD_BADFORMAT	-1
-
 /**
  * @}
  */
diff --git a/pjmedia/include/pjmedia-audiodev/errno.h b/pjmedia/include/pjmedia-audiodev/errno.h
new file mode 100644
index 0000000..0b13f0b
--- /dev/null
+++ b/pjmedia/include/pjmedia-audiodev/errno.h
@@ -0,0 +1,188 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#ifndef __PJMEDIA_AUDIODEV_AUDIODEV_ERRNO_H__
+#define __PJMEDIA_AUDIODEV_AUDIODEV_ERRNO_H__
+
+/**
+ * @file errno.h Error Codes
+ * @brief Audiodev specific error codes.
+ */
+
+#include <pjmedia-audiodev/config.h>
+#include <pj/errno.h>
+
+/**
+ * @defgroup error_codes Error Codes
+ * @ingroup audio_device_api
+ * @brief Audio devive library specific error codes.
+ * @{
+ */
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * Start of error code relative to PJ_ERRNO_START_USER.
+ * This value is 420000.
+ */
+#define PJMEDIA_AUDIODEV_ERRNO_START \
+	    (PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE*5)
+#define PJMEDIA_AUDIODEV_ERRNO_END   \
+	    (PJMEDIA_AUDIODEV_ERRNO_START + PJ_ERRNO_SPACE_SIZE - 1)
+
+
+/**
+ * Mapping from PortAudio error codes to pjmedia error space.
+ */
+#define PJMEDIA_AUDIODEV_PORTAUDIO_ERRNO_START \
+	    (PJMEDIA_AUDIODEV_ERRNO_END-10000)
+#define PJMEDIA_AUDIODEV_PORTAUDIO_ERRNO_END   \
+	    (PJMEDIA_AUDIODEV_PORTAUDIO_ERRNO_START + 10000 -1)
+/**
+ * Convert PortAudio error code to PJLIB error code.
+ * PortAudio error code range: 0 >= err >= -10000
+ */
+#define PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err) \
+	    ((int)PJMEDIA_AUDIODEV_PORTAUDIO_ERRNO_START-err)
+
+/**
+ * Mapping from Windows multimedia WaveIn error codes.
+ */
+#define PJMEDIA_AUDIODEV_WMME_IN_ERROR_START	\
+	    (PJMEDIA_AUDIODEV_ERRNO_START + 30000)
+#define PJMEDIA_AUDIODEV_WMME_IN_ERROR_END	\
+	    (PJMEDIA_AUDIODEV_WMME_IN_ERROR_START + 1000 - 1)
+/**
+ * Convert WaveIn operation error codes to PJLIB error space.
+ */
+#define PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_IN(err) \
+	    ((int)PJMEDIA_AUDIODEV_WMME_IN_ERROR_START+err)
+
+
+/**
+ * Mapping from Windows multimedia WaveOut error codes.
+ */
+#define PJMEDIA_AUDIODEV_WMME_OUT_ERROR_START	\
+	    (PJMEDIA_AUDIODEV_WMME_IN_ERROR_END + 1000)
+#define PJMEDIA_AUDIODEV_WMME_OUT_ERROR_END	\
+	    (PJMEDIA_AUDIODEV_WMME_OUT_ERROR_START + 1000)
+/**
+ * Convert WaveOut operation error codes to PJLIB error space.
+ */
+#define PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_OUT(err) \
+	    ((int)PJMEDIA_AUDIODEV_WMME_OUT_ERROR_START+err)
+
+
+/************************************************************
+ * Audio Device API error codes
+ ***********************************************************/
+/**
+ * @hideinitializer
+ * General/unknown error.
+ */
+#define PJMEDIA_AUDIODEV_ERROR	(PJMEDIA_AUDIODEV_ERRNO_START+1) /* 420001 */
+
+/**
+ * @hideinitializer
+ * Unknown error from audio driver
+ */
+#define PJMEDIA_EAUD_SYSERR	(PJMEDIA_AUDIODEV_ERRNO_START+2) /* 420002 */
+
+/**
+ * @hideinitializer
+ * Audio subsystem not initialized
+ */
+#define PJMEDIA_EAUD_INIT	(PJMEDIA_AUDIODEV_ERRNO_START+3) /* 420003 */
+
+/**
+ * @hideinitializer
+ * Invalid audio device
+ */
+#define PJMEDIA_EAUD_INVDEV	(PJMEDIA_AUDIODEV_ERRNO_START+4) /* 420004 */
+
+/**
+ * @hideinitializer
+ * Found no devices
+ */
+#define PJMEDIA_EAUD_NODEV	(PJMEDIA_AUDIODEV_ERRNO_START+5) /* 420005 */
+
+/**
+ * @hideinitializer
+ * Unable to find default device
+ */
+#define PJMEDIA_EAUD_NODEFDEV	(PJMEDIA_AUDIODEV_ERRNO_START+6) /* 420006 */
+
+/**
+ * @hideinitializer
+ * Device not ready
+ */
+#define PJMEDIA_EAUD_NOTREADY	(PJMEDIA_AUDIODEV_ERRNO_START+7) /* 420007 */
+
+/**
+ * @hideinitializer
+ * The audio capability is invalid or not supported
+ */
+#define PJMEDIA_EAUD_INVCAP	(PJMEDIA_AUDIODEV_ERRNO_START+8) /* 420008 */
+
+/**
+ * @hideinitializer
+ * The operation is invalid or not supported
+ */
+#define PJMEDIA_EAUD_INVOP	(PJMEDIA_AUDIODEV_ERRNO_START+9) /* 420009 */
+
+/**
+ * @hideinitializer
+ * Bad or invalid audio device format
+ */
+#define PJMEDIA_EAUD_BADFORMAT	(PJMEDIA_AUDIODEV_ERRNO_START+10) /* 4200010 */
+
+/**
+ * @hideinitializer
+ * Invalid audio device sample format
+ */
+#define PJMEDIA_EAUD_SAMPFORMAT	(PJMEDIA_AUDIODEV_ERRNO_START+11) /* 4200011 */
+
+/**
+ * Get error message for the specified error code. Note that this
+ * function is only able to decode PJMEDIA Audiodev specific error code.
+ * Application should use pj_strerror(), which should be able to
+ * decode all error codes belonging to all subsystems (e.g. pjlib,
+ * pjmedia, pjsip, etc).
+ *
+ * @param status    The error code.
+ * @param buffer    The buffer where to put the error message.
+ * @param bufsize   Size of the buffer.
+ *
+ * @return	    The error message as NULL terminated string,
+ *                  wrapped with pj_str_t.
+ */
+PJ_DECL(pj_str_t) pjmedia_audiodev_strerror(pj_status_t status, char *buffer,
+					    pj_size_t bufsize);
+
+
+PJ_END_DECL
+
+/**
+ * @}
+ */
+
+
+#endif	/* __PJMEDIA_AUDIODEV_AUDIODEV_ERRNO_H__ */
+
diff --git a/pjmedia/src/pjmedia-audiodev/audiodev.c b/pjmedia/src/pjmedia-audiodev/audiodev.c
index 52d53b1..968ae0c 100644
--- a/pjmedia/src/pjmedia-audiodev/audiodev.c
+++ b/pjmedia/src/pjmedia-audiodev/audiodev.c
@@ -25,6 +25,8 @@
 
 #define THIS_FILE   "audiodev.c"
 
+#define DEFINE_CAP(name, info)	{name, info}
+
 /* Capability names */
 static struct cap_info
 {
@@ -32,20 +34,20 @@
     const char *info;
 } cap_infos[] = 
 {
-    {"ext-fmt",	    "Extended/non-PCM format"},
-    {"latency-in",  "Input latency/buffer size setting"},
-    {"latency-out", "Output latency/buffer size setting"},
-    {"vol-in",	    "Input volume setting"},
-    {"vol-out",	    "Output volume setting"},
-    {"meter-in",    "Input meter"},
-    {"meter-out",   "Output meter"},
-    {"route-in",    "Input routing"},
-    {"route-out",   "Output routing"},
-    {"aec",	    "Accoustic echo cancellation"},
-    {"aec-tail",    "Tail length setting for AEC"},
-    {"vad",	    "Voice activity detection"},
-    {"cng",	    "Comfort noise generation"},
-    {"plg",	    "Packet loss concealment"}
+    DEFINE_CAP("ext-fmt",     "Extended/non-PCM format"),
+    DEFINE_CAP("latency-in",  "Input latency/buffer size setting"),
+    DEFINE_CAP("latency-out", "Output latency/buffer size setting"),
+    DEFINE_CAP("vol-in",      "Input volume setting"),
+    DEFINE_CAP("vol-out",     "Output volume setting"),
+    DEFINE_CAP("meter-in",    "Input meter"),
+    DEFINE_CAP("meter-out",   "Output meter"),
+    DEFINE_CAP("route-in",    "Input routing"),
+    DEFINE_CAP("route-out",   "Output routing"),
+    DEFINE_CAP("aec",	      "Accoustic echo cancellation"),
+    DEFINE_CAP("aec-tail",    "Tail length setting for AEC"),
+    DEFINE_CAP("vad",	      "Voice activity detection"),
+    DEFINE_CAP("cng",	      "Comfort noise generation"),
+    DEFINE_CAP("plg",	      "Packet loss concealment")
 };
 
 
@@ -227,6 +229,12 @@
 	return PJ_SUCCESS;
     }
 
+    /* Register error subsystem */
+    pj_register_strerror(PJMEDIA_AUDIODEV_ERRNO_START, 
+			 PJ_ERRNO_SPACE_SIZE, 
+			 &pjmedia_audiodev_strerror);
+
+    /* Init */
     aud_subsys.pf = pf;
     aud_subsys.drv_cnt = 0;
     aud_subsys.dev_cnt = 0;
diff --git a/pjmedia/src/pjmedia-audiodev/errno.c b/pjmedia/src/pjmedia-audiodev/errno.c
new file mode 100644
index 0000000..639a1cd
--- /dev/null
+++ b/pjmedia/src/pjmedia-audiodev/errno.c
@@ -0,0 +1,189 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjmedia-audiodev/errno.h>
+#include <pj/string.h>
+#include <pj/unicode.h>
+#if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
+#   include <portaudio.h>
+#endif
+#if PJMEDIA_AUDIO_DEV_HAS_WMME
+#   ifdef _MSC_VER
+#	pragma warning(push, 3)
+#   endif
+#   include <windows.h>
+#   include <mmsystem.h>
+#   ifdef _MSC_VER
+#	pragma warning(pop)
+#   endif
+#endif
+
+/* PJMEDIA-Audiodev's own error codes/messages 
+ * MUST KEEP THIS ARRAY SORTED!!
+ * Message must be limited to 64 chars!
+ */
+
+#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)
+
+static const struct 
+{
+    int code;
+    const char *msg;
+} err_str[] = 
+{
+    PJ_BUILD_ERR( PJMEDIA_AUDIODEV_ERROR,   "Unspecified audio device error" ),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_SYSERR,	    "Unknown error from audio driver" ),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_INIT,	    "Audio subsystem not initialized" ),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_INVDEV,	    "Invalid audio device" ),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_NODEV,	    "Found no audio devices" ),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_NODEFDEV,    "Unable to find default audio device" ),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_NOTREADY,    "Audio device not ready" ),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_INVCAP,	    "Invalid or unsupported audio capability" ),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_INVOP,	    "Invalid or unsupported audio device operation" ),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_BADFORMAT,   "Bad or invalid audio device format" ),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_SAMPFORMAT,  "Invalid audio device sample format")
+
+};
+
+#endif	/* PJ_HAS_ERROR_STRING */
+
+
+
+/*
+ * pjmedia_audiodev_strerror()
+ */
+PJ_DEF(pj_str_t) pjmedia_audiodev_strerror(pj_status_t statcode, 
+					   char *buf, pj_size_t bufsize )
+{
+    pj_str_t errstr;
+
+#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)
+
+    /* See if the error comes from PortAudio. */
+#if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
+    if (statcode >= PJMEDIA_AUDIODEV_PORTAUDIO_ERRNO_START &&
+	statcode <= PJMEDIA_AUDIODEV_PORTAUDIO_ERRNO_END)
+    {
+
+	//int pa_err = statcode - PJMEDIA_ERRNO_FROM_PORTAUDIO(0);
+	int pa_err = PJMEDIA_AUDIODEV_PORTAUDIO_ERRNO_START - statcode;
+	pj_str_t msg;
+	
+	msg.ptr = (char*)Pa_GetErrorText(pa_err);
+	msg.slen = pj_ansi_strlen(msg.ptr);
+
+	errstr.ptr = buf;
+	pj_strncpy_with_null(&errstr, &msg, bufsize);
+	return errstr;
+
+    } else 
+#endif	/* PJMEDIA_SOUND_IMPLEMENTATION */
+
+    /* See if the error comes from WMME */
+#if PJMEDIA_AUDIO_DEV_HAS_WMME
+    if ((statcode >= PJMEDIA_AUDIODEV_WMME_IN_ERROR_START &&
+	 statcode < PJMEDIA_AUDIODEV_WMME_IN_ERROR_END) ||
+	(statcode >= PJMEDIA_AUDIODEV_WMME_OUT_ERROR_START &&
+	 statcode < PJMEDIA_AUDIODEV_WMME_OUT_ERROR_END))
+    {
+	MMRESULT native_err, mr;
+	MMRESULT (WINAPI *waveGetErrText)(UINT mmrError, LPTSTR pszText, UINT cchText);
+	PJ_DECL_UNICODE_TEMP_BUF(wbuf, 80)
+
+	if (statcode >= PJMEDIA_AUDIODEV_WMME_IN_ERROR_START &&
+	    statcode <= PJMEDIA_AUDIODEV_WMME_IN_ERROR_END)
+	{
+	    native_err = statcode - PJMEDIA_AUDIODEV_WMME_IN_ERROR_START;
+	    waveGetErrText = &waveInGetErrorText;
+	} else {
+	    native_err = statcode - PJMEDIA_AUDIODEV_WMME_OUT_ERROR_START;
+	    waveGetErrText = &waveOutGetErrorText;
+	}
+
+#if PJ_NATIVE_STRING_IS_UNICODE
+	mr = (*waveGetErrText)(native_err, wbuf, PJ_ARRAY_SIZE(wbuf));
+	if (mr == MMSYSERR_NOERROR) {
+	    int len = wcslen(wbuf);
+	    pj_unicode_to_ansi(wbuf, len, buf, bufsize);
+	}
+#else
+	mr = (*waveGetErrText)(native_err, buf, bufsize);
+#endif
+
+	if (mr==MMSYSERR_NOERROR) {
+	    errstr.ptr = buf;
+	    errstr.slen = pj_ansi_strlen(buf);
+	    return errstr;
+	} else {
+	    pj_ansi_snprintf(buf, bufsize, "MMSYSTEM native error %d", 
+			     native_err);
+	    return pj_str(buf);
+	}
+
+    } else
+#endif
+
+    /* Audiodev error */
+    if (statcode >= PJMEDIA_AUDIODEV_ERRNO_START && 
+	statcode < PJMEDIA_AUDIODEV_ERRNO_END)
+    {
+	/* Find the error in the table.
+	 * Use binary search!
+	 */
+	int first = 0;
+	int n = PJ_ARRAY_SIZE(err_str);
+
+	while (n > 0) {
+	    int half = n/2;
+	    int mid = first + half;
+
+	    if (err_str[mid].code < statcode) {
+		first = mid+1;
+		n -= (half+1);
+	    } else if (err_str[mid].code > statcode) {
+		n = half;
+	    } else {
+		first = mid;
+		break;
+	    }
+	}
+
+
+	if (PJ_ARRAY_SIZE(err_str) && err_str[first].code == statcode) {
+	    pj_str_t msg;
+	    
+	    msg.ptr = (char*)err_str[first].msg;
+	    msg.slen = pj_ansi_strlen(err_str[first].msg);
+
+	    errstr.ptr = buf;
+	    pj_strncpy_with_null(&errstr, &msg, bufsize);
+	    return errstr;
+
+	} 
+    } 
+#endif	/* PJ_HAS_ERROR_STRING */
+
+    /* Error not found. */
+    errstr.ptr = buf;
+    errstr.slen = pj_ansi_snprintf(buf, bufsize, 
+				   "Unknown pjmedia-audiodev error %d",
+				   statcode);
+
+    return errstr;
+}
+
diff --git a/pjmedia/src/pjmedia-audiodev/pa_dev.c b/pjmedia/src/pjmedia-audiodev/pa_dev.c
index e3eb8e6..5644e1f 100644
--- a/pjmedia/src/pjmedia-audiodev/pa_dev.c
+++ b/pjmedia/src/pjmedia-audiodev/pa_dev.c
@@ -18,13 +18,15 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
 #include <pjmedia-audiodev/audiodev_imp.h>
-#include <pjmedia/errno.h>
 #include <pj/assert.h>
 #include <pj/log.h>
 #include <pj/os.h>
 #include <pj/string.h>
 #include <portaudio.h>
 
+#if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
+
+
 #define THIS_FILE	"pa_dev.c"
 #define DRIVER_NAME	"PA"
 
@@ -451,7 +453,7 @@
     PJ_LOG(4,(THIS_FILE, "Sound device count=%d",
 			 pa_get_dev_count(f)));
 
-    return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
+    return err ? PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
 }
 
 
@@ -470,7 +472,7 @@
     pa->pool = NULL;
     pj_pool_release(pool);
     
-    return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
+    return err ? PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
 }
 
 
@@ -692,14 +694,14 @@
 	rec_id = pa_get_default_input_dev(param->channel_count);
 	if (rec_id < 0) {
 	    /* No such device. */
-	    return PJMEDIA_ENOSNDREC;
+	    return PJMEDIA_EAUD_NODEFDEV;
 	}
     }
 
     paDevInfo = Pa_GetDeviceInfo(rec_id);
     if (!paDevInfo) {
 	/* Assumed it is "No such device" error. */
-	return PJMEDIA_ESNDINDEVID;
+	return PJMEDIA_EAUD_INVDEV;
     }
 
     if (param->bits_per_sample == 8)
@@ -709,7 +711,7 @@
     else if (param->bits_per_sample == 32)
 	sampleFormat = paInt32;
     else
-	return PJMEDIA_ESNDINSAMPLEFMT;
+	return PJMEDIA_EAUD_SAMPFORMAT;
     
     pool = pj_pool_create(pa->pf, "recstrm", 1024, 1024, NULL);
     if (!pool)
@@ -752,7 +754,7 @@
 			 paClipOff, &PaRecorderCallback, stream );
     if (err != paNoError) {
 	pj_pool_release(pool);
-	return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
+	return PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err);
     }
 
     paSI = Pa_GetStreamInfo(stream->rec_strm);
@@ -797,14 +799,14 @@
 	play_id = pa_get_default_output_dev(param->channel_count);
 	if (play_id < 0) {
 	    /* No such device. */
-	    return PJMEDIA_ENOSNDPLAY;
+	    return PJMEDIA_EAUD_NODEFDEV;
 	}
     } 
 
     paDevInfo = Pa_GetDeviceInfo(play_id);
     if (!paDevInfo) {
 	/* Assumed it is "No such device" error. */
-	return PJMEDIA_ESNDINDEVID;
+	return PJMEDIA_EAUD_INVDEV;
     }
 
     if (param->bits_per_sample == 8)
@@ -814,7 +816,7 @@
     else if (param->bits_per_sample == 32)
 	sampleFormat = paInt32;
     else
-	return PJMEDIA_ESNDINSAMPLEFMT;
+	return PJMEDIA_EAUD_SAMPFORMAT;
     
     pool = pj_pool_create(pa->pf, "playstrm", 1024, 1024, NULL);
     if (!pool)
@@ -858,7 +860,7 @@
 			 paClipOff, &PaPlayerCallback, stream );
     if (err != paNoError) {
 	pj_pool_release(pool);
-	return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
+	return PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err);
     }
 
     paSI = Pa_GetStreamInfo(stream->play_strm);
@@ -909,14 +911,14 @@
 	rec_id = pa_get_default_input_dev(param->channel_count);
 	if (rec_id < 0) {
 	    /* No such device. */
-	    return PJMEDIA_ENOSNDREC;
+	    return PJMEDIA_EAUD_NODEFDEV;
 	}
     }
 
     paRecDevInfo = Pa_GetDeviceInfo(rec_id);
     if (!paRecDevInfo) {
 	/* Assumed it is "No such device" error. */
-	return PJMEDIA_ESNDINDEVID;
+	return PJMEDIA_EAUD_INVDEV;
     }
 
     play_id = param->play_id;
@@ -924,14 +926,14 @@
 	play_id = pa_get_default_output_dev(param->channel_count);
 	if (play_id < 0) {
 	    /* No such device. */
-	    return PJMEDIA_ENOSNDPLAY;
+	    return PJMEDIA_EAUD_NODEFDEV;
 	}
     } 
 
     paPlayDevInfo = Pa_GetDeviceInfo(play_id);
     if (!paPlayDevInfo) {
 	/* Assumed it is "No such device" error. */
-	return PJMEDIA_ESNDINDEVID;
+	return PJMEDIA_EAUD_INVDEV;
     }
 
 
@@ -942,7 +944,7 @@
     else if (param->bits_per_sample == 32)
 	sampleFormat = paInt32;
     else
-	return PJMEDIA_ESNDINSAMPLEFMT;
+	return PJMEDIA_EAUD_SAMPFORMAT;
     
     pool = pj_pool_create(pa->pf, "sndstream", 1024, 1024, NULL);
     if (!pool)
@@ -1033,7 +1035,7 @@
 
     if (err != paNoError) {
 	pj_pool_release(pool);
-	return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
+	return PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err);
     }
 
     paSI = Pa_GetStreamInfo(stream->rec_strm);
@@ -1142,19 +1144,19 @@
     if (cap==PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY && strm->rec_strm) {
 	const PaStreamInfo *si = Pa_GetStreamInfo(strm->rec_strm);
 	if (!si)
-	    return PJ_EINVALIDOP;
+	    return PJMEDIA_EAUD_SYSERR;
 
 	*(unsigned*)pval = (unsigned)(si->inputLatency * 1000);
 	return PJ_SUCCESS;
     } else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY && strm->play_strm) {
 	const PaStreamInfo *si = Pa_GetStreamInfo(strm->play_strm);
 	if (!si)
-	    return PJ_EINVALIDOP;
+	    return PJMEDIA_EAUD_SYSERR;
 
 	*(unsigned*)pval = (unsigned)(si->outputLatency * 1000);
 	return PJ_SUCCESS;
     } else {
-	return PJ_ENOTSUP;
+	return PJMEDIA_EAUD_INVCAP;
     }
 }
 
@@ -1169,7 +1171,7 @@
     PJ_UNUSED_ARG(value);
 
     /* Nothing is supported */
-    return PJ_ENOTSUP;
+    return PJMEDIA_EAUD_INVCAP;
 }
 
 
@@ -1192,7 +1194,7 @@
 
     PJ_LOG(5,(THIS_FILE, "Done, status=%d", err));
 
-    return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
+    return err ? PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
 }
 
 
@@ -1223,7 +1225,7 @@
 
     PJ_LOG(5,(THIS_FILE, "Done, status=%d", err));
 
-    return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
+    return err ? PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
 }
 
 
@@ -1254,6 +1256,8 @@
 
     pj_pool_release(stream->pool);
 
-    return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
+    return err ? PJMEDIA_AUDIODEV_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
 }
 
+#endif	/* PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO */
+
diff --git a/pjmedia/src/pjmedia-audiodev/wmme_dev.c b/pjmedia/src/pjmedia-audiodev/wmme_dev.c
index e1b9215..9630ceb 100644
--- a/pjmedia/src/pjmedia-audiodev/wmme_dev.c
+++ b/pjmedia/src/pjmedia-audiodev/wmme_dev.c
@@ -18,12 +18,14 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
 #include <pjmedia-audiodev/audiodev_imp.h>
-#include <pjmedia/errno.h>
 #include <pj/assert.h>
 #include <pj/log.h>
 #include <pj/os.h>
 #include <pj/string.h>
 #include <pj/unicode.h>
+
+#if PJMEDIA_AUDIO_DEV_HAS_WMME
+
 #ifdef _MSC_VER
 #   pragma warning(push, 3)
 #endif
@@ -167,12 +169,6 @@
     &stream_destroy
 };
 
-/* Utility: convert MMERROR to pj_status_t */
-PJ_INLINE(pj_status_t) CONVERT_MM_ERROR(MMRESULT mr)
-{
-    return PJ_RETURN_OS_ERROR(mr);
-}
-
 
 /****************************************************************************
  * Factory operations
@@ -547,13 +543,13 @@
 		     wf->dev_info[prm->play_id].deviceId,
 		     &wfx, (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT);
     if (mr != MMSYSERR_NOERROR) {
-	return CONVERT_MM_ERROR(mr);
+	return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_OUT(mr);
     }
 
     /* Pause the wave out device */
     mr = waveOutPause(wmme_strm->hWave.Out);
     if (mr != MMSYSERR_NOERROR) {
-	return CONVERT_MM_ERROR(mr);
+	return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_OUT(mr);
     }
 
     /*
@@ -569,12 +565,12 @@
 				  &(wmme_strm->WaveHdr[i]),
 				  sizeof(WAVEHDR));
 	if (mr != MMSYSERR_NOERROR) {
-	    return CONVERT_MM_ERROR(mr); 
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_OUT(mr); 
 	}
 	mr = waveOutWrite(wmme_strm->hWave.Out, &(wmme_strm->WaveHdr[i]), 
 			  sizeof(WAVEHDR));
 	if (mr != MMSYSERR_NOERROR) {
-	    return CONVERT_MM_ERROR(mr);
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_OUT(mr);
 	}
     }
 
@@ -633,7 +629,7 @@
 		    wf->dev_info[prm->rec_id].deviceId, 
 		    &wfx, (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT);
     if (mr != MMSYSERR_NOERROR) {
-	return CONVERT_MM_ERROR(mr);
+	return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_IN(mr);
     }
 
     /*
@@ -649,12 +645,12 @@
 				 &(wmme_strm->WaveHdr[i]),
 				 sizeof(WAVEHDR));
 	if (mr != MMSYSERR_NOERROR) {
-	    return CONVERT_MM_ERROR(mr);
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_IN(mr);
 	}
 	mr = waveInAddBuffer(wmme_strm->hWave.In, &(wmme_strm->WaveHdr[i]), 
 			     sizeof(WAVEHDR));
 	if (mr != MMSYSERR_NOERROR) {
-	    return CONVERT_MM_ERROR(mr);
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_IN(mr);
 	}
     }
 
@@ -830,7 +826,7 @@
 				  &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]),
 				  sizeof(WAVEHDR));
 		if (mr != MMSYSERR_NOERROR) {
-		    status = CONVERT_MM_ERROR(mr);
+		    status = PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_OUT(mr);
 		    break;
 		}
 
@@ -927,7 +923,7 @@
 				     &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]), 
 				     sizeof(WAVEHDR));
 		if (mr != MMSYSERR_NOERROR) {
-		    status = CONVERT_MM_ERROR(mr);
+		    status = PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_IN(mr);
 		    break;
 		}
 
@@ -1146,7 +1142,7 @@
 
 	mr = waveOutGetVolume(strm->play_strm.hWave.Out, &dwVol);
 	if (mr != MMSYSERR_NOERROR) {
-	    return CONVERT_MM_ERROR(mr);
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_OUT(mr);
 	}
 
 	dwVol &= 0xFFFF;
@@ -1177,7 +1173,8 @@
 	dwVol |= (dwVol << 16);
 
 	mr = waveOutSetVolume(strm->play_strm.hWave.Out, dwVol);
-	return (mr==MMSYSERR_NOERROR)? PJ_SUCCESS : CONVERT_MM_ERROR(mr);
+	return (mr==MMSYSERR_NOERROR)? PJ_SUCCESS : 
+				PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_OUT(mr);
     } else {
 	return PJ_ENOTSUP;
     }
@@ -1195,7 +1192,7 @@
     {
 	mr = waveOutRestart(stream->play_strm.hWave.Out);
 	if (mr != MMSYSERR_NOERROR) {
-	    return CONVERT_MM_ERROR(mr);
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_OUT(mr);
 	}
 	PJ_LOG(4,(THIS_FILE, "WMME playback stream started"));
     }
@@ -1204,7 +1201,7 @@
     {
 	mr = waveInStart(stream->rec_strm.hWave.In);
 	if (mr != MMSYSERR_NOERROR) {
-	    return CONVERT_MM_ERROR(mr);
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_IN(mr);
 	}
 	PJ_LOG(4,(THIS_FILE, "WMME capture stream started"));
     }
@@ -1224,7 +1221,7 @@
     {
 	mr = waveOutPause(stream->play_strm.hWave.Out);
 	if (mr != MMSYSERR_NOERROR) {
-	    return CONVERT_MM_ERROR(mr);
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_OUT(mr);
 	}
 	PJ_LOG(4,(THIS_FILE, "Stopped WMME playback stream"));
     }
@@ -1233,7 +1230,7 @@
     {
 	mr = waveInStop(stream->rec_strm.hWave.In);
 	if (mr != MMSYSERR_NOERROR) {
-	    return CONVERT_MM_ERROR(mr);
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_IN(mr);
 	}
 	PJ_LOG(4,(THIS_FILE, "Stopped WMME capture stream"));
     }
@@ -1303,3 +1300,5 @@
     return PJ_SUCCESS;
 }
 
+#endif	/* PJMEDIA_AUDIO_DEV_HAS_WMME */
+