]> Repos - portaudio/commitdiff
wasapi:
authordmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Fri, 23 Jul 2010 10:04:03 +0000 (10:04 +0000)
committerdmitrykos <dmitrykos@0f58301d-fd10-0410-b4af-bbb618454e57>
Fri, 23 Jul 2010 10:04:03 +0000 (10:04 +0000)
 - added functionality to enumerate jacks and their description
 - added example which demonstrates jacks enumeration technique
Thanks Reid Bishop for providing the idea for this extended functionality and patch with implementation.

build/msvc/portaudio.def
include/pa_win_wasapi.h
src/hostapi/wasapi/pa_win_wasapi.c
test/patest_jack_wasapi.c [new file with mode: 0644]

index 90c01a3be71c681215288df0092293ecb0c3ca4f..d25414fa25bfaf4121dcb6abff5879464d2ebae1 100644 (file)
@@ -45,4 +45,6 @@ PaWasapi_GetDeviceDefaultFormat     @56
 PaWasapi_GetDeviceRole              @57
 PaWasapi_ThreadPriorityBoost        @58
 PaWasapi_ThreadPriorityRevert       @59
-PaWasapi_GetFramesPerHostBuffer     @60
\ No newline at end of file
+PaWasapi_GetFramesPerHostBuffer     @60
+PaWasapi_GetJackDescription         @61
+PaWasapi_GetJackCount               @62
\ No newline at end of file
index a0bcf7ace5bb5cdca28b3c548b36266ad4428266..e949dfe3aadab2f13446edd711fadcf7191e9f65 100644 (file)
@@ -109,6 +109,70 @@ typedef enum PaWasapiDeviceRole
 PaWasapiDeviceRole;\r
 \r
 \r
+/* Jack connection type */\r
+typedef enum PaWasapiJackConnectionType\r
+{\r
+    eJackConnTypeUnknown,\r
+    eJackConnType3Point5mm,\r
+    eJackConnTypeQuarter,\r
+    eJackConnTypeAtapiInternal,\r
+    eJackConnTypeRCA,\r
+    eJackConnTypeOptical,\r
+    eJackConnTypeOtherDigital,\r
+    eJackConnTypeOtherAnalog,\r
+    eJackConnTypeMultichannelAnalogDIN,\r
+    eJackConnTypeXlrProfessional,\r
+    eJackConnTypeRJ11Modem,\r
+    eJackConnTypeCombination\r
+} \r
+PaWasapiJackConnectionType;\r
+\r
+\r
+/* Jack geometric location */\r
+typedef enum PaWasapiJackGeoLocation\r
+{\r
+       eJackGeoLocUnk = 0,\r
+    eJackGeoLocRear = 0x1, /* matches EPcxGeoLocation::eGeoLocRear */\r
+    eJackGeoLocFront,\r
+    eJackGeoLocLeft,\r
+    eJackGeoLocRight,\r
+    eJackGeoLocTop,\r
+    eJackGeoLocBottom,\r
+    eJackGeoLocRearPanel,\r
+    eJackGeoLocRiser,\r
+    eJackGeoLocInsideMobileLid,\r
+    eJackGeoLocDrivebay,\r
+    eJackGeoLocHDMI,\r
+    eJackGeoLocOutsideMobileLid,\r
+    eJackGeoLocATAPI,\r
+    eJackGeoLocReserved5,\r
+    eJackGeoLocReserved6,\r
+} \r
+PaWasapiJackGeoLocation;\r
+\r
+\r
+/* Jack general location */\r
+typedef enum PaWasapiJackGenLocation\r
+{\r
+    eJackGenLocPrimaryBox = 0,\r
+    eJackGenLocInternal,\r
+    eJackGenLocSeparate,\r
+    eJackGenLocOther\r
+} \r
+PaWasapiJackGenLocation;\r
+\r
+\r
+/* Jack's type of port */\r
+typedef enum PaWasapiJackPortConnection\r
+{\r
+    eJackPortConnJack = 0,\r
+    eJackPortConnIntegratedDevice,\r
+    eJackPortConnBothIntegratedAndJack,\r
+    eJackPortConnUnknown\r
+} \r
+PaWasapiJackPortConnection;\r
+\r
+\r
 /* Thread priority */\r
 typedef enum PaWasapiThreadPriority\r
 {\r
@@ -124,6 +188,20 @@ typedef enum PaWasapiThreadPriority
 PaWasapiThreadPriority;\r
 \r
 \r
+/* Stream descriptor. */\r
+typedef struct PaWasapiJackDescription \r
+{\r
+    unsigned long              channelMapping;\r
+    unsigned long              color; /* derived from macro: #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) */\r
+    PaWasapiJackConnectionType connectionType;\r
+    PaWasapiJackGeoLocation    geoLocation;\r
+    PaWasapiJackGenLocation    genLocation;\r
+    PaWasapiJackPortConnection portConnection;\r
+    unsigned int               isConnected;\r
+}\r
+PaWasapiJackDescription;\r
+\r
+\r
 /* Stream descriptor. */\r
 typedef struct PaWasapiStreamInfo \r
 {\r
@@ -223,6 +301,31 @@ PaError PaWasapi_ThreadPriorityRevert( void *hTask );
 PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput, unsigned int *nOutput );\r
 \r
 \r
+/** Get number of jacks associated with a WASAPI device.  Use this method to determine if\r
+    there are any jacks associated with the provided WASAPI device.  Not all audio devices\r
+       will support this capability.  This is valid for both input and output devices.\r
+ @param  nDevice  device index.\r
+ @param  jcount   Number of jacks is returned in this variable\r
+ @return Error code indicating success or failure\r
+ @see PaWasapi_GetJackDescription\r
+ */\r
+PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount);\r
+\r
+\r
+/** Get the jack description associated with a WASAPI device and jack number\r
+    Before this function is called, use PaWasapi_GetJackCount to determine the\r
+       number of jacks associated with device.  If jcount is greater than zero, then\r
+       each jack from 0 to jcount can be queried with this function to get the jack\r
+       description.\r
+ @param  nDevice  device index.\r
+ @param  jindex   Which jack to return information\r
+ @param  KSJACK_DESCRIPTION This structure filled in on success.\r
+ @return Error code indicating success or failure\r
+ @see PaWasapi_GetJackCount\r
+ */\r
+PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription);\r
+\r
+\r
 /*\r
     IMPORTANT:\r
 \r
index ff4a3d38d3c73f96209183494b7eac5975201e45..e3549288ffbf92d1c5b863850ce87334b78030f5 100644 (file)
        #define COBJMACROS\r
        #include <Audioclient.h>\r
        #include <endpointvolume.h>\r
-       #define INITGUID //<< avoid additional linkage of static libs, uneeded code will be optimized out\r
+       #define INITGUID // Avoid additional linkage of static libs, excessive code will be optimized out by the compiler\r
        #include <mmdeviceapi.h>\r
        #include <functiondiscoverykeys.h>\r
+    #include <devicetopology.h>        // Used to get IKsJackDescription interface\r
        #undef INITGUID\r
 #endif\r
 #ifndef __MWERKS__\r
@@ -275,6 +276,12 @@ PA_DEFINE_CLSID(IMMDeviceEnumerator,bcde0395, e52f, 467c, 8e, 3d, c4, 57, 92, 91
 PA_DEFINE_IID(IAudioRenderClient,   f294acfc, 3146, 4483, a7, bf, ad, dc, a7, c2, 60, e2);\r
 // "C8ADBD64-E71E-48a0-A4DE-185C395CD317"\r
 PA_DEFINE_IID(IAudioCaptureClient,  c8adbd64, e71e, 48a0, a4, de, 18, 5c, 39, 5c, d3, 17);\r
+// *2A07407E-6497-4A18-9787-32F79BD0D98F*  Or this??\r
+PA_DEFINE_IID(IDeviceTopology,      2A07407E, 6497, 4A18, 97, 87, 32, f7, 9b, d0, d9, 8f);\r
+// *AE2DE0E4-5BCA-4F2D-AA46-5D13F8FDB3A9*\r
+PA_DEFINE_IID(IPart,                AE2DE0E4, 5BCA, 4F2D, aa, 46, 5d, 13, f8, fd, b3, a9);\r
+// *4509F757-2D46-4637-8E62-CE7DB944F57B*\r
+PA_DEFINE_IID(IKsJackDescription,   4509F757, 2D46, 4637, 8e, 62, ce, 7d, b9, 44, f5, 7b);\r
 // Media formats:\r
 __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_PCM,        0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );\r
 __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_ADPCM,      0x00000002, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );\r
@@ -1422,7 +1429,7 @@ int PaWasapi_GetDeviceRole( PaDeviceIndex nDevice )
        // Get API\r
        PaWasapiHostApiRepresentation *paWasapi = _GetHostApi(&ret);\r
        if (paWasapi == NULL)\r
-               return ret;\r
+               return paNotInitialized;\r
 \r
        // Get device index\r
        ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);\r
@@ -3460,6 +3467,235 @@ PaError PaWasapi_ThreadPriorityRevert(void *hTask)
        return paNoError;\r
 }\r
 \r
+// ------------------------------------------------------------------------------------------\r
+// Described at:\r
+// http://msdn.microsoft.com/en-us/library/dd371387(v=VS.85).aspx\r
+\r
+PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount)\r
+{\r
+       PaError ret;\r
+       HRESULT hr = S_OK;\r
+       PaDeviceIndex index;\r
+    IDeviceTopology *pDeviceTopology = NULL;\r
+    IConnector *pConnFrom = NULL;\r
+    IConnector *pConnTo = NULL;\r
+    IPart *pPart = NULL;\r
+    IKsJackDescription *pJackDesc = NULL;\r
+       UINT jackCount = 0;\r
+\r
+       PaWasapiHostApiRepresentation *paWasapi = _GetHostApi(&ret);\r
+       if (paWasapi == NULL)\r
+               return paNotInitialized;\r
+\r
+       // Get device index.\r
+       ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);\r
+    if (ret != paNoError)\r
+        return ret;\r
+\r
+       // Validate index.\r
+       if ((UINT32)index >= paWasapi->deviceCount)\r
+               return paInvalidDevice;\r
+\r
+       // Get the endpoint device's IDeviceTopology interface.\r
+       hr = IMMDevice_Activate(paWasapi->devInfo[index].device, &pa_IID_IDeviceTopology, \r
+               CLSCTX_INPROC_SERVER, NULL, (void**)&pDeviceTopology);\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+    // The device topology for an endpoint device always contains just one connector (connector number 0).\r
+       hr = IDeviceTopology_GetConnector(pDeviceTopology, 0, &pConnFrom);\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+    // Step across the connection to the jack on the adapter.\r
+       hr = IConnector_GetConnectedTo(pConnFrom, &pConnTo);\r
+    if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)\r
+    {\r
+        // The adapter device is not currently active.\r
+        hr = E_NOINTERFACE;\r
+    }\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+       // Get the connector's IPart interface.\r
+       hr = IConnector_QueryInterface(pConnTo, &pa_IID_IPart, (void**)&pPart);\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+       // Activate the connector's IKsJackDescription interface.\r
+       hr = IPart_Activate(pPart, CLSCTX_INPROC_SERVER, &pa_IID_IKsJackDescription, (void**)&pJackDesc);\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+       // Return jack count for this device.\r
+       hr = IKsJackDescription_GetJackCount(pJackDesc, &jackCount);\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+       // Set.\r
+       (*jcount) = jackCount;\r
+\r
+       // Ok.\r
+       ret = paNoError;\r
+\r
+error:\r
+\r
+       SAFE_RELEASE(pDeviceTopology);\r
+       SAFE_RELEASE(pConnFrom);\r
+       SAFE_RELEASE(pConnTo);\r
+       SAFE_RELEASE(pPart);\r
+       SAFE_RELEASE(pJackDesc);\r
+\r
+       LogHostError(hr);\r
+       return paNoError;\r
+}\r
+\r
+// ------------------------------------------------------------------------------------------\r
+static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connType)\r
+{\r
+       switch (connType)\r
+       {\r
+               case eConnTypeUnknown:                  return eJackConnTypeUnknown;\r
+               case eConnType3Point5mm:                return eJackConnType3Point5mm;\r
+               case eConnTypeQuarter:                  return eJackConnTypeQuarter;\r
+               case eConnTypeAtapiInternal:    return eJackConnTypeAtapiInternal;\r
+               case eConnTypeRCA:                              return eJackConnTypeRCA;\r
+               case eConnTypeOptical:                  return eJackConnTypeOptical;\r
+               case eConnTypeOtherDigital:             return eJackConnTypeOtherDigital;\r
+               case eConnTypeOtherAnalog:              return eJackConnTypeOtherAnalog;\r
+               case eConnTypeMultichannelAnalogDIN: return eJackConnTypeMultichannelAnalogDIN;\r
+               case eConnTypeXlrProfessional:  return eJackConnTypeXlrProfessional;\r
+               case eConnTypeRJ11Modem:                return eJackConnTypeRJ11Modem;\r
+               case eConnTypeCombination:              return eJackConnTypeCombination;\r
+       }\r
+       return eJackConnTypeUnknown;\r
+}\r
+\r
+// ------------------------------------------------------------------------------------------\r
+static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc)\r
+{\r
+       switch (geoLoc)\r
+       {\r
+       case eGeoLocRear:                               return eJackGeoLocRear;\r
+       case eGeoLocFront:                              return eJackGeoLocFront;\r
+       case eGeoLocLeft:                               return eJackGeoLocLeft;\r
+       case eGeoLocRight:                              return eJackGeoLocRight;\r
+       case eGeoLocTop:                                return eJackGeoLocTop;\r
+       case eGeoLocBottom:                             return eJackGeoLocBottom;\r
+       case eGeoLocRearPanel:                  return eJackGeoLocRearPanel;\r
+       case eGeoLocRiser:                              return eJackGeoLocRiser;\r
+       case eGeoLocInsideMobileLid:    return eJackGeoLocInsideMobileLid;\r
+       case eGeoLocDrivebay:                   return eJackGeoLocDrivebay;\r
+       case eGeoLocHDMI:                               return eJackGeoLocHDMI;\r
+       case eGeoLocOutsideMobileLid:   return eJackGeoLocOutsideMobileLid;\r
+       case eGeoLocATAPI:                              return eJackGeoLocATAPI;\r
+       }\r
+       return eJackGeoLocUnk;\r
+}\r
+\r
+// ------------------------------------------------------------------------------------------\r
+static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc)\r
+{\r
+       switch (genLoc)\r
+       {\r
+       case eGenLocPrimaryBox: return eJackGenLocPrimaryBox;\r
+       case eGenLocInternal:   return eJackGenLocInternal;\r
+       case eGenLocSeparate:   return eJackGenLocSeparate;\r
+       case eGenLocOther:              return eJackGenLocOther;\r
+       }\r
+       return eJackGenLocPrimaryBox;\r
+}\r
+\r
+// ------------------------------------------------------------------------------------------\r
+static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portConn)\r
+{\r
+       switch (portConn)\r
+       {\r
+       case ePortConnJack:                                     return eJackPortConnJack;\r
+       case ePortConnIntegratedDevice:         return eJackPortConnIntegratedDevice;\r
+       case ePortConnBothIntegratedAndJack:return eJackPortConnBothIntegratedAndJack;\r
+       case ePortConnUnknown:                          return eJackPortConnUnknown;\r
+       }\r
+       return eJackPortConnJack;\r
+}\r
+\r
+// ------------------------------------------------------------------------------------------\r
+// Described at:\r
+// http://msdn.microsoft.com/en-us/library/dd371387(v=VS.85).aspx\r
+\r
+PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription)\r
+{\r
+       PaError ret;\r
+       HRESULT hr = S_OK;\r
+       PaDeviceIndex index;\r
+    IDeviceTopology *pDeviceTopology = NULL;\r
+    IConnector *pConnFrom = NULL;\r
+    IConnector *pConnTo = NULL;\r
+    IPart *pPart = NULL;\r
+    IKsJackDescription *pJackDesc = NULL;\r
+       KSJACK_DESCRIPTION jack = { 0 };\r
+\r
+       PaWasapiHostApiRepresentation *paWasapi = _GetHostApi(&ret);\r
+       if (paWasapi == NULL)\r
+               return paNotInitialized;\r
+\r
+       // Get device index.\r
+       ret = PaUtil_DeviceIndexToHostApiDeviceIndex(&index, nDevice, &paWasapi->inheritedHostApiRep);\r
+    if (ret != paNoError)\r
+        return ret;\r
+\r
+       // Validate index.\r
+       if ((UINT32)index >= paWasapi->deviceCount)\r
+               return paInvalidDevice;\r
+\r
+       // Get the endpoint device's IDeviceTopology interface.\r
+       hr = IMMDevice_Activate(paWasapi->devInfo[index].device, &pa_IID_IDeviceTopology, \r
+               CLSCTX_INPROC_SERVER, NULL, (void**)&pDeviceTopology);\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+    // The device topology for an endpoint device always contains just one connector (connector number 0).\r
+       hr = IDeviceTopology_GetConnector(pDeviceTopology, 0, &pConnFrom);\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+    // Step across the connection to the jack on the adapter.\r
+       hr = IConnector_GetConnectedTo(pConnFrom, &pConnTo);\r
+    if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr)\r
+    {\r
+        // The adapter device is not currently active.\r
+        hr = E_NOINTERFACE;\r
+    }\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+       // Get the connector's IPart interface.\r
+       hr = IConnector_QueryInterface(pConnTo, &pa_IID_IPart, (void**)&pPart);\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+       // Activate the connector's IKsJackDescription interface.\r
+       hr = IPart_Activate(pPart, CLSCTX_INPROC_SERVER, &pa_IID_IKsJackDescription, (void**)&pJackDesc);\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+       // Test to return jack description struct for index 0.\r
+       hr = IKsJackDescription_GetJackDescription(pJackDesc, jindex, &jack);\r
+       IF_FAILED_JUMP(hr, error);\r
+\r
+       // Convert WASAPI values to PA format.\r
+       pJackDescription->channelMapping = jack.ChannelMapping;\r
+       pJackDescription->color          = jack.Color;\r
+       pJackDescription->connectionType = ConvertJackConnectionTypeWASAPIToPA(jack.ConnectionType);\r
+       pJackDescription->genLocation    = ConvertJackGenLocationWASAPIToPA(jack.GenLocation);\r
+       pJackDescription->geoLocation    = ConvertJackGeoLocationWASAPIToPA(jack.GeoLocation);\r
+       pJackDescription->isConnected    = jack.IsConnected;\r
+       pJackDescription->portConnection = ConvertJackPortConnectionWASAPIToPA(jack.PortConnection);\r
+\r
+       // Ok.\r
+       ret = paNoError;\r
+\r
+error:\r
+\r
+       SAFE_RELEASE(pDeviceTopology);\r
+       SAFE_RELEASE(pConnFrom);\r
+       SAFE_RELEASE(pConnTo);\r
+       SAFE_RELEASE(pPart);\r
+       SAFE_RELEASE(pJackDesc);\r
+\r
+       LogHostError(hr);\r
+       return ret;\r
+}\r
+\r
 // ------------------------------------------------------------------------------------------\r
 static HRESULT ProcessOutputBuffer(PaWasapiStream *stream, PaWasapiHostProcessor *processor, UINT32 frames)\r
 {\r
diff --git a/test/patest_jack_wasapi.c b/test/patest_jack_wasapi.c
new file mode 100644 (file)
index 0000000..fed1b05
--- /dev/null
@@ -0,0 +1,343 @@
+/** @file pa_test_jack_wasapi.c\r
+       @ingroup test_src\r
+       @brief Print out jack information for WASAPI endpoints\r
+       @author Reid Bishop <rbish@attglobal.net>\r
+*/\r
+/*\r
+ * $Id: pa_test_jack_wasapi.c 1368 2008-03-01 00:38:27Z rbishop $\r
+ *\r
+ * This program uses the PortAudio Portable Audio Library.\r
+ * For more information see: http://www.portaudio.com/\r
+ * Copyright (c) 1999-2010 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ */\r
+\r
+/*\r
+ * The text above constitutes the entire PortAudio license; however, \r
+ * the PortAudio community also makes the following non-binding requests:\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version. It is also \r
+ * requested that these non-binding requests be included along with the \r
+ * license above.\r
+ */\r
+#include <stdio.h>\r
+#include "portaudio.h"\r
+#include "pa_win_wasapi.h"\r
+\r
+\r
+/*\r
+* Helper function to determine if a given enum is present in mask variable\r
+*\r
+*/\r
+static int IsInMask(int val, int val2)\r
+{\r
+       return ((val & val2) == val2);\r
+}\r
+\r
+/*\r
+* This routine enumerates through the ChannelMapping for the IJackDescription\r
+*/\r
+\r
+static void EnumIJackChannels(int channelMapping)\r
+{\r
+       printf("Channel Mapping: ");\r
+       if(channelMapping == PAWIN_SPEAKER_DIRECTOUT)\r
+       {\r
+               printf("DIRECTOUT\n");\r
+               return;\r
+       }\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_FRONT_LEFT))\r
+               printf("FRONT_LEFT, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_FRONT_RIGHT))\r
+               printf("FRONT_RIGHT, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_FRONT_CENTER))\r
+               printf("FRONT_CENTER, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_LOW_FREQUENCY))\r
+               printf("LOW_FREQUENCY, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_BACK_LEFT))\r
+               printf("BACK_LEFT, ");\r
+       if(IsInMask(channelMapping,PAWIN_SPEAKER_BACK_RIGHT))\r
+               printf("BACK_RIGHT, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_FRONT_LEFT_OF_CENTER))\r
+               printf("FRONT_LEFT_OF_CENTER, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_FRONT_RIGHT_OF_CENTER))\r
+               printf("FRONT_RIGHT_OF_CENTER, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_BACK_CENTER))\r
+               printf("BACK_CENTER, ");\r
+       if(IsInMask(channelMapping,PAWIN_SPEAKER_SIDE_LEFT))\r
+               printf("SIDE_LEFT, ");\r
+       if(IsInMask(channelMapping,PAWIN_SPEAKER_SIDE_RIGHT))\r
+               printf("SIDE_RIGHT, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_CENTER))\r
+               printf("TOP_CENTER, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_FRONT_LEFT))\r
+               printf("TOP_FRONT_LEFT, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_FRONT_CENTER))\r
+               printf("TOP_FRONT_CENTER, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_FRONT_RIGHT))\r
+               printf("TOP_FRONT_RIGHT, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_BACK_LEFT))\r
+               printf("TOP_BACK_LEFT, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_BACK_CENTER))\r
+               printf("TOP_BACK_CENTER, ");\r
+       if(IsInMask(channelMapping, PAWIN_SPEAKER_TOP_BACK_RIGHT))\r
+               printf("TOP_BACK_RIGHT, ");\r
+\r
+       printf("\n");\r
+}\r
+\r
+/*\r
+* This routine enumerates through the Jack Connection Types enums for IJackDescription\r
+*/\r
+static void EnumIJackConnectionType(int cType)\r
+{\r
+       printf("Connection Type: ");\r
+       switch(cType)\r
+       {\r
+               case eJackConnTypeUnknown:\r
+                       printf("eJackConnTypeUnknown");\r
+                       break;\r
+               case eJackConnType3Point5mm:\r
+                       printf("eJackConnType3Point5mm");\r
+                       break;\r
+               case eJackConnTypeQuarter:\r
+                       printf("eJackConnTypeQuarter");\r
+                       break;\r
+               case eJackConnTypeAtapiInternal:\r
+                       printf("eJackConnTypeAtapiInternal");\r
+                       break;\r
+               case eJackConnTypeRCA:\r
+                       printf("eJackConnTypeRCA");\r
+                       break;\r
+               case eJackConnTypeOptical:\r
+                       printf("eJackConnTypeOptical");\r
+                       break;\r
+               case eJackConnTypeOtherDigital:\r
+                       printf("eJackConnTypeOtherDigital");\r
+                       break;\r
+               case eJackConnTypeOtherAnalog:\r
+                       printf("eJackConnTypeOtherAnalog");\r
+                       break;\r
+               case eJackConnTypeMultichannelAnalogDIN:\r
+                       printf("eJackConnTypeMultichannelAnalogDIN");\r
+                       break;\r
+               case eJackConnTypeXlrProfessional:\r
+                       printf("eJackConnTypeXlrProfessional");\r
+                       break;\r
+               case eJackConnTypeRJ11Modem:\r
+                       printf("eJackConnTypeRJ11Modem");\r
+                       break;\r
+               case eJackConnTypeCombination:\r
+                       printf("eJackConnTypeCombination");\r
+                       break;\r
+       }\r
+       printf("\n");\r
+}\r
+\r
+/*\r
+* This routine enumerates through the GeoLocation enums for the IJackDescription\r
+*/\r
+static void EnumIJackGeoLocation(int iVal)\r
+{\r
+       printf("Geometric Location: ");\r
+       switch(iVal)\r
+       {\r
+       case eJackGeoLocRear:\r
+               printf("eJackGeoLocRear");\r
+               break;\r
+       case eJackGeoLocFront:\r
+               printf("eJackGeoLocFront");\r
+               break;\r
+       case eJackGeoLocLeft:\r
+               printf("eJackGeoLocLeft");\r
+               break;\r
+       case eJackGeoLocRight:\r
+               printf("eJackGeoLocRight");\r
+               break;\r
+       case eJackGeoLocTop:\r
+               printf("eJackGeoLocTop");\r
+               break;\r
+       case eJackGeoLocBottom:\r
+               printf("eJackGeoLocBottom");\r
+               break;\r
+       case eJackGeoLocRearPanel:\r
+               printf("eJackGeoLocRearPanel");\r
+               break;\r
+       case eJackGeoLocRiser:\r
+               printf("eJackGeoLocRiser");\r
+               break;\r
+       case eJackGeoLocInsideMobileLid:\r
+               printf("eJackGeoLocInsideMobileLid");\r
+               break;\r
+       case eJackGeoLocDrivebay:\r
+               printf("eJackGeoLocDrivebay");\r
+               break;\r
+       case eJackGeoLocHDMI:\r
+               printf("eJackGeoLocHDMI");\r
+               break;\r
+       case eJackGeoLocOutsideMobileLid:\r
+               printf("eJackGeoLocOutsideMobileLid");\r
+               break;\r
+       case eJackGeoLocATAPI:\r
+               printf("eJackGeoLocATAPI");\r
+               break;\r
+       }\r
+       printf("\n");\r
+}\r
+\r
+/*\r
+* This routine enumerates through the GenLocation enums for the IJackDescription\r
+*/\r
+static void EnumIJackGenLocation(int iVal)\r
+{\r
+       printf("General Location: ");\r
+       switch(iVal)\r
+       {\r
+               case eJackGenLocPrimaryBox:\r
+                       printf("eJackGenLocPrimaryBox");\r
+                       break;\r
+               case eJackGenLocInternal:\r
+                       printf("eJackGenLocInternal");\r
+                       break;\r
+               case eJackGenLocSeparate:\r
+                       printf("eJackGenLocSeparate");\r
+                       break;\r
+               case eJackGenLocOther:\r
+                       printf("eJackGenLocOther");\r
+                       break;\r
+       }\r
+       printf("\n");\r
+}\r
+\r
+/*\r
+* This routine enumerates through the PortConnection enums for the IJackDescription\r
+*/\r
+static void EnumIJackPortConnection(int iVal)\r
+{\r
+       printf("Port Type: ");\r
+       switch(iVal)\r
+       {\r
+               case eJackPortConnJack:\r
+                       printf("eJackPortConnJack");\r
+                       break;\r
+               case eJackPortConnIntegratedDevice:\r
+                       printf("eJackPortConnIntegratedDevice");\r
+                       break;\r
+               case eJackPortConnBothIntegratedAndJack:\r
+                       printf("eJackPortConnBothIntegratedAndJack");\r
+                       break;\r
+               case eJackPortConnUnknown:\r
+                       printf("eJackPortConnUnknown");\r
+                       break;\r
+       }\r
+       printf("\n");\r
+}\r
+\r
+/*\r
+* This routine retrieves and parses the KSJACK_DESCRIPTION structure for\r
+* the provided device ID.\r
+*/\r
+static PaError GetJackInformation(int deviceId)\r
+{\r
+    PaError err;\r
+       int i;\r
+       int jackCount = 0;\r
+       PaWasapiJackDescription jackDesc;\r
+\r
+       err = PaWasapi_GetJackCount(deviceId, &jackCount);\r
+       if( err != paNoError ) return err;\r
+\r
+       fprintf( stderr,"Number of Jacks: %d \n", jackCount );\r
+\r
+       for( i = 0; i<jackCount; i++ )\r
+       {\r
+               fprintf( stderr,"Jack #%d:\n", i );\r
+\r
+               err = PaWasapi_GetJackDescription(deviceId, i, &jackDesc);\r
+               if( err != paNoError ) \r
+               {\r
+                       fprintf( stderr,"Failed getting description." );\r
+                       continue;\r
+               }\r
+               else\r
+               {\r
+                       printf("Is connected: %s\n",(jackDesc.isConnected)?"true":"false");\r
+                       EnumIJackChannels(jackDesc.channelMapping);\r
+                       EnumIJackConnectionType(jackDesc.connectionType);\r
+                       EnumIJackGeoLocation(jackDesc.geoLocation);\r
+                       EnumIJackGenLocation(jackDesc.genLocation);\r
+                       EnumIJackPortConnection(jackDesc.portConnection);\r
+                       printf("Jack Color: 0x%06X\n", jackDesc.color);\r
+                       printf("\n");\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+/*******************************************************************/\r
+int main(void);\r
+int main(void)\r
+{\r
+    PaError err;\r
+       const PaDeviceInfo *device;\r
+    int i;\r
+       int jackCount = 0;\r
+       int isInput = 0;\r
+\r
+       printf("PortAudio Test: WASAPI Jack Configuratin");\r
+    err = Pa_Initialize();\r
+    if( err != paNoError ) goto error;\r
+\r
+       /* Find all WASAPI devices */\r
+       for( i = 0; i < Pa_GetDeviceCount(); ++i )\r
+       {\r
+               device = Pa_GetDeviceInfo(i);\r
+               if( Pa_GetDeviceInfo(i)->hostApi == Pa_HostApiTypeIdToHostApiIndex(paWASAPI) )\r
+               {\r
+                       if( device->maxOutputChannels == 0 )\r
+                       {\r
+                               isInput = 1;\r
+                       }\r
+                       printf("------------------------------------------\n");\r
+                       printf("Device: %s",device->name);\r
+                       if(isInput)\r
+                               printf("  (Input) %d Channels\n",device->maxInputChannels);\r
+                       else\r
+                               printf("  (Output) %d Channels\n",device->maxOutputChannels);\r
+                       // Try to see if this WASAPI device can provide Jack information\r
+                       err = GetJackInformation(i);\r
+                       if( err != paNoError ) goto error;\r
+               }\r
+       }\r
+    Pa_Terminate();\r
+    printf("Test finished.\n");\r
+    return err;\r
+\r
+error:\r
+    Pa_Terminate();\r
+    fprintf( stderr, "An error occured while using the portaudio stream\n" );\r
+    fprintf( stderr, "Error number: %d\n", err );\r
+    fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );\r
+    return err;\r
+}\r