pa_win_wdmks_utils.c (11563B)
1 /* 2 * PortAudio Portable Real-Time Audio Library 3 * Windows WDM KS utilities 4 * 5 * Copyright (c) 1999 - 2007 Andrew Baldwin, Ross Bencina 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining 8 * a copy of this software and associated documentation files 9 * (the "Software"), to deal in the Software without restriction, 10 * including without limitation the rights to use, copy, modify, merge, 11 * publish, distribute, sublicense, and/or sell copies of the Software, 12 * and to permit persons to whom the Software is furnished to do so, 13 * subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be 16 * included in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 23 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 /* 28 * The text above constitutes the entire PortAudio license; however, 29 * the PortAudio community also makes the following non-binding requests: 30 * 31 * Any person wishing to distribute modifications to the Software is 32 * requested to send the modifications to the original developer so that 33 * they can be incorporated into the canonical version. It is also 34 * requested that these non-binding requests be included along with the 35 * license above. 36 */ 37 38 #include <windows.h> 39 #include <mmreg.h> 40 #ifndef WAVE_FORMAT_IEEE_FLOAT 41 #define WAVE_FORMAT_IEEE_FLOAT 0x0003 // MinGW32 does not define this 42 #endif 43 #ifndef _WAVEFORMATEXTENSIBLE_ 44 #define _WAVEFORMATEXTENSIBLE_ // MinGW32 does not define this 45 #endif 46 #ifndef _INC_MMREG 47 #define _INC_MMREG // for STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT 48 #endif 49 #include <winioctl.h> // MinGW32 does not define this automatically 50 51 #if defined(__GNUC__) 52 53 #include "../../hostapi/wasapi/mingw-include/ks.h" 54 #include "../../hostapi/wasapi/mingw-include/ksmedia.h" 55 56 #else 57 58 #include <ks.h> 59 #include <ksmedia.h> 60 61 #endif 62 63 #include <stdio.h> // just for some development printfs 64 65 #include "portaudio.h" 66 #include "pa_util.h" 67 #include "pa_win_wdmks_utils.h" 68 69 70 /* PortAudio-local instances of GUIDs previously sourced from ksguid.lib */ 71 72 /* GUID KSDATAFORMAT_TYPE_AUDIO */ 73 static const GUID pa_KSDATAFORMAT_TYPE_AUDIO = { STATIC_KSDATAFORMAT_TYPE_AUDIO }; 74 75 /* GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT */ 76 static const GUID pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT }; 77 78 /* GUID KSDATAFORMAT_SUBTYPE_PCM */ 79 static const GUID pa_KSDATAFORMAT_SUBTYPE_PCM = { STATIC_KSDATAFORMAT_SUBTYPE_PCM }; 80 81 /* GUID KSDATAFORMAT_SUBTYPE_WAVEFORMATEX */ 82 static const GUID pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX = { STATIC_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX }; 83 84 /* GUID KSMEDIUMSETID_Standard */ 85 static const GUID pa_KSMEDIUMSETID_Standard = { STATIC_KSMEDIUMSETID_Standard }; 86 87 /* GUID KSINTERFACESETID_Standard */ 88 static const GUID pa_KSINTERFACESETID_Standard = { STATIC_KSINTERFACESETID_Standard }; 89 90 /* GUID KSPROPSETID_Pin */ 91 static const GUID pa_KSPROPSETID_Pin = { STATIC_KSPROPSETID_Pin }; 92 93 #define pa_IS_VALID_WAVEFORMATEX_GUID(Guid)\ 94 (!memcmp(((PUSHORT)&pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX) + 1, ((PUSHORT)(Guid)) + 1, sizeof(GUID) - sizeof(USHORT))) 95 96 97 static PaError WdmGetPinPropertySimple( 98 HANDLE handle, 99 unsigned long pinId, 100 unsigned long property, 101 void* value, 102 unsigned long valueSize ) 103 { 104 DWORD bytesReturned; 105 KSP_PIN ksPProp; 106 ksPProp.Property.Set = pa_KSPROPSETID_Pin; 107 ksPProp.Property.Id = property; 108 ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; 109 ksPProp.PinId = pinId; 110 ksPProp.Reserved = 0; 111 112 if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN), 113 value, valueSize, &bytesReturned, NULL ) == 0 || bytesReturned != valueSize ) 114 { 115 return paUnanticipatedHostError; 116 } 117 else 118 { 119 return paNoError; 120 } 121 } 122 123 124 static PaError WdmGetPinPropertyMulti( 125 HANDLE handle, 126 unsigned long pinId, 127 unsigned long property, 128 KSMULTIPLE_ITEM** ksMultipleItem) 129 { 130 unsigned long multipleItemSize = 0; 131 KSP_PIN ksPProp; 132 DWORD bytesReturned; 133 134 *ksMultipleItem = 0; 135 136 ksPProp.Property.Set = pa_KSPROPSETID_Pin; 137 ksPProp.Property.Id = property; 138 ksPProp.Property.Flags = KSPROPERTY_TYPE_GET; 139 ksPProp.PinId = pinId; 140 ksPProp.Reserved = 0; 141 142 if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp.Property, 143 sizeof(KSP_PIN), NULL, 0, &multipleItemSize, NULL ) == 0 && GetLastError() != ERROR_MORE_DATA ) 144 { 145 return paUnanticipatedHostError; 146 } 147 148 *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize ); 149 if( !*ksMultipleItem ) 150 { 151 return paInsufficientMemory; 152 } 153 154 if( DeviceIoControl( handle, IOCTL_KS_PROPERTY, &ksPProp, sizeof(KSP_PIN), 155 (void*)*ksMultipleItem, multipleItemSize, &bytesReturned, NULL ) == 0 || bytesReturned != multipleItemSize ) 156 { 157 PaUtil_FreeMemory( ksMultipleItem ); 158 return paUnanticipatedHostError; 159 } 160 161 return paNoError; 162 } 163 164 165 static int GetKSFilterPinCount( HANDLE deviceHandle ) 166 { 167 DWORD result; 168 169 if( WdmGetPinPropertySimple( deviceHandle, 0, KSPROPERTY_PIN_CTYPES, &result, sizeof(result) ) == paNoError ){ 170 return result; 171 }else{ 172 return 0; 173 } 174 } 175 176 177 static KSPIN_COMMUNICATION GetKSFilterPinPropertyCommunication( HANDLE deviceHandle, int pinId ) 178 { 179 KSPIN_COMMUNICATION result; 180 181 if( WdmGetPinPropertySimple( deviceHandle, pinId, KSPROPERTY_PIN_COMMUNICATION, &result, sizeof(result) ) == paNoError ){ 182 return result; 183 }else{ 184 return KSPIN_COMMUNICATION_NONE; 185 } 186 } 187 188 189 static KSPIN_DATAFLOW GetKSFilterPinPropertyDataflow( HANDLE deviceHandle, int pinId ) 190 { 191 KSPIN_DATAFLOW result; 192 193 if( WdmGetPinPropertySimple( deviceHandle, pinId, KSPROPERTY_PIN_DATAFLOW, &result, sizeof(result) ) == paNoError ){ 194 return result; 195 }else{ 196 return (KSPIN_DATAFLOW)0; 197 } 198 } 199 200 201 static int KSFilterPinPropertyIdentifiersInclude( 202 HANDLE deviceHandle, int pinId, unsigned long property, const GUID *identifierSet, unsigned long identifierId ) 203 { 204 KSMULTIPLE_ITEM* item = NULL; 205 KSIDENTIFIER* identifier; 206 int i; 207 int result = 0; 208 209 if( WdmGetPinPropertyMulti( deviceHandle, pinId, property, &item) != paNoError ) 210 return 0; 211 212 identifier = (KSIDENTIFIER*)(item+1); 213 214 for( i = 0; i < (int)item->Count; i++ ) 215 { 216 if( !memcmp( (void*)&identifier[i].Set, (void*)identifierSet, sizeof( GUID ) ) && 217 ( identifier[i].Id == identifierId ) ) 218 { 219 result = 1; 220 break; 221 } 222 } 223 224 PaUtil_FreeMemory( item ); 225 226 return result; 227 } 228 229 230 /* return the maximum channel count supported by any pin on the device. 231 if isInput is non-zero we query input pins, otherwise output pins. 232 */ 233 int PaWin_WDMKS_QueryFilterMaximumChannelCount( void *wcharDevicePath, int isInput ) 234 { 235 HANDLE deviceHandle; 236 ULONG i; 237 int pinCount, pinId; 238 int result = 0; 239 KSPIN_DATAFLOW requiredDataflowDirection = (isInput ? KSPIN_DATAFLOW_OUT : KSPIN_DATAFLOW_IN ); 240 241 if( !wcharDevicePath ) 242 return 0; 243 244 deviceHandle = CreateFileW( (LPCWSTR)wcharDevicePath, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); 245 if( deviceHandle == INVALID_HANDLE_VALUE ) 246 return 0; 247 248 pinCount = GetKSFilterPinCount( deviceHandle ); 249 for( pinId = 0; pinId < pinCount; ++pinId ) 250 { 251 KSPIN_COMMUNICATION communication = GetKSFilterPinPropertyCommunication( deviceHandle, pinId ); 252 KSPIN_DATAFLOW dataflow = GetKSFilterPinPropertyDataflow( deviceHandle, pinId ); 253 if( ( dataflow == requiredDataflowDirection ) && 254 (( communication == KSPIN_COMMUNICATION_SINK) || 255 ( communication == KSPIN_COMMUNICATION_BOTH)) 256 && ( KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, 257 KSPROPERTY_PIN_INTERFACES, &pa_KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_STREAMING ) 258 || KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, 259 KSPROPERTY_PIN_INTERFACES, &pa_KSINTERFACESETID_Standard, KSINTERFACE_STANDARD_LOOPED_STREAMING ) ) 260 && KSFilterPinPropertyIdentifiersInclude( deviceHandle, pinId, 261 KSPROPERTY_PIN_MEDIUMS, &pa_KSMEDIUMSETID_Standard, KSMEDIUM_STANDARD_DEVIO ) ) 262 { 263 KSMULTIPLE_ITEM* item = NULL; 264 if( WdmGetPinPropertyMulti( deviceHandle, pinId, KSPROPERTY_PIN_DATARANGES, &item ) == paNoError ) 265 { 266 KSDATARANGE *dataRange = (KSDATARANGE*)(item+1); 267 268 for( i=0; i < item->Count; ++i ){ 269 270 if( pa_IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) 271 || memcmp( (void*)&dataRange->SubFormat, (void*)&pa_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID) ) == 0 272 || memcmp( (void*)&dataRange->SubFormat, (void*)&pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID) ) == 0 273 || ( ( memcmp( (void*)&dataRange->MajorFormat, (void*)&pa_KSDATAFORMAT_TYPE_AUDIO, sizeof(GUID) ) == 0 ) 274 && ( memcmp( (void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_WILDCARD, sizeof(GUID) ) == 0 ) ) ) 275 { 276 KSDATARANGE_AUDIO *dataRangeAudio = (KSDATARANGE_AUDIO*)dataRange; 277 278 /* 279 printf( ">>> %d %d %d %d %S\n", isInput, dataflow, communication, dataRangeAudio->MaximumChannels, devicePath ); 280 281 if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_WAVEFORMATEX, sizeof(GUID) ) == 0 ) 282 printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_WAVEFORMATEX\n" ); 283 else if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_DSOUND, sizeof(GUID) ) == 0 ) 284 printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_DSOUND\n" ); 285 else if( memcmp((void*)&dataRange->Specifier, (void*)&KSDATAFORMAT_SPECIFIER_WILDCARD, sizeof(GUID) ) == 0 ) 286 printf( "\tspecifier: KSDATAFORMAT_SPECIFIER_WILDCARD\n" ); 287 else 288 printf( "\tspecifier: ?\n" ); 289 */ 290 291 /* 292 We assume that very high values for MaximumChannels are not useful and indicate 293 that the driver isn't prepared to tell us the real number of channels which it supports. 294 */ 295 if( dataRangeAudio->MaximumChannels < 0xFFFFUL && (int)dataRangeAudio->MaximumChannels > result ) 296 result = (int)dataRangeAudio->MaximumChannels; 297 } 298 299 dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize); 300 } 301 302 PaUtil_FreeMemory( item ); 303 } 304 } 305 } 306 307 CloseHandle( deviceHandle ); 308 return result; 309 }