diff --git a/Externals/portaudio/CMakeLists.txt b/Externals/portaudio/CMakeLists.txt index 3522142378..a8b7534cc3 100644 --- a/Externals/portaudio/CMakeLists.txt +++ b/Externals/portaudio/CMakeLists.txt @@ -137,6 +137,8 @@ IF(WIN32) SET(PA_PRIVATE_INCLUDES ${PA_PRIVATE_INCLUDES} ${PA_PLATFORM_INCLUDES}) SET(PA_PRIVATE_INCLUDE_PATHS ${PA_PRIVATE_INCLUDE_PATHS} src/os/win) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} winmm) + # Try to find ASIO SDK (assumes that portaudio and asiosdk folders are side-by-side, see # http://www.portaudio.com/trac/wiki/TutorialDir/Compile/WindowsASIOMSVC) FIND_PACKAGE(ASIOSDK) @@ -156,7 +158,7 @@ IF(WIN32) SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_asio.h) SET(PA_SOURCES ${PA_SOURCES} ${PA_ASIO_SOURCES}) SET(PA_NON_UNICODE_SOURCES ${PA_NON_UNICODE_SOURCES} ${PA_ASIOSDK_SOURCES}) - SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} winmm ole32 uuid) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} ole32 uuid) ELSE() # Set variables for DEF file expansion SET(DEF_EXCLUDE_ASIO_SYMBOLS ";") @@ -195,6 +197,7 @@ IF(WIN32) SOURCE_GROUP("hostapi\\wmme" FILES ${PA_WMME_SOURCES}) SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_win_wmme.h) SET(PA_SOURCES ${PA_SOURCES} ${PA_WMME_SOURCES}) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} ole32 uuid) ENDIF() IF(MSVS) @@ -209,6 +212,7 @@ IF(WIN32) SOURCE_GROUP("hostapi\\wasapi" FILES ${PA_WASAPI_SOURCES}) SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_win_wasapi.h) SET(PA_SOURCES ${PA_SOURCES} ${PA_WASAPI_SOURCES}) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} ole32 uuid) IF(NOT MSVC) SET(PA_PRIVATE_INCLUDE_PATHS ${PA_PRIVATE_INCLUDE_PATHS} src/hostapi/wasapi/mingw-include) ENDIF() @@ -222,8 +226,7 @@ IF(WIN32) SOURCE_GROUP("hostapi\\wdmks" FILES ${PA_WDMKS_SOURCES}) SET(PA_PUBLIC_INCLUDES ${PA_PUBLIC_INCLUDES} include/pa_win_wdmks.h) SET(PA_SOURCES ${PA_SOURCES} ${PA_WDMKS_SOURCES}) - # If we use WDM/KS we need setupapi.lib - SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} setupapi) + SET(PA_LIBRARY_DEPENDENCIES ${PA_LIBRARY_DEPENDENCIES} setupapi ole32 uuid) ENDIF() OPTION(PA_USE_WDMKS_DEVICE_INFO "Use WDM/KS API for device info" ON) @@ -250,7 +253,7 @@ ELSE() IF(APPLE) - # SET(CMAKE_MACOSX_RPATH 1) + SET(CMAKE_MACOSX_RPATH 1) OPTION(PA_USE_COREAUDIO "Enable support for CoreAudio" ON) IF(PA_USE_COREAUDIO) SET(PA_COREAUDIO_SOURCES @@ -344,14 +347,14 @@ ENDIF() ADD_LIBRARY(portaudio SHARED ${PA_INCLUDES} ${PA_COMMON_INCLUDES} ${PA_SOURCES} ${PA_NON_UNICODE_SOURCES} ${PA_EXTRA_SHARED_SOURCES}) SET_PROPERTY(TARGET portaudio APPEND_STRING PROPERTY COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS}) -TARGET_INCLUDE_DIRECTORIES(portaudio PRIVATE ${PA_PRIVATE_INCLUDE_PATHS}) -TARGET_INCLUDE_DIRECTORIES(portaudio PUBLIC include) +TARGET_INCLUDE_DIRECTORIES(portaudio BEFORE PRIVATE ${PA_PRIVATE_INCLUDE_PATHS}) +TARGET_INCLUDE_DIRECTORIES(portaudio BEFORE PUBLIC include) TARGET_LINK_LIBRARIES(portaudio ${PA_LIBRARY_DEPENDENCIES}) ADD_LIBRARY(portaudio_static STATIC ${PA_INCLUDES} ${PA_COMMON_INCLUDES} ${PA_SOURCES} ${PA_NON_UNICODE_SOURCES}) SET_PROPERTY(TARGET portaudio_static APPEND_STRING PROPERTY COMPILE_DEFINITIONS ${PA_PRIVATE_COMPILE_DEFINITIONS}) -TARGET_INCLUDE_DIRECTORIES(portaudio_static PRIVATE ${PA_PRIVATE_INCLUDE_PATHS}) -TARGET_INCLUDE_DIRECTORIES(portaudio_static PUBLIC include) +TARGET_INCLUDE_DIRECTORIES(portaudio_static BEFORE PRIVATE ${PA_PRIVATE_INCLUDE_PATHS}) +TARGET_INCLUDE_DIRECTORIES(portaudio_static BEFORE PUBLIC include) TARGET_LINK_LIBRARIES(portaudio_static ${PA_LIBRARY_DEPENDENCIES}) IF(WIN32 AND MSVC) @@ -402,3 +405,4 @@ OPTION(PA_BUILD_EXAMPLES "Include example projects" OFF) IF(PA_BUILD_EXAMPLES) SUBDIRS(examples) ENDIF() + diff --git a/Externals/portaudio/cmake_support/template_portaudio.def b/Externals/portaudio/cmake_support/template_portaudio.def index 33e7a1b4d8..d05da59ab1 100644 --- a/Externals/portaudio/cmake_support/template_portaudio.def +++ b/Externals/portaudio/cmake_support/template_portaudio.def @@ -1,53 +1,53 @@ -; $Id: $ -; -; !!! @GENERATED_MESSAGE@ !!! -EXPORTS - -; -Pa_GetVersion @1 -Pa_GetVersionText @2 -Pa_GetErrorText @3 -Pa_Initialize @4 -Pa_Terminate @5 -Pa_GetHostApiCount @6 -Pa_GetDefaultHostApi @7 -Pa_GetHostApiInfo @8 -Pa_HostApiTypeIdToHostApiIndex @9 -Pa_HostApiDeviceIndexToDeviceIndex @10 -Pa_GetLastHostErrorInfo @11 -Pa_GetDeviceCount @12 -Pa_GetDefaultInputDevice @13 -Pa_GetDefaultOutputDevice @14 -Pa_GetDeviceInfo @15 -Pa_IsFormatSupported @16 -Pa_OpenStream @17 -Pa_OpenDefaultStream @18 -Pa_CloseStream @19 -Pa_SetStreamFinishedCallback @20 -Pa_StartStream @21 -Pa_StopStream @22 -Pa_AbortStream @23 -Pa_IsStreamStopped @24 -Pa_IsStreamActive @25 -Pa_GetStreamInfo @26 -Pa_GetStreamTime @27 -Pa_GetStreamCpuLoad @28 -Pa_ReadStream @29 -Pa_WriteStream @30 -Pa_GetStreamReadAvailable @31 -Pa_GetStreamWriteAvailable @32 -Pa_GetSampleSize @33 -Pa_Sleep @34 -@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_GetAvailableBufferSizes @50 -@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_ShowControlPanel @51 -@DEF_EXCLUDE_X86_PLAIN_CONVERTERS@PaUtil_InitializeX86PlainConverters @52 -@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_GetInputChannelName @53 -@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_GetOutputChannelName @54 -PaUtil_SetDebugPrintFunction @55 -@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetDeviceDefaultFormat @56 -@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetDeviceRole @57 -@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_ThreadPriorityBoost @58 -@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_ThreadPriorityRevert @59 -@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetFramesPerHostBuffer @60 -@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetJackDescription @61 -@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetJackCount @62 +; $Id: $ +; +; !!! @GENERATED_MESSAGE@ !!! +EXPORTS + +; +Pa_GetVersion @1 +Pa_GetVersionText @2 +Pa_GetErrorText @3 +Pa_Initialize @4 +Pa_Terminate @5 +Pa_GetHostApiCount @6 +Pa_GetDefaultHostApi @7 +Pa_GetHostApiInfo @8 +Pa_HostApiTypeIdToHostApiIndex @9 +Pa_HostApiDeviceIndexToDeviceIndex @10 +Pa_GetLastHostErrorInfo @11 +Pa_GetDeviceCount @12 +Pa_GetDefaultInputDevice @13 +Pa_GetDefaultOutputDevice @14 +Pa_GetDeviceInfo @15 +Pa_IsFormatSupported @16 +Pa_OpenStream @17 +Pa_OpenDefaultStream @18 +Pa_CloseStream @19 +Pa_SetStreamFinishedCallback @20 +Pa_StartStream @21 +Pa_StopStream @22 +Pa_AbortStream @23 +Pa_IsStreamStopped @24 +Pa_IsStreamActive @25 +Pa_GetStreamInfo @26 +Pa_GetStreamTime @27 +Pa_GetStreamCpuLoad @28 +Pa_ReadStream @29 +Pa_WriteStream @30 +Pa_GetStreamReadAvailable @31 +Pa_GetStreamWriteAvailable @32 +Pa_GetSampleSize @33 +Pa_Sleep @34 +@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_GetAvailableBufferSizes @50 +@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_ShowControlPanel @51 +@DEF_EXCLUDE_X86_PLAIN_CONVERTERS@PaUtil_InitializeX86PlainConverters @52 +@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_GetInputChannelName @53 +@DEF_EXCLUDE_ASIO_SYMBOLS@PaAsio_GetOutputChannelName @54 +PaUtil_SetDebugPrintFunction @55 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetDeviceDefaultFormat @56 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetDeviceRole @57 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_ThreadPriorityBoost @58 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_ThreadPriorityRevert @59 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetFramesPerHostBuffer @60 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetJackDescription @61 +@DEF_EXCLUDE_WASAPI_SYMBOLS@PaWasapi_GetJackCount @62 diff --git a/Externals/portaudio/include/pa_asio.h b/Externals/portaudio/include/pa_asio.h index 8f4624e686..9c606a9c7c 100644 --- a/Externals/portaudio/include/pa_asio.h +++ b/Externals/portaudio/include/pa_asio.h @@ -1,7 +1,7 @@ #ifndef PA_ASIO_H #define PA_ASIO_H /* - * $Id: pa_asio.h 1667 2011-05-02 15:49:20Z rossb $ + * $Id$ * PortAudio Portable Real-Time Audio Library * ASIO specific extensions * diff --git a/Externals/portaudio/include/pa_linux_alsa.h b/Externals/portaudio/include/pa_linux_alsa.h index 21627bdf11..7ac6736456 100644 --- a/Externals/portaudio/include/pa_linux_alsa.h +++ b/Externals/portaudio/include/pa_linux_alsa.h @@ -2,7 +2,7 @@ #define PA_LINUX_ALSA_H /* - * $Id: pa_linux_alsa.h 1597 2011-02-11 00:15:51Z dmitrykos $ + * $Id$ * PortAudio Portable Real-Time Audio Library * ALSA-specific extensions * diff --git a/Externals/portaudio/include/pa_mac_core.h b/Externals/portaudio/include/pa_mac_core.h index f7a90f08ff..83e40a6ac5 100644 --- a/Externals/portaudio/include/pa_mac_core.h +++ b/Externals/portaudio/include/pa_mac_core.h @@ -46,7 +46,7 @@ #include "portaudio.h" #include -//#include +#include #ifdef __cplusplus extern "C" { @@ -124,6 +124,19 @@ AudioDeviceID PaMacCore_GetStreamOutputDevice( PaStream* s ); */ const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ); + +/** Retrieve the range of legal native buffer sizes for the specificed device, in sample frames. + + @param device The global index of the PortAudio device about which the query is being made. + @param minBufferSizeFrames A pointer to the location which will receive the minimum buffer size value. + @param maxBufferSizeFrames A pointer to the location which will receive the maximum buffer size value. + + @see kAudioDevicePropertyBufferFrameSizeRange in the CoreAudio SDK. + */ +PaError PaMacCore_GetBufferSizeRange( PaDeviceIndex device, + long *minBufferSizeFrames, long *maxBufferSizeFrames ); + + /** * Flags */ diff --git a/Externals/portaudio/include/pa_win_ds.h b/Externals/portaudio/include/pa_win_ds.h index 0833a4c0d0..5d3864168c 100644 --- a/Externals/portaudio/include/pa_win_ds.h +++ b/Externals/portaudio/include/pa_win_ds.h @@ -61,24 +61,21 @@ typedef struct PaWinDirectSoundStreamInfo{ PaHostApiTypeId hostApiType; /**< paDirectSound */ unsigned long version; /**< 2 */ - unsigned long flags; + unsigned long flags; /**< enable other features of this struct */ - /* low-level latency setting support - Control the size of host buffers in order to set latency. They will - be used instead of the generic parameters to Pa_OpenStream() if - flags contains the paWinDirectSoundUseLowLevelLatencyParameters - flag. + /** + low-level latency setting support + Sets the size of the DirectSound host buffer. + When flags contains the paWinDirectSoundUseLowLevelLatencyParameters + this size will be used instead of interpreting the generic latency + parameters to Pa_OpenStream(). If the flag is not set this value is ignored. - If PaWinDirectSoundStreamInfo structures with paWinDirectSoundUseLowLevelLatencyParameters - are supplied for both input and output in a full duplex stream, then the - input and output framesPerBuffer must be the same, or the larger of the - two must be a multiple of the smaller, otherwise a - paIncompatibleHostApiSpecificStreamInfo error will be returned from - Pa_OpenStream(). + If the stream is a full duplex stream the implementation requires that + the values of framesPerBuffer for input and output match (if both are specified). */ - unsigned long framesPerBuffer; /* NOT IMPLEMENTED see http://www.portaudio.com/trac/ticket/129 */ + unsigned long framesPerBuffer; - /* + /** support for WAVEFORMATEXTENSIBLE channel masks. If flags contains paWinDirectSoundUseChannelMask this allows you to specify which speakers to address in a multichannel stream. Constants for channelMask diff --git a/Externals/portaudio/include/pa_win_wasapi.h b/Externals/portaudio/include/pa_win_wasapi.h index a60aa047a6..1d86896cae 100644 --- a/Externals/portaudio/include/pa_win_wasapi.h +++ b/Externals/portaudio/include/pa_win_wasapi.h @@ -69,8 +69,8 @@ typedef enum PaWasapiFlags method can only provide 15-20ms latency. */ paWinWasapiPolling = (1 << 3), - /* forces custom thread priority setting. must be used if PaWasapiStreamInfo::threadPriority - is set to custom value. */ + /* forces custom thread priority setting, must be used if PaWasapiStreamInfo::threadPriority + is set to a custom value */ paWinWasapiThreadPriority = (1 << 4) } PaWasapiFlags; @@ -91,7 +91,7 @@ typedef void (*PaWasapiHostProcessorCallback) (void *inputBuffer, long inputFra void *outputBuffer, long outputFrames, void *userData); -/* Device role */ +/* Device role. */ typedef enum PaWasapiDeviceRole { eRoleRemoteNetworkDevice = 0, @@ -109,7 +109,7 @@ typedef enum PaWasapiDeviceRole PaWasapiDeviceRole; -/* Jack connection type */ +/* Jack connection type. */ typedef enum PaWasapiJackConnectionType { eJackConnTypeUnknown, @@ -128,10 +128,10 @@ typedef enum PaWasapiJackConnectionType PaWasapiJackConnectionType; -/* Jack geometric location */ +/* Jack geometric location. */ typedef enum PaWasapiJackGeoLocation { - eJackGeoLocUnk = 0, + eJackGeoLocUnk = 0, eJackGeoLocRear = 0x1, /* matches EPcxGeoLocation::eGeoLocRear */ eJackGeoLocFront, eJackGeoLocLeft, @@ -151,7 +151,7 @@ typedef enum PaWasapiJackGeoLocation PaWasapiJackGeoLocation; -/* Jack general location */ +/* Jack general location. */ typedef enum PaWasapiJackGenLocation { eJackGenLocPrimaryBox = 0, @@ -162,7 +162,7 @@ typedef enum PaWasapiJackGenLocation PaWasapiJackGenLocation; -/* Jack's type of port */ +/* Jack's type of port. */ typedef enum PaWasapiJackPortConnection { eJackPortConnJack = 0, @@ -173,7 +173,7 @@ typedef enum PaWasapiJackPortConnection PaWasapiJackPortConnection; -/* Thread priority */ +/* Thread priority. */ typedef enum PaWasapiThreadPriority { eThreadPriorityNone = 0, @@ -202,6 +202,46 @@ typedef struct PaWasapiJackDescription PaWasapiJackDescription; +/** Stream category. + Note: + - values are equal to WASAPI AUDIO_STREAM_CATEGORY enum + - supported since Windows 8.0, noop on earler versions + - values 1,2 are deprecated on Windows 10 and not included into enumeration + + @version Available as of 19.6.0 +*/ +typedef enum PaWasapiStreamCategory +{ + eAudioCategoryOther = 0, + eAudioCategoryCommunications = 3, + eAudioCategoryAlerts = 4, + eAudioCategorySoundEffects = 5, + eAudioCategoryGameEffects = 6, + eAudioCategoryGameMedia = 7, + eAudioCategoryGameChat = 8, + eAudioCategorySpeech = 9, + eAudioCategoryMovie = 10, + eAudioCategoryMedia = 11 +} +PaWasapiStreamCategory; + + +/** Stream option. + Note: + - values are equal to WASAPI AUDCLNT_STREAMOPTIONS enum + - supported since Windows 8.1, noop on earler versions + + @version Available as of 19.6.0 +*/ +typedef enum PaWasapiStreamOption +{ + eStreamOptionNone = 0, //!< default + eStreamOptionRaw = 1, //!< bypass WASAPI Audio Engine DSP effects, supported since Windows 8.1 + eStreamOptionMatchFormat = 2 //!< force WASAPI Audio Engine into a stream format, supported since Windows 10 +} +PaWasapiStreamOption; + + /* Stream descriptor. */ typedef struct PaWasapiStreamInfo { @@ -211,7 +251,7 @@ typedef struct PaWasapiStreamInfo unsigned long flags; /**< collection of PaWasapiFlags */ - /* Support for WAVEFORMATEXTENSIBLE channel masks. If flags contains + /** Support for WAVEFORMATEXTENSIBLE channel masks. If flags contains paWinWasapiUseChannelMask this allows you to specify which speakers to address in a multichannel stream. Constants for channelMask are specified in pa_win_waveformat.h. Will be used only if @@ -219,7 +259,7 @@ typedef struct PaWasapiStreamInfo */ PaWinWaveFormatChannelMask channelMask; - /* Delivers raw data to callback obtained from GetBuffer() methods skipping + /** Delivers raw data to callback obtained from GetBuffer() methods skipping internal PortAudio processing inventory completely. userData parameter will be the same that was passed to Pa_OpenStream method. Will be used only if paWinWasapiRedirectHostProcessor flag is specified. @@ -227,7 +267,7 @@ typedef struct PaWasapiStreamInfo PaWasapiHostProcessorCallback hostProcessorOutput; PaWasapiHostProcessorCallback hostProcessorInput; - /* Specifies thread priority explicitly. Will be used only if paWinWasapiThreadPriority flag + /** Specifies thread priority explicitly. Will be used only if paWinWasapiThreadPriority flag is specified. Please note, if Input/Output streams are opened simultaniously (Full-Duplex mode) @@ -235,6 +275,18 @@ typedef struct PaWasapiStreamInfo to setup thread priority. */ PaWasapiThreadPriority threadPriority; + + /** Stream category. + @see PaWasapiStreamCategory + @version Available as of 19.6.0 + */ + PaWasapiStreamCategory streamCategory; + + /** Stream option. + @see PaWasapiStreamOption + @version Available as of 19.6.0 + */ + PaWasapiStreamOption streamOption; } PaWasapiStreamInfo; @@ -303,7 +355,7 @@ PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput /** Get number of jacks associated with a WASAPI device. Use this method to determine if there are any jacks associated with the provided WASAPI device. Not all audio devices - will support this capability. This is valid for both input and output devices. + will support this capability. This is valid for both input and output devices. @param nDevice device index. @param jcount Number of jacks is returned in this variable @return Error code indicating success or failure @@ -314,9 +366,9 @@ PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount); /** Get the jack description associated with a WASAPI device and jack number Before this function is called, use PaWasapi_GetJackCount to determine the - number of jacks associated with device. If jcount is greater than zero, then - each jack from 0 to jcount can be queried with this function to get the jack - description. + number of jacks associated with device. If jcount is greater than zero, then + each jack from 0 to jcount can be queried with this function to get the jack + description. @param nDevice device index. @param jindex Which jack to return information @param KSJACK_DESCRIPTION This structure filled in on success. @@ -347,7 +399,7 @@ PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJ This is the most powerful WASAPI implementation which provides glitch-free audio at around 3ms latency in Exclusive mode. Lowest possible latency for this mode is 3 ms for HD Audio class audio chips. For the Shared mode latency can not be - lower than 20 ms. + lower than 20 ms. 2) Poll-Driven: Polling is another 2-nd method to operate with WASAPI. It is less efficient than Event-Driven diff --git a/Externals/portaudio/include/pa_win_wdmks.h b/Externals/portaudio/include/pa_win_wdmks.h new file mode 100644 index 0000000000..35929625e2 --- /dev/null +++ b/Externals/portaudio/include/pa_win_wdmks.h @@ -0,0 +1,137 @@ +#ifndef PA_WIN_WDMKS_H +#define PA_WIN_WDMKS_H +/* + * $Id$ + * PortAudio Portable Real-Time Audio Library + * WDM/KS specific extensions + * + * Copyright (c) 1999-2007 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +/** @file + @ingroup public_header + @brief WDM Kernel Streaming-specific PortAudio API extension header file. +*/ + + +#include "portaudio.h" + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + /** Flags to indicate valid fields in PaWinWDMKSInfo. + @see PaWinWDMKSInfo + @version Available as of 19.5.0. + */ + typedef enum PaWinWDMKSFlags + { + /** Makes WDMKS use the supplied latency figures instead of relying on the frame size reported + by the WaveCyclic device. Use at own risk! + */ + paWinWDMKSOverrideFramesize = (1 << 0), + + /** Makes WDMKS (output stream) use the given channelMask instead of the default. + @version Available as of 19.5.0. + */ + paWinWDMKSUseGivenChannelMask = (1 << 1), + + } PaWinWDMKSFlags; + + typedef struct PaWinWDMKSInfo{ + unsigned long size; /**< sizeof(PaWinWDMKSInfo) */ + PaHostApiTypeId hostApiType; /**< paWDMKS */ + unsigned long version; /**< 1 */ + + /** Flags indicate which fields are valid. + @see PaWinWDMKSFlags + @version Available as of 19.5.0. + */ + unsigned long flags; + + /** The number of packets to use for WaveCyclic devices, range is [2, 8]. Set to zero for default value of 2. */ + unsigned noOfPackets; + + /** If paWinWDMKSUseGivenChannelMask bit is set in flags, use this as channelMask instead of default. + @see PaWinWDMKSFlags + @version Available as of 19.5.0. + */ + unsigned channelMask; + } PaWinWDMKSInfo; + + typedef enum PaWDMKSType + { + Type_kNotUsed, + Type_kWaveCyclic, + Type_kWaveRT, + Type_kCnt, + } PaWDMKSType; + + typedef enum PaWDMKSSubType + { + SubType_kUnknown, + SubType_kNotification, + SubType_kPolled, + SubType_kCnt, + } PaWDMKSSubType; + + typedef struct PaWinWDMKSDeviceInfo { + wchar_t filterPath[MAX_PATH]; /**< KS filter path in Unicode! */ + wchar_t topologyPath[MAX_PATH]; /**< Topology filter path in Unicode! */ + PaWDMKSType streamingType; + GUID deviceProductGuid; /**< The product GUID of the device (if supported) */ + } PaWinWDMKSDeviceInfo; + + typedef struct PaWDMKSDirectionSpecificStreamInfo + { + PaDeviceIndex device; + unsigned channels; /**< No of channels the device is opened with */ + unsigned framesPerHostBuffer; /**< No of frames of the device buffer */ + int endpointPinId; /**< Endpoint pin ID (on topology filter if topologyName is not empty) */ + int muxNodeId; /**< Only valid for input */ + PaWDMKSSubType streamingSubType; /**< Not known until device is opened for streaming */ + } PaWDMKSDirectionSpecificStreamInfo; + + typedef struct PaWDMKSSpecificStreamInfo { + PaWDMKSDirectionSpecificStreamInfo input; + PaWDMKSDirectionSpecificStreamInfo output; + } PaWDMKSSpecificStreamInfo; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* PA_WIN_DS_H */ diff --git a/Externals/portaudio/include/pa_win_wmme.h b/Externals/portaudio/include/pa_win_wmme.h index ac5efe782f..f84b68b892 100644 --- a/Externals/portaudio/include/pa_win_wmme.h +++ b/Externals/portaudio/include/pa_win_wmme.h @@ -1,7 +1,7 @@ #ifndef PA_WIN_WMME_H #define PA_WIN_WMME_H /* - * $Id: pa_win_wmme.h 1592 2011-02-04 10:41:58Z rossb $ + * $Id$ * PortAudio Portable Real-Time Audio Library * MME specific extensions * diff --git a/Externals/portaudio/include/portaudio.h b/Externals/portaudio/include/portaudio.h index b80e1d1ef9..8a94aafbbb 100644 --- a/Externals/portaudio/include/portaudio.h +++ b/Externals/portaudio/include/portaudio.h @@ -1,7 +1,7 @@ #ifndef PORTAUDIO_H #define PORTAUDIO_H /* - * $Id: portaudio.h 1745 2011-08-25 17:44:01Z rossb $ + * $Id$ * PortAudio Portable Real-Time Audio Library * PortAudio API Header File * Latest version available at: http://www.portaudio.com/ @@ -50,18 +50,69 @@ extern "C" { #endif /* __cplusplus */ - -/** Retrieve the release number of the currently running PortAudio build, - eg 1900. +/** Retrieve the release number of the currently running PortAudio build. + For example, for version "19.5.1" this will return 0x00130501. + + @see paMakeVersionNumber */ int Pa_GetVersion( void ); - /** Retrieve a textual description of the current PortAudio build, - eg "PortAudio V19-devel 13 October 2002". + e.g. "PortAudio V19.5.0-devel, revision 1952M". + The format of the text may change in the future. Do not try to parse the + returned string. + + @deprecated As of 19.5.0, use Pa_GetVersionInfo()->versionText instead. */ const char* Pa_GetVersionText( void ); +/** + Generate a packed integer version number in the same format used + by Pa_GetVersion(). Use this to compare a specified version number with + the currently running version. For example: + + @code + if( Pa_GetVersion() < paMakeVersionNumber(19,5,1) ) {} + @endcode + + @see Pa_GetVersion, Pa_GetVersionInfo + @version Available as of 19.5.0. +*/ +#define paMakeVersionNumber(major, minor, subminor) \ + (((major)&0xFF)<<16 | ((minor)&0xFF)<<8 | ((subminor)&0xFF)) + + +/** + A structure containing PortAudio API version information. + @see Pa_GetVersionInfo, paMakeVersionNumber + @version Available as of 19.5.0. +*/ +typedef struct PaVersionInfo { + int versionMajor; + int versionMinor; + int versionSubMinor; + /** + This is currently the Git revision hash but may change in the future. + The versionControlRevision is updated by running a script before compiling the library. + If the update does not occur, this value may refer to an earlier revision. + */ + const char *versionControlRevision; + /** Version as a string, for example "PortAudio V19.5.0-devel, revision 1952M" */ + const char *versionText; +} PaVersionInfo; + +/** Retrieve version information for the currently running PortAudio build. + @return A pointer to an immutable PaVersionInfo structure. + + @note This function can be called at any time. It does not require PortAudio + to be initialized. The structure pointed to is statically allocated. Do not + attempt to free it or modify it. + + @see PaVersionInfo, paMakeVersionNumber + @version Available as of 19.5.0. +*/ +const PaVersionInfo* Pa_GetVersionInfo(); + /** Error codes returned by PortAudio functions. Note that with the exception of paNoError, all PaErrorCodes are negative. @@ -900,7 +951,7 @@ PaError Pa_CloseStream( PaStream *stream ); (ie once a call to Pa_StopStream() will not block). A stream will become inactive after the stream callback returns non-zero, or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio - output, if the stream callback returns paComplete, or Pa_StopStream is called, + output, if the stream callback returns paComplete, or Pa_StopStream() is called, the stream finished callback will not be called until all generated sample data has been played. @@ -1021,7 +1072,7 @@ typedef struct PaStreamInfo /** Retrieve a pointer to a PaStreamInfo structure containing information about the specified stream. @return A pointer to an immutable PaStreamInfo structure. If the stream - parameter invalid, or an error is encountered, the function returns NULL. + parameter is invalid, or an error is encountered, the function returns NULL. @param stream A pointer to an open stream previously created with Pa_OpenStream. @@ -1098,7 +1149,7 @@ PaError Pa_ReadStream( PaStream* stream, /** Write samples to an output stream. This function doesn't return until the - entire buffer has been consumed - this may involve waiting for the operating + entire buffer has been written - this may involve waiting for the operating system to consume the data. @param stream A pointer to an open stream previously created with Pa_OpenStream. diff --git a/Externals/portaudio/src/common/pa_allocation.c b/Externals/portaudio/src/common/pa_allocation.c index c78c2cf7e2..51fe15aba8 100644 --- a/Externals/portaudio/src/common/pa_allocation.c +++ b/Externals/portaudio/src/common/pa_allocation.c @@ -1,5 +1,5 @@ /* - * $Id: pa_allocation.c 1097 2006-08-26 08:27:53Z rossb $ + * $Id$ * Portable Audio I/O Library allocation group implementation * memory allocation group for tracking allocation groups * diff --git a/Externals/portaudio/src/common/pa_allocation.h b/Externals/portaudio/src/common/pa_allocation.h index 811dd72e0e..bd1f4b0fd4 100644 --- a/Externals/portaudio/src/common/pa_allocation.h +++ b/Externals/portaudio/src/common/pa_allocation.h @@ -1,7 +1,7 @@ #ifndef PA_ALLOCATION_H #define PA_ALLOCATION_H /* - * $Id: pa_allocation.h 1339 2008-02-15 07:50:33Z rossb $ + * $Id$ * Portable Audio I/O Library allocation context header * memory allocation context for tracking allocation groups * diff --git a/Externals/portaudio/src/common/pa_converters.c b/Externals/portaudio/src/common/pa_converters.c index ef65b68a5c..2107f5e289 100644 --- a/Externals/portaudio/src/common/pa_converters.c +++ b/Externals/portaudio/src/common/pa_converters.c @@ -1,5 +1,5 @@ /* - * $Id: pa_converters.c 1748 2011-09-01 22:08:32Z philburk $ + * $Id$ * Portable Audio I/O Library sample conversion mechanism * * Based on the Open Source API proposed by Ross Bencina diff --git a/Externals/portaudio/src/common/pa_converters.h b/Externals/portaudio/src/common/pa_converters.h index 7ddfcaa3c2..469f075d6f 100644 --- a/Externals/portaudio/src/common/pa_converters.h +++ b/Externals/portaudio/src/common/pa_converters.h @@ -1,7 +1,7 @@ #ifndef PA_CONVERTERS_H #define PA_CONVERTERS_H /* - * $Id: pa_converters.h 1097 2006-08-26 08:27:53Z rossb $ + * $Id$ * Portable Audio I/O Library sample conversion mechanism * * Based on the Open Source API proposed by Ross Bencina diff --git a/Externals/portaudio/src/common/pa_cpuload.c b/Externals/portaudio/src/common/pa_cpuload.c index 4465a50b62..4adf21adc5 100644 --- a/Externals/portaudio/src/common/pa_cpuload.c +++ b/Externals/portaudio/src/common/pa_cpuload.c @@ -1,5 +1,5 @@ /* - * $Id: pa_cpuload.c 1577 2011-02-01 13:03:45Z rossb $ + * $Id$ * Portable Audio I/O Library CPU Load measurement functions * Portable CPU load measurement facility. * diff --git a/Externals/portaudio/src/common/pa_cpuload.h b/Externals/portaudio/src/common/pa_cpuload.h index 4a594430b8..2a323aa790 100644 --- a/Externals/portaudio/src/common/pa_cpuload.h +++ b/Externals/portaudio/src/common/pa_cpuload.h @@ -1,7 +1,7 @@ #ifndef PA_CPULOAD_H #define PA_CPULOAD_H /* - * $Id: pa_cpuload.h 1097 2006-08-26 08:27:53Z rossb $ + * $Id$ * Portable Audio I/O Library CPU Load measurement functions * Portable CPU load measurement facility. * diff --git a/Externals/portaudio/src/common/pa_dither.c b/Externals/portaudio/src/common/pa_dither.c index 7a1b13125b..140e480afb 100644 --- a/Externals/portaudio/src/common/pa_dither.c +++ b/Externals/portaudio/src/common/pa_dither.c @@ -1,5 +1,5 @@ /* - * $Id: pa_dither.c 1418 2009-10-12 21:00:53Z philburk $ + * $Id$ * Portable Audio I/O Library triangular dither generator * * Based on the Open Source API proposed by Ross Bencina diff --git a/Externals/portaudio/src/common/pa_dither.h b/Externals/portaudio/src/common/pa_dither.h index a5131b27fa..12ffc4fc67 100644 --- a/Externals/portaudio/src/common/pa_dither.h +++ b/Externals/portaudio/src/common/pa_dither.h @@ -1,7 +1,7 @@ #ifndef PA_DITHER_H #define PA_DITHER_H /* - * $Id: pa_dither.h 1418 2009-10-12 21:00:53Z philburk $ + * $Id$ * Portable Audio I/O Library triangular dither generator * * Based on the Open Source API proposed by Ross Bencina diff --git a/Externals/portaudio/src/common/pa_endianness.h b/Externals/portaudio/src/common/pa_endianness.h index 84e904ca7b..9e8e059624 100644 --- a/Externals/portaudio/src/common/pa_endianness.h +++ b/Externals/portaudio/src/common/pa_endianness.h @@ -1,7 +1,7 @@ #ifndef PA_ENDIANNESS_H #define PA_ENDIANNESS_H /* - * $Id: pa_endianness.h 1324 2008-01-27 02:03:30Z bjornroche $ + * $Id$ * Portable Audio I/O Library current platform endianness macros * * Based on the Open Source API proposed by Ross Bencina diff --git a/Externals/portaudio/src/common/pa_front.c b/Externals/portaudio/src/common/pa_front.c index 957d1eac47..188cee9e55 100644 --- a/Externals/portaudio/src/common/pa_front.c +++ b/Externals/portaudio/src/common/pa_front.c @@ -1,5 +1,5 @@ /* - * $Id: pa_front.c 1730 2011-08-18 03:43:51Z rossb $ + * $Id$ * Portable Audio I/O Library Multi-Host API front end * Validate function parameters and manage multiple host APIs. * @@ -27,26 +27,26 @@ */ /* - * The text above constitutes the entire PortAudio license; however, + * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the * license above. */ /** @file @ingroup common_src - @brief Implements PortAudio API functions defined in portaudio.h, checks + @brief Implements PortAudio API functions defined in portaudio.h, checks some errors, delegates platform-specific behavior to host API implementations. - - Implements the functions defined in the PortAudio API (portaudio.h), - validates some parameters and checks for state inconsistencies before - forwarding API requests to specific Host API implementations (via the - interface declared in pa_hostapi.h), and Streams (via the interface + + Implements the functions defined in the PortAudio API (portaudio.h), + validates some parameters and checks for state inconsistencies before + forwarding API requests to specific Host API implementations (via the + interface declared in pa_hostapi.h), and Streams (via the interface declared in pa_stream.h). This file manages initialization and termination of Host API @@ -65,6 +65,7 @@ #include #include #include +#include /* needed for strtol() */ #include /* needed by PA_VALIDATE_ENDIANNESS */ #include "portaudio.h" @@ -76,25 +77,63 @@ #include "pa_trace.h" /* still usefull?*/ #include "pa_debugprint.h" +#ifndef PA_GIT_REVISION +#include "pa_gitrevision.h" +#endif -#define PA_VERSION_ 1899 -#define PA_VERSION_TEXT_ "PortAudio V19-devel (built " __DATE__ " " __TIME__ ")" +/** + * This is incremented if we make incompatible API changes. + * This version scheme is based loosely on http://semver.org/ + */ +#define paVersionMajor 19 +/** + * This is incremented when we add functionality in a backwards-compatible manner. + * Or it is set to zero when paVersionMajor is incremented. + */ +#define paVersionMinor 6 +/** + * This is incremented when we make backwards-compatible bug fixes. + * Or it is set to zero when paVersionMinor changes. + */ +#define paVersionSubMinor 0 +/** + * This is a combination of paVersionMajor, paVersionMinor and paVersionSubMinor. + * It will always increase so that version numbers can be compared as integers to + * see which is later. + */ +#define paVersion paMakeVersionNumber(paVersionMajor, paVersionMinor, paVersionSubMinor) + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +#define PA_VERSION_STRING_ TOSTRING(paVersionMajor) "." TOSTRING(paVersionMinor) "." TOSTRING(paVersionSubMinor) +#define PA_VERSION_TEXT_ "PortAudio V" PA_VERSION_STRING_ "-devel, revision " TOSTRING(PA_GIT_REVISION) int Pa_GetVersion( void ) { - return PA_VERSION_; + return paVersion; } - const char* Pa_GetVersionText( void ) { return PA_VERSION_TEXT_; } +static PaVersionInfo versionInfo_ = { + /*.versionMajor =*/ paVersionMajor, + /*.versionMinor =*/ paVersionMinor, + /*.versionSubMinor =*/ paVersionSubMinor, + /*.versionControlRevision =*/ TOSTRING(PA_GIT_REVISION), + /*.versionText =*/ PA_VERSION_TEXT_ +}; +const PaVersionInfo* Pa_GetVersionInfo() +{ + return &versionInfo_; +} #define PA_LAST_HOST_ERROR_TEXT_LENGTH_ 1024 @@ -170,7 +209,7 @@ static PaError InitializeHostApis( void ) if( !hostApis_ ) { result = paInsufficientMemory; - goto error; + goto error; } hostApisCount_ = 0; @@ -196,11 +235,11 @@ static PaError InitializeHostApis( void ) assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount ); assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount ); - /* the first successfully initialized host API with a default input *or* + /* the first successfully initialized host API with a default input *or* output device is used as the default host API. */ if( (defaultHostApiIndex_ == -1) && - ( hostApi->info.defaultInputDevice != paNoDevice + ( hostApi->info.defaultInputDevice != paNoDevice || hostApi->info.defaultOutputDevice != paNoDevice ) ) { defaultHostApiIndex_ = hostApisCount_; @@ -238,7 +277,7 @@ error: belongs and returns it. if is non-null, the host specific device index is returned in it. returns -1 if is out of range. - + */ static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex ) { @@ -328,7 +367,7 @@ PaError Pa_Initialize( void ) { PA_VALIDATE_TYPE_SIZES; PA_VALIDATE_ENDIANNESS; - + PaUtil_InitializeClock(); PaUtil_ResetTraceMessages(); @@ -351,7 +390,8 @@ PaError Pa_Terminate( void ) if( PA_IS_INITIALISED_ ) { - if( --initializationCount_ == 0 ) + // leave initializationCount_>0 so that Pa_CloseStream() can execute + if( initializationCount_ == 1 ) { CloseOpenStreams(); @@ -359,6 +399,7 @@ PaError Pa_Terminate( void ) PaUtil_DumpTraceMessages(); } + --initializationCount_; result = paNoError; } else @@ -415,11 +456,11 @@ const char *Pa_GetErrorText( PaError errorCode ) case paCanNotWriteToAnInputOnlyStream: result = "Can't write to an input only stream"; break; case paIncompatibleStreamHostApi: result = "Incompatible stream host API"; break; case paBadBufferPtr: result = "Bad buffer pointer"; break; - default: + default: if( errorCode > 0 ) - result = "Invalid error code (value greater than zero)"; + result = "Invalid error code (value greater than zero)"; else - result = "Invalid error code"; + result = "Invalid error code"; break; } return result; @@ -430,7 +471,7 @@ PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ) { PaHostApiIndex result; int i; - + PA_LOGAPI_ENTER_PARAMS( "Pa_HostApiTypeIdToHostApiIndex" ); PA_LOGAPI(("\tPaHostApiTypeId type: %d\n", type )); @@ -441,14 +482,14 @@ PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ) else { result = paHostApiNotFound; - + for( i=0; i < hostApisCount_; ++i ) { if( hostApis_[i]->info.type == type ) { result = i; break; - } + } } } @@ -463,7 +504,7 @@ PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **ho { PaError result; int i; - + if( !PA_IS_INITIALISED_ ) { result = paNotInitialized; @@ -471,7 +512,7 @@ PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **ho else { result = paHostApiNotFound; - + for( i=0; i < hostApisCount_; ++i ) { if( hostApis_[i]->info.type == type ) @@ -492,7 +533,7 @@ PaError PaUtil_DeviceIndexToHostApiDeviceIndex( { PaError result; PaDeviceIndex x; - + x = device - hostApi->privatePaFrontInfo.baseDeviceIndex; if( x < 0 || x >= hostApi->info.deviceCount ) @@ -577,7 +618,7 @@ const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi ) else if( hostApi < 0 || hostApi >= hostApisCount_ ) { info = NULL; - + PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" )); PA_LOGAPI(("\tPaHostApiInfo*: NULL [ hostApi out of range ]\n" )); @@ -686,7 +727,7 @@ PaDeviceIndex Pa_GetDefaultOutputDevice( void ) { PaHostApiIndex hostApi; PaDeviceIndex result; - + PA_LOGAPI_ENTER( "Pa_GetDefaultOutputDevice" ); hostApi = Pa_GetDefaultHostApi(); @@ -770,7 +811,7 @@ static int SampleFormatIsValid( PaSampleFormat format ) ValidateOpenStreamParameters() checks that parameters to Pa_OpenStream() conform to the expected values as described below. This function is also designed to be used with the proposed Pa_IsFormatSupported() function. - + There are basically two types of validation that could be performed: Generic conformance validation, and device capability mismatch validation. This function performs only generic conformance validation. @@ -779,21 +820,21 @@ static int SampleFormatIsValid( PaSampleFormat format ) combinations of parameters - for example, even if the sampleRate seems ok, it might not be for a duplex stream - we have no way of checking this in an API-neutral way, so we don't try. - + On success the function returns PaNoError and fills in hostApi, hostApiInputDeviceID, and hostApiOutputDeviceID fields. On failure the function returns an error code indicating the first encountered parameter error. - - + + If ValidateOpenStreamParameters() returns paNoError, the following assertions are guaranteed to be true. - + - at least one of inputParameters & outputParmeters is valid (not NULL) - if inputParameters & outputParameters are both valid, that inputParameters->device & outputParameters->device both use the same host api - + PaDeviceIndex inputParameters->device - is within range (0 to Pa_GetDeviceCount-1) Or: - is paUseHostApiSpecificDeviceSpecification and @@ -803,30 +844,30 @@ static int SampleFormatIsValid( PaSampleFormat format ) int inputParameters->channelCount - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, channelCount is > 0 - upper bound is NOT validated against device capabilities - + PaSampleFormat inputParameters->sampleFormat - is one of the sample formats defined in portaudio.h void *inputParameters->hostApiSpecificStreamInfo - if supplied its hostApi field matches the input device's host Api - + PaDeviceIndex outputParmeters->device - is within range (0 to Pa_GetDeviceCount-1) - + int outputParmeters->channelCount - if inputDevice is valid, channelCount is > 0 - upper bound is NOT validated against device capabilities - + PaSampleFormat outputParmeters->sampleFormat - is one of the sample formats defined in portaudio.h - + void *outputParmeters->hostApiSpecificStreamInfo - if supplied its hostApi field matches the output device's host Api - + double sampleRate - - is not an 'absurd' rate (less than 1000. or greater than 200000.) + - is not an 'absurd' rate (less than 1000. or greater than 384000.) - sampleRate is NOT validated against device capabilities - + PaStreamFlags streamFlags - unused platform neutral flags are zero - paNeverDropInput is only used for full-duplex callback streams with @@ -953,7 +994,7 @@ static PaError ValidateOpenStreamParameters( != (*hostApi)->info.type ) return paIncompatibleHostApiSpecificStreamInfo; } - } + } if( (inputParameters != NULL) && (outputParameters != NULL) ) { @@ -962,10 +1003,10 @@ static PaError ValidateOpenStreamParameters( return paBadIODeviceCombination; } } - - + + /* Check for absurd sample rates. */ - if( (sampleRate < 1000.0) || (sampleRate > 200000.0) ) + if( (sampleRate < 1000.0) || (sampleRate > 384000.0) ) return paInvalidSampleRate; if( ((streamFlags & ~paPlatformSpecificFlags) & ~(paClipOff | paDitherOff | paNeverDropInput | paPrimeOutputBuffersUsingStreamCallback ) ) != 0 ) @@ -985,7 +1026,7 @@ static PaError ValidateOpenStreamParameters( if( framesPerBuffer != paFramesPerBufferUnspecified ) return paInvalidFlag; } - + return paNoError; } @@ -1025,7 +1066,7 @@ PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, PA_LOGAPI(("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency )); PA_LOGAPI(("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo )); } - + PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate )); #endif @@ -1048,7 +1089,7 @@ PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, PA_LOGAPI_EXIT_PAERROR( "Pa_IsFormatSupported", result ); return result; } - + if( inputParameters ) { @@ -1135,7 +1176,7 @@ PaError Pa_OpenStream( PaStream** stream, PA_LOGAPI(("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency )); PA_LOGAPI(("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo )); } - + PA_LOGAPI(("\tdouble sampleRate: %g\n", sampleRate )); PA_LOGAPI(("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer )); PA_LOGAPI(("\tPaStreamFlags streamFlags: 0x%x\n", streamFlags )); @@ -1182,7 +1223,7 @@ PaError Pa_OpenStream( PaStream** stream, PA_LOGAPI(("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )); return result; } - + if( inputParameters ) { @@ -1256,8 +1297,8 @@ PaError Pa_OpenDefaultStream( PaStream** stream, { hostApiInputParameters.device = Pa_GetDefaultInputDevice(); if( hostApiInputParameters.device == paNoDevice ) - return paDeviceUnavailable; - + return paDeviceUnavailable; + hostApiInputParameters.channelCount = inputChannelCount; hostApiInputParameters.sampleFormat = sampleFormat; /* defaultHighInputLatency is used below instead of @@ -1265,7 +1306,7 @@ PaError Pa_OpenDefaultStream( PaStream** stream, stream to work reliably than it is for it to work with the lowest latency. */ - hostApiInputParameters.suggestedLatency = + hostApiInputParameters.suggestedLatency = Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency; hostApiInputParameters.hostApiSpecificStreamInfo = NULL; hostApiInputParametersPtr = &hostApiInputParameters; @@ -1279,7 +1320,7 @@ PaError Pa_OpenDefaultStream( PaStream** stream, { hostApiOutputParameters.device = Pa_GetDefaultOutputDevice(); if( hostApiOutputParameters.device == paNoDevice ) - return paDeviceUnavailable; + return paDeviceUnavailable; hostApiOutputParameters.channelCount = outputChannelCount; hostApiOutputParameters.sampleFormat = sampleFormat; @@ -1663,7 +1704,7 @@ PaError Pa_WriteStream( PaStream* stream, else if( result == 1 ) { result = paStreamIsStopped; - } + } } } diff --git a/Externals/portaudio/src/common/pa_gitrevision.h b/Externals/portaudio/src/common/pa_gitrevision.h new file mode 100644 index 0000000000..2a6cfca8d2 --- /dev/null +++ b/Externals/portaudio/src/common/pa_gitrevision.h @@ -0,0 +1 @@ +#define PA_GIT_REVISION 396fe4b6699ae929d3a685b3ef8a7e97396139a4 diff --git a/Externals/portaudio/src/common/pa_hostapi.h b/Externals/portaudio/src/common/pa_hostapi.h index 1437f629dc..54b527ea81 100644 --- a/Externals/portaudio/src/common/pa_hostapi.h +++ b/Externals/portaudio/src/common/pa_hostapi.h @@ -1,7 +1,7 @@ #ifndef PA_HOSTAPI_H #define PA_HOSTAPI_H /* - * $Id: pa_hostapi.h 1740 2011-08-25 07:17:48Z philburk $ + * $Id$ * Portable Audio I/O Library * host api representation * @@ -264,7 +264,7 @@ typedef struct PaUtilHostApiRepresentation { - if supplied its hostApi field matches the output device's host Api double sampleRate - - is not an 'absurd' rate (less than 1000. or greater than 200000.) + - is not an 'absurd' rate (less than 1000. or greater than 384000.) - sampleRate is NOT validated against device capabilities PaStreamFlags streamFlags diff --git a/Externals/portaudio/src/common/pa_process.c b/Externals/portaudio/src/common/pa_process.c index 383f9cafa5..0faf8414cf 100644 --- a/Externals/portaudio/src/common/pa_process.c +++ b/Externals/portaudio/src/common/pa_process.c @@ -1,5 +1,5 @@ /* - * $Id: pa_process.c 1706 2011-07-21 18:44:58Z philburk $ + * $Id$ * Portable Audio I/O Library * streamCallback <-> host buffer processing adapter * @@ -238,7 +238,7 @@ PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp, bp->inputConverter = PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, tempInputStreamFlags ); - bp->inputZeroer = PaUtil_SelectZeroer( hostInputSampleFormat ); + bp->inputZeroer = PaUtil_SelectZeroer( userInputSampleFormat ); bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1; @@ -743,8 +743,10 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, destSampleStrideSamples = bp->inputChannelCount; destChannelStrideBytes = bp->bytesPerUserInputSample; - /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved */ - if( bp->userInputSampleFormatIsEqualToHost && bp->hostInputIsInterleaved && bp->hostInputChannels[0][0].data) + /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved, + * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */ + if( bp->userInputSampleFormatIsEqualToHost && bp->hostInputIsInterleaved + && bp->hostInputChannels[0][0].data && bp->inputChannelCount == hostInputChannels[0].stride ) { userInput = hostInputChannels[0].data; destBytePtr = (unsigned char *)hostInputChannels[0].data; @@ -832,8 +834,10 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, { if( bp->userOutputIsInterleaved ) { - /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved */ - if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved ) + /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved, + * or if num channels differs between the host (set in stride) and the user (eg with some Alsa hw:) */ + if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved + && bp->outputChannelCount == hostOutputChannels[0].stride ) { userOutput = hostOutputChannels[0].data; skipOutputConvert = 1; @@ -1683,9 +1687,9 @@ unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp, hostInputChannels[i].stride, framesToCopy, &bp->ditherGenerator ); - destBytePtr += destChannelStrideBytes; /* skip to next source channel */ + destBytePtr += destChannelStrideBytes; /* skip to next dest channel */ - /* advance dest ptr for next iteration */ + /* advance source ptr for next iteration */ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample; } @@ -1715,7 +1719,7 @@ unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp, destBytePtr += bp->bytesPerUserInputSample * framesToCopy; nonInterleavedDestPtrs[i] = destBytePtr; - /* advance dest ptr for next iteration */ + /* advance source ptr for next iteration */ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample; } diff --git a/Externals/portaudio/src/common/pa_process.h b/Externals/portaudio/src/common/pa_process.h index 4d5f56ad63..37b91d7218 100644 --- a/Externals/portaudio/src/common/pa_process.h +++ b/Externals/portaudio/src/common/pa_process.h @@ -1,7 +1,7 @@ #ifndef PA_PROCESS_H #define PA_PROCESS_H /* - * $Id: pa_process.h 1668 2011-05-02 17:07:11Z rossb $ + * $Id$ * Portable Audio I/O Library callback buffer processing adapters * * Based on the Open Source API proposed by Ross Bencina diff --git a/Externals/portaudio/src/common/pa_ringbuffer.c b/Externals/portaudio/src/common/pa_ringbuffer.c index 19c91497ce..93b3e430a5 100644 --- a/Externals/portaudio/src/common/pa_ringbuffer.c +++ b/Externals/portaudio/src/common/pa_ringbuffer.c @@ -1,5 +1,5 @@ /* - * $Id: pa_ringbuffer.c 1738 2011-08-18 11:47:28Z rossb $ + * $Id$ * Portable Audio I/O Library * Ring Buffer utility. * diff --git a/Externals/portaudio/src/common/pa_ringbuffer.h b/Externals/portaudio/src/common/pa_ringbuffer.h index 51577f0707..9edba0dd65 100644 --- a/Externals/portaudio/src/common/pa_ringbuffer.h +++ b/Externals/portaudio/src/common/pa_ringbuffer.h @@ -1,7 +1,7 @@ #ifndef PA_RINGBUFFER_H #define PA_RINGBUFFER_H /* - * $Id: pa_ringbuffer.h 1734 2011-08-18 11:19:36Z rossb $ + * $Id$ * Portable Audio I/O Library * Ring Buffer utility. * @@ -65,6 +65,9 @@ The memory area used to store the buffer elements must be allocated by the client prior to calling PaUtil_InitializeRingBuffer() and must outlive the use of the ring buffer. + + @note The ring buffer functions are not normally exposed in the PortAudio libraries. + If you want to call them then you will need to add pa_ringbuffer.c to your application source code. */ #if defined(__APPLE__) diff --git a/Externals/portaudio/src/common/pa_stream.c b/Externals/portaudio/src/common/pa_stream.c index ea91821f8d..03a0ee6ee3 100644 --- a/Externals/portaudio/src/common/pa_stream.c +++ b/Externals/portaudio/src/common/pa_stream.c @@ -1,5 +1,5 @@ /* - * $Id: pa_stream.c 1339 2008-02-15 07:50:33Z rossb $ + * $Id$ * Portable Audio I/O Library * stream interface * diff --git a/Externals/portaudio/src/common/pa_stream.h b/Externals/portaudio/src/common/pa_stream.h index 8d707b79cf..678e2ad5ea 100644 --- a/Externals/portaudio/src/common/pa_stream.h +++ b/Externals/portaudio/src/common/pa_stream.h @@ -1,7 +1,7 @@ #ifndef PA_STREAM_H #define PA_STREAM_H /* - * $Id: pa_stream.h 1339 2008-02-15 07:50:33Z rossb $ + * $Id$ * Portable Audio I/O Library * stream interface * diff --git a/Externals/portaudio/src/common/pa_trace.c b/Externals/portaudio/src/common/pa_trace.c index 24305003f7..818abffbee 100644 --- a/Externals/portaudio/src/common/pa_trace.c +++ b/Externals/portaudio/src/common/pa_trace.c @@ -1,5 +1,5 @@ /* - * $Id: pa_trace.c 1339 2008-02-15 07:50:33Z rossb $ + * $Id$ * Portable Audio I/O Library Trace Facility * Store trace information in real-time for later printing. * @@ -46,12 +46,16 @@ #include #include +#include #include +#include #include "pa_trace.h" +#include "pa_util.h" +#include "pa_debugprint.h" #if PA_TRACE_REALTIME_EVENTS -static char *traceTextArray[PA_MAX_TRACE_RECORDS]; +static char const *traceTextArray[PA_MAX_TRACE_RECORDS]; static int traceIntArray[PA_MAX_TRACE_RECORDS]; static int traceIndex = 0; static int traceBlock = 0; @@ -94,4 +98,141 @@ void PaUtil_AddTraceMessage( const char *msg, int data ) } } +/************************************************************************/ +/* High performance log alternative */ +/************************************************************************/ + +typedef unsigned long long PaUint64; + +typedef struct __PaHighPerformanceLog +{ + unsigned magik; + int writePtr; + int readPtr; + int size; + double refTime; + char* data; +} PaHighPerformanceLog; + +static const unsigned kMagik = 0xcafebabe; + +#define USEC_PER_SEC (1000000ULL) + +int PaUtil_InitializeHighSpeedLog( LogHandle* phLog, unsigned maxSizeInBytes ) +{ + PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)PaUtil_AllocateMemory(sizeof(PaHighPerformanceLog)); + if (pLog == 0) + { + return paInsufficientMemory; + } + assert(phLog != 0); + *phLog = pLog; + + pLog->data = (char*)PaUtil_AllocateMemory(maxSizeInBytes); + if (pLog->data == 0) + { + PaUtil_FreeMemory(pLog); + return paInsufficientMemory; + } + pLog->magik = kMagik; + pLog->size = maxSizeInBytes; + pLog->refTime = PaUtil_GetTime(); + return paNoError; +} + +void PaUtil_ResetHighSpeedLogTimeRef( LogHandle hLog ) +{ + PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; + assert(pLog->magik == kMagik); + pLog->refTime = PaUtil_GetTime(); +} + +typedef struct __PaLogEntryHeader +{ + int size; + double timeStamp; +} PaLogEntryHeader; + +#ifdef __APPLE__ +#define _vsnprintf vsnprintf +#define min(a,b) ((a)<(b)?(a):(b)) +#endif + + +int PaUtil_AddHighSpeedLogMessage( LogHandle hLog, const char* fmt, ... ) +{ + va_list l; + int n = 0; + PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; + if (pLog != 0) + { + PaLogEntryHeader* pHeader; + char* p; + int maxN; + assert(pLog->magik == kMagik); + pHeader = (PaLogEntryHeader*)( pLog->data + pLog->writePtr ); + p = (char*)( pHeader + 1 ); + maxN = pLog->size - pLog->writePtr - 2 * sizeof(PaLogEntryHeader); + + pHeader->timeStamp = PaUtil_GetTime() - pLog->refTime; + if (maxN > 0) + { + if (maxN > 32) + { + va_start(l, fmt); + n = _vsnprintf(p, min(1024, maxN), fmt, l); + va_end(l); + } + else { + n = sprintf(p, "End of log..."); + } + n = ((n + sizeof(unsigned)) & ~(sizeof(unsigned)-1)) + sizeof(PaLogEntryHeader); + pHeader->size = n; +#if 0 + PaUtil_DebugPrint("%05u.%03u: %s\n", pHeader->timeStamp/1000, pHeader->timeStamp%1000, p); +#endif + pLog->writePtr += n; + } + } + return n; +} + +void PaUtil_DumpHighSpeedLog( LogHandle hLog, const char* fileName ) +{ + FILE* f = (fileName != NULL) ? fopen(fileName, "w") : stdout; + unsigned localWritePtr; + PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; + assert(pLog->magik == kMagik); + localWritePtr = pLog->writePtr; + while (pLog->readPtr != localWritePtr) + { + const PaLogEntryHeader* pHeader = (const PaLogEntryHeader*)( pLog->data + pLog->readPtr ); + const char* p = (const char*)( pHeader + 1 ); + const PaUint64 ts = (const PaUint64)( pHeader->timeStamp * USEC_PER_SEC ); + assert(pHeader->size < (1024+sizeof(unsigned)+sizeof(PaLogEntryHeader))); + fprintf(f, "%05u.%03u: %s\n", (unsigned)(ts/1000), (unsigned)(ts%1000), p); + pLog->readPtr += pHeader->size; + } + if (f != stdout) + { + fclose(f); + } +} + +void PaUtil_DiscardHighSpeedLog( LogHandle hLog ) +{ + PaHighPerformanceLog* pLog = (PaHighPerformanceLog*)hLog; + assert(pLog->magik == kMagik); + PaUtil_FreeMemory(pLog->data); + PaUtil_FreeMemory(pLog); +} + +#else +/* This stub was added so that this file will generate a symbol. + * Otherwise linker/archiver programs will complain. + */ +int PaUtil_TraceStubToSatisfyLinker(void) +{ + return 0; +} #endif /* TRACE_REALTIME_EVENTS */ diff --git a/Externals/portaudio/src/common/pa_trace.h b/Externals/portaudio/src/common/pa_trace.h index b11509e0ec..6dfaeb79ec 100644 --- a/Externals/portaudio/src/common/pa_trace.h +++ b/Externals/portaudio/src/common/pa_trace.h @@ -1,7 +1,7 @@ #ifndef PA_TRACE_H #define PA_TRACE_H /* - * $Id: pa_trace.h 1339 2008-02-15 07:50:33Z rossb $ + * $Id$ * Portable Audio I/O Library Trace Facility * Store trace information in real-time for later printing. * @@ -84,13 +84,29 @@ extern "C" void PaUtil_ResetTraceMessages(); void PaUtil_AddTraceMessage( const char *msg, int data ); void PaUtil_DumpTraceMessages(); - + +/* Alternative interface */ + +typedef void* LogHandle; + +int PaUtil_InitializeHighSpeedLog(LogHandle* phLog, unsigned maxSizeInBytes); +void PaUtil_ResetHighSpeedLogTimeRef(LogHandle hLog); +int PaUtil_AddHighSpeedLogMessage(LogHandle hLog, const char* fmt, ...); +void PaUtil_DumpHighSpeedLog(LogHandle hLog, const char* fileName); +void PaUtil_DiscardHighSpeedLog(LogHandle hLog); + #else #define PaUtil_ResetTraceMessages() /* noop */ #define PaUtil_AddTraceMessage(msg,data) /* noop */ #define PaUtil_DumpTraceMessages() /* noop */ +#define PaUtil_InitializeHighSpeedLog(phLog, maxSizeInBytes) (0) +#define PaUtil_ResetHighSpeedLogTimeRef(hLog) +#define PaUtil_AddHighSpeedLogMessage(...) (0) +#define PaUtil_DumpHighSpeedLog(hLog, fileName) +#define PaUtil_DiscardHighSpeedLog(hLog) + #endif diff --git a/Externals/portaudio/src/common/pa_util.h b/Externals/portaudio/src/common/pa_util.h index c454ea771d..ad5dac5287 100644 --- a/Externals/portaudio/src/common/pa_util.h +++ b/Externals/portaudio/src/common/pa_util.h @@ -1,7 +1,7 @@ #ifndef PA_UTIL_H #define PA_UTIL_H /* - * $Id: pa_util.h 1584 2011-02-02 18:58:17Z rossb $ + * $Id$ * Portable Audio I/O Library implementation utilities header * common implementation utilities and interfaces * diff --git a/Externals/portaudio/src/hostapi/alsa/pa_linux_alsa.c b/Externals/portaudio/src/hostapi/alsa/pa_linux_alsa.c index 97c2ebcfce..584cde8901 100644 --- a/Externals/portaudio/src/hostapi/alsa/pa_linux_alsa.c +++ b/Externals/portaudio/src/hostapi/alsa/pa_linux_alsa.c @@ -1,5 +1,5 @@ /* - * $Id: pa_linux_alsa.c 1691 2011-05-26 20:19:19Z aknudsen $ + * $Id$ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * ALSA implementation by Joshua Haberman and Arve Knudsen @@ -79,10 +79,17 @@ #include "pa_linux_alsa.h" +/* Add missing define (for compatibility with older ALSA versions) */ #ifndef SND_PCM_TSTAMP_ENABLE -#define SND_PCM_TSTAMP_ENABLE SND_PCM_TSTAMP_MMAP + #define SND_PCM_TSTAMP_ENABLE SND_PCM_TSTAMP_MMAP #endif +/* Combine version elements into a single (unsigned) integer */ +#define ALSA_VERSION_INT(major, minor, subminor) ((major << 16) | (minor << 8) | subminor) + +/* The acceptable tolerance of sample rate set, to that requested (as a ratio, eg 50 is 2%, 100 is 1%) */ +#define RATE_MAX_DEVIATE_RATIO 100 + /* Defines Alsa function types and pointers to these functions. */ #define _PA_DEFINE_FUNC(x) typedef typeof(x) x##_ft; static x##_ft *alsa_##x = 0 @@ -219,6 +226,7 @@ _PA_DEFINE_FUNC(snd_pcm_status_get_delay); #define alsa_snd_pcm_status_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_status) _PA_DEFINE_FUNC(snd_card_next); +_PA_DEFINE_FUNC(snd_asoundlib_version); _PA_DEFINE_FUNC(snd_strerror); _PA_DEFINE_FUNC(snd_output_stdio_attach); @@ -244,96 +252,96 @@ static void *g_AlsaLib = NULL; int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_rate_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir) { - int ret; + int ret; - if ((ret = alsa_snd_pcm_hw_params_set_rate(pcm, params, (*val), (*dir))) < 0) - return ret; + if(( ret = alsa_snd_pcm_hw_params_set_rate(pcm, params, (*val), (*dir)) ) < 0 ) + return ret; - return 0; + return 0; } int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_buffer_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) { - int ret; + int ret; - if ((ret = alsa_snd_pcm_hw_params_set_buffer_size(pcm, params, (*val))) < 0) - return ret; + if(( ret = alsa_snd_pcm_hw_params_set_buffer_size(pcm, params, (*val)) ) < 0 ) + return ret; - return 0; + return 0; } int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_period_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir) { - int ret; + int ret; - if ((ret = alsa_snd_pcm_hw_params_set_period_size(pcm, params, (*val), (*dir))) < 0) - return ret; + if(( ret = alsa_snd_pcm_hw_params_set_period_size(pcm, params, (*val), (*dir)) ) < 0 ) + return ret; - return 0; + return 0; } int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_channels_min) (const snd_pcm_hw_params_t *params, unsigned int *val) { - (*val) = 1; - return 0; + (*val) = 1; + return 0; } int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_channels_max) (const snd_pcm_hw_params_t *params, unsigned int *val) { - (*val) = 2; - return 0; + (*val) = 2; + return 0; } int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_min) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) { - (*val) = 2; - return 0; + (*val) = 2; + return 0; } int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_max) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) { - (*val) = 8; - return 0; + (*val) = 8; + return 0; } int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_min) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir) { - (*frames) = 64; - return 0; + (*frames) = 64; + return 0; } int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_max) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir) { - (*frames) = 512; - return 0; + (*frames) = 512; + return 0; } int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_buffer_size_max) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val) { - int ret; - int dir = 0; - snd_pcm_uframes_t pmax = 0; - unsigned int pcnt = 0; + int ret; + int dir = 0; + snd_pcm_uframes_t pmax = 0; + unsigned int pcnt = 0; - if ((ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_max)(params, &pmax, &dir)) < 0) - return ret; - if ((ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_max)(params, &pcnt, &dir)) < 0) - return ret; + if(( ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_max)(params, &pmax, &dir) ) < 0 ) + return ret; + if(( ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_max)(params, &pcnt, &dir) ) < 0 ) + return ret; - (*val) = pmax * pcnt; - return 0; + (*val) = pmax * pcnt; + return 0; } int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_rate_min) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) { - (*val) = 44100; - return 0; + (*val) = 44100; + return 0; } int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_rate_max) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir) { - (*val) = 44100; - return 0; + (*val) = 44100; + return 0; } #endif // PA_ALSA_DYNAMIC @@ -345,22 +353,22 @@ static int PaAlsa_LoadLibrary() { #ifdef PA_ALSA_DYNAMIC - PA_DEBUG(( "%s: loading ALSA library file - %s\n", __FUNCTION__, g_AlsaLibName )); + PA_DEBUG(( "%s: loading ALSA library file - %s\n", __FUNCTION__, g_AlsaLibName )); - dlerror(); - g_AlsaLib = dlopen(g_AlsaLibName, (RTLD_NOW|RTLD_GLOBAL)); + dlerror(); + g_AlsaLib = dlopen(g_AlsaLibName, (RTLD_NOW|RTLD_GLOBAL) ); if (g_AlsaLib == NULL) { - PA_DEBUG(( "%s: failed dlopen() ALSA library file - %s, error: %s\n", __FUNCTION__, g_AlsaLibName, dlerror() )); - return 0; + PA_DEBUG(( "%s: failed dlopen() ALSA library file - %s, error: %s\n", __FUNCTION__, g_AlsaLibName, dlerror() )); + return 0; } PA_DEBUG(( "%s: loading ALSA API\n", __FUNCTION__ )); #define _PA_LOAD_FUNC(x) do { \ - alsa_##x = dlsym(g_AlsaLib, #x); \ - if (alsa_##x == NULL) { \ - PA_DEBUG(( "%s: symbol [%s] not found in - %s, error: %s\n", __FUNCTION__, #x, g_AlsaLibName, dlerror() )); }\ + alsa_##x = dlsym( g_AlsaLib, #x ); \ + if( alsa_##x == NULL ) { \ + PA_DEBUG(( "%s: symbol [%s] not found in - %s, error: %s\n", __FUNCTION__, #x, g_AlsaLibName, dlerror() )); }\ } while(0) #else @@ -369,159 +377,160 @@ static int PaAlsa_LoadLibrary() #endif -_PA_LOAD_FUNC(snd_pcm_open); -_PA_LOAD_FUNC(snd_pcm_close); -_PA_LOAD_FUNC(snd_pcm_nonblock); -_PA_LOAD_FUNC(snd_pcm_frames_to_bytes); -_PA_LOAD_FUNC(snd_pcm_prepare); -_PA_LOAD_FUNC(snd_pcm_start); -_PA_LOAD_FUNC(snd_pcm_resume); -_PA_LOAD_FUNC(snd_pcm_wait); -_PA_LOAD_FUNC(snd_pcm_state); -_PA_LOAD_FUNC(snd_pcm_avail_update); -_PA_LOAD_FUNC(snd_pcm_areas_silence); -_PA_LOAD_FUNC(snd_pcm_mmap_begin); -_PA_LOAD_FUNC(snd_pcm_mmap_commit); -_PA_LOAD_FUNC(snd_pcm_readi); -_PA_LOAD_FUNC(snd_pcm_readn); -_PA_LOAD_FUNC(snd_pcm_writei); -_PA_LOAD_FUNC(snd_pcm_writen); -_PA_LOAD_FUNC(snd_pcm_drain); -_PA_LOAD_FUNC(snd_pcm_recover); -_PA_LOAD_FUNC(snd_pcm_drop); -_PA_LOAD_FUNC(snd_pcm_area_copy); -_PA_LOAD_FUNC(snd_pcm_poll_descriptors); -_PA_LOAD_FUNC(snd_pcm_poll_descriptors_count); -_PA_LOAD_FUNC(snd_pcm_poll_descriptors_revents); -_PA_LOAD_FUNC(snd_pcm_format_size); -_PA_LOAD_FUNC(snd_pcm_link); -_PA_LOAD_FUNC(snd_pcm_delay); + _PA_LOAD_FUNC(snd_pcm_open); + _PA_LOAD_FUNC(snd_pcm_close); + _PA_LOAD_FUNC(snd_pcm_nonblock); + _PA_LOAD_FUNC(snd_pcm_frames_to_bytes); + _PA_LOAD_FUNC(snd_pcm_prepare); + _PA_LOAD_FUNC(snd_pcm_start); + _PA_LOAD_FUNC(snd_pcm_resume); + _PA_LOAD_FUNC(snd_pcm_wait); + _PA_LOAD_FUNC(snd_pcm_state); + _PA_LOAD_FUNC(snd_pcm_avail_update); + _PA_LOAD_FUNC(snd_pcm_areas_silence); + _PA_LOAD_FUNC(snd_pcm_mmap_begin); + _PA_LOAD_FUNC(snd_pcm_mmap_commit); + _PA_LOAD_FUNC(snd_pcm_readi); + _PA_LOAD_FUNC(snd_pcm_readn); + _PA_LOAD_FUNC(snd_pcm_writei); + _PA_LOAD_FUNC(snd_pcm_writen); + _PA_LOAD_FUNC(snd_pcm_drain); + _PA_LOAD_FUNC(snd_pcm_recover); + _PA_LOAD_FUNC(snd_pcm_drop); + _PA_LOAD_FUNC(snd_pcm_area_copy); + _PA_LOAD_FUNC(snd_pcm_poll_descriptors); + _PA_LOAD_FUNC(snd_pcm_poll_descriptors_count); + _PA_LOAD_FUNC(snd_pcm_poll_descriptors_revents); + _PA_LOAD_FUNC(snd_pcm_format_size); + _PA_LOAD_FUNC(snd_pcm_link); + _PA_LOAD_FUNC(snd_pcm_delay); -_PA_LOAD_FUNC(snd_pcm_hw_params_sizeof); -_PA_LOAD_FUNC(snd_pcm_hw_params_malloc); -_PA_LOAD_FUNC(snd_pcm_hw_params_free); -_PA_LOAD_FUNC(snd_pcm_hw_params_any); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_access); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_format); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_channels); -//_PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_near); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_near); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_rate); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_resample); -//_PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min); -//_PA_LOAD_FUNC(snd_pcm_hw_params_set_period_time_near); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size_near); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_integer); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_min); + _PA_LOAD_FUNC(snd_pcm_hw_params_sizeof); + _PA_LOAD_FUNC(snd_pcm_hw_params_malloc); + _PA_LOAD_FUNC(snd_pcm_hw_params_free); + _PA_LOAD_FUNC(snd_pcm_hw_params_any); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_access); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_format); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_channels); +// _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_resample); +// _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min); +// _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_time_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size_near); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_integer); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_min); -_PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size); -//_PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size); -//_PA_LOAD_FUNC(snd_pcm_hw_params_get_access); -//_PA_LOAD_FUNC(snd_pcm_hw_params_get_periods); -//_PA_LOAD_FUNC(snd_pcm_hw_params_get_rate); -_PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_min); -_PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_max); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size); +// _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size); +// _PA_LOAD_FUNC(snd_pcm_hw_params_get_access); +// _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods); +// _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_min); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_max); -_PA_LOAD_FUNC(snd_pcm_hw_params_test_period_size); -_PA_LOAD_FUNC(snd_pcm_hw_params_test_format); -_PA_LOAD_FUNC(snd_pcm_hw_params_test_access); -_PA_LOAD_FUNC(snd_pcm_hw_params_dump); -_PA_LOAD_FUNC(snd_pcm_hw_params); + _PA_LOAD_FUNC(snd_pcm_hw_params_test_period_size); + _PA_LOAD_FUNC(snd_pcm_hw_params_test_format); + _PA_LOAD_FUNC(snd_pcm_hw_params_test_access); + _PA_LOAD_FUNC(snd_pcm_hw_params_dump); + _PA_LOAD_FUNC(snd_pcm_hw_params); -_PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_min); -_PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_max); -_PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size); -_PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_min); -_PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_max); -_PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size_max); -_PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_min); -_PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_max); -_PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_numden); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_min); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_max); + _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_min); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_max); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size_max); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_min); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_max); + _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_numden); -_PA_LOAD_FUNC(snd_pcm_sw_params_sizeof); -_PA_LOAD_FUNC(snd_pcm_sw_params_malloc); -_PA_LOAD_FUNC(snd_pcm_sw_params_current); -_PA_LOAD_FUNC(snd_pcm_sw_params_set_avail_min); -_PA_LOAD_FUNC(snd_pcm_sw_params); -_PA_LOAD_FUNC(snd_pcm_sw_params_free); -_PA_LOAD_FUNC(snd_pcm_sw_params_set_start_threshold); -_PA_LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold); -_PA_LOAD_FUNC(snd_pcm_sw_params_get_boundary); -_PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_threshold); -_PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_size); -_PA_LOAD_FUNC(snd_pcm_sw_params_set_xfer_align); -_PA_LOAD_FUNC(snd_pcm_sw_params_set_tstamp_mode); + _PA_LOAD_FUNC(snd_pcm_sw_params_sizeof); + _PA_LOAD_FUNC(snd_pcm_sw_params_malloc); + _PA_LOAD_FUNC(snd_pcm_sw_params_current); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_avail_min); + _PA_LOAD_FUNC(snd_pcm_sw_params); + _PA_LOAD_FUNC(snd_pcm_sw_params_free); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_start_threshold); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold); + _PA_LOAD_FUNC(snd_pcm_sw_params_get_boundary); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_threshold); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_size); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_xfer_align); + _PA_LOAD_FUNC(snd_pcm_sw_params_set_tstamp_mode); -_PA_LOAD_FUNC(snd_pcm_info); -_PA_LOAD_FUNC(snd_pcm_info_sizeof); -_PA_LOAD_FUNC(snd_pcm_info_malloc); -_PA_LOAD_FUNC(snd_pcm_info_free); -_PA_LOAD_FUNC(snd_pcm_info_set_device); -_PA_LOAD_FUNC(snd_pcm_info_set_subdevice); -_PA_LOAD_FUNC(snd_pcm_info_set_stream); -_PA_LOAD_FUNC(snd_pcm_info_get_name); -_PA_LOAD_FUNC(snd_pcm_info_get_card); + _PA_LOAD_FUNC(snd_pcm_info); + _PA_LOAD_FUNC(snd_pcm_info_sizeof); + _PA_LOAD_FUNC(snd_pcm_info_malloc); + _PA_LOAD_FUNC(snd_pcm_info_free); + _PA_LOAD_FUNC(snd_pcm_info_set_device); + _PA_LOAD_FUNC(snd_pcm_info_set_subdevice); + _PA_LOAD_FUNC(snd_pcm_info_set_stream); + _PA_LOAD_FUNC(snd_pcm_info_get_name); + _PA_LOAD_FUNC(snd_pcm_info_get_card); -_PA_LOAD_FUNC(snd_ctl_pcm_next_device); -_PA_LOAD_FUNC(snd_ctl_pcm_info); -_PA_LOAD_FUNC(snd_ctl_open); -_PA_LOAD_FUNC(snd_ctl_close); -_PA_LOAD_FUNC(snd_ctl_card_info_malloc); -_PA_LOAD_FUNC(snd_ctl_card_info_free); -_PA_LOAD_FUNC(snd_ctl_card_info); -_PA_LOAD_FUNC(snd_ctl_card_info_sizeof); -_PA_LOAD_FUNC(snd_ctl_card_info_get_name); + _PA_LOAD_FUNC(snd_ctl_pcm_next_device); + _PA_LOAD_FUNC(snd_ctl_pcm_info); + _PA_LOAD_FUNC(snd_ctl_open); + _PA_LOAD_FUNC(snd_ctl_close); + _PA_LOAD_FUNC(snd_ctl_card_info_malloc); + _PA_LOAD_FUNC(snd_ctl_card_info_free); + _PA_LOAD_FUNC(snd_ctl_card_info); + _PA_LOAD_FUNC(snd_ctl_card_info_sizeof); + _PA_LOAD_FUNC(snd_ctl_card_info_get_name); -_PA_LOAD_FUNC(snd_config); -_PA_LOAD_FUNC(snd_config_update); -_PA_LOAD_FUNC(snd_config_search); -_PA_LOAD_FUNC(snd_config_iterator_entry); -_PA_LOAD_FUNC(snd_config_iterator_first); -_PA_LOAD_FUNC(snd_config_iterator_end); -_PA_LOAD_FUNC(snd_config_iterator_next); -_PA_LOAD_FUNC(snd_config_get_string); -_PA_LOAD_FUNC(snd_config_get_id); -_PA_LOAD_FUNC(snd_config_update_free_global); + _PA_LOAD_FUNC(snd_config); + _PA_LOAD_FUNC(snd_config_update); + _PA_LOAD_FUNC(snd_config_search); + _PA_LOAD_FUNC(snd_config_iterator_entry); + _PA_LOAD_FUNC(snd_config_iterator_first); + _PA_LOAD_FUNC(snd_config_iterator_end); + _PA_LOAD_FUNC(snd_config_iterator_next); + _PA_LOAD_FUNC(snd_config_get_string); + _PA_LOAD_FUNC(snd_config_get_id); + _PA_LOAD_FUNC(snd_config_update_free_global); -_PA_LOAD_FUNC(snd_pcm_status); -_PA_LOAD_FUNC(snd_pcm_status_sizeof); -_PA_LOAD_FUNC(snd_pcm_status_get_tstamp); -_PA_LOAD_FUNC(snd_pcm_status_get_state); -_PA_LOAD_FUNC(snd_pcm_status_get_trigger_tstamp); -_PA_LOAD_FUNC(snd_pcm_status_get_delay); + _PA_LOAD_FUNC(snd_pcm_status); + _PA_LOAD_FUNC(snd_pcm_status_sizeof); + _PA_LOAD_FUNC(snd_pcm_status_get_tstamp); + _PA_LOAD_FUNC(snd_pcm_status_get_state); + _PA_LOAD_FUNC(snd_pcm_status_get_trigger_tstamp); + _PA_LOAD_FUNC(snd_pcm_status_get_delay); -_PA_LOAD_FUNC(snd_card_next); -_PA_LOAD_FUNC(snd_strerror); -_PA_LOAD_FUNC(snd_output_stdio_attach); + _PA_LOAD_FUNC(snd_card_next); + _PA_LOAD_FUNC(snd_asoundlib_version); + _PA_LOAD_FUNC(snd_strerror); + _PA_LOAD_FUNC(snd_output_stdio_attach); #undef _PA_LOAD_FUNC #ifdef PA_ALSA_DYNAMIC - PA_DEBUG(( "%s: loaded ALSA API - ok\n", __FUNCTION__ )); + PA_DEBUG(( "%s: loaded ALSA API - ok\n", __FUNCTION__ )); #define _PA_VALIDATE_LOAD_REPLACEMENT(x)\ - do {\ - if (alsa_##x == NULL)\ - {\ - alsa_##x = &_PA_LOCAL_IMPL(x);\ - PA_DEBUG(( "%s: replacing [%s] with local implementation\n", __FUNCTION__, #x ));\ - }\ - } while (0) + do {\ + if( alsa_##x == NULL )\ + {\ + alsa_##x = &_PA_LOCAL_IMPL(x);\ + PA_DEBUG(( "%s: replacing [%s] with local implementation\n", __FUNCTION__, #x ));\ + }\ + } while (0) - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_rate_near); - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_buffer_size_near); - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_period_size_near); - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_min); - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_max); - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_min); - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_max); - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_min); - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_max); - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_buffer_size_max); - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_min); - _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_rate_near); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_buffer_size_near); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_period_size_near); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_buffer_size_max); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_min); + _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_max); #undef _PA_LOCAL_IMPL #undef _PA_VALIDATE_LOAD_REPLACEMENT @@ -545,14 +554,14 @@ static void PaAlsa_CloseLibrary() { #ifdef PA_ALSA_DYNAMIC dlclose(g_AlsaLib); - g_AlsaLib = NULL; + g_AlsaLib = NULL; #endif } /* Check return value of ALSA function, and map it to PaError */ #define ENSURE_(expr, code) \ do { \ - int __pa_unsure_error_id;\ + int __pa_unsure_error_id;\ if( UNLIKELY( (__pa_unsure_error_id = (expr)) < 0 ) ) \ { \ /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ @@ -570,10 +579,10 @@ static void PaAlsa_CloseLibrary() #define ASSERT_CALL_(expr, success) \ do {\ - int __pa_assert_error_id;\ - __pa_assert_error_id = (expr);\ - assert( success == __pa_assert_error_id );\ - } while (0) + int __pa_assert_error_id;\ + __pa_assert_error_id = (expr);\ + assert( success == __pa_assert_error_id );\ + } while (0) static int numPeriods_ = 4; static int busyRetries_ = 100; @@ -593,16 +602,17 @@ typedef enum typedef struct { PaSampleFormat hostSampleFormat; - unsigned long framesPerBuffer; int numUserChannels, numHostChannels; int userInterleaved, hostInterleaved; int canMmap; void *nonMmapBuffer; unsigned int nonMmapBufferSize; PaDeviceIndex device; /* Keep the device index */ + int deviceIsPlug; /* Distinguish plug types from direct 'hw:' devices */ + int useReventFix; /* Alsa older than 1.0.16, plug devices need a fix */ snd_pcm_t *pcm; - snd_pcm_uframes_t bufferSize; + snd_pcm_uframes_t framesPerPeriod, alsaBufferSize; snd_pcm_format_t nativeFormat; unsigned int nfds; int ready; /* Marked ready from poll */ @@ -659,6 +669,7 @@ typedef struct PaAlsaHostApiRepresentation PaUtilAllocationGroup *allocations; PaHostApiIndex hostApiIndex; + PaUint32 alsaLibVersion; /* Retrieved from the library at run-time */ } PaAlsaHostApiRepresentation; @@ -699,6 +710,7 @@ static double GetStreamCpuLoad( PaStream* stream ); static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi ); static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate ); static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate ); +static PaUint32 PaAlsaVersionNum(void); /* Callback prototypes */ static void *CallbackThreadFunc( void *userData ); @@ -735,6 +747,7 @@ PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex sizeof(PaAlsaHostApiRepresentation) ), paInsufficientMemory ); PA_UNLESS( alsaHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); alsaHostApi->hostApiIndex = hostApiIndex; + alsaHostApi->alsaLibVersion = PaAlsaVersionNum(); *hostApi = (PaUtilHostApiRepresentation*)alsaHostApi; (*hostApi)->info.structVersion = 1; @@ -823,12 +836,13 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in { PaError result = paNoError; snd_pcm_hw_params_t *hwParams; - snd_pcm_uframes_t lowLatency = 512, highLatency = 2048; + snd_pcm_uframes_t alsaBufferFrames, alsaPeriodFrames; unsigned int minChans, maxChans; int* minChannels, * maxChannels; double * defaultLowLatency, * defaultHighLatency, * defaultSampleRate = &devInfo->baseDeviceInfo.defaultSampleRate; double defaultSr = *defaultSampleRate; + int dir; assert( pcm ); @@ -861,6 +875,7 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in if( SetApproximateSampleRate( pcm, hwParams, defaultSr ) < 0 ) { defaultSr = -1.; + alsa_snd_pcm_hw_params_any( pcm, hwParams ); /* Clear any params (rate) that might have been set */ PA_DEBUG(( "%s: Original default samplerate failed, trying again ..\n", __FUNCTION__ )); } } @@ -868,7 +883,10 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in if( defaultSr < 0. ) /* Default sample rate not set */ { unsigned int sampleRate = 44100; /* Will contain approximate rate returned by alsa-lib */ - if( alsa_snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ) < 0) + + /* Don't allow rate resampling when probing for the default rate (but ignore if this call fails) */ + alsa_snd_pcm_hw_params_set_rate_resample( pcm, hwParams, 0 ); + if( alsa_snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ) < 0 ) { result = paUnanticipatedHostError; goto error; @@ -890,35 +908,34 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in } /* TWEAKME: - * - * Giving values for default min and max latency is not - * straightforward. Here are our objectives: - * - * * for low latency, we want to give the lowest value - * that will work reliably. This varies based on the - * sound card, kernel, CPU, etc. I think it is better - * to give sub-optimal latency than to give a number - * too low and cause dropouts. My conservative - * estimate at this point is to base it on 4096-sample - * latency at 44.1 kHz, which gives a latency of 23ms. - * * for high latency we want to give a large enough - * value that dropouts are basically impossible. This - * doesn't really require as much tweaking, since - * providing too large a number will just cause us to - * select the nearest setting that will work at stream - * config time. + * Giving values for default min and max latency is not straightforward. + * * for low latency, we want to give the lowest value that will work reliably. + * This varies based on the sound card, kernel, CPU, etc. Better to give + * sub-optimal latency than to give a number too low and cause dropouts. + * * for high latency we want to give a large enough value that dropouts are basically impossible. + * This doesn't really require as much tweaking, since providing too large a number will + * just cause us to select the nearest setting that will work at stream config time. */ - ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &lowLatency ), paUnanticipatedHostError ); + /* Try low latency values, (sometimes the buffer & period that result are larger) */ + alsaBufferFrames = 512; + alsaPeriodFrames = 128; + ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir ), paUnanticipatedHostError ); + *defaultLowLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr; - /* Have to reset hwParams, to set new buffer size */ + /* Base the high latency case on values four times larger */ + alsaBufferFrames = 2048; + alsaPeriodFrames = 512; + /* Have to reset hwParams, to set new buffer size; need to also set sample rate again */ ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); - ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &highLatency ), paUnanticipatedHostError ); + ENSURE_( SetApproximateSampleRate( pcm, hwParams, defaultSr ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir ), paUnanticipatedHostError ); + *defaultHighLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr; *minChannels = (int)minChans; *maxChannels = (int)maxChans; *defaultSampleRate = defaultSr; - *defaultLowLatency = (double) lowLatency / *defaultSampleRate; - *defaultHighLatency = (double) highLatency / *defaultSampleRate; end: alsa_snd_pcm_close( pcm ); @@ -929,7 +946,7 @@ error: } /* Initialize device info with invalid values (maxInputChannels and maxOutputChannels are set to zero since these indicate - * wether input/output is available) */ + * whether input/output is available) */ static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo ) { deviceInfo->structVersion = -1; @@ -944,6 +961,24 @@ static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo ) deviceInfo->defaultSampleRate = -1.; } + +/* Retrieve the version of the runtime Alsa-lib, as a single number equivalent to + * SND_LIB_VERSION. Only a version string is available ("a.b.c") so this has to be converted. + * Assume 'a' and 'b' are single digits only. + */ +static PaUint32 PaAlsaVersionNum(void) +{ + char* verStr; + PaUint32 verNum; + + verStr = (char*) alsa_snd_asoundlib_version(); + verNum = ALSA_VERSION_INT( atoi(verStr), atoi(verStr + 2), atoi(verStr + 4) ); + PA_DEBUG(( "ALSA version (build): " SND_LIB_VERSION_STR "\nALSA version (runtime): %s\n", verStr )); + + return verNum; +} + + /* Helper struct */ typedef struct { @@ -957,10 +992,10 @@ typedef struct HwDevInfo predefinedNames[] = { { "center_lfe", NULL, 0, 1, 0 }, -/* { "default", NULL, 0, 1, 0 }, */ -/* { "dmix", NULL, 0, 1, 0 }, */ +/* { "default", NULL, 0, 1, 1 }, */ + { "dmix", NULL, 0, 1, 0 }, /* { "dpl", NULL, 0, 1, 0 }, */ -/* { "dsnoop", NULL, 0, 1, 0 }, */ +/* { "dsnoop", NULL, 0, 0, 1 }, */ { "front", NULL, 0, 1, 0 }, { "iec958", NULL, 0, 1, 0 }, /* { "modem", NULL, 0, 1, 0 }, */ @@ -982,11 +1017,11 @@ HwDevInfo predefinedNames[] = { { "AndroidPlayback_ExtraDockSpeaker_normal", NULL, 0, 1, 0 }, { "AndroidPlayback_TvOut_normal", NULL, 0, 1, 0 }, - { "AndroidRecord_Microphone", NULL, 0, 0, 1 }, + { "AndroidRecord_Microphone", NULL, 0, 0, 1 }, { "AndroidRecord_Earpiece_normal", NULL, 0, 0, 1 }, - { "AndroidRecord_Speaker_normal", NULL, 0, 0, 1 }, + { "AndroidRecord_Speaker_normal", NULL, 0, 0, 1 }, { "AndroidRecord_Headset_normal", NULL, 0, 0, 1 }, - { "AndroidRecord_Bluetooth_normal", NULL, 0, 0, 1 }, + { "AndroidRecord_Bluetooth_normal", NULL, 0, 0, 1 }, { "AndroidRecord_Speaker_Headset_normal", NULL, 0, 0, 1 }, { NULL, NULL, 0, 1, 0 } @@ -1043,6 +1078,38 @@ static int IgnorePlugin( const char *pluginId ) return 0; } +/* Skip past parts at the beginning of a (pcm) info name that are already in the card name, to avoid duplication */ +static char *SkipCardDetailsInName( char *infoSkipName, char *cardRefName ) +{ + char *lastSpacePosn = infoSkipName; + + /* Skip matching chars; but only in chunks separated by ' ' (not part words etc), so track lastSpacePosn */ + while( *cardRefName ) + { + while( *infoSkipName && *cardRefName && *infoSkipName == *cardRefName) + { + infoSkipName++; + cardRefName++; + if( *infoSkipName == ' ' || *infoSkipName == '\0' ) + lastSpacePosn = infoSkipName; + } + infoSkipName = lastSpacePosn; + /* Look for another chunk; post-increment means ends pointing to next char */ + while( *cardRefName && ( *cardRefName++ != ' ' )); + } + if( *infoSkipName == '\0' ) + return "-"; /* The 2 names were identical; instead of a nul-string, return a marker string */ + + /* Now want to move to the first char after any spaces */ + while( *lastSpacePosn && *lastSpacePosn == ' ' ) + lastSpacePosn++; + /* Skip a single separator char if present in the remaining pcm name; (pa will add its own) */ + if(( *lastSpacePosn == '-' || *lastSpacePosn == ':' ) && *(lastSpacePosn + 1) == ' ' ) + lastSpacePosn += 2; + + return lastSpacePosn; +} + /** Open PCM device. * * Wrapper around alsa_snd_pcm_open which may repeatedly retry opening a device if it is busy, for @@ -1053,16 +1120,17 @@ static int IgnorePlugin( const char *pluginId ) **/ static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode, int waitOnBusy ) { - int tries = 0, maxTries = waitOnBusy ? busyRetries_ : 0; - int ret = alsa_snd_pcm_open( pcmp, name, stream, mode ); + int ret, tries = 0, maxTries = waitOnBusy ? busyRetries_ : 0; + + ret = alsa_snd_pcm_open( pcmp, name, stream, mode ); + for( tries = 0; tries < maxTries && -EBUSY == ret; ++tries ) { Pa_Sleep( 10 ); ret = alsa_snd_pcm_open( pcmp, name, stream, mode ); if( -EBUSY != ret ) { - PA_DEBUG(( "%s: Successfully opened initially busy device after %d tries\n", - __FUNCTION__, tries )); + PA_DEBUG(( "%s: Successfully opened initially busy device after %d tries\n", __FUNCTION__, tries )); } } if( -EBUSY == ret ) @@ -1071,14 +1139,14 @@ static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, } else { - if (ret < 0) - PA_DEBUG(( "%s: Opened device '%s' ptr[%p] - result: [%d:%s]\n", __FUNCTION__, name, *pcmp, ret, alsa_snd_strerror(ret) )); + if( ret < 0 ) + PA_DEBUG(( "%s: Opened device '%s' ptr[%p] - result: [%d:%s]\n", __FUNCTION__, name, *pcmp, ret, alsa_snd_strerror(ret) )); } return ret; } -static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* deviceName, int blocking, +static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* deviceHwInfo, int blocking, PaAlsaDeviceInfo* devInfo, int* devIdx ) { PaError result = 0; @@ -1086,45 +1154,43 @@ static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* d snd_pcm_t *pcm = NULL; PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep; - PA_DEBUG(( "%s: filling device info for: %s\n", __FUNCTION__, deviceName->name )); + PA_DEBUG(( "%s: Filling device info for: %s\n", __FUNCTION__, deviceHwInfo->name )); /* Zero fields */ InitializeDeviceInfo( baseDeviceInfo ); - /* to determine device capabilities, we must open the device and query the + /* To determine device capabilities, we must open the device and query the * hardware parameter configuration space */ /* Query capture */ - if( deviceName->hasCapture && - OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 ) - >= 0 ) + if( deviceHwInfo->hasCapture && + OpenPcm( &pcm, deviceHwInfo->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 ) >= 0 ) { - if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_In, blocking, devInfo ) != paNoError ) + if( GropeDevice( pcm, deviceHwInfo->isPlug, StreamDirection_In, blocking, devInfo ) != paNoError ) { /* Error */ - PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceName->alsaName)); + PA_DEBUG(( "%s: Failed groping %s for capture\n", __FUNCTION__, deviceHwInfo->alsaName )); goto end; } } /* Query playback */ - if( deviceName->hasPlayback && - OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 ) - >= 0 ) + if( deviceHwInfo->hasPlayback && + OpenPcm( &pcm, deviceHwInfo->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 ) >= 0 ) { - if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out, blocking, devInfo ) != paNoError ) + if( GropeDevice( pcm, deviceHwInfo->isPlug, StreamDirection_Out, blocking, devInfo ) != paNoError ) { /* Error */ - PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceName->alsaName)); + PA_DEBUG(( "%s: Failed groping %s for playback\n", __FUNCTION__, deviceHwInfo->alsaName )); goto end; } } baseDeviceInfo->structVersion = 2; baseDeviceInfo->hostApi = alsaApi->hostApiIndex; - baseDeviceInfo->name = deviceName->name; - devInfo->alsaName = deviceName->alsaName; - devInfo->isPlug = deviceName->isPlug; + baseDeviceInfo->name = deviceHwInfo->name; + devInfo->alsaName = deviceHwInfo->alsaName; + devInfo->isPlug = deviceHwInfo->isPlug; /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object. * Should now be safe to add device info, unless the device supports neither capture nor playback @@ -1132,25 +1198,25 @@ static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* d if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 ) { /* Make device default if there isn't already one or it is the ALSA "default" device */ - if( (baseApi->info.defaultInputDevice == paNoDevice || !strcmp(deviceName->alsaName, - "default" )) && baseDeviceInfo->maxInputChannels > 0 ) + if( ( baseApi->info.defaultInputDevice == paNoDevice || + !strcmp( deviceHwInfo->alsaName, "default" ) ) && baseDeviceInfo->maxInputChannels > 0 ) { baseApi->info.defaultInputDevice = *devIdx; - PA_DEBUG(("Default input device: %s\n", deviceName->name)); + PA_DEBUG(( "Default input device: %s\n", deviceHwInfo->name )); } - if( (baseApi->info.defaultOutputDevice == paNoDevice || !strcmp(deviceName->alsaName, - "default" )) && baseDeviceInfo->maxOutputChannels > 0 ) + if( ( baseApi->info.defaultOutputDevice == paNoDevice || + !strcmp( deviceHwInfo->alsaName, "default" ) ) && baseDeviceInfo->maxOutputChannels > 0 ) { baseApi->info.defaultOutputDevice = *devIdx; - PA_DEBUG(("Default output device: %s\n", deviceName->name)); + PA_DEBUG(( "Default output device: %s\n", deviceHwInfo->name )); } - PA_DEBUG(("%s: Adding device %s: %d\n", __FUNCTION__, deviceName->name, *devIdx)); + PA_DEBUG(( "%s: Adding device %s: %d\n", __FUNCTION__, deviceHwInfo->name, *devIdx )); baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo; (*devIdx) += 1; } else { - PA_DEBUG(( "%s: skipped device: %s, all channels - 0\n", __FUNCTION__, deviceName->name )); + PA_DEBUG(( "%s: Skipped device: %s, all channels == 0\n", __FUNCTION__, deviceHwInfo->name )); } end: @@ -1171,6 +1237,8 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) snd_pcm_info_t *pcmInfo; int res; int blocking = SND_PCM_NONBLOCK; + int usePlughw = 0; + char *hwPrefix = ""; char alsaCardName[50]; #ifdef PA_ENABLE_DEBUG_OUTPUT PaTime startTime = PaUtil_GetTime(); @@ -1179,6 +1247,14 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) ) blocking = 0; + /* If PA_ALSA_PLUGHW is 1 (non-zero), use the plughw: pcm throughout instead of hw: */ + if( getenv( "PA_ALSA_PLUGHW" ) && atoi( getenv( "PA_ALSA_PLUGHW" ) ) ) + { + usePlughw = 1; + hwPrefix = "plug"; + PA_DEBUG(( "%s: Using Plughw\n", __FUNCTION__ )); + } + /* These two will be set to the first working input and output device, respectively */ baseApi->info.defaultInputDevice = paNoDevice; baseApi->info.defaultOutputDevice = paNoDevice; @@ -1216,10 +1292,11 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) while( alsa_snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 ) { - char *alsaDeviceName, *deviceName; + char *alsaDeviceName, *deviceName, *infoName; size_t len; int hasPlayback = 0, hasCapture = 0; - snprintf( buf, sizeof (buf), "hw:%d,%d", cardIdx, devIdx ); + + snprintf( buf, sizeof (buf), "%s%s,%d", hwPrefix, alsaCardName, devIdx ); /* Obtain info about this particular device */ alsa_snd_pcm_info_set_device( pcmInfo, devIdx ); @@ -1242,12 +1319,13 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) continue; } + infoName = SkipCardDetailsInName( (char *)alsa_snd_pcm_info_get_name( pcmInfo ), cardName ); + /* The length of the string written by snprintf plus terminating 0 */ - len = snprintf( NULL, 0, "%s: %s (%s)", cardName, alsa_snd_pcm_info_get_name( pcmInfo ), buf ) + 1; + len = snprintf( NULL, 0, "%s: %s (%s)", cardName, infoName, buf ) + 1; PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ), paInsufficientMemory ); - snprintf( deviceName, len, "%s: %s (%s)", cardName, - alsa_snd_pcm_info_get_name( pcmInfo ), buf ); + snprintf( deviceName, len, "%s: %s (%s)", cardName, infoName, buf ); ++numDeviceNames; if( !hwDevInfos || numDeviceNames > maxDeviceNames ) @@ -1261,7 +1339,7 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) hwDevInfos[ numDeviceNames - 1 ].alsaName = alsaDeviceName; hwDevInfos[ numDeviceNames - 1 ].name = deviceName; - hwDevInfos[ numDeviceNames - 1 ].isPlug = 0; + hwDevInfos[ numDeviceNames - 1 ].isPlug = usePlughw; hwDevInfos[ numDeviceNames - 1 ].hasPlayback = hasPlayback; hwDevInfos[ numDeviceNames - 1 ].hasCapture = hasCapture; } @@ -1269,15 +1347,14 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) } /* Iterate over plugin devices */ - if( NULL == (*alsa_snd_config) ) { /* alsa_snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */ ENSURE_( alsa_snd_config_update(), paUnanticipatedHostError ); PA_DEBUG(( "Updating snd_config\n" )); } - assert( *alsa_snd_config ); - if( (res = alsa_snd_config_search( *alsa_snd_config, "pcm", &topNode )) >= 0 ) + assert( *alsa_snd_config ); + if( ( res = alsa_snd_config_search( *alsa_snd_config, "pcm", &topNode ) ) >= 0 ) { snd_config_iterator_t i, next; @@ -1327,18 +1404,18 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) predefined = FindDeviceName( alsaDeviceName ); hwDevInfos[numDeviceNames - 1].alsaName = alsaDeviceName; - hwDevInfos[numDeviceNames - 1].name = deviceName; - hwDevInfos[numDeviceNames - 1].isPlug = 1; + hwDevInfos[numDeviceNames - 1].name = deviceName; + hwDevInfos[numDeviceNames - 1].isPlug = 1; if( predefined ) { hwDevInfos[numDeviceNames - 1].hasPlayback = predefined->hasPlayback; - hwDevInfos[numDeviceNames - 1].hasCapture = predefined->hasCapture; + hwDevInfos[numDeviceNames - 1].hasCapture = predefined->hasCapture; } else { hwDevInfos[numDeviceNames - 1].hasPlayback = 1; - hwDevInfos[numDeviceNames - 1].hasCapture = 1; + hwDevInfos[numDeviceNames - 1].hasCapture = 1; } } } @@ -1361,7 +1438,7 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) * (dmix) is closed. The 'default' plugin may also point to the dmix plugin, so the same goes * for this. */ - PA_DEBUG(( "%s: filling device info for %d devices\n", __FUNCTION__, numDeviceNames )); + PA_DEBUG(( "%s: Filling device info for %d devices\n", __FUNCTION__, numDeviceNames )); for( i = 0, devIdx = 0; i < numDeviceNames; ++i ) { PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i]; @@ -1384,8 +1461,7 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) continue; } - PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, - &devIdx ) ); + PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) ); } free( hwDevInfos ); @@ -1432,8 +1508,8 @@ static PaError ValidateParameters( const PaStreamParameters *parameters, PaUtilH assert( deviceInfo ); assert( parameters->hostApiSpecificStreamInfo == NULL ); - maxChans = (StreamDirection_In == mode ? deviceInfo->baseDeviceInfo.maxInputChannels : - deviceInfo->baseDeviceInfo.maxOutputChannels); + maxChans = ( StreamDirection_In == mode ? deviceInfo->baseDeviceInfo.maxInputChannels : + deviceInfo->baseDeviceInfo.maxOutputChannels ); PA_UNLESS( parameters->channelCount <= maxChans, paInvalidChannelCount ); error: @@ -1484,7 +1560,7 @@ static void LogAllAvailableFormats( snd_pcm_t *pcm ) alsa_snd_pcm_hw_params_any( pcm, hwParams ); - PA_DEBUG(( " --- Supported Formats ---\n" )); + PA_DEBUG(( " --- Supported Formats ---\n" )); if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0) PA_DEBUG(( "SND_PCM_FORMAT_S8\n" )); @@ -1630,32 +1706,22 @@ static snd_pcm_format_t Pa2AlsaFormat( PaSampleFormat paFormat ) /** Open an ALSA pcm handle. * - * The device to be open can be specified in a custom PaAlsaStreamInfo struct, or it will be a device number. In case of a - * device number, it maybe specified through an env variable (PA_ALSA_PLUGHW) that we should open the corresponding plugin - * device. + * The device to be open can be specified by name in a custom PaAlsaStreamInfo struct, or it will be by + * the Portaudio device number supplied in the stream parameters. */ static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *params, StreamDirection streamDir, snd_pcm_t **pcm ) { PaError result = paNoError; int ret; - char dnameArray[50]; - const char* deviceName = dnameArray; + const char* deviceName = ""; const PaAlsaDeviceInfo *deviceInfo = NULL; PaAlsaStreamInfo *streamInfo = (PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo; if( !streamInfo ) { - int usePlug = 0; deviceInfo = GetDeviceInfo( hostApi, params->device ); - - /* If device name starts with hw: and PA_ALSA_PLUGHW is 1, we open the plughw device instead */ - if( !strncmp( "hw:", deviceInfo->alsaName, 3 ) && getenv( "PA_ALSA_PLUGHW" ) ) - usePlug = atoi( getenv( "PA_ALSA_PLUGHW" ) ); - if( usePlug ) - snprintf( dnameArray, 50, "plug%s", deviceInfo->alsaName ); - else - deviceName = deviceInfo->alsaName; + deviceName = deviceInfo->alsaName; } else deviceName = streamInfo->deviceString; @@ -1724,7 +1790,7 @@ static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const { /* It happens that this call fails because the device is busy */ int ret = 0; - if( (ret = alsa_snd_pcm_hw_params( pcm, hwParams )) < 0) + if( ( ret = alsa_snd_pcm_hw_params( pcm, hwParams ) ) < 0 ) { if( -EINVAL == ret ) { @@ -1784,13 +1850,13 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, if( inputChannelCount ) { - if( (result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In )) + if( ( result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In ) ) != paNoError ) goto error; } if ( outputChannelCount ) { - if( (result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out )) + if( ( result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out ) ) != paNoError ) goto error; } @@ -1801,6 +1867,7 @@ error: return result; } + static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *params, StreamDirection streamDir, int callbackMode ) { @@ -1816,12 +1883,19 @@ static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, Pa const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->baseHostApiRep, params->device ); self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels : devInfo->minOutputChannels ); + self->deviceIsPlug = devInfo->isPlug; + PA_DEBUG(( "%s: Host Chans %c %i\n", __FUNCTION__, streamDir == StreamDirection_In ? 'C' : 'P', self->numHostChannels )); } else { /* We're blissfully unaware of the minimum channelCount */ self->numHostChannels = params->channelCount; + /* Check if device name does not start with hw: to determine if it is a 'plug' device */ + if( strncmp( "hw:", ((PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo)->deviceString, 3 ) != 0 ) + self->deviceIsPlug = 1; /* An Alsa plug device, not a direct hw device */ } + if( self->deviceIsPlug && alsaApi->alsaLibVersion < ALSA_VERSION_INT( 1, 0, 16 ) ) + self->useReventFix = 1; /* Prior to Alsa1.0.16, plug devices may stutter without this fix */ self->device = params->device; @@ -1832,7 +1906,7 @@ static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, Pa self->hostSampleFormat = hostSampleFormat; self->nativeFormat = Pa2AlsaFormat( hostSampleFormat ); - self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved); + self->hostInterleaved = self->userInterleaved = !( userSampleFormat & paNonInterleaved ); self->numUserChannels = params->channelCount; self->streamDir = streamDir; self->canMmap = 0; @@ -1850,7 +1924,7 @@ error: /* Log all available formats. */ if ( hostSampleFormat == paSampleFormatNotSupported ) - { + { LogAllAvailableFormats( self->pcm ); PA_DEBUG(( "%s: Please provide the log output to PortAudio developers, your hardware does not have any sample format implemented yet.\n", __FUNCTION__ )); } @@ -1861,8 +1935,8 @@ error: static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self ) { alsa_snd_pcm_close( self->pcm ); - if( self->userBuffers ) - PaUtil_FreeMemory( self->userBuffers ); + PaUtil_FreeMemory( self->userBuffers ); /* (Ptr can be NULL; PaUtil_FreeMemory includes a NULL check) */ + PaUtil_FreeMemory( self->nonMmapBuffer ); } /* @@ -1893,7 +1967,7 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se double sr = *sampleRate; unsigned int minPeriods = 2; - /* self->framesPerBuffer = framesPerHostBuffer; */ + /* self->framesPerPeriod = framesPerHostBuffer; */ /* ... fill up the configuration space with all possibile * combinations of parameters this device will accept */ @@ -1913,10 +1987,10 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se self->canMmap = alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 || alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0; - PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, (alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO"))); - PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, (alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO"))); + PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO" ) )); + PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO" ) )); - if (!self->canMmap) + if( !self->canMmap ) { accessMode = SND_PCM_ACCESS_RW_INTERLEAVED; alternateAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED; @@ -1931,23 +2005,23 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se self->canMmap = alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 || alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0; - PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, (alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO"))); - PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, (alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO"))); + PA_DEBUG((" %s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO" ) )); + PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO" ) )); - if (!self->canMmap) + if( !self->canMmap ) { accessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED; alternateAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED; } } - PA_DEBUG(("%s: device can MMAP: %s\n", __FUNCTION__, (self->canMmap ? "YES" : "NO"))); + PA_DEBUG(( "%s: device can MMAP: %s\n", __FUNCTION__, ( self->canMmap ? "YES" : "NO" ) )); /* If requested access mode fails, try alternate mode */ if( alsa_snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 ) { int err = 0; - if( (err = alsa_snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0) + if( ( err = alsa_snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0 ) { result = paUnanticipatedHostError; PaUtil_SetLastHostErrorInfo( paALSA, err, alsa_snd_strerror( err ) ); @@ -1960,13 +2034,18 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se /* Some specific hardware (reported: Audio8 DJ) can fail with assertion during this step. */ ENSURE_( alsa_snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError ); - ENSURE_( SetApproximateSampleRate( pcm, hwParams, sr ), paInvalidSampleRate ); - ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError ); - /* reject if there's no sample rate within 1% of the one requested */ - if( (fabs( *sampleRate - sr ) / *sampleRate) > 0.01 ) + if( ( result = SetApproximateSampleRate( pcm, hwParams, sr )) != paUnanticipatedHostError ) { - PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr )); - PA_ENSURE( paInvalidSampleRate ); + ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError ); + if( result == paInvalidSampleRate ) /* From the SetApproximateSampleRate() call above */ + { /* The sample rate was returned as 'out of tolerance' of the one requested */ + PA_DEBUG(( "%s: Wanted %.3f, closest sample rate was %.3f\n", __FUNCTION__, sampleRate, sr )); + PA_ENSURE( paInvalidSampleRate ); + } + } + else + { + PA_ENSURE( paUnanticipatedHostError ); } ENSURE_( alsa_snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount ); @@ -1983,7 +2062,7 @@ error: /** Finish the configuration of the component's ALSA device. * - * As part of this method, the component's bufferSize attribute will be set. + * As part of this method, the component's alsaBufferSize attribute will be set. * @param latency: The latency for this component. */ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *self, snd_pcm_hw_params_t* hwParams, @@ -1996,7 +2075,7 @@ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *sel alsa_snd_pcm_sw_params_alloca( &swParams ); - bufSz = params->suggestedLatency * sampleRate; + bufSz = params->suggestedLatency * sampleRate + self->framesPerPeriod; ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError ); /* Set the parameters! */ @@ -2010,25 +2089,25 @@ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *sel alsa_snd_pcm_hw_params_dump( hwParams, output ); } #endif - ENSURE_(r, paUnanticipatedHostError ); + ENSURE_( r, paUnanticipatedHostError ); } - if (alsa_snd_pcm_hw_params_get_buffer_size != NULL) + if( alsa_snd_pcm_hw_params_get_buffer_size != NULL ) { - ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError ); - } - else - { - self->bufferSize = bufSz; - } + ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size( hwParams, &self->alsaBufferSize ), paUnanticipatedHostError ); + } + else + { + self->alsaBufferSize = bufSz; + } /* Latency in seconds */ - *latency = self->bufferSize / sampleRate; + *latency = (self->alsaBufferSize - self->framesPerPeriod) / sampleRate; /* Now software parameters... */ ENSURE_( alsa_snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError ); - ENSURE_( alsa_snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError ); - ENSURE_( alsa_snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->bufferSize ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerPeriod ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->alsaBufferSize ), paUnanticipatedHostError ); /* Silence buffer in the case of underrun */ if( !primeBuffers ) /* XXX: Make sense? */ @@ -2039,7 +2118,7 @@ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *sel ENSURE_( alsa_snd_pcm_sw_params_set_silence_size( self->pcm, swParams, boundary ), paUnanticipatedHostError ); } - ENSURE_( alsa_snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerPeriod ), paUnanticipatedHostError ); ENSURE_( alsa_snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError ); ENSURE_( alsa_snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError ); @@ -2057,7 +2136,7 @@ static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiReprese PaError result = paNoError; assert( self ); - memset( self, 0, sizeof (PaAlsaStream) ); + memset( self, 0, sizeof( PaAlsaStream ) ); if( NULL != callback ) { @@ -2093,8 +2172,8 @@ static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiReprese assert( self->capture.nfds || self->playback.nfds ); - PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( (self->capture.nfds + - self->playback.nfds) * sizeof (struct pollfd) ), paInsufficientMemory ); + PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( ( self->capture.nfds + + self->playback.nfds ) * sizeof( struct pollfd ) ), paInsufficientMemory ); PaUtil_InitializeCpuLoadMeasurer( &self->cpuLoadMeasurer, sampleRate ); ASSERT_CALL_( PaUnixMutex_Initialize( &self->stateMtx ), paNoError ); @@ -2145,7 +2224,7 @@ static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frame */ static unsigned long PaAlsa_AlignBackward(unsigned long v, unsigned long align) { - return ((v - (align ? v % align : 0))); + return ( v - ( align ? v % align : 0 ) ); } /** Align value in forward direction. @@ -2155,8 +2234,8 @@ static unsigned long PaAlsa_AlignBackward(unsigned long v, unsigned long align) */ static unsigned long PaAlsa_AlignForward(unsigned long v, unsigned long align) { - unsigned long remainder = (align ? (v % align) : 0); - return (remainder != 0 ? v + (align - remainder) : v); + unsigned long remainder = ( align ? ( v % align ) : 0); + return ( remainder != 0 ? v + ( align - remainder ) : v ); } /** Get size of host buffer maintained from the number of user frames, sample rate and suggested latency. Minimum double buffering @@ -2168,13 +2247,13 @@ static unsigned long PaAlsa_AlignForward(unsigned long v, unsigned long align) */ static unsigned long PaAlsa_GetFramesPerHostBuffer(unsigned long userFramesPerBuffer, PaTime suggestedLatency, double sampleRate) { - unsigned long frames = userFramesPerBuffer + PA_MAX( userFramesPerBuffer, (unsigned long)(suggestedLatency * sampleRate) ); - return frames; + unsigned long frames = userFramesPerBuffer + PA_MAX( userFramesPerBuffer, (unsigned long)( suggestedLatency * sampleRate ) ); + return frames; } /** Determine size per host buffer. * - * During this method call, the component's framesPerBuffer attribute gets computed, and the corresponding period size + * During this method call, the component's framesPerPeriod attribute gets computed, and the corresponding period size * gets configured for the device. * @param accurate: If the configured period size is non-integer, this will be set to 0. */ @@ -2239,7 +2318,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo #endif - { + { unsigned numPeriods = numPeriods_, maxPeriods = 0, minPeriods = numPeriods_; /* It may be that the device only supports 2 periods for instance */ @@ -2272,8 +2351,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo { if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 ) framesPerHostBuffer *= 2; - else - if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 ) + else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 ) framesPerHostBuffer /= 2; } } @@ -2284,8 +2362,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo { if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 ) framesPerHostBuffer += framesPerUserBuffer; - else - if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 ) + else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 ) framesPerHostBuffer -= framesPerUserBuffer; } } @@ -2314,7 +2391,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo { while( bufferSize / framesPerHostBuffer < numPeriods ) { - if( framesPerUserBuffer % (framesPerHostBuffer / 2) != 0 ) + if( framesPerUserBuffer % ( framesPerHostBuffer / 2 ) != 0 ) { /* Can't be divided any further */ break; @@ -2356,7 +2433,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo framesPerHostBuffer = 2048; #endif PA_DEBUG(( "%s: suggested host buffer period = %lu \n", __FUNCTION__, framesPerHostBuffer )); - } + } { /* Get min/max period sizes and adjust our chosen */ @@ -2368,19 +2445,18 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo if( framesPerHostBuffer < min ) { PA_DEBUG(( "%s: The determined period size (%lu) is less than minimum (%lu)\n", __FUNCTION__, framesPerHostBuffer, min )); - framesPerHostBuffer = ((minmax_diff == 2) ? min + 1 : min); + framesPerHostBuffer = (( minmax_diff == 2 ) ? min + 1 : min ); } - else - if( framesPerHostBuffer > max ) + else if( framesPerHostBuffer > max ) { PA_DEBUG(( "%s: The determined period size (%lu) is greater than maximum (%lu)\n", __FUNCTION__, framesPerHostBuffer, max )); - framesPerHostBuffer = ((minmax_diff == 2) ? max - 1 : max); + framesPerHostBuffer = (( minmax_diff == 2 ) ? max - 1 : max ); } - PA_DEBUG(( "%s: device period minimum = %lu\n", __FUNCTION__, min )); - PA_DEBUG(( "%s: device period maximum = %lu\n", __FUNCTION__, max )); - PA_DEBUG(( "%s: host buffer period = %lu\n", __FUNCTION__, framesPerHostBuffer )); - PA_DEBUG(( "%s: host buffer period latency = %f\n", __FUNCTION__, (double)(framesPerHostBuffer / sampleRate) )); + PA_DEBUG(( "%s: device period minimum = %lu\n", __FUNCTION__, min )); + PA_DEBUG(( "%s: device period maximum = %lu\n", __FUNCTION__, max )); + PA_DEBUG(( "%s: host buffer period = %lu\n", __FUNCTION__, framesPerHostBuffer )); + PA_DEBUG(( "%s: host buffer period latency = %f\n", __FUNCTION__, (double)( framesPerHostBuffer / sampleRate ) )); /* Try setting period size */ dir = 0; @@ -2393,7 +2469,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo } /* Set result */ - self->framesPerBuffer = framesPerHostBuffer; + self->framesPerPeriod = framesPerHostBuffer; error: return result; @@ -2420,7 +2496,7 @@ error: * which should be fine if the period size is the same for capture and playback. In general, if there is a specified user * buffer size, this method tries it best to determine a period size which is a multiple of the user buffer size. * - * The framesPerBuffer attributes of the individual capture and playback components of the stream are set to corresponding + * The framesPerPeriod attributes of the individual capture and playback components of the stream are set to corresponding * values determined here. Since these should be reported as * * This is one of those blocks of code that will just take a lot of @@ -2463,8 +2539,8 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double maxPeriodSize = PA_MIN( maxPlayback, maxCapture ); PA_UNLESS( minPeriodSize <= maxPeriodSize, paBadIODeviceCombination ); - desiredBufSz = (snd_pcm_uframes_t)(PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency ) - * sampleRate); + desiredBufSz = (snd_pcm_uframes_t)( PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency ) + * sampleRate ); /* Clamp desiredBufSz */ { snd_pcm_uframes_t maxBufferSize; @@ -2478,7 +2554,7 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double /* Find the closest power of 2 */ e = ilogb( minPeriodSize ); - if( minPeriodSize & (minPeriodSize - 1) ) + if( minPeriodSize & ( minPeriodSize - 1 ) ) e += 1; periodSize = (snd_pcm_uframes_t)pow( 2, e ); @@ -2524,7 +2600,7 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double paUnanticipatedHostError ); ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ), paUnanticipatedHostError ); - self->capture.framesPerBuffer = self->playback.framesPerBuffer = periodSize; + self->capture.framesPerPeriod = self->playback.framesPerPeriod = periodSize; framesPerHostBuffer = periodSize; } else @@ -2533,15 +2609,15 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize ); optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize ); - self->capture.framesPerBuffer = optimalPeriodSize; + self->capture.framesPerPeriod = optimalPeriodSize; dir = 0; - ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerBuffer, &dir ), + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerPeriod, &dir ), paUnanticipatedHostError ); - self->playback.framesPerBuffer = optimalPeriodSize; + self->playback.framesPerPeriod = optimalPeriodSize; dir = 0; - ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerBuffer, &dir ), + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerPeriod, &dir ), paUnanticipatedHostError ); - framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer ); + framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod ); *hostBufferSizeMode = paUtilBoundedHostBufferSize; } } @@ -2571,17 +2647,17 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( first, firstStreamParams, framesPerUserBuffer, sampleRate, firstHwParams, &accurate ) ); - second->framesPerBuffer = first->framesPerBuffer; + second->framesPerPeriod = first->framesPerPeriod; dir = 0; - ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerBuffer, &dir ), + ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerPeriod, &dir ), paUnanticipatedHostError ); - if( self->capture.framesPerBuffer == self->playback.framesPerBuffer ) + if( self->capture.framesPerPeriod == self->playback.framesPerPeriod ) { - framesPerHostBuffer = self->capture.framesPerBuffer; + framesPerHostBuffer = self->capture.framesPerPeriod; } else { - framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer ); + framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod ); *hostBufferSizeMode = paUtilBoundedHostBufferSize; } } @@ -2592,14 +2668,14 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double { PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->capture, inputParameters, framesPerUserBuffer, sampleRate, hwParamsCapture, &accurate) ); - framesPerHostBuffer = self->capture.framesPerBuffer; + framesPerHostBuffer = self->capture.framesPerPeriod; } else { assert( self->playback.pcm ); PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->playback, outputParameters, framesPerUserBuffer, sampleRate, hwParamsPlayback, &accurate ) ); - framesPerHostBuffer = self->playback.framesPerBuffer; + framesPerHostBuffer = self->playback.framesPerPeriod; } } @@ -2645,17 +2721,17 @@ static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParamet if( self->capture.pcm ) { - assert( self->capture.framesPerBuffer != 0 ); + assert( self->capture.framesPerPeriod != 0 ); PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->capture, hwParamsCapture, inParams, self->primeBuffers, realSr, inputLatency ) ); - PA_DEBUG(( "%s: Capture period size: %lu, latency: %f\n", __FUNCTION__, self->capture.framesPerBuffer, *inputLatency )); + PA_DEBUG(( "%s: Capture period size: %lu, latency: %f\n", __FUNCTION__, self->capture.framesPerPeriod, *inputLatency )); } if( self->playback.pcm ) { - assert( self->playback.framesPerBuffer != 0 ); + assert( self->playback.framesPerPeriod != 0 ); PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->playback, hwParamsPlayback, outParams, self->primeBuffers, realSr, outputLatency ) ); - PA_DEBUG(( "%s: Playback period size: %lu, latency: %f\n", __FUNCTION__, self->playback.framesPerBuffer, *outputLatency )); + PA_DEBUG(( "%s: Playback period size: %lu, latency: %f\n", __FUNCTION__, self->playback.framesPerPeriod, *outputLatency )); } /* Should be exact now */ @@ -2675,8 +2751,8 @@ static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParamet } { - unsigned long minFramesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerBuffer : ULONG_MAX, - self->playback.pcm ? self->playback.framesPerBuffer : ULONG_MAX ); + unsigned long minFramesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerPeriod : ULONG_MAX, + self->playback.pcm ? self->playback.framesPerPeriod : ULONG_MAX ); self->pollTimeout = CalculatePollTimeout( self, minFramesPerHostBuffer ); /* Period in msecs, rounded up */ /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */ @@ -2686,7 +2762,7 @@ static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParamet if( self->callbackMode ) { /* If the user expects a certain number of frames per callback we will either have to rely on block adaption - * (framesPerHostBuffer is not an integer multiple of framesPerBuffer) or we can simply align the number + * (framesPerHostBuffer is not an integer multiple of framesPerPeriod) or we can simply align the number * of host buffer frames with what the user specified */ if( self->framesPerUserBuffer != paFramesPerBufferUnspecified ) { @@ -2695,8 +2771,8 @@ static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParamet /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely * on block adaption */ /* - if( framesPerHostBuffer % framesPerBuffer != 0 || (self->capture.pcm && self->playback.pcm && - self->capture.framesPerBuffer != self->playback.framesPerBuffer) ) + if( framesPerHostBuffer % framesPerPeriod != 0 || (self->capture.pcm && self->playback.pcm && + self->capture.framesPerPeriod != self->playback.framesPerPeriod) ) self->useBlockAdaption = 1; else self->alignFrames = 1; @@ -2729,7 +2805,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* XXX: Use Bounded by default? Output tends to get stuttery with Fixed ... */ PaUtilHostBufferSizeMode hostBufferSizeMode = paUtilFixedHostBufferSize; - if( (streamFlags & paPlatformSpecificFlags) != 0 ) + if( ( streamFlags & paPlatformSpecificFlags ) != 0 ) return paInvalidFlag; if( inputParameters ) @@ -2750,7 +2826,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* XXX: Why do we support this anyway? */ if( framesPerBuffer == paFramesPerBufferUnspecified && getenv( "PA_ALSA_PERIODSIZE" ) != NULL ) { - PA_DEBUG(( "%s: Getting framesPerBuffer from environment\n", __FUNCTION__ )); + PA_DEBUG(( "%s: Getting framesPerBuffer (Alsa period-size) from environment\n", __FUNCTION__ )); framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") ); } @@ -2777,7 +2853,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, stream->streamRepresentation.streamInfo.outputLatency = outputLatency + (PaTime)( PaUtil_GetBufferProcessorOutputLatencyFrames( &stream->bufferProcessor ) / sampleRate); - PA_DEBUG(( "%s: Stream: framesPerBuffer = %lu, maxFramesPerHostBuffer = %lu, latency = i(%f)/o(%f), \n", __FUNCTION__, framesPerBuffer, stream->maxFramesPerHostBuffer, stream->streamRepresentation.streamInfo.inputLatency, stream->streamRepresentation.streamInfo.outputLatency)); + PA_DEBUG(( "%s: Stream: framesPerBuffer = %lu, maxFramesPerHostBuffer = %lu, latency i=%f, o=%f\n", __FUNCTION__, framesPerBuffer, stream->maxFramesPerHostBuffer, stream->streamRepresentation.streamInfo.inputLatency, stream->streamRepresentation.streamInfo.outputLatency)); *s = (PaStream*)stream; @@ -2818,7 +2894,7 @@ static void SilenceBuffer( PaAlsaStream *stream ) /** Start/prepare pcm(s) for streaming. * - * Depending on wether the stream is in callback or blocking mode, we will respectively start or simply + * Depending on whether the stream is in callback or blocking mode, we will respectively start or simply * prepare the playback pcm. If the buffer has _not_ been primed, we will in callback mode prepare and * silence the buffer before starting playback. In blocking mode we simply prepare, as the playback will * be started automatically as the user writes to output. @@ -2904,7 +2980,7 @@ static PaError StartStream( PaStream *s ) { PaError result = paNoError; PaAlsaStream* stream = (PaAlsaStream*)s; - int streamStarted = 0; /* So we can know wether we need to take the stream down */ + int streamStarted = 0; /* So we can know whether we need to take the stream down */ /* Ready the processor */ PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); @@ -2995,7 +3071,7 @@ error: /** Stop or abort stream. * - * If a stream is in callback mode we will have to inspect wether the background thread has + * If a stream is in callback mode we will have to inspect whether the background thread has * finished, or we will have to take it out. In either case we join the thread before * returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish * buffers (drain) @@ -3106,50 +3182,43 @@ static double GetStreamCpuLoad( PaStream* s ) return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } +/* Set the stream sample rate to a nominal value requested; allow only a defined tolerance range */ static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate ) { PaError result = paNoError; - unsigned long approx = (unsigned long) sampleRate; - int dir = 0; - double fraction = sampleRate - approx; + unsigned int reqRate, setRate, deviation; assert( pcm && hwParams ); - if( fraction > 0.0 ) - { - if( fraction > 0.5 ) - { - ++approx; - dir = -1; - } - else - dir = 1; - } + /* The Alsa sample rate is set by integer value; also the actual rate may differ */ + reqRate = setRate = (unsigned int) sampleRate; - if( alsa_snd_pcm_hw_params_set_rate( pcm, hwParams, approx, dir ) < 0) + ENSURE_( alsa_snd_pcm_hw_params_set_rate_near( pcm, hwParams, &setRate, NULL ), paUnanticipatedHostError ); + /* The value actually set will be put in 'setRate' (may be way off); check the deviation as a proportion + * of the requested-rate with reference to the max-deviate-ratio (larger values allow less deviation) */ + deviation = abs( setRate - reqRate ); + if( deviation > 0 && deviation * RATE_MAX_DEVIATE_RATIO > reqRate ) result = paInvalidSampleRate; end: - return result; error: - /* Log */ { - unsigned int _min = 0, _max = 0; int _dir = 0; + unsigned int _min = 0, _max = 0; + int _dir = 0; ENSURE_( alsa_snd_pcm_hw_params_get_rate_min( hwParams, &_min, &_dir ), paUnanticipatedHostError ); ENSURE_( alsa_snd_pcm_hw_params_get_rate_max( hwParams, &_max, &_dir ), paUnanticipatedHostError ); - PA_DEBUG(( "%s: SR min = %d, max = %d, req = %lu\n", __FUNCTION__, _min, _max, approx )); + PA_DEBUG(( "%s: SR min = %u, max = %u, req = %u\n", __FUNCTION__, _min, _max, reqRate )); } - goto end; } /* Return exact sample rate in param sampleRate */ static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate ) { - unsigned int num, den; + unsigned int num, den = 1; int err; assert( hwParams ); @@ -3198,11 +3267,11 @@ static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self ) if( alsa_snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN ) { alsa_snd_pcm_status_get_trigger_tstamp( st, &t ); - self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000); + self->underrun = now * 1000 - ( (PaTime)t.tv_sec * 1000 + (PaTime)t.tv_usec / 1000 ); - if (!self->playback.canMmap) + if( !self->playback.canMmap ) { - if (alsa_snd_pcm_recover( self->playback.pcm, -EPIPE, 0 ) < 0) + if( alsa_snd_pcm_recover( self->playback.pcm, -EPIPE, 0 ) < 0 ) { PA_DEBUG(( "%s: [playback] non-MMAP-PCM failed recovering from XRUN, will restart Alsa\n", __FUNCTION__ )); ++ restartAlsa; /* did not manage to recover */ @@ -3269,7 +3338,7 @@ static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamD } /* ALSA docs say that negative delay should indicate xrun, but in my experience alsa_snd_pcm_delay returns -EPIPE */ - if( (err = alsa_snd_pcm_delay( otherComponent->pcm, &delay )) < 0 ) + if( ( err = alsa_snd_pcm_delay( otherComponent->pcm, &delay ) ) < 0 ) { if( err == -EPIPE ) { @@ -3284,16 +3353,16 @@ static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamD if( StreamDirection_Out == streamDir ) { /* Number of eligible frames before capture overrun */ - delay = otherComponent->bufferSize - delay; + delay = otherComponent->alsaBufferSize - delay; } - margin = delay - otherComponent->framesPerBuffer / 2; + margin = delay - otherComponent->framesPerPeriod / 2; if( margin < 0 ) { PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" )); *continuePoll = 0; } - else if( margin < otherComponent->framesPerBuffer ) + else if( margin < otherComponent->framesPerPeriod ) { *pollTimeout = CalculatePollTimeout( stream, margin ); PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n", @@ -3345,7 +3414,7 @@ static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *t alsa_snd_pcm_status_get_tstamp( capture_status, &capture_timestamp ); capture_time = capture_timestamp.tv_sec + - ((PaTime)capture_timestamp.tv_usec / 1000000.0); + ( (PaTime)capture_timestamp.tv_usec / 1000000.0 ); timeInfo->currentTime = capture_time; capture_delay = alsa_snd_pcm_status_get_delay( capture_status ); @@ -3367,7 +3436,7 @@ static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *t /* Hmm, we have both a playback and a capture timestamp. * Hopefully they are the same... */ if( fabs( capture_time - playback_time ) > 0.01 ) - PA_DEBUG(("Capture time and playback time differ by %f\n", fabs(capture_time-playback_time))); + PA_DEBUG(( "Capture time and playback time differ by %f\n", fabs( capture_time-playback_time ) )); } else timeInfo->currentTime = playback_time; @@ -3404,7 +3473,7 @@ static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, else { void *bufs[self->numHostChannels]; - int bufsize = alsa_snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ); + int bufsize = alsa_snd_pcm_format_size( self->nativeFormat, self->framesPerPeriod + 1 ); unsigned char *buffer = self->nonMmapBuffer; int i; for( i = 0; i < self->numHostChannels; ++i ) @@ -3418,13 +3487,6 @@ static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, if( self->canMmap ) res = alsa_snd_pcm_mmap_commit( self->pcm, self->offset, numFrames ); - else - { - /* using realloc for optimisation - free( self->nonMmapBuffer ); - self->nonMmapBuffer = NULL; - */ - } if( res == -EPIPE || res == -ESTRPIPE ) { @@ -3443,7 +3505,7 @@ error: /* Extract buffer from channel area */ static unsigned char *ExtractAddress( const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset ) { - return (unsigned char *) area->addr + (area->first + offset * area->step) / 8; + return (unsigned char *) area->addr + ( area->first + offset * area->step ) / 8; } /** Do necessary adaption between user and host channels. @@ -3458,7 +3520,7 @@ static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *s int i; int unusedChans = self->numHostChannels - self->numUserChannels; unsigned char *src, *dst; - int convertMono = (self->numHostChannels % 2) == 0 && (self->numUserChannels % 2) != 0; + int convertMono = ( self->numHostChannels % 2 ) == 0 && ( self->numUserChannels % 2 ) != 0; assert( StreamDirection_Out == self->streamDir ); @@ -3473,7 +3535,7 @@ static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *s if( convertMono ) { /* Convert the last user channel into stereo pair */ - src = buffer + (self->numUserChannels - 1) * swidth; + src = buffer + ( self->numUserChannels - 1 ) * swidth; for( i = 0; i < numFrames; ++i ) { dst = src + swidth; @@ -3502,12 +3564,12 @@ static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *s if( convertMono ) { ENSURE_( alsa_snd_pcm_area_copy( self->channelAreas + self->numUserChannels, self->offset, self->channelAreas + - (self->numUserChannels - 1), self->offset, numFrames, self->nativeFormat ), paUnanticipatedHostError ); + ( self->numUserChannels - 1 ), self->offset, numFrames, self->nativeFormat ), paUnanticipatedHostError ); --unusedChans; } if( unusedChans > 0 ) { - alsa_snd_pcm_areas_silence( self->channelAreas + (self->numHostChannels - unusedChans), self->offset, unusedChans, numFrames, + alsa_snd_pcm_areas_silence( self->channelAreas + ( self->numHostChannels - unusedChans ), self->offset, unusedChans, numFrames, self->nativeFormat ); } } @@ -3596,8 +3658,7 @@ static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent* self, st { *xrun = 1; } - else - if( revents & POLLHUP ) + else if( revents & POLLHUP ) { *xrun = 1; PA_DEBUG(( "%s: revents has POLLHUP, processing as XRUN\n", __FUNCTION__ )); @@ -3607,6 +3668,16 @@ static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent* self, st *shouldPoll = 0; } + else /* (A zero revent occurred) */ + /* Work around an issue with Alsa older than 1.0.16 using some plugins (eg default with plug + dmix) where + * POLLIN or POLLOUT are zeroed by Alsa-lib if _mmap_avail() is a few frames short of avail_min at period + * boundary, possibly due to erratic dma interrupts at period boundary? Treat as a valid event. + */ + if( self->useReventFix ) + { + self->ready = 1; + *shouldPoll = 0; + } error: return result; @@ -3728,13 +3799,29 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr } if( pollPlayback ) { - playbackPfds = self->pfds + (self->capture.pcm ? self->capture.nfds : 0); + /* self->pfds is in effect an array of fds; if necessary, index past the capture fds */ + playbackPfds = self->pfds + (pollCapture ? self->capture.nfds : 0); PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) ); totalFds += self->playback.nfds; } +#ifdef PTHREAD_CANCELED + if( self->callbackMode ) + { + /* To allow 'Abort' to terminate the callback thread, enable cancelability just for poll() (& disable after) */ + pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL ); + } +#endif + pollResults = poll( self->pfds, totalFds, pollTimeout ); +#ifdef PTHREAD_CANCELED + if( self->callbackMode ) + { + pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL ); + } +#endif + if( pollResults < 0 ) { /* XXX: Depend on preprocessor condition? */ @@ -3748,10 +3835,8 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr /* TODO: Add macro for checking system calls */ PA_ENSURE( paInternalError ); } - else - if (pollResults == 0) + else if( pollResults == 0 ) { - /* Suspended, paused or failed device can provide 0 poll results. To avoid deadloop in such situation * we simply run counter 'timeouts' which detects 0 poll result and accumulates. As soon as 2048 timouts (around 2 seconds) * are achieved we simply fail function with paTimedOut to notify waiting methods that device is not capable @@ -3760,24 +3845,22 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr */ /*PA_DEBUG(( "%s: poll == 0 results, timed out, %d times left\n", __FUNCTION__, 2048 - timeouts ));*/ - ++ timeouts; - if (timeouts > 1) /* sometimes device times out, but normally once, so we do not sleep any time */ + if( timeouts > 1 ) /* sometimes device times out, but normally once, so we do not sleep any time */ { Pa_Sleep( 1 ); /* avoid hot loop */ } /* not else ! */ - if (timeouts >= 2048) /* audio device not working, shall return error to notify waiters */ + if( timeouts >= 2048 ) /* audio device not working, shall return error to notify waiters */ { - *framesAvail = 0; /* no frames available for processing */ - xrun = 1; /* try recovering device */ + *framesAvail = 0; /* no frames available for processing */ + xrun = 1; /* try recovering device */ PA_DEBUG(( "%s: poll timed out\n", __FUNCTION__, timeouts )); goto end;/*PA_ENSURE( paTimedOut );*/ } } - else - if (pollResults > 0) + else if( pollResults > 0 ) { /* reset timouts counter */ timeouts = 0; @@ -3831,7 +3914,7 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr { /* Drop input, a period's worth */ assert( self->capture.ready ); - PaAlsaStreamComponent_EndProcessing( &self->capture, PA_MIN( self->capture.framesPerBuffer, + PaAlsaStreamComponent_EndProcessing( &self->capture, PA_MIN( self->capture.framesPerPeriod, *framesAvail ), &xrun ); *framesAvail = 0; self->capture.ready = 0; @@ -3899,10 +3982,10 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se else { unsigned int bufferSize = self->numHostChannels * alsa_snd_pcm_format_size( self->nativeFormat, *numFrames ); - if (bufferSize > self->nonMmapBufferSize) + if( bufferSize > self->nonMmapBufferSize ) { - self->nonMmapBuffer = realloc(self->nonMmapBuffer, (self->nonMmapBufferSize = bufferSize)); - if (!self->nonMmapBuffer) + self->nonMmapBuffer = realloc( self->nonMmapBuffer, ( self->nonMmapBufferSize = bufferSize ) ); + if( !self->nonMmapBuffer ) { result = paInsufficientMemory; goto error; @@ -4107,12 +4190,18 @@ static void *CallbackThreadFunc( void *userData ) int streamStarted = 0; assert( stream ); + /* Not implemented */ + assert( !stream->primeBuffers ); /* Execute OnExit when exiting */ pthread_cleanup_push( &OnExit, stream ); - - /* Not implemented */ - assert( !stream->primeBuffers ); +#ifdef PTHREAD_CANCELED + /* 'Abort' will use thread cancellation to terminate the callback thread, but the Alsa-lib functions + * are NOT cancel-safe, (and can end up in an inconsistent state). So, disable cancelability for + * the thread here, and just re-enable it for the poll() in PaAlsaStream_WaitForFrames(). */ + pthread_testcancel(); + pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL ); +#endif /* @concern StreamStart If the output is being primed the output pcm needs to be prepared, otherwise the * stream is started immediately. The latter involves signaling the waiting main thread. @@ -4129,8 +4218,8 @@ static void *CallbackThreadFunc( void *userData ) /* We can't be certain that the whole ring buffer is available for priming, but there should be * at least one period */ avail = alsa_snd_pcm_avail_update( stream->playback.pcm ); - startThreshold = avail - (avail % stream->playback.framesPerBuffer); - assert( startThreshold >= stream->playback.framesPerBuffer ); + startThreshold = avail - (avail % stream->playback.framesPerPeriod); + assert( startThreshold >= stream->playback.framesPerPeriod ); } else { @@ -4148,7 +4237,7 @@ static void *CallbackThreadFunc( void *userData ) int xrun = 0; #ifdef PTHREAD_CANCELED - pthread_testcancel(); + pthread_testcancel(); #endif /* @concern StreamStop if the main thread has requested a stop and the stream has not been effectively @@ -4162,7 +4251,7 @@ static void *CallbackThreadFunc( void *userData ) if( paContinue != callbackResult ) { - stream->callbackAbort = (paAbort == callbackResult); + stream->callbackAbort = ( paAbort == callbackResult ); if( stream->callbackAbort || /** @concern BlockAdaption: Go on if adaption buffers are empty */ PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) @@ -4197,10 +4286,6 @@ static void *CallbackThreadFunc( void *userData ) { xrun = 0; -#ifdef PTHREAD_CANCELED - pthread_testcancel(); -#endif - /** @concern Xruns Under/overflows are to be reported to the callback */ if( stream->underrun > 0.0 ) { @@ -4231,11 +4316,12 @@ static void *CallbackThreadFunc( void *userData ) #if 0 CallbackUpdate( &stream->threading ); #endif + CalculateTimeInfo( stream, &timeInfo ); PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags ); cbFlags = 0; - /* CPU load measurement should include processing activivity external to the stream callback */ + /* CPU load measurement should include processing activity external to the stream callback */ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); framesGot = framesAvail; @@ -4266,7 +4352,6 @@ static void *CallbackThreadFunc( void *userData ) { /* Go back to polling for more frames */ break; - } if( paContinue != callbackResult ) @@ -4400,10 +4485,10 @@ static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frame /* Frames residing in buffer */ PA_ENSURE( err = GetStreamWriteAvailable( stream ) ); framesAvail = err; - hwAvail = stream->playback.bufferSize - framesAvail; + hwAvail = stream->playback.alsaBufferSize - framesAvail; if( alsa_snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED && - hwAvail >= stream->playback.framesPerBuffer ) + hwAvail >= stream->playback.framesPerPeriod ) { ENSURE_( alsa_snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError ); } @@ -4509,7 +4594,8 @@ error: return paNoError; } -PaError PaAlsa_GetStreamInputCard(PaStream* s, int* card) { +PaError PaAlsa_GetStreamInputCard( PaStream* s, int* card ) +{ PaAlsaStream *stream; PaError result = paNoError; snd_pcm_info_t* pcmInfo; @@ -4527,7 +4613,8 @@ error: return result; } -PaError PaAlsa_GetStreamOutputCard(PaStream* s, int* card) { +PaError PaAlsa_GetStreamOutputCard( PaStream* s, int* card ) +{ PaAlsaStream *stream; PaError result = paNoError; snd_pcm_info_t* pcmInfo; diff --git a/Externals/portaudio/src/hostapi/asio/pa_asio.cpp b/Externals/portaudio/src/hostapi/asio/pa_asio.cpp index 28eee9dbb5..f230d8788d 100644 --- a/Externals/portaudio/src/hostapi/asio/pa_asio.cpp +++ b/Externals/portaudio/src/hostapi/asio/pa_asio.cpp @@ -1,5 +1,5 @@ /* - * $Id: pa_asio.cpp 1778 2011-11-10 13:59:53Z rossb $ + * $Id$ * Portable Audio I/O Library for ASIO Drivers * * Author: Stephane Letz @@ -1019,6 +1019,149 @@ static ASIOSampleRate defaultSampleRateSearchOrder_[] 192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 }; +static PaError InitPaDeviceInfoFromAsioDriver( PaAsioHostApiRepresentation *asioHostApi, + const char *driverName, int driverIndex, + PaDeviceInfo *deviceInfo, PaAsioDeviceInfo *asioDeviceInfo ) +{ + PaError result = paNoError; + + /* Due to the headless design of the ASIO API, drivers are free to write over data given to them (like M-Audio + drivers f.i.). This is an attempt to overcome that. */ + union _tag_local { + PaAsioDriverInfo info; + char _padding[4096]; + } paAsioDriver; + + asioDeviceInfo->asioChannelInfos = 0; /* we check this below to handle error cleanup */ + + result = LoadAsioDriver( asioHostApi, driverName, &paAsioDriver.info, asioHostApi->systemSpecific ); + if( result == paNoError ) + { + PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n", driverIndex,deviceInfo->name)); + PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels = %d\n", driverIndex, paAsioDriver.info.inputChannelCount)); + PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels = %d\n", driverIndex, paAsioDriver.info.outputChannelCount)); + PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", driverIndex, paAsioDriver.info.bufferMinSize)); + PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", driverIndex, paAsioDriver.info.bufferMaxSize)); + PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", driverIndex, paAsioDriver.info.bufferPreferredSize)); + PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", driverIndex, paAsioDriver.info.bufferGranularity)); + + deviceInfo->maxInputChannels = paAsioDriver.info.inputChannelCount; + deviceInfo->maxOutputChannels = paAsioDriver.info.outputChannelCount; + + deviceInfo->defaultSampleRate = 0.; + bool foundDefaultSampleRate = false; + for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j ) + { + ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] ); + if( asioError != ASE_NoClock && asioError != ASE_NotPresent ) + { + deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j]; + foundDefaultSampleRate = true; + break; + } + } + + PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", driverIndex, deviceInfo->defaultSampleRate)); + + if( foundDefaultSampleRate ){ + + /* calculate default latency values from bufferPreferredSize + for default low latency, and bufferMaxSize + for default high latency. + use the default sample rate to convert from samples to + seconds. Without knowing what sample rate the user will + use this is the best we can do. + */ + + double defaultLowLatency = + paAsioDriver.info.bufferPreferredSize / deviceInfo->defaultSampleRate; + + deviceInfo->defaultLowInputLatency = defaultLowLatency; + deviceInfo->defaultLowOutputLatency = defaultLowLatency; + + double defaultHighLatency = + paAsioDriver.info.bufferMaxSize / deviceInfo->defaultSampleRate; + + if( defaultHighLatency < defaultLowLatency ) + defaultHighLatency = defaultLowLatency; /* just in case the driver returns something strange */ + + deviceInfo->defaultHighInputLatency = defaultHighLatency; + deviceInfo->defaultHighOutputLatency = defaultHighLatency; + + }else{ + + deviceInfo->defaultLowInputLatency = 0.; + deviceInfo->defaultLowOutputLatency = 0.; + deviceInfo->defaultHighInputLatency = 0.; + deviceInfo->defaultHighOutputLatency = 0.; + } + + PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", driverIndex, deviceInfo->defaultLowInputLatency)); + PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", driverIndex, deviceInfo->defaultLowOutputLatency)); + PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", driverIndex, deviceInfo->defaultHighInputLatency)); + PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", driverIndex, deviceInfo->defaultHighOutputLatency)); + + asioDeviceInfo->minBufferSize = paAsioDriver.info.bufferMinSize; + asioDeviceInfo->maxBufferSize = paAsioDriver.info.bufferMaxSize; + asioDeviceInfo->preferredBufferSize = paAsioDriver.info.bufferPreferredSize; + asioDeviceInfo->bufferGranularity = paAsioDriver.info.bufferGranularity; + + + asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory( + asioHostApi->allocations, + sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels + + deviceInfo->maxOutputChannels) ); + if( !asioDeviceInfo->asioChannelInfos ) + { + result = paInsufficientMemory; + goto error_unload; + } + + int a; + + for( a=0; a < deviceInfo->maxInputChannels; ++a ){ + asioDeviceInfo->asioChannelInfos[a].channel = a; + asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue; + ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] ); + if( asioError != ASE_OK ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + goto error_unload; + } + } + + for( a=0; a < deviceInfo->maxOutputChannels; ++a ){ + int b = deviceInfo->maxInputChannels + a; + asioDeviceInfo->asioChannelInfos[b].channel = a; + asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse; + ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] ); + if( asioError != ASE_OK ) + { + result = paUnanticipatedHostError; + PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); + goto error_unload; + } + } + + /* unload the driver */ + UnloadAsioDriver(); + } + + return result; + +error_unload: + UnloadAsioDriver(); + + if( asioDeviceInfo->asioChannelInfos ){ + PaUtil_GroupFreeMemory( asioHostApi->allocations, asioDeviceInfo->asioChannelInfos ); + asioDeviceInfo->asioChannelInfos = 0; + } + + return result; +} + + /* we look up IsDebuggerPresent at runtime incase it isn't present (on Win95 for example) */ typedef BOOL (WINAPI *IsDebuggerPresentPtr)(VOID); IsDebuggerPresentPtr IsDebuggerPresent_ = 0; @@ -1031,8 +1174,6 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex PaAsioHostApiRepresentation *asioHostApi; PaAsioDeviceInfo *deviceInfoArray; char **names; - PaAsioDriverInfo paAsioDriverInfo; - asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) ); if( !asioHostApi ) { @@ -1040,6 +1181,8 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex goto error; } + memset( asioHostApi, 0, sizeof(PaAsioHostApiRepresentation) ); /* ensure all fields are zeroed. especially asioHostApi->allocations */ + /* We initialize COM ourselves here and uninitialize it in Terminate(). This should be the only COM initialization needed in this module. @@ -1142,7 +1285,6 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex for( i=0; i < driverCount; ++i ) { - PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i])); // Since portaudio opens ALL ASIO drivers, and no one else does that, @@ -1170,13 +1312,12 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex if( strcmp(names[i], "ASIO Digidesign Driver") == 0 ) { PA_DEBUG(("BLACKLISTED!!! ASIO Digidesign Driver would quit the debugger\n")); - continue; + continue; } } - /* Attempt to load the asio driver... */ - if( LoadAsioDriver( asioHostApi, names[i], &paAsioDriverInfo, asioHostApi->systemSpecific ) == paNoError ) + /* Attempt to init device info from the asio driver... */ { PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo; @@ -1185,119 +1326,17 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex deviceInfo->hostApi = hostApiIndex; deviceInfo->name = names[i]; - PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n", i,deviceInfo->name)); - PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels = %d\n", i, paAsioDriverInfo.inputChannelCount)); - PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels = %d\n", i, paAsioDriverInfo.outputChannelCount)); - PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", i, paAsioDriverInfo.bufferMinSize)); - PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", i, paAsioDriverInfo.bufferMaxSize)); - PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", i, paAsioDriverInfo.bufferPreferredSize)); - PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", i, paAsioDriverInfo.bufferGranularity)); - deviceInfo->maxInputChannels = paAsioDriverInfo.inputChannelCount; - deviceInfo->maxOutputChannels = paAsioDriverInfo.outputChannelCount; - - deviceInfo->defaultSampleRate = 0.; - bool foundDefaultSampleRate = false; - for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j ) + if( InitPaDeviceInfoFromAsioDriver( asioHostApi, names[i], i, deviceInfo, asioDeviceInfo ) == paNoError ) { - ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] ); - if( asioError != ASE_NoClock && asioError != ASE_NotPresent ) - { - deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j]; - foundDefaultSampleRate = true; - break; - } + (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; + ++(*hostApi)->info.deviceCount; } - - PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", i, deviceInfo->defaultSampleRate)); - - if( foundDefaultSampleRate ){ - - /* calculate default latency values from bufferPreferredSize - for default low latency, and bufferMaxSize - for default high latency. - use the default sample rate to convert from samples to - seconds. Without knowing what sample rate the user will - use this is the best we can do. - */ - - double defaultLowLatency = - paAsioDriverInfo.bufferPreferredSize / deviceInfo->defaultSampleRate; - - deviceInfo->defaultLowInputLatency = defaultLowLatency; - deviceInfo->defaultLowOutputLatency = defaultLowLatency; - - double defaultHighLatency = - paAsioDriverInfo.bufferMaxSize / deviceInfo->defaultSampleRate; - - if( defaultHighLatency < defaultLowLatency ) - defaultHighLatency = defaultLowLatency; /* just in case the driver returns something strange */ - - deviceInfo->defaultHighInputLatency = defaultHighLatency; - deviceInfo->defaultHighOutputLatency = defaultHighLatency; - - }else{ - - deviceInfo->defaultLowInputLatency = 0.; - deviceInfo->defaultLowOutputLatency = 0.; - deviceInfo->defaultHighInputLatency = 0.; - deviceInfo->defaultHighOutputLatency = 0.; + else + { + PA_DEBUG(("Skipping ASIO device:%s\n",names[i])); + continue; } - - PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", i, deviceInfo->defaultLowInputLatency)); - PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", i, deviceInfo->defaultLowOutputLatency)); - PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", i, deviceInfo->defaultHighInputLatency)); - PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", i, deviceInfo->defaultHighOutputLatency)); - - asioDeviceInfo->minBufferSize = paAsioDriverInfo.bufferMinSize; - asioDeviceInfo->maxBufferSize = paAsioDriverInfo.bufferMaxSize; - asioDeviceInfo->preferredBufferSize = paAsioDriverInfo.bufferPreferredSize; - asioDeviceInfo->bufferGranularity = paAsioDriverInfo.bufferGranularity; - - - asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory( - asioHostApi->allocations, - sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels - + deviceInfo->maxOutputChannels) ); - if( !asioDeviceInfo->asioChannelInfos ) - { - result = paInsufficientMemory; - goto error_unload; - } - - int a; - - for( a=0; a < deviceInfo->maxInputChannels; ++a ){ - asioDeviceInfo->asioChannelInfos[a].channel = a; - asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue; - ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] ); - if( asioError != ASE_OK ) - { - result = paUnanticipatedHostError; - PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); - goto error_unload; - } - } - - for( a=0; a < deviceInfo->maxOutputChannels; ++a ){ - int b = deviceInfo->maxInputChannels + a; - asioDeviceInfo->asioChannelInfos[b].channel = a; - asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse; - ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] ); - if( asioError != ASE_OK ) - { - result = paUnanticipatedHostError; - PA_ASIO_SET_LAST_ASIO_ERROR( asioError ); - goto error_unload; - } - } - - - /* unload the driver */ - UnloadAsioDriver(); - - (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; - ++(*hostApi)->info.deviceCount; } } } @@ -1331,9 +1370,6 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex return result; -error_unload: - UnloadAsioDriver(); - error: if( asioHostApi ) { @@ -1744,7 +1780,7 @@ static unsigned long SelectHostBufferSizeForSpecifiedUserFramesPerBuffer( do { if( (x % userFramesPerBuffer) == 0 ) { - /* any power-of-two multiple of userFramesPerBuffer is acceptable */ + /* any multiple of userFramesPerBuffer is acceptable */ result = x; if( result >= targetBufferingLatencyFrames ) break; /* stop. a value >= to targetBufferingLatencyFrames is ideal. */ @@ -1767,7 +1803,7 @@ static unsigned long SelectHostBufferSizeForSpecifiedUserFramesPerBuffer( do { if( (x % userFramesPerBuffer) == 0 ) { - /* any power-of-two multiple of userFramesPerBuffer is acceptable */ + /* any multiple of userFramesPerBuffer is acceptable */ result = x; if( result >= targetBufferingLatencyFrames ) break; /* stop. a value >= to targetBufferingLatencyFrames is ideal. */ @@ -2447,10 +2483,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor , inputChannelCount , inputSampleFormat & ~paNonInterleaved , /* Ring buffer. */ - hostInputSampleFormat , /* Host format. */ + (hostInputSampleFormat | paNonInterleaved), /* Host format. */ outputChannelCount , outputSampleFormat & ~paNonInterleaved, /* Ring buffer. */ - hostOutputSampleFormat , /* Host format. */ + (hostOutputSampleFormat | paNonInterleaved), /* Host format. */ sampleRate , streamFlags , framesPerBuffer , /* Frames per ring buffer block. */ @@ -3046,7 +3082,7 @@ previousIndex = index; paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + theAsioStream->streamRepresentation.streamInfo.outputLatency; */ -/* Disabled! Stopping and re-starting the stream causes an input overflow / output undeflow. S.Fischer */ +/* Disabled! Stopping and re-starting the stream causes an input overflow / output underflow. S.Fischer */ #if 0 // detect underflows by checking inter-callback time > 2 buffer period static double previousTime = -1; @@ -3498,6 +3534,7 @@ static PaError IsStreamActive( PaStream *s ) static PaTime GetStreamTime( PaStream *s ) { (void) s; /* unused parameter */ + return (double)timeGetTime() * .001; } diff --git a/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core.c b/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core.c index b182dac05a..257e9dedc3 100644 --- a/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core.c +++ b/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core.c @@ -125,87 +125,114 @@ static bool ensureChannelNameSize( int size ) */ const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ) { - struct PaUtilHostApiRepresentation *hostApi; - PaError err; - OSStatus error; - err = PaUtil_GetHostApiRepresentation( &hostApi, paCoreAudio ); - assert(err == paNoError); - if( err != paNoError ) - return NULL; - PaMacAUHAL *macCoreHostApi = (PaMacAUHAL*)hostApi; - AudioDeviceID hostApiDevice = macCoreHostApi->devIds[device]; - - UInt32 size = 0; - - error = AudioDeviceGetPropertyInfo( hostApiDevice, - channelIndex + 1, - input, - kAudioDevicePropertyChannelName, - &size, - NULL ); - if( error ) { - //try the CFString - CFStringRef name; - bool isDeviceName = false; - size = sizeof( name ); - error = AudioDeviceGetProperty( hostApiDevice, - channelIndex + 1, - input, - kAudioDevicePropertyChannelNameCFString, - &size, - &name ); - if( error ) { //as a last-ditch effort, get the device name. Later we'll append the channel number. - size = sizeof( name ); - error = AudioDeviceGetProperty( hostApiDevice, - channelIndex + 1, - input, - kAudioDevicePropertyDeviceNameCFString, - &size, - &name ); - if( error ) - return NULL; - isDeviceName = true; - } - if( isDeviceName ) { - name = CFStringCreateWithFormat( NULL, NULL, CFSTR( "%@: %d"), name, channelIndex + 1 ); - } - - CFIndex length = CFStringGetLength(name); - while( ensureChannelNameSize( length * sizeof(UniChar) + 1 ) ) { - if( CFStringGetCString( name, channelName, channelNameSize, kCFStringEncodingUTF8 ) ) { - if( isDeviceName ) - CFRelease( name ); - return channelName; - } - if( length == 0 ) - ++length; - length *= 2; - } - if( isDeviceName ) - CFRelease( name ); - return NULL; - } - - //continue with C string: - if( !ensureChannelNameSize( size ) ) - return NULL; - - error = AudioDeviceGetProperty( hostApiDevice, - channelIndex + 1, - input, - kAudioDevicePropertyChannelName, - &size, - channelName ); - - if( error ) { - ERR( error ); - return NULL; - } - return channelName; + struct PaUtilHostApiRepresentation *hostApi; + PaError err; + OSStatus error; + err = PaUtil_GetHostApiRepresentation( &hostApi, paCoreAudio ); + assert(err == paNoError); + if( err != paNoError ) + return NULL; + PaMacAUHAL *macCoreHostApi = (PaMacAUHAL*)hostApi; + AudioDeviceID hostApiDevice = macCoreHostApi->devIds[device]; + CFStringRef nameRef; + + /* First try with CFString */ + UInt32 size = sizeof(nameRef); + error = AudioDeviceGetProperty( hostApiDevice, + channelIndex + 1, + input, + kAudioDevicePropertyChannelNameCFString, + &size, + &nameRef ); + if( error ) + { + /* try the C String */ + size = 0; + error = AudioDeviceGetPropertyInfo( hostApiDevice, + channelIndex + 1, + input, + kAudioDevicePropertyChannelName, + &size, + NULL); + if( !error ) + { + if( !ensureChannelNameSize( size ) ) + return NULL; + + error = AudioDeviceGetProperty( hostApiDevice, + channelIndex + 1, + input, + kAudioDevicePropertyChannelName, + &size, + channelName ); + + + if( !error ) + return channelName; + } + + /* as a last-ditch effort, we use the device name and append the channel number. */ + nameRef = CFStringCreateWithFormat( NULL, NULL, CFSTR( "%s: %d"), hostApi->deviceInfos[device]->name, channelIndex + 1 ); + + + size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), kCFStringEncodingUTF8);; + if( !ensureChannelNameSize( size ) ) + { + CFRelease( nameRef ); + return NULL; + } + CFStringGetCString( nameRef, channelName, size+1, kCFStringEncodingUTF8 ); + CFRelease( nameRef ); + } + else + { + size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), kCFStringEncodingUTF8);; + if( !ensureChannelNameSize( size ) ) + { + CFRelease( nameRef ); + return NULL; + } + CFStringGetCString( nameRef, channelName, size+1, kCFStringEncodingUTF8 ); + CFRelease( nameRef ); + } + + return channelName; } + +PaError PaMacCore_GetBufferSizeRange( PaDeviceIndex device, + long *minBufferSizeFrames, long *maxBufferSizeFrames ) +{ + PaError result; + PaUtilHostApiRepresentation *hostApi; + + result = PaUtil_GetHostApiRepresentation( &hostApi, paCoreAudio ); + + if( result == paNoError ) + { + PaDeviceIndex hostApiDeviceIndex; + result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDeviceIndex, device, hostApi ); + if( result == paNoError ) + { + PaMacAUHAL *macCoreHostApi = (PaMacAUHAL*)hostApi; + AudioDeviceID macCoreDeviceId = macCoreHostApi->devIds[hostApiDeviceIndex]; + AudioValueRange audioRange; + UInt32 propSize = sizeof( audioRange ); + + // return the size range for the output scope unless we only have inputs + Boolean isInput = 0; + if( macCoreHostApi->inheritedHostApiRep.deviceInfos[hostApiDeviceIndex]->maxOutputChannels == 0 ) + isInput = 1; + + result = WARNING(AudioDeviceGetProperty( macCoreDeviceId, 0, isInput, kAudioDevicePropertyBufferFrameSizeRange, &propSize, &audioRange ) ); - + *minBufferSizeFrames = audioRange.mMinimum; + *maxBufferSizeFrames = audioRange.mMaximum; + } + } + + return result; +} AudioDeviceID PaMacCore_GetStreamInputDevice( PaStream* s ) @@ -280,7 +307,7 @@ static PaError OpenAndSetupOneAudioUnit( /* for setting errors. */ #define PA_AUHAL_SET_LAST_HOST_ERROR( errorCode, errorText ) \ - PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText ) + PaUtil_SetLastHostErrorInfo( paCoreAudio, errorCode, errorText ) /* * Callback called when starting or stopping a stream. @@ -625,26 +652,46 @@ static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi, Float64 sampleRate; char *name; PaError err = paNoError; + CFStringRef nameRef; UInt32 propSize; VVDBUG(("InitializeDeviceInfo(): macCoreDeviceId=%ld\n", macCoreDeviceId)); - memset(deviceInfo, 0, sizeof(deviceInfo)); + memset(deviceInfo, 0, sizeof(PaDeviceInfo)); deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; - - /* Get the device name. Fail if we can't get it. */ - err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL)); + + /* Get the device name using CFString */ + propSize = sizeof(nameRef); + err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceNameCFString, &propSize, &nameRef)); if (err) - return err; + { + /* Get the device name using c string. Fail if we can't get it. */ + err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL)); + if (err) + return err; - name = PaUtil_GroupAllocateMemory(auhalHostApi->allocations,propSize); - if ( !name ) - return paInsufficientMemory; - err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name)); - if (err) - return err; + name = PaUtil_GroupAllocateMemory(auhalHostApi->allocations,propSize+1); + if ( !name ) + return paInsufficientMemory; + err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name)); + if (err) + return err; + } + else + { + /* valid CFString so we just allocate a c string big enough to contain the data */ + propSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(nameRef), kCFStringEncodingUTF8); + name = PaUtil_GroupAllocateMemory(auhalHostApi->allocations, propSize+1); + if ( !name ) + { + CFRelease(nameRef); + return paInsufficientMemory; + } + CFStringGetCString(nameRef, name, propSize+1, kCFStringEncodingUTF8); + CFRelease(nameRef); + } deviceInfo->name = name; /* Try to get the default sample rate. Don't fail if we can't get this. */ @@ -990,18 +1037,19 @@ static void UpdateTimeStampOffsets( PaMacCoreStream *stream ) } /* ================================================================================= */ -/* Query sample rate property. */ -static OSStatus UpdateSampleRateFromDeviceProperty( PaMacCoreStream *stream, AudioDeviceID deviceID, Boolean isInput ) + +/* can be used to update from nominal or actual sample rate */ +static OSStatus UpdateSampleRateFromDeviceProperty( PaMacCoreStream *stream, AudioDeviceID deviceID, Boolean isInput, AudioDevicePropertyID sampleRatePropertyID ) { PaMacCoreDeviceProperties * deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties; - /* FIXME: not sure if this should be the sample rate of the output device or the output unit */ - Float64 actualSampleRate = deviceProperties->sampleRate; + + Float64 sampleRate = 0.0; UInt32 propSize = sizeof(Float64); - OSStatus osErr = AudioDeviceGetProperty( deviceID, 0, isInput, kAudioDevicePropertyActualSampleRate, &propSize, &actualSampleRate); - if( (osErr == noErr) && (actualSampleRate > 1000.0) ) // avoid divide by zero if there's an error + OSStatus osErr = AudioDeviceGetProperty( deviceID, 0, isInput, sampleRatePropertyID, &propSize, &sampleRate); + if( (osErr == noErr) && (sampleRate > 1000.0) ) /* avoid divide by zero if there's an error */ { - deviceProperties->sampleRate = actualSampleRate; - deviceProperties->samplePeriod = 1.0 / actualSampleRate; + deviceProperties->sampleRate = sampleRate; + deviceProperties->samplePeriod = 1.0 / sampleRate; } return osErr; } @@ -1013,7 +1061,7 @@ static OSStatus AudioDevicePropertyActualSampleRateListenerProc( AudioDeviceID i // Make sure the callback is operating on a stream that is still valid! assert( stream->streamRepresentation.magic == PA_STREAM_MAGIC ); - OSStatus osErr = UpdateSampleRateFromDeviceProperty( stream, inDevice, isInput ); + OSStatus osErr = UpdateSampleRateFromDeviceProperty( stream, inDevice, isInput, kAudioDevicePropertyActualSampleRate ); if( osErr == noErr ) { UpdateTimeStampOffsets( stream ); @@ -1077,9 +1125,6 @@ static OSStatus SetupDevicePropertyListeners( PaMacCoreStream *stream, AudioDevi OSStatus osErr = noErr; PaMacCoreDeviceProperties *deviceProperties = isInput ? &stream->inputProperties : &stream->outputProperties; - // Start with the current values for the device properties. - UpdateSampleRateFromDeviceProperty( stream, deviceID, isInput ); - if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput, kAudioDevicePropertyLatency, &deviceProperties->deviceLatency )) != noErr ) return osErr; if( (osErr = QueryUInt32DeviceProperty( deviceID, isInput, @@ -1598,12 +1643,19 @@ static UInt32 CalculateOptimalBufferSize( PaMacAUHAL *auhalHostApi, resultBufferSizeFrames = MAX( resultBufferSizeFrames, (UInt32) variableLatencyFrames ); } + // can't have zero frames. code to round up to next user buffer requires non-zero + resultBufferSizeFrames = MAX( resultBufferSizeFrames, 1 ); + if( requestedFramesPerBuffer != paFramesPerBufferUnspecified ) { // make host buffer the next highest integer multiple of user frames per buffer UInt32 n = (resultBufferSizeFrames + requestedFramesPerBuffer - 1) / requestedFramesPerBuffer; resultBufferSizeFrames = n * requestedFramesPerBuffer; + + // FIXME: really we should be searching for a multiple of requestedFramesPerBuffer + // that is >= suggested latency and also fits within device buffer min/max + }else{ VDBUG( ("Block Size unspecified. Based on Latency, the user wants a Block Size near: %ld.\n", resultBufferSizeFrames ) ); @@ -1737,25 +1789,16 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, do is initialize everything so that if we fail, we know what hasn't been touched. */ - - stream->inputAudioBufferList.mBuffers[0].mData = NULL; - stream->inputRingBuffer.buffer = NULL; - bzero( &stream->blio, sizeof( PaMacBlio ) ); -/* + bzero( stream, sizeof( PaMacCoreStream ) ); + + /* stream->blio.inputRingBuffer.buffer = NULL; stream->blio.outputRingBuffer.buffer = NULL; stream->blio.inputSampleFormat = inputParameters?inputParameters->sampleFormat:0; stream->blio.inputSampleSize = computeSampleSizeFromFormat(stream->blio.inputSampleFormat); stream->blio.outputSampleFormat=outputParameters?outputParameters->sampleFormat:0; stream->blio.outputSampleSize = computeSampleSizeFromFormat(stream->blio.outputSampleFormat); -*/ - stream->inputSRConverter = NULL; - stream->inputUnit = NULL; - stream->outputUnit = NULL; - stream->inputFramesPerBuffer = 0; - stream->outputFramesPerBuffer = 0; - stream->bufferProcessorIsInitialized = FALSE; - stream->timingInformationMutexIsInitialized = 0; + */ /* assert( streamCallback ) ; */ /* only callback mode is implemented */ if( streamCallback ) @@ -1878,14 +1921,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* * If input and output devs are different or we are doing SR conversion, - * we also need a - * ring buffer to store inpt data while waiting for output - * data. + * we also need a ring buffer to store input data while waiting for + * output data. */ if( (stream->outputUnit && (stream->inputUnit != stream->outputUnit)) || stream->inputSRConverter ) { - /* May want the ringSize ot initial position in + /* May want the ringSize or initial position in ring buffer to depend somewhat on sample rate change */ void *data; @@ -1908,7 +1950,15 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, } /* now we can initialize the ring buffer */ - PaUtil_InitializeRingBuffer( &stream->inputRingBuffer, szfl*inputParameters->channelCount, ringSize, data ) ; + result = PaUtil_InitializeRingBuffer( &stream->inputRingBuffer, szfl*inputParameters->channelCount, ringSize, data ); + if( result != 0 ) + { + /* The only reason this should fail is if ringSize is not a power of 2, which we do not anticipate happening. */ + result = paUnanticipatedHostError; + free(data); + goto error; + } + /* advance the read point a little, so we are reading from the middle of the buffer */ if( stream->outputUnit ) @@ -1930,12 +1980,11 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, stream->outputFramesPerBuffer, sampleRate ); result = initializeBlioRingBuffers( &stream->blio, - inputParameters?inputParameters->sampleFormat:0 , - outputParameters?outputParameters->sampleFormat:0 , - MAX(stream->inputFramesPerBuffer,stream->outputFramesPerBuffer), + inputParameters ? inputParameters->sampleFormat : 0, + outputParameters ? outputParameters->sampleFormat : 0, ringSize, - inputParameters?inputChannelCount:0 , - outputParameters?outputChannelCount:0 ) ; + inputParameters ? inputChannelCount : 0, + outputParameters ? outputChannelCount : 0 ) ; if( result != paNoError ) goto error; @@ -1993,53 +2042,48 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, stream->streamRepresentation.streamInfo.sampleRate = sampleRate; - stream->sampleRate = sampleRate; - stream->outDeviceSampleRate = 0; - if( stream->outputUnit ) { - Float64 rate; - UInt32 size = sizeof( rate ); - result = ERR( AudioDeviceGetProperty( stream->outputDevice, - 0, - FALSE, - kAudioDevicePropertyNominalSampleRate, - &size, &rate ) ); - if( result ) - goto error; - stream->outDeviceSampleRate = rate; - } - stream->inDeviceSampleRate = 0; - if( stream->inputUnit ) { - Float64 rate; - UInt32 size = sizeof( rate ); - result = ERR( AudioDeviceGetProperty( stream->inputDevice, - 0, - TRUE, - kAudioDevicePropertyNominalSampleRate, - &size, &rate ) ); - if( result ) - goto error; - stream->inDeviceSampleRate = rate; - } + stream->sampleRate = sampleRate; + stream->userInChan = inputChannelCount; stream->userOutChan = outputChannelCount; // Setup property listeners for timestamp and latency calculations. pthread_mutex_init( &stream->timingInformationMutex, NULL ); stream->timingInformationMutexIsInitialized = 1; - InitializeDeviceProperties( &stream->inputProperties ); - InitializeDeviceProperties( &stream->outputProperties ); + InitializeDeviceProperties( &stream->inputProperties ); // zeros the struct. doesn't actually init it to useful values + InitializeDeviceProperties( &stream->outputProperties ); // zeros the struct. doesn't actually init it to useful values if( stream->outputUnit ) { Boolean isInput = FALSE; + + // Start with the current values for the device properties. + // Init with nominal sample rate. Use actual sample rate where available + + result = ERR( UpdateSampleRateFromDeviceProperty( + stream, stream->outputDevice, isInput, kAudioDevicePropertyNominalSampleRate ) ); + if( result ) + goto error; /* fail if we can't even get a nominal device sample rate */ + + UpdateSampleRateFromDeviceProperty( stream, stream->outputDevice, isInput, kAudioDevicePropertyActualSampleRate ); + SetupDevicePropertyListeners( stream, stream->outputDevice, isInput ); } if( stream->inputUnit ) { Boolean isInput = TRUE; + + // as above + result = ERR( UpdateSampleRateFromDeviceProperty( + stream, stream->inputDevice, isInput, kAudioDevicePropertyNominalSampleRate ) ); + if( result ) + goto error; + + UpdateSampleRateFromDeviceProperty( stream, stream->inputDevice, isInput, kAudioDevicePropertyActualSampleRate ); + SetupDevicePropertyListeners( stream, stream->inputDevice, isInput ); } UpdateTimeStampOffsets( stream ); - // Setup copies to be used by audio callback. + // Setup timestamp copies to be used by audio callback. stream->timestampOffsetCombined_ioProcCopy = stream->timestampOffsetCombined; stream->timestampOffsetInputDevice_ioProcCopy = stream->timestampOffsetInputDevice; stream->timestampOffsetOutputDevice_ioProcCopy = stream->timestampOffsetOutputDevice; @@ -2113,11 +2157,11 @@ static OSStatus AudioIOProc( void *inRefCon, const bool isRender = inBusNumber == OUTPUT_ELEMENT; int callbackResult = paContinue ; double hostTimeStampInPaTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime); - + VVDBUG(("AudioIOProc()\n")); PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); - + /* -----------------------------------------------------------------*\ This output may be useful for debugging, But printing durring the callback is a bad enough idea that @@ -2218,7 +2262,8 @@ static OSStatus AudioIOProc( void *inRefCon, * */ OSStatus err = 0; - unsigned long frames; + unsigned long frames; + long bytesPerFrame = sizeof( float ) * ioData->mBuffers[0].mNumberChannels; /* -- start processing -- */ PaUtil_BeginBufferProcessing( &(stream->bufferProcessor), @@ -2229,8 +2274,8 @@ static OSStatus AudioIOProc( void *inRefCon, /* -- compute frames. do some checks -- */ assert( ioData->mNumberBuffers == 1 ); assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan ); - frames = ioData->mBuffers[0].mDataByteSize; - frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels; + + frames = ioData->mBuffers[0].mDataByteSize / bytesPerFrame; /* -- copy and process input data -- */ err= AudioUnitRender(stream->inputUnit, ioActionFlags, @@ -2238,9 +2283,10 @@ static OSStatus AudioIOProc( void *inRefCon, INPUT_ELEMENT, inNumberFrames, &stream->inputAudioBufferList ); - /* FEEDBACK: I'm not sure what to do when this call fails. There's nothing in the PA API to - * do about failures in the callback system. */ - assert( !err ); + if(err != noErr) + { + goto stop_stream; + } PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), @@ -2268,7 +2314,8 @@ static OSStatus AudioIOProc( void *inRefCon, * and into the PA buffer processor. If sample rate conversion * is required on input, that is done here as well. */ - unsigned long frames; + unsigned long frames; + long bytesPerFrame = sizeof( float ) * ioData->mBuffers[0].mNumberChannels; /* Sometimes, when stopping a duplex stream we get erroneous xrun flags, so if this is our last run, clear the flags. */ @@ -2290,8 +2337,7 @@ static OSStatus AudioIOProc( void *inRefCon, /* -- Copy and process output data -- */ assert( ioData->mNumberBuffers == 1 ); - frames = ioData->mBuffers[0].mDataByteSize; - frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels; + frames = ioData->mBuffers[0].mDataByteSize / bytesPerFrame; assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan ); PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor), @@ -2305,6 +2351,8 @@ static OSStatus AudioIOProc( void *inRefCon, /* Here, we read the data out of the ring buffer, through the audio converter. */ int inChan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels; + long bytesPerFrame = flsz * inChan; + if( stream->inputSRConverter ) { OSStatus err; @@ -2318,14 +2366,22 @@ static OSStatus AudioIOProc( void *inRefCon, &size, (void *)&data ); if( err == RING_BUFFER_EMPTY ) - { /*the ring buffer callback underflowed */ + { /* the ring buffer callback underflowed */ err = 0; bzero( ((char *)data) + size, sizeof(data)-size ); - stream->xrunFlags |= paInputUnderflow; + /* The ring buffer can underflow normally when the stream is stopping. + * So only report an error if the stream is active. */ + if( stream->state == ACTIVE ) + { + stream->xrunFlags |= paInputUnderflow; + } } ERR( err ); - assert( !err ); - + if(err != noErr) + { + goto stop_stream; + } + PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), 0, @@ -2342,7 +2398,7 @@ static OSStatus AudioIOProc( void *inRefCon, AudioConverter would otherwise handle for us. */ void *data1, *data2; ring_buffer_size_t size1, size2; - PaUtil_GetRingBufferReadRegions( &stream->inputRingBuffer, + ring_buffer_size_t framesReadable = PaUtil_GetRingBufferReadRegions( &stream->inputRingBuffer, frames, &data1, &size1, &data2, &size2 ); @@ -2357,14 +2413,21 @@ static OSStatus AudioIOProc( void *inRefCon, PaUtil_EndBufferProcessing( &(stream->bufferProcessor), &callbackResult ); PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, size1 ); - } else if( size1 + size2 < frames ) { + } else if( framesReadable < frames ) { + + long sizeBytes1 = size1 * bytesPerFrame; + long sizeBytes2 = size2 * bytesPerFrame; /*we underflowed. take what data we can, zero the rest.*/ - unsigned char data[frames*inChan*flsz]; - if( size1 ) - memcpy( data, data1, size1 ); - if( size2 ) - memcpy( data+size1, data2, size2 ); - bzero( data+size1+size2, frames*flsz*inChan - size1 - size2 ); + unsigned char data[ frames * bytesPerFrame ]; + if( size1 > 0 ) + { + memcpy( data, data1, sizeBytes1 ); + } + if( size2 > 0 ) + { + memcpy( data+sizeBytes1, data2, sizeBytes2 ); + } + bzero( data+sizeBytes1+sizeBytes2, (frames*bytesPerFrame) - sizeBytes1 - sizeBytes2 ); PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames ); PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor), @@ -2375,7 +2438,7 @@ static OSStatus AudioIOProc( void *inRefCon, PaUtil_EndBufferProcessing( &(stream->bufferProcessor), &callbackResult ); PaUtil_AdvanceRingBufferReadIndex( &stream->inputRingBuffer, - size1+size2 ); + framesReadable ); /* flag underflow */ stream->xrunFlags |= paInputUnderflow; } else { @@ -2393,7 +2456,7 @@ static OSStatus AudioIOProc( void *inRefCon, framesProcessed = PaUtil_EndBufferProcessing( &(stream->bufferProcessor), &callbackResult ); - PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, size1+size2 ); + PaUtil_AdvanceRingBufferReadIndex(&stream->inputRingBuffer, framesReadable ); } } } else { @@ -2424,20 +2487,23 @@ static OSStatus AudioIOProc( void *inRefCon, if( err == -10874 ) inNumberFrames /= 2; } while( err == -10874 && inNumberFrames > 1 ); - /* FEEDBACK: I'm not sure what to do when this call fails */ ERR( err ); - assert( !err ); + if(err != noErr) + { + goto stop_stream; + } + if( stream->inputSRConverter || stream->outputUnit ) { /* If this is duplex or we use a converter, put the data into the ring buffer. */ - long bytesIn, bytesOut; - bytesIn = sizeof( float ) * inNumberFrames * chan; - bytesOut = PaUtil_WriteRingBuffer( &stream->inputRingBuffer, + ring_buffer_size_t framesWritten = PaUtil_WriteRingBuffer( &stream->inputRingBuffer, stream->inputAudioBufferList.mBuffers[0].mData, inNumberFrames ); - if( bytesIn != bytesOut ) - stream->xrunFlags |= paInputOverflow ; + if( framesWritten != inNumberFrames ) + { + stream->xrunFlags |= paInputOverflow ; + } } else { @@ -2469,11 +2535,11 @@ static OSStatus AudioIOProc( void *inRefCon, * chunks, and let the BufferProcessor deal with the rest. * */ - /*This might be too big or small depending on SR conversion*/ + /* This might be too big or small depending on SR conversion. */ float data[ chan * inNumberFrames ]; OSStatus err; do - { /*Run the buffer processor until we are out of data*/ + { /* Run the buffer processor until we are out of data. */ UInt32 size; long f; @@ -2486,7 +2552,11 @@ static OSStatus AudioIOProc( void *inRefCon, (void *)data ); if( err != RING_BUFFER_EMPTY ) ERR( err ); - assert( err == 0 || err == RING_BUFFER_EMPTY ); + if( err != noErr && err != RING_BUFFER_EMPTY ) + { + goto stop_stream; + } + f = size / ( chan * sizeof(float) ); PaUtil_SetInputFrameCount( &(stream->bufferProcessor), f ); @@ -2509,24 +2579,24 @@ static OSStatus AudioIOProc( void *inRefCon, } } - switch( callbackResult ) - { - case paContinue: break; - case paComplete: - case paAbort: - stream->state = CALLBACK_STOPPED ; - if( stream->outputUnit ) - AudioOutputUnitStop(stream->outputUnit); - if( stream->inputUnit ) - AudioOutputUnitStop(stream->inputUnit); - break; - } + // Should we return successfully or fall through to stopping the stream? + if( callbackResult == paContinue ) + { + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); + return noErr; + } - PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); - return noErr; +stop_stream: + stream->state = CALLBACK_STOPPED ; + if( stream->outputUnit ) + AudioOutputUnitStop(stream->outputUnit); + if( stream->inputUnit ) + AudioOutputUnitStop(stream->inputUnit); + + PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); + return noErr; } - /* When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted. @@ -2654,18 +2724,10 @@ static ComponentResult BlockWhileAudioUnitIsRunning( AudioUnit audioUnit, AudioU return noErr; } -static PaError StopStream( PaStream *s ) +static PaError FinishStoppingStream( PaMacCoreStream *stream ) { - PaMacCoreStream *stream = (PaMacCoreStream*)s; OSStatus result = noErr; PaError paErr; - VVDBUG(("StopStream()\n")); - - VDBUG( ("Waiting for BLIO.\n") ); - waitUntilBlioWriteBufferIsFlushed( &stream->blio ); - VDBUG( ( "Stopping stream.\n" ) ); - - stream->state = STOPPING; #define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0) /* -- stop and reset -- */ @@ -2717,12 +2779,34 @@ static PaError StopStream( PaStream *s ) #undef ERR_WRAP } +/* Block until buffer is empty then stop the stream. */ +static PaError StopStream( PaStream *s ) +{ + PaError paErr; + PaMacCoreStream *stream = (PaMacCoreStream*)s; + VVDBUG(("StopStream()\n")); + + /* Tell WriteStream to stop filling the buffer. */ + stream->state = STOPPING; + + if( stream->userOutChan > 0 ) /* Does this stream do output? */ + { + size_t maxHostFrames = MAX( stream->inputFramesPerBuffer, stream->outputFramesPerBuffer ); + VDBUG( ("Waiting for write buffer to be drained.\n") ); + paErr = waitUntilBlioWriteBufferIsEmpty( &stream->blio, stream->sampleRate, + maxHostFrames ); + VDBUG( ( "waitUntilBlioWriteBufferIsEmpty returned %d\n", paErr ) ); + } + return FinishStoppingStream( stream ); +} + +/* Immediately stop the stream. */ static PaError AbortStream( PaStream *s ) { - VVDBUG(("AbortStream()->StopStream()\n")); - VDBUG( ( "Aborting stream.\n" ) ); - /* We have nothing faster than StopStream. */ - return StopStream(s); + PaMacCoreStream *stream = (PaMacCoreStream*)s; + VDBUG( ( "AbortStream()\n" ) ); + stream->state = STOPPING; + return FinishStoppingStream( stream ); } diff --git a/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c b/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c index b514f64119..679c6ba0ae 100644 --- a/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c +++ b/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.c @@ -108,14 +108,16 @@ static size_t computeSampleSizeFromFormatPow2( PaSampleFormat format ) * */ -/* This should be called with the relevant info when initializing a stream for - callback. */ +/** + * This should be called with the relevant info when initializing a stream for callback. + * + * @param ringBufferSizeInFrames must be a power of 2 + */ PaError initializeBlioRingBuffers( PaMacBlio *blio, PaSampleFormat inputSampleFormat, PaSampleFormat outputSampleFormat, - size_t framesPerBuffer, - long ringBufferSize, + long ringBufferSizeInFrames, int inChan, int outChan ) { @@ -126,20 +128,19 @@ PaError initializeBlioRingBuffers( /* zeroify things */ bzero( blio, sizeof( PaMacBlio ) ); /* this is redundant, but the buffers are used to check - if the bufffers have been initialized, so we do it explicitly. */ + if the buffers have been initialized, so we do it explicitly. */ blio->inputRingBuffer.buffer = NULL; blio->outputRingBuffer.buffer = NULL; /* initialize simple data */ - blio->ringBufferFrames = ringBufferSize; + blio->ringBufferFrames = ringBufferSizeInFrames; blio->inputSampleFormat = inputSampleFormat; blio->inputSampleSizeActual = computeSampleSizeFromFormat(inputSampleFormat); - blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat); + blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat); // FIXME: WHY? blio->outputSampleFormat = outputSampleFormat; blio->outputSampleSizeActual = computeSampleSizeFromFormat(outputSampleFormat); blio->outputSampleSizePow2 = computeSampleSizeFromFormatPow2(outputSampleFormat); - blio->framesPerBuffer = framesPerBuffer; blio->inChan = inChan; blio->outChan = outChan; blio->statusFlags = 0; @@ -163,7 +164,7 @@ PaError initializeBlioRingBuffers( result = UNIX_ERR( pthread_cond_init( &(blio->outputCond), NULL ) ); #endif if( inChan ) { - data = calloc( ringBufferSize, blio->inputSampleSizePow2*inChan ); + data = calloc( ringBufferSizeInFrames, blio->inputSampleSizePow2 * inChan ); if( !data ) { result = paInsufficientMemory; @@ -172,12 +173,13 @@ PaError initializeBlioRingBuffers( err = PaUtil_InitializeRingBuffer( &blio->inputRingBuffer, - 1, ringBufferSize*blio->inputSampleSizePow2*inChan, + blio->inputSampleSizePow2 * inChan, + ringBufferSizeInFrames, data ); assert( !err ); } if( outChan ) { - data = calloc( ringBufferSize, blio->outputSampleSizePow2*outChan ); + data = calloc( ringBufferSizeInFrames, blio->outputSampleSizePow2 * outChan ); if( !data ) { result = paInsufficientMemory; @@ -186,7 +188,8 @@ PaError initializeBlioRingBuffers( err = PaUtil_InitializeRingBuffer( &blio->outputRingBuffer, - 1, ringBufferSize*blio->outputSampleSizePow2*outChan, + blio->outputSampleSizePow2 * outChan, + ringBufferSizeInFrames, data ); assert( !err ); } @@ -266,12 +269,11 @@ PaError resetBlioRingBuffers( PaMacBlio *blio ) #endif blio->statusFlags = 0; if( blio->outputRingBuffer.buffer ) { - PaUtil_FlushRingBuffer( &blio->outputRingBuffer ); - bzero( blio->outputRingBuffer.buffer, - blio->outputRingBuffer.bufferSize ); - /* Advance buffer */ - PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames*blio->outputSampleSizeActual*blio->outChan ); - //PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->outputRingBuffer.bufferSize ); + PaUtil_FlushRingBuffer( &blio->outputRingBuffer ); + /* Fill the buffer with zeros. */ + bzero( blio->outputRingBuffer.buffer, + blio->outputRingBuffer.bufferSize * blio->outputRingBuffer.elementSizeBytes ); + PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames ); /* Update isOutputFull. */ #ifdef PA_MAC__BLIO_MUTEX @@ -280,16 +282,14 @@ PaError resetBlioRingBuffers( PaMacBlio *blio ) goto error; #endif /* - printf( "------%d\n" , blio->framesPerBuffer ); printf( "------%d\n" , blio->outChan ); printf( "------%d\n" , blio->outputSampleSize ); - printf( "------%d\n" , blio->framesPerBuffer*blio->outChan*blio->outputSampleSize ); */ } if( blio->inputRingBuffer.buffer ) { PaUtil_FlushRingBuffer( &blio->inputRingBuffer ); bzero( blio->inputRingBuffer.buffer, - blio->inputRingBuffer.bufferSize ); + blio->inputRingBuffer.bufferSize * blio->inputRingBuffer.elementSizeBytes ); /* Update isInputEmpty. */ #ifdef PA_MAC__BLIO_MUTEX result = blioSetIsInputEmpty( blio, true ); @@ -344,29 +344,32 @@ int BlioCallback( const void *input, void *output, unsigned long frameCount, void *userData ) { PaMacBlio *blio = (PaMacBlio*)userData; - long avail; - long toRead; - long toWrite; - long read; - long written; + ring_buffer_size_t framesAvailable; + ring_buffer_size_t framesToTransfer; + ring_buffer_size_t framesTransferred; /* set flags returned by OS: */ OSAtomicOr32( statusFlags, &blio->statusFlags ) ; /* --- Handle Input Buffer --- */ if( blio->inChan ) { - avail = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer ); + framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer ); /* check for underflow */ - if( avail < frameCount * blio->inputSampleSizeActual * blio->inChan ) - OSAtomicOr32( paInputOverflow, &blio->statusFlags ); + if( framesAvailable < frameCount ) + { + OSAtomicOr32( paInputOverflow, &blio->statusFlags ); + framesToTransfer = framesAvailable; + } + else + { + framesToTransfer = (ring_buffer_size_t)frameCount; + } - toRead = MIN( avail, frameCount * blio->inputSampleSizeActual * blio->inChan ); - - /* copy the data */ + /* Copy the data from the audio input to the application ring buffer. */ /*printf( "reading %d\n", toRead );*/ - read = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, toRead ); - assert( toRead == read ); + framesTransferred = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, framesToTransfer ); + assert( framesToTransfer == framesTransferred ); #ifdef PA_MAC__BLIO_MUTEX /* Priority inversion. See notes below. */ blioSetIsInputEmpty( blio, false ); @@ -376,21 +379,31 @@ int BlioCallback( const void *input, void *output, unsigned long frameCount, /* --- Handle Output Buffer --- */ if( blio->outChan ) { - avail = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer ); + framesAvailable = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer ); /* check for underflow */ - if( avail < frameCount * blio->outputSampleSizeActual * blio->outChan ) - OSAtomicOr32( paOutputUnderflow, &blio->statusFlags ); + if( framesAvailable < frameCount ) + { + /* zero out the end of the output buffer that we do not have data for */ + framesToTransfer = framesAvailable; - toWrite = MIN( avail, frameCount * blio->outputSampleSizeActual * blio->outChan ); + size_t bytesPerFrame = blio->outputSampleSizeActual * blio->outChan; + size_t offsetInBytes = framesToTransfer * bytesPerFrame; + size_t countInBytes = (frameCount - framesToTransfer) * bytesPerFrame; + bzero( ((char *)output) + offsetInBytes, countInBytes ); + + OSAtomicOr32( paOutputUnderflow, &blio->statusFlags ); + framesToTransfer = framesAvailable; + } + else + { + framesToTransfer = (ring_buffer_size_t)frameCount; + } - if( toWrite != frameCount * blio->outputSampleSizeActual * blio->outChan ) - bzero( ((char *)output)+toWrite, - frameCount * blio->outputSampleSizeActual * blio->outChan - toWrite ); /* copy the data */ /*printf( "writing %d\n", toWrite );*/ - written = PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, toWrite ); - assert( toWrite == written ); + framesTransferred = PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, framesToTransfer ); + assert( framesToTransfer == framesTransferred ); #ifdef PA_MAC__BLIO_MUTEX /* We have a priority inversion here. However, we will only have to wait if this was true and is now false, which means we've got @@ -405,24 +418,25 @@ int BlioCallback( const void *input, void *output, unsigned long frameCount, PaError ReadStream( PaStream* stream, void *buffer, - unsigned long frames ) + unsigned long framesRequested ) { PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; char *cbuf = (char *) buffer; PaError ret = paNoError; VVDBUG(("ReadStream()\n")); - while( frames > 0 ) { - long avail; - long toRead; + while( framesRequested > 0 ) { + ring_buffer_size_t framesAvailable; + ring_buffer_size_t framesToTransfer; + ring_buffer_size_t framesTransferred; do { - avail = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ); + framesAvailable = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ); /* printf( "Read Buffer is %%%g full: %ld of %ld.\n", 100 * (float)avail / (float) blio->inputRingBuffer.bufferSize, - avail, blio->inputRingBuffer.bufferSize ); + framesAvailable, blio->inputRingBuffer.bufferSize ); */ - if( avail == 0 ) { + if( framesAvailable == 0 ) { #ifdef PA_MAC_BLIO_MUTEX /**block when empty*/ ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) ); @@ -440,14 +454,13 @@ PaError ReadStream( PaStream* stream, Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); #endif } - } while( avail == 0 ); - toRead = MIN( avail, frames * blio->inputSampleSizeActual * blio->inChan ); - toRead -= toRead % blio->inputSampleSizeActual * blio->inChan ; - PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, toRead ); - cbuf += toRead; - frames -= toRead / ( blio->inputSampleSizeActual * blio->inChan ); + } while( framesAvailable == 0 ); + framesToTransfer = (ring_buffer_size_t) MIN( framesAvailable, framesRequested ); + framesTransferred = PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, framesToTransfer ); + cbuf += framesTransferred * blio->inputSampleSizeActual * blio->inChan; + framesRequested -= framesTransferred; - if( toRead == avail ) { + if( framesToTransfer == framesAvailable ) { #ifdef PA_MAC_BLIO_MUTEX /* we just emptied the buffer, so we need to mark it as empty. */ ret = blioSetIsInputEmpty( blio, true ); @@ -456,8 +469,10 @@ PaError ReadStream( PaStream* stream, /* of course, in the meantime, the callback may have put some sats in, so so check for that, too, to avoid a race condition. */ + /* FIXME - this does not seem to fix any race condition. */ if( PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) ) { blioSetIsInputEmpty( blio, false ); + /* FIXME - why check? ret has not been set? */ if( ret ) return ret; } @@ -467,6 +482,7 @@ PaError ReadStream( PaStream* stream, /* Report either paNoError or paInputOverflowed. */ /* may also want to report other errors, but this is non-standard. */ + /* FIXME should not clobber ret, use if(blio->statusFlags & paInputOverflow) */ ret = blio->statusFlags & paInputOverflow; /* report underflow only once: */ @@ -481,25 +497,27 @@ PaError ReadStream( PaStream* stream, PaError WriteStream( PaStream* stream, const void *buffer, - unsigned long frames ) + unsigned long framesRequested ) { - PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; + PaMacCoreStream *macStream = (PaMacCoreStream*)stream; + PaMacBlio *blio = &macStream->blio; char *cbuf = (char *) buffer; PaError ret = paNoError; VVDBUG(("WriteStream()\n")); - while( frames > 0 ) { - long avail = 0; - long toWrite; + while( framesRequested > 0 && macStream->state != STOPPING ) { + ring_buffer_size_t framesAvailable; + ring_buffer_size_t framesToTransfer; + ring_buffer_size_t framesTransferred; do { - avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); + framesAvailable = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); /* printf( "Write Buffer is %%%g full: %ld of %ld.\n", 100 - 100 * (float)avail / (float) blio->outputRingBuffer.bufferSize, - avail, blio->outputRingBuffer.bufferSize ); + framesAvailable, blio->outputRingBuffer.bufferSize ); */ - if( avail == 0 ) { + if( framesAvailable == 0 ) { #ifdef PA_MAC_BLIO_MUTEX /*block while full*/ ret = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) ); @@ -517,16 +535,20 @@ PaError WriteStream( PaStream* stream, Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); #endif } - } while( avail == 0 ); + } while( framesAvailable == 0 && macStream->state != STOPPING ); - toWrite = MIN( avail, frames * blio->outputSampleSizeActual * blio->outChan ); - toWrite -= toWrite % blio->outputSampleSizeActual * blio->outChan ; - PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, toWrite ); - cbuf += toWrite; - frames -= toWrite / ( blio->outputSampleSizeActual * blio->outChan ); + if( macStream->state == STOPPING ) + { + break; + } + + framesToTransfer = MIN( framesAvailable, framesRequested ); + framesTransferred = PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, framesToTransfer ); + cbuf += framesTransferred * blio->outputSampleSizeActual * blio->outChan; + framesRequested -= framesTransferred; #ifdef PA_MAC_BLIO_MUTEX - if( toWrite == avail ) { + if( framesToTransfer == framesAvailable ) { /* we just filled up the buffer, so we need to mark it as filled. */ ret = blioSetIsOutputFull( blio, true ); if( ret ) @@ -535,6 +557,7 @@ PaError WriteStream( PaStream* stream, so check for that, too, to avoid a race condition. */ if( PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) ) { blioSetIsOutputFull( blio, false ); + /* FIXME remove or review this code, does not fix race, ret not set! */ if( ret ) return ret; } @@ -542,42 +565,65 @@ PaError WriteStream( PaStream* stream, #endif } - /* Report either paNoError or paOutputUnderflowed. */ - /* may also want to report other errors, but this is non-standard. */ - ret = blio->statusFlags & paOutputUnderflow; + if ( macStream->state == STOPPING ) + { + ret = paInternalError; + } + else if (ret == paNoError ) + { + /* Test for underflow. */ + ret = blio->statusFlags & paOutputUnderflow; - /* report underflow only once: */ - if( ret ) { - OSAtomicAnd32( (uint32_t)(~paOutputUnderflow), &blio->statusFlags ); - ret = paOutputUnderflowed; + /* report underflow only once: */ + if( ret ) + { + OSAtomicAnd32( (uint32_t)(~paOutputUnderflow), &blio->statusFlags ); + ret = paOutputUnderflowed; + } } return ret; } /* - * + * Wait until the data in the buffer has finished playing. */ -void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio ) +PaError waitUntilBlioWriteBufferIsEmpty( PaMacBlio *blio, double sampleRate, + size_t framesPerBuffer ) { + PaError result = paNoError; if( blio->outputRingBuffer.buffer ) { - long avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); - while( avail != blio->outputRingBuffer.bufferSize ) { - if( avail == 0 ) - Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); - avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); - } - } -} + ring_buffer_size_t framesLeft = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer ); + /* Calculate when we should give up waiting. To be safe wait for two extra periods. */ + PaTime now = PaUtil_GetTime(); + PaTime startTime = now; + PaTime timeoutTime = startTime + (framesLeft + (2 * framesPerBuffer)) / sampleRate; + + long msecPerBuffer = 1 + (long)( 1000.0 * framesPerBuffer / sampleRate); + while( framesLeft > 0 && now < timeoutTime ) { + VDBUG(( "waitUntilBlioWriteBufferIsFlushed: framesLeft = %d, framesPerBuffer = %ld\n", + framesLeft, framesPerBuffer )); + Pa_Sleep( msecPerBuffer ); + framesLeft = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer ); + now = PaUtil_GetTime(); + } + + if( framesLeft > 0 ) + { + VDBUG(( "waitUntilBlioWriteBufferIsFlushed: TIMED OUT - framesLeft = %d\n", framesLeft )); + result = paTimedOut; + } + } + return result; +} signed long GetStreamReadAvailable( PaStream* stream ) { PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; VVDBUG(("GetStreamReadAvailable()\n")); - return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ) - / ( blio->inputSampleSizeActual * blio->inChan ); + return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ); } @@ -586,7 +632,6 @@ signed long GetStreamWriteAvailable( PaStream* stream ) PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio; VVDBUG(("GetStreamWriteAvailable()\n")); - return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ) - / ( blio->outputSampleSizeActual * blio->outChan ); + return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); } diff --git a/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.h b/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.h index a6f0ad5dc1..c994f0903a 100644 --- a/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.h +++ b/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_blocking.h @@ -64,7 +64,7 @@ #include "pa_mac_core_utilities.h" /* - * Number of miliseconds to busy wait whil waiting for data in blocking calls. + * Number of milliseconds to busy wait while waiting for data in blocking calls. */ #define PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL (5) /* @@ -79,7 +79,7 @@ typedef struct { PaUtilRingBuffer inputRingBuffer; PaUtilRingBuffer outputRingBuffer; - size_t ringBufferFrames; + ring_buffer_size_t ringBufferFrames; PaSampleFormat inputSampleFormat; size_t inputSampleSizeActual; size_t inputSampleSizePow2; @@ -87,8 +87,6 @@ typedef struct { size_t outputSampleSizeActual; size_t outputSampleSizePow2; - size_t framesPerBuffer; - int inChan; int outChan; @@ -117,8 +115,7 @@ PaError initializeBlioRingBuffers( PaMacBlio *blio, PaSampleFormat inputSampleFormat, PaSampleFormat outputSampleFormat, - size_t framesPerBuffer, - long ringBufferSize, + long ringBufferSizeInFrames, int inChan, int outChan ); PaError destroyBlioRingBuffers( PaMacBlio *blio ); @@ -131,6 +128,7 @@ int BlioCallback( PaStreamCallbackFlags statusFlags, void *userData ); -void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio ); +PaError waitUntilBlioWriteBufferIsEmpty( PaMacBlio *blio, double sampleRate, + size_t framesPerBuffer ); #endif /*PA_MAC_CORE_BLOCKING_H_*/ diff --git a/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_internal.h b/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_internal.h index 462240bb4b..14e3d075de 100644 --- a/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_internal.h +++ b/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_internal.h @@ -120,7 +120,11 @@ typedef struct PaMacCoreDeviceProperties UInt32 bufferFrameSize; // UInt32 streamLatency; // Seems to be the same as deviceLatency!? UInt32 deviceLatency; - /* Current device sample rate. May change! */ + /* Current device sample rate. May change! + These are initialized to the nominal device sample rate, + and updated with the actual sample rate, when/where available. + Note that these are the *device* sample rates, prior to any required + SR conversion. */ Float64 sampleRate; Float64 samplePeriod; // reciprocal } @@ -166,10 +170,6 @@ typedef struct PaMacCoreStream ACTIVE = 3 /* The stream is active and running. */ } state; double sampleRate; - //these may be different from the stream sample rate due to SR conversion: - double outDeviceSampleRate; - double inDeviceSampleRate; - PaMacCoreDeviceProperties inputProperties; PaMacCoreDeviceProperties outputProperties; diff --git a/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c b/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c index 4ef89549b0..0e9b357e9b 100644 --- a/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c +++ b/Externals/portaudio/src/hostapi/coreaudio/pa_mac_core_old.c @@ -1,5 +1,5 @@ /* - * $Id: pa_mac_core_old.c 1083 2006-08-23 07:30:49Z rossb $ + * $Id$ * pa_mac_core.c * Implementation of PortAudio for Mac OS X CoreAudio * diff --git a/Externals/portaudio/src/hostapi/dsound/pa_win_ds.c b/Externals/portaudio/src/hostapi/dsound/pa_win_ds.c index 77d1924955..35fac5f7f0 100644 --- a/Externals/portaudio/src/hostapi/dsound/pa_win_ds.c +++ b/Externals/portaudio/src/hostapi/dsound/pa_win_ds.c @@ -1,5 +1,5 @@ /* - * $Id: pa_win_ds.c 1779 2011-11-10 14:51:15Z rossb $ + * $Id$ * Portable Audio I/O Library DirectSound implementation * * Authors: Phil Burk, Robert Marsanyi & Ross Bencina @@ -152,6 +152,13 @@ PA_THREAD_FUNC ProcessingThreadProc( void *pArg ); #define PA_DS_WIN_WDM_DEFAULT_LATENCY_ (.120) +/* we allow the polling period to range between 1 and 100ms. + prior to August 2011 we limited the minimum polling period to 10ms. +*/ +#define PA_DS_MINIMUM_POLLING_PERIOD_SECONDS (0.001) /* 1ms */ +#define PA_DS_MAXIMUM_POLLING_PERIOD_SECONDS (0.100) /* 100ms */ +#define PA_DS_POLLING_JITTER_SECONDS (0.001) /* 1ms */ + #define SECONDS_PER_MSEC (0.001) #define MSECS_PER_SECOND (1000) @@ -201,9 +208,9 @@ static signed long GetStreamWriteAvailable( PaStream* stream ); PaUtil_SetLastHostErrorInfo( paDirectSound, hr, "DirectSound error" ) /************************************************* DX Prototypes **********/ -static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID, - LPCTSTR lpszDesc, - LPCTSTR lpszDrvName, +static BOOL CALLBACK CollectGUIDsProcW(LPGUID lpGUID, + LPCWSTR lpszDesc, + LPCWSTR lpszDrvName, LPVOID lpContext ); /************************************************************************************/ @@ -311,30 +318,43 @@ typedef struct PaWinDsStream */ static double PaWinDS_GetMinSystemLatencySeconds( void ) { +/* +NOTE: GetVersionEx() is deprecated as of Windows 8.1 and can not be used to reliably detect +versions of Windows higher than Windows 8 (due to manifest requirements for reporting higher versions). +Microsoft recommends switching to VerifyVersionInfo (available on Win 2k and later), however GetVersionEx +is is faster, for now we just disable the deprecation warning. +See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx +See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe +*/ +#pragma warning (disable : 4996) /* use of GetVersionEx */ + double minLatencySeconds; /* Set minimal latency based on whether NT or other OS. * NT has higher latency. */ + OSVERSIONINFO osvi; - osvi.dwOSVersionInfoSize = sizeof( osvi ); - GetVersionEx( &osvi ); + osvi.dwOSVersionInfoSize = sizeof( osvi ); + GetVersionEx( &osvi ); DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId )); DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion )); DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion )); /* Check for NT */ - if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) - { - minLatencySeconds = PA_DS_WIN_NT_DEFAULT_LATENCY_; - } - else if(osvi.dwMajorVersion >= 5) - { - minLatencySeconds = PA_DS_WIN_WDM_DEFAULT_LATENCY_; - } - else - { - minLatencySeconds = PA_DS_WIN_9X_DEFAULT_LATENCY_; - } + if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) + { + minLatencySeconds = PA_DS_WIN_NT_DEFAULT_LATENCY_; + } + else if(osvi.dwMajorVersion >= 5) + { + minLatencySeconds = PA_DS_WIN_WDM_DEFAULT_LATENCY_; + } + else + { + minLatencySeconds = PA_DS_WIN_9X_DEFAULT_LATENCY_; + } return minLatencySeconds; + +#pragma warning (default : 4996) } @@ -360,7 +380,7 @@ static double PaWinDs_GetMinLatencySeconds( double sampleRate ) double minLatencySeconds = 0; /* Let user determine minimal latency by setting environment variable. */ - hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); + hresult = GetEnvironmentVariableA( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { minLatencySeconds = atoi( envbuf ) * SECONDS_PER_MSEC; @@ -378,20 +398,35 @@ static double PaWinDs_GetMinLatencySeconds( double sampleRate ) /************************************************************************************ -** Duplicate the input string using the allocations allocator. +** Duplicate and convert the input string using the group allocations allocator. ** A NULL string is converted to a zero length string. ** If memory cannot be allocated, NULL is returned. **/ -static char *DuplicateDeviceNameString( PaUtilAllocationGroup *allocations, const char* src ) +static char *DuplicateDeviceNameString( PaUtilAllocationGroup *allocations, const wchar_t* src ) { char *result = 0; if( src != NULL ) { - size_t len = strlen(src); +#if !defined(_UNICODE) && !defined(UNICODE) + size_t len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); + result = (char*)PaUtil_GroupAllocateMemory( allocations, (long)(len + 1) ); - if( result ) - memcpy( (void *) result, src, len+1 ); + if( result ) { + if (WideCharToMultiByte(CP_ACP, 0, src, -1, result, (int)len, NULL, NULL) == 0) { + result = 0; + } + } +#else + size_t len = WideCharToMultiByte(CP_UTF8, 0, src, -1, NULL, 0, NULL, NULL); + + result = (char*)PaUtil_GroupAllocateMemory( allocations, (long)(len + 1) ); + if( result ) { + if (WideCharToMultiByte(CP_UTF8, 0, src, -1, result, (int)len, NULL, NULL) == 0) { + result = 0; + } + } +#endif } else { @@ -473,7 +508,7 @@ static PaError ExpandDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidV else { newItems[i].lpGUID = &newItems[i].guid; - memcpy( &newItems[i].guid, guidVector->items[i].lpGUID, sizeof(GUID) );; + memcpy( &newItems[i].guid, guidVector->items[i].lpGUID, sizeof(GUID) ); } newItems[i].pnpInterface = guidVector->items[i].pnpInterface; } @@ -506,9 +541,9 @@ static PaError TerminateDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *gu /************************************************************************************ ** Collect preliminary device information during DirectSound enumeration */ -static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID, - LPCTSTR lpszDesc, - LPCTSTR lpszDrvName, +static BOOL CALLBACK CollectGUIDsProcW(LPGUID lpGUID, + LPCWSTR lpszDesc, + LPCWSTR lpszDrvName, LPVOID lpContext ) { DSDeviceNameAndGUIDVector *namesAndGUIDs = (DSDeviceNameAndGUIDVector*)lpContext; @@ -574,29 +609,38 @@ static BOOL CALLBACK KsPropertySetEnumerateCallback( PDSPROPERTY_DIRECTSOUNDDEVI int i; DSDeviceNamesAndGUIDs *deviceNamesAndGUIDs = (DSDeviceNamesAndGUIDs*)context; - if( data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ) + /* + Apparently data->Interface can be NULL in some cases. + Possibly virtual devices without hardware. + So we check for NULLs now. See mailing list message November 10, 2012: + "[Portaudio] portaudio initialization crash in KsPropertySetEnumerateCallback(pa_win_ds.c)" + */ + if( data->Interface ) { - for( i=0; i < deviceNamesAndGUIDs->outputNamesAndGUIDs.count; ++i ) + if( data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_RENDER ) { - if( deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].lpGUID - && memcmp( &data->DeviceId, deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].lpGUID, sizeof(GUID) ) == 0 ) + for( i=0; i < deviceNamesAndGUIDs->outputNamesAndGUIDs.count; ++i ) { - deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].pnpInterface = + if( deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].lpGUID + && memcmp( &data->DeviceId, deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].lpGUID, sizeof(GUID) ) == 0 ) + { + deviceNamesAndGUIDs->outputNamesAndGUIDs.items[i].pnpInterface = (char*)DuplicateWCharString( deviceNamesAndGUIDs->winDsHostApi->allocations, data->Interface ); - break; + break; + } } } - } - else if( data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ) - { - for( i=0; i < deviceNamesAndGUIDs->inputNamesAndGUIDs.count; ++i ) + else if( data->DataFlow == DIRECTSOUNDDEVICE_DATAFLOW_CAPTURE ) { - if( deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].lpGUID - && memcmp( &data->DeviceId, deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].lpGUID, sizeof(GUID) ) == 0 ) + for( i=0; i < deviceNamesAndGUIDs->inputNamesAndGUIDs.count; ++i ) { - deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].pnpInterface = + if( deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].lpGUID + && memcmp( &data->DeviceId, deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].lpGUID, sizeof(GUID) ) == 0 ) + { + deviceNamesAndGUIDs->inputNamesAndGUIDs.items[i].pnpInterface = (char*)DuplicateWCharString( deviceNamesAndGUIDs->winDsHostApi->allocations, data->Interface ); - break; + break; + } } } } @@ -922,7 +966,7 @@ static PaError AddOutputDeviceInfoFromDirectSound( } else { - deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; + deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; } } else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) ) @@ -1160,6 +1204,8 @@ PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInde goto error; } + memset( winDsHostApi, 0, sizeof(PaWinDsHostApiRepresentation) ); /* ensure all fields are zeroed. especially winDsHostApi->allocations */ + result = PaWinUtil_CoInitialize( paDirectSound, &winDsHostApi->comInitializationResult ); if( result != paNoError ) { @@ -1193,9 +1239,9 @@ PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInde if( result != paNoError ) goto error; - paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.inputNamesAndGUIDs ); + paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW( (LPDSENUMCALLBACKW)CollectGUIDsProcW, (void *)&deviceNamesAndGUIDs.inputNamesAndGUIDs ); - paWinDsDSoundEntryPoints.DirectSoundEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.outputNamesAndGUIDs ); + paWinDsDSoundEntryPoints.DirectSoundEnumerateW( (LPDSENUMCALLBACKW)CollectGUIDsProcW, (void *)&deviceNamesAndGUIDs.outputNamesAndGUIDs ); if( deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError != paNoError ) { @@ -1299,7 +1345,7 @@ error: TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs ); TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs ); - Terminate( winDsHostApi ); + Terminate( (struct PaUtilHostApiRepresentation *)winDsHostApi ); return result; } @@ -1329,16 +1375,23 @@ static PaError ValidateWinDirectSoundSpecificStreamInfo( const PaStreamParameters *streamParameters, const PaWinDirectSoundStreamInfo *streamInfo ) { - if( streamInfo ) - { - if( streamInfo->size != sizeof( PaWinDirectSoundStreamInfo ) - || streamInfo->version != 2 ) - { - return paIncompatibleHostApiSpecificStreamInfo; - } - } + if( streamInfo ) + { + if( streamInfo->size != sizeof( PaWinDirectSoundStreamInfo ) + || streamInfo->version != 2 ) + { + return paIncompatibleHostApiSpecificStreamInfo; + } - return paNoError; + if( streamInfo->flags & paWinDirectSoundUseLowLevelLatencyParameters ) + { + if( streamInfo->framesPerBuffer <= 0 ) + return paIncompatibleHostApiSpecificStreamInfo; + + } + } + + return paNoError; } /***********************************************************************************/ @@ -1375,8 +1428,8 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, /* validate inputStreamInfo */ inputStreamInfo = (PaWinDirectSoundStreamInfo*)inputParameters->hostApiSpecificStreamInfo; - result = ValidateWinDirectSoundSpecificStreamInfo( inputParameters, inputStreamInfo ); - if( result != paNoError ) return result; + result = ValidateWinDirectSoundSpecificStreamInfo( inputParameters, inputStreamInfo ); + if( result != paNoError ) return result; } else { @@ -1404,8 +1457,8 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, /* validate outputStreamInfo */ outputStreamInfo = (PaWinDirectSoundStreamInfo*)outputParameters->hostApiSpecificStreamInfo; - result = ValidateWinDirectSoundSpecificStreamInfo( outputParameters, outputStreamInfo ); - if( result != paNoError ) return result; + result = ValidateWinDirectSoundSpecificStreamInfo( outputParameters, outputStreamInfo ); + if( result != paNoError ) return result; } else { @@ -1541,7 +1594,13 @@ static HRESULT InitFullDuplexInputOutputBuffers( PaWinDsStream *stream, #endif /* PAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE */ -static HRESULT InitInputBuffer( PaWinDsStream *stream, PaWinDsDeviceInfo *device, PaSampleFormat sampleFormat, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer, PaWinWaveFormatChannelMask channelMask ) +static HRESULT InitInputBuffer( PaWinDsStream *stream, + PaWinDsDeviceInfo *device, + PaSampleFormat sampleFormat, + unsigned long nFrameRate, + WORD nChannels, + int bytesPerBuffer, + PaWinWaveFormatChannelMask channelMask ) { DSCBUFFERDESC captureDesc; PaWinWaveFormat waveFormat; @@ -1582,7 +1641,10 @@ static HRESULT InitInputBuffer( PaWinDsStream *stream, PaWinDsDeviceInfo *device } -static HRESULT InitOutputBuffer( PaWinDsStream *stream, PaWinDsDeviceInfo *device, PaSampleFormat sampleFormat, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer, PaWinWaveFormatChannelMask channelMask ) +static HRESULT InitOutputBuffer( PaWinDsStream *stream, PaWinDsDeviceInfo *device, + PaSampleFormat sampleFormat, unsigned long nFrameRate, + WORD nChannels, int bytesPerBuffer, + PaWinWaveFormatChannelMask channelMask ) { HRESULT result; HWND hWnd; @@ -1680,12 +1742,9 @@ static void CalculateBufferSettings( unsigned long *hostBufferSizeFrames, unsigned long suggestedOutputLatencyFrames, double sampleRate, unsigned long userFramesPerBuffer ) { - /* we allow the polling period to range between 1 and 100ms. - prior to August 2011 we limited the minimum polling period to 10ms. - */ - unsigned long minimumPollingPeriodFrames = sampleRate / 1000; /* 1ms */ - unsigned long maximumPollingPeriodFrames = sampleRate / 10; /* 100ms */ - unsigned long pollingJitterFrames = sampleRate / 1000; /* 1ms */ + unsigned long minimumPollingPeriodFrames = (unsigned long)(sampleRate * PA_DS_MINIMUM_POLLING_PERIOD_SECONDS); + unsigned long maximumPollingPeriodFrames = (unsigned long)(sampleRate * PA_DS_MAXIMUM_POLLING_PERIOD_SECONDS); + unsigned long pollingJitterFrames = (unsigned long)(sampleRate * PA_DS_POLLING_JITTER_SECONDS); if( userFramesPerBuffer == paFramesPerBufferUnspecified ) { @@ -1747,6 +1806,23 @@ static void CalculateBufferSettings( unsigned long *hostBufferSizeFrames, } +static void CalculatePollingPeriodFrames( unsigned long hostBufferSizeFrames, + unsigned long *pollingPeriodFrames, + double sampleRate, unsigned long userFramesPerBuffer ) +{ + unsigned long minimumPollingPeriodFrames = (unsigned long)(sampleRate * PA_DS_MINIMUM_POLLING_PERIOD_SECONDS); + unsigned long maximumPollingPeriodFrames = (unsigned long)(sampleRate * PA_DS_MAXIMUM_POLLING_PERIOD_SECONDS); + unsigned long pollingJitterFrames = (unsigned long)(sampleRate * PA_DS_POLLING_JITTER_SECONDS); + + *pollingPeriodFrames = max( max(1, userFramesPerBuffer / 4), hostBufferSizeFrames / 16 ); + + if( *pollingPeriodFrames > maximumPollingPeriodFrames ) + { + *pollingPeriodFrames = maximumPollingPeriodFrames; + } +} + + static void SetStreamInfoLatencies( PaWinDsStream *stream, unsigned long userFramesPerBuffer, unsigned long pollingPeriodFrames, @@ -1808,6 +1884,8 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; + int userRequestedHostInputBufferSizeFrames = 0; + int userRequestedHostOutputBufferSizeFrames = 0; unsigned long suggestedInputLatencyFrames, suggestedOutputLatencyFrames; PaWinDirectSoundStreamInfo *inputStreamInfo, *outputStreamInfo; PaWinWaveFormatChannelMask inputChannelMask, outputChannelMask; @@ -1837,8 +1915,11 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* validate hostApiSpecificStreamInfo */ inputStreamInfo = (PaWinDirectSoundStreamInfo*)inputParameters->hostApiSpecificStreamInfo; - result = ValidateWinDirectSoundSpecificStreamInfo( inputParameters, inputStreamInfo ); - if( result != paNoError ) return result; + result = ValidateWinDirectSoundSpecificStreamInfo( inputParameters, inputStreamInfo ); + if( result != paNoError ) return result; + + if( inputStreamInfo && inputStreamInfo->flags & paWinDirectSoundUseLowLevelLatencyParameters ) + userRequestedHostInputBufferSizeFrames = inputStreamInfo->framesPerBuffer; if( inputStreamInfo && inputStreamInfo->flags & paWinDirectSoundUseChannelMask ) inputChannelMask = inputStreamInfo->channelMask; @@ -1848,7 +1929,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, else { inputChannelCount = 0; - inputSampleFormat = 0; + inputSampleFormat = 0; suggestedInputLatencyFrames = 0; } @@ -1874,8 +1955,11 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* validate hostApiSpecificStreamInfo */ outputStreamInfo = (PaWinDirectSoundStreamInfo*)outputParameters->hostApiSpecificStreamInfo; - result = ValidateWinDirectSoundSpecificStreamInfo( outputParameters, outputStreamInfo ); - if( result != paNoError ) return result; + result = ValidateWinDirectSoundSpecificStreamInfo( outputParameters, outputStreamInfo ); + if( result != paNoError ) return result; + + if( outputStreamInfo && outputStreamInfo->flags & paWinDirectSoundUseLowLevelLatencyParameters ) + userRequestedHostOutputBufferSizeFrames = outputStreamInfo->framesPerBuffer; if( outputStreamInfo && outputStreamInfo->flags & paWinDirectSoundUseChannelMask ) outputChannelMask = outputStreamInfo->channelMask; @@ -1885,10 +1969,20 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, else { outputChannelCount = 0; - outputSampleFormat = 0; + outputSampleFormat = 0; suggestedOutputLatencyFrames = 0; } + /* + If low level host buffer size is specified for both input and output + the current code requires the sizes to match. + */ + + if( (userRequestedHostInputBufferSizeFrames > 0 && userRequestedHostOutputBufferSizeFrames > 0) + && userRequestedHostInputBufferSizeFrames != userRequestedHostOutputBufferSizeFrames ) + return paIncompatibleHostApiSpecificStreamInfo; + + /* IMPLEMENT ME: @@ -1956,10 +2050,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( nativeInputFormats, inputParameters->sampleFormat ); } - else - { - hostInputSampleFormat = 0; - } + else + { + hostInputSampleFormat = 0; + } if( outputParameters ) { @@ -1971,9 +2065,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaUtil_SelectClosestAvailableFormat( nativeOutputFormats, outputParameters->sampleFormat ); } else - { - hostOutputSampleFormat = 0; - } + { + hostOutputSampleFormat = 0; + } result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, hostInputSampleFormat, @@ -2016,7 +2110,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, #endif #ifndef PA_WIN_DS_USE_WMME_TIMER - stream->processingThreadCompleted = CreateEvent( NULL, /* bManualReset = */ TRUE, /* bInitialState = */ FALSE, NULL ); + stream->processingThreadCompleted = CreateEvent( NULL, /* bManualReset = */ TRUE, /* bInitialState = */ FALSE, NULL ); if( stream->processingThreadCompleted == NULL ) { result = paUnanticipatedHostError; @@ -2027,14 +2121,34 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* set up i/o parameters */ - CalculateBufferSettings( &stream->hostBufferSizeFrames, &pollingPeriodFrames, - /* isFullDuplex = */ (inputParameters && outputParameters), - suggestedInputLatencyFrames, - suggestedOutputLatencyFrames, - sampleRate, framesPerBuffer ); + if( userRequestedHostInputBufferSizeFrames > 0 || userRequestedHostOutputBufferSizeFrames > 0 ) + { + /* use low level parameters */ + + /* since we use the same host buffer size for input and output + we choose the highest user specified value. + */ + stream->hostBufferSizeFrames = max( userRequestedHostInputBufferSizeFrames, userRequestedHostOutputBufferSizeFrames ); + + CalculatePollingPeriodFrames( + stream->hostBufferSizeFrames, &pollingPeriodFrames, + sampleRate, framesPerBuffer ); + } + else + { + CalculateBufferSettings( &stream->hostBufferSizeFrames, &pollingPeriodFrames, + /* isFullDuplex = */ (inputParameters && outputParameters), + suggestedInputLatencyFrames, + suggestedOutputLatencyFrames, + sampleRate, framesPerBuffer ); + } stream->pollingPeriodSeconds = pollingPeriodFrames / sampleRate; + DBUG(("DirectSound host buffer size frames: %d, polling period seconds: %f, @ sr: %f\n", + stream->hostBufferSizeFrames, stream->pollingPeriodSeconds, sampleRate )); + + /* ------------------ OUTPUT */ if( outputParameters ) { @@ -2396,6 +2510,8 @@ static int TimeSlice( PaWinDsStream *stream ) framesToXfer = numOutFramesReady = bytesEmpty / stream->outputFrameSizeBytes; /* Check for underflow */ + /* FIXME QueryOutputSpace should not adjust underflow count as a side effect. + A query function should be a const operator on the stream and return a flag on underflow. */ if( stream->outputUnderflowCount != previousUnderflowCount ) stream->callbackFlags |= paOutputUnderflow; @@ -2460,8 +2576,8 @@ static int TimeSlice( PaWinDsStream *stream ) if( stream->bufferProcessor.outputChannelCount > 0 ) { /* - We don't currently add outputLatency here because it appears to produce worse - results than non adding it. Need to do more testing to verify this. + We don't currently add outputLatency here because it appears to produce worse + results than not adding it. Need to do more testing to verify this. */ /* timeInfo.outputBufferDacTime = timeInfo.currentTime + outputLatency; */ timeInfo.outputBufferDacTime = timeInfo.currentTime; @@ -2649,12 +2765,10 @@ static void CALLBACK WaitableTimerAPCProc( PA_THREAD_FUNC ProcessingThreadProc( void *pArg ) { PaWinDsStream *stream = (PaWinDsStream *)pArg; - MMRESULT mmResult; - HANDLE hWaitableTimer; LARGE_INTEGER dueTime; int timerPeriodMs; - timerPeriodMs = stream->pollingPeriodSeconds * MSECS_PER_SECOND; + timerPeriodMs = (int)(stream->pollingPeriodSeconds * MSECS_PER_SECOND); if( timerPeriodMs < 1 ) timerPeriodMs = 1; @@ -2712,7 +2826,7 @@ static PaError CloseStream( PaStream* s ) #endif #ifndef PA_WIN_DS_USE_WMME_TIMER - CloseHandle( stream->processingThreadCompleted ); + CloseHandle( stream->processingThreadCompleted ); #endif // Cleanup the sound buffers @@ -2810,7 +2924,7 @@ static PaError StartStream( PaStream *s ) ResetEvent( stream->processingCompleted ); #ifndef PA_WIN_DS_USE_WMME_TIMER - ResetEvent( stream->processingThreadCompleted ); + ResetEvent( stream->processingThreadCompleted ); #endif if( stream->bufferProcessor.inputChannelCount > 0 ) @@ -2878,7 +2992,7 @@ static PaError StartStream( PaStream *s ) if( stream->streamRepresentation.streamCallback ) { TIMECAPS timecaps; - int timerPeriodMs = stream->pollingPeriodSeconds * MSECS_PER_SECOND; + int timerPeriodMs = (int)(stream->pollingPeriodSeconds * MSECS_PER_SECOND); if( timerPeriodMs < 1 ) timerPeriodMs = 1; @@ -2889,10 +3003,10 @@ static PaError StartStream( PaStream *s ) we're using an MM timer callback via timeSetEvent or not. */ assert( stream->systemTimerResolutionPeriodMs == 0 ); - if( timeGetDevCaps( &timecaps, sizeof(TIMECAPS) == MMSYSERR_NOERROR && timecaps.wPeriodMin > 0 ) ) + if( timeGetDevCaps( &timecaps, sizeof(TIMECAPS) ) == MMSYSERR_NOERROR && timecaps.wPeriodMin > 0 ) { /* aim for resolution 4 times higher than polling rate */ - stream->systemTimerResolutionPeriodMs = (stream->pollingPeriodSeconds * MSECS_PER_SECOND) / 4; + stream->systemTimerResolutionPeriodMs = (UINT)((stream->pollingPeriodSeconds * MSECS_PER_SECOND) * .25); if( stream->systemTimerResolutionPeriodMs < timecaps.wPeriodMin ) stream->systemTimerResolutionPeriodMs = timecaps.wPeriodMin; if( stream->systemTimerResolutionPeriodMs > timecaps.wPeriodMax ) @@ -2920,9 +3034,9 @@ static PaError StartStream( PaStream *s ) goto error; } #else - /* Create processing thread which calls TimerCallback */ + /* Create processing thread which calls TimerCallback */ - stream->processingThread = CREATE_THREAD( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId ); + stream->processingThread = CREATE_THREAD( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId ); if( !stream->processingThread ) { result = paUnanticipatedHostError; @@ -2992,8 +3106,8 @@ static PaError StopStream( PaStream *s ) #else if( stream->processingThread ) { - if( WaitForSingleObject( stream->processingThreadCompleted, 30*100 ) == WAIT_TIMEOUT ) - return paUnanticipatedHostError; + if( WaitForSingleObject( stream->processingThreadCompleted, 30*100 ) == WAIT_TIMEOUT ) + return paUnanticipatedHostError; #ifdef CLOSE_THREAD_HANDLE CloseHandle( stream->processingThread ); /* Delete thread. */ diff --git a/Externals/portaudio/src/hostapi/jack/pa_jack.c b/Externals/portaudio/src/hostapi/jack/pa_jack.c index 25b7fd2d74..a800f8e1dd 100644 --- a/Externals/portaudio/src/hostapi/jack/pa_jack.c +++ b/Externals/portaudio/src/hostapi/jack/pa_jack.c @@ -1,5 +1,5 @@ /* - * $Id: pa_jack.c 1668 2011-05-02 17:07:11Z rossb $ + * $Id$ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * JACK Implementation by Joshua Haberman @@ -232,6 +232,10 @@ typedef struct PaJackStream } PaJackStream; +/* In calls to jack_get_ports() this filter expression is used instead of "" + * to prevent any other types (eg Midi ports etc) being listed */ +#define JACK_PORT_TYPE_FILTER "audio" + #define TRUE 1 #define FALSE 0 @@ -492,7 +496,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi ) * according to the client_name:port_name convention (which is * enforced by jackd) * A: If jack_get_ports returns NULL, there's nothing for us to do */ - UNLESS( (jack_ports = jack_get_ports( jackApi->jack_client, "", "", 0 )) && jack_ports[0], paNoError ); + UNLESS( (jack_ports = jack_get_ports( jackApi->jack_client, "", JACK_PORT_TYPE_FILTER, 0 )) && jack_ports[0], paNoError ); /* Find number of ports */ while( jack_ports[numPorts] ) ++numPorts; @@ -583,7 +587,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi ) /* ... what are your output ports (that we could input from)? */ clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern, - NULL, JackPortIsOutput); + JACK_PORT_TYPE_FILTER, JackPortIsOutput); curDevInfo->maxInputChannels = 0; curDevInfo->defaultLowInputLatency = 0.; curDevInfo->defaultHighInputLatency = 0.; @@ -604,7 +608,7 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi ) /* ... what are your input ports (that we could output to)? */ clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern, - NULL, JackPortIsInput); + JACK_PORT_TYPE_FILTER, JackPortIsInput); curDevInfo->maxOutputChannels = 0; curDevInfo->defaultLowOutputLatency = 0.; curDevInfo->defaultHighOutputLatency = 0.; @@ -1235,7 +1239,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* Get output ports of our capture device */ snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ inputParameters->device ]->name ); UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, - NULL, JackPortIsOutput ), paUnanticipatedHostError ); + JACK_PORT_TYPE_FILTER, JackPortIsOutput ), paUnanticipatedHostError ); for( i = 0; i < inputChannelCount && jack_ports[i]; i++ ) { if( (stream->remote_output_ports[i] = jack_port_by_name( @@ -1259,7 +1263,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* Get input ports of our playback device */ snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ outputParameters->device ]->name ); UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, - NULL, JackPortIsInput ), paUnanticipatedHostError ); + JACK_PORT_TYPE_FILTER, JackPortIsInput ), paUnanticipatedHostError ); for( i = 0; i < outputChannelCount && jack_ports[i]; i++ ) { if( (stream->remote_input_ports[i] = jack_port_by_name( diff --git a/Externals/portaudio/src/hostapi/oss/pa_unix_oss.c b/Externals/portaudio/src/hostapi/oss/pa_unix_oss.c index b91577beeb..51e963048f 100644 --- a/Externals/portaudio/src/hostapi/oss/pa_unix_oss.c +++ b/Externals/portaudio/src/hostapi/oss/pa_unix_oss.c @@ -1,5 +1,5 @@ /* - * $Id: pa_unix_oss.c 1668 2011-05-02 17:07:11Z rossb $ + * $Id$ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * OSS implementation by: @@ -318,6 +318,13 @@ error: return result; } +static int CalcHigherLogTwo( int n ) +{ + int log2 = 0; + while( (1<> 16) - 1) * fragFrames / *defaultSampleRate; + + /* Cannot now try setting a high latency (device would need closing and opening again). Make + * high-latency 4 times the low unless the fragFrames are significantly more than requested 128 */ + temp = (fragFrames < 256) ? 4 : (fragFrames < 512) ? 2 : 1; + *defaultHighLatency = temp * *defaultLowLatency; error: if( devHandle >= 0 ) @@ -962,13 +983,6 @@ static unsigned long PaOssStreamComponent_BufferSize( PaOssStreamComponent *comp return PaOssStreamComponent_FrameSize( component ) * component->hostFrames * component->numBufs; } -static int CalcHigherLogTwo( int n ) -{ - int log2 = 0; - while( (1<latency * sampleRate); - fragSz = bufSz / 4; + /* Aim for 4 fragments in the complete buffer; the latency comes from 3 of these */ + fragSz = (unsigned long)(component->latency * sampleRate / 3); + bufSz = fragSz * 4; } else { diff --git a/Externals/portaudio/src/hostapi/skeleton/pa_hostapi_skeleton.c b/Externals/portaudio/src/hostapi/skeleton/pa_hostapi_skeleton.c index 24eb450096..6edc22cf70 100644 --- a/Externals/portaudio/src/hostapi/skeleton/pa_hostapi_skeleton.c +++ b/Externals/portaudio/src/hostapi/skeleton/pa_hostapi_skeleton.c @@ -1,5 +1,5 @@ /* - * $Id: pa_hostapi_skeleton.c 1668 2011-05-02 17:07:11Z rossb $ + * $Id$ * Portable Audio I/O Library skeleton implementation * demonstrates how to use the common functions to implement support * for a host API diff --git a/Externals/portaudio/src/hostapi/wasapi/mingw-include/AudioSessionTypes.h b/Externals/portaudio/src/hostapi/wasapi/mingw-include/AudioSessionTypes.h deleted file mode 100644 index 385e9007e3..0000000000 --- a/Externals/portaudio/src/hostapi/wasapi/mingw-include/AudioSessionTypes.h +++ /dev/null @@ -1,94 +0,0 @@ -// -// AudioSessionTypes.h -- Copyright Microsoft Corporation, All Rights Reserved. -// -// Description: Type definitions used by the audio session manager RPC/COM interfaces -// -#pragma once - -#ifndef __AUDIOSESSIONTYPES__ -#define __AUDIOSESSIONTYPES__ - -#if defined(__midl) -#define MIDL_SIZE_IS(x) [size_is(x)] -#define MIDL_STRING [string] -#define MIDL_ANYSIZE_ARRAY -#else // !defined(__midl) -#define MIDL_SIZE_IS(x) -#define MIDL_STRING -#define MIDL_ANYSIZE_ARRAY ANYSIZE_ARRAY -#endif // defined(__midl) - -//------------------------------------------------------------------------- -// Description: AudioClient share mode -// -// AUDCLNT_SHAREMODE_SHARED - The device will be opened in shared mode and use the -// WAS format. -// AUDCLNT_SHAREMODE_EXCLUSIVE - The device will be opened in exclusive mode and use the -// application specified format. -// -typedef enum _AUDCLNT_SHAREMODE -{ - AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_SHAREMODE_EXCLUSIVE -} AUDCLNT_SHAREMODE; - -//------------------------------------------------------------------------- -// Description: AudioClient stream flags -// -// Can be a combination of AUDCLNT_STREAMFLAGS and AUDCLNT_SYSFXFLAGS: -// -// AUDCLNT_STREAMFLAGS (this group of flags uses the high word, w/exception of high-bit which is reserved, 0x7FFF0000): -// -// AUDCLNT_STREAMFLAGS_CROSSPROCESS - Audio policy control for this stream will be shared with -// with other process sessions that use the same audio session -// GUID. -// AUDCLNT_STREAMFLAGS_LOOPBACK - Initializes a renderer endpoint for a loopback audio application. -// In this mode, a capture stream will be opened on the specified -// renderer endpoint. Shared mode and a renderer endpoint is required. -// Otherwise the IAudioClient::Initialize call will fail. If the -// initialize is successful, a capture stream will be available -// from the IAudioClient object. -// -// AUDCLNT_STREAMFLAGS_EVENTCALLBACK - An exclusive mode client will supply an event handle that will be -// signaled when an IRP completes (or a waveRT buffer completes) telling -// it to fill the next buffer -// -// AUDCLNT_STREAMFLAGS_NOPERSIST - Session state will not be persisted -// -// AUDCLNT_SYSFXFLAGS (these flags use low word 0x0000FFFF): -// -// none defined currently -// -#define AUDCLNT_STREAMFLAGS_CROSSPROCESS 0x00010000 -#define AUDCLNT_STREAMFLAGS_LOOPBACK 0x00020000 -#define AUDCLNT_STREAMFLAGS_EVENTCALLBACK 0x00040000 -#define AUDCLNT_STREAMFLAGS_NOPERSIST 0x00080000 - -//------------------------------------------------------------------------- -// Description: Device share mode - sharing mode for the audio device. -// -// DeviceShared - The device can be shared with other processes. -// DeviceExclusive - The device will only be used by this process. -// -typedef enum _DeviceShareMode -{ - DeviceShared, - DeviceExclusive -} DeviceShareMode; - - -//------------------------------------------------------------------------- -// Description: AudioSession State. -// -// AudioSessionStateInactive - The session has no active audio streams. -// AudioSessionStateActive - The session has active audio streams. -// AudioSessionStateExpired - The session is dormant. -typedef enum _AudioSessionState -{ - AudioSessionStateInactive = 0, - AudioSessionStateActive = 1, - AudioSessionStateExpired = 2 -} AudioSessionState; - -#endif - diff --git a/Externals/portaudio/src/hostapi/wasapi/mingw-include/FunctionDiscoveryKeys_devpkey.h b/Externals/portaudio/src/hostapi/wasapi/mingw-include/FunctionDiscoveryKeys_devpkey.h deleted file mode 100644 index abfd661e67..0000000000 --- a/Externals/portaudio/src/hostapi/wasapi/mingw-include/FunctionDiscoveryKeys_devpkey.h +++ /dev/null @@ -1,186 +0,0 @@ - -/*++ - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - devpkey.h - -Abstract: - - Defines property keys for the Plug and Play Device Property API. - -Author: - - Jim Cavalaris (jamesca) 10-14-2003 - -Environment: - - User-mode only. - -Revision History: - - 14-October-2003 jamesca - - Creation and initial implementation. - - 20-June-2006 dougb - - Copied Jim's version replaced "DEFINE_DEVPROPKEY(DEVPKEY_" with "DEFINE_PROPERTYKEY(PKEY_" - ---*/ - -//#include - -// -// _NAME -// - -DEFINE_PROPERTYKEY(PKEY_NAME, 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac, 10); // DEVPROP_TYPE_STRING - -// -// Device properties -// These PKEYs correspond to the old setupapi SPDRP_XXX properties -// -DEFINE_PROPERTYKEY(PKEY_Device_DeviceDesc, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_HardwareIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 3); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_Device_CompatibleIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 4); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_Device_Service, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 6); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_Class, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 9); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_ClassGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 10); // DEVPROP_TYPE_GUID -DEFINE_PROPERTYKEY(PKEY_Device_Driver, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 11); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_ConfigFlags, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 12); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_Manufacturer, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_LocationInfo, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 15); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_PDOName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 16); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_Capabilities, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 17); // DEVPROP_TYPE_UNINT32 -DEFINE_PROPERTYKEY(PKEY_Device_UINumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 18); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_UpperFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 19); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_Device_LowerFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 20); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_Device_BusTypeGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 21); // DEVPROP_TYPE_GUID -DEFINE_PROPERTYKEY(PKEY_Device_LegacyBusType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 22); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_BusNumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 23); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_EnumeratorName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 24); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_Security, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR -DEFINE_PROPERTYKEY(PKEY_Device_SecuritySDS, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING -DEFINE_PROPERTYKEY(PKEY_Device_DevType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 27); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_Exclusive, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 28); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_Characteristics, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 29); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_Address, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 30); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_UINumberDescFormat, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 31); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_PowerData, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 32); // DEVPROP_TYPE_BINARY -DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicy, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 33); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyDefault, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 34); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyOverride, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 35); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_InstallState, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 36); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_LocationPaths, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 37); // DEVPROP_TYPE_STRING_LIST - -// -// Device properties -// These PKEYs correspond to a device's status and problem code -// -DEFINE_PROPERTYKEY(PKEY_Device_DevNodeStatus, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 2); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_ProblemCode, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 3); // DEVPROP_TYPE_UINT32 - -// -// Device properties -// These PKEYs correspond to device relations -// -DEFINE_PROPERTYKEY(PKEY_Device_EjectionRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 4); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_Device_RemovalRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 5); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_Device_PowerRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 6); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_Device_BusRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 7); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_Device_Parent, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 8); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_Children, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 9); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_Device_Siblings, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 10); // DEVPROP_TYPE_STRING_LIST - -// -// Other Device properties -// -DEFINE_PROPERTYKEY(PKEY_Device_Reported, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 2); // DEVPROP_TYPE_BOOLEAN -DEFINE_PROPERTYKEY(PKEY_Device_Legacy, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 3); // DEVPROP_TYPE_BOOLEAN -DEFINE_PROPERTYKEY(PKEY_Device_InstanceId, 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 256); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Numa_Proximity_Domain, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 1); // DEVPROP_TYPE_UINT32 - -// -// Device driver properties -// -DEFINE_PROPERTYKEY(PKEY_Device_DriverDate, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 2); // DEVPROP_TYPE_FILETIME -DEFINE_PROPERTYKEY(PKEY_Device_DriverVersion, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 3); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_DriverDesc, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 4); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_DriverInfPath, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 5); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSection, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 6); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSectionExt, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 7); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_MatchingDeviceId, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 8); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_DriverProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 9); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_DriverPropPageProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 10); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_DriverCoInstallers, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 11); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerTags, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 12); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerExceptions, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 13); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_Device_DriverRank, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 14); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_DriverLogoLevel, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 15); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_Device_NoConnectSound, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 17); // DEVPROP_TYPE_BOOLEAN -DEFINE_PROPERTYKEY(PKEY_Device_GenericDriverInstalled, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 18); // DEVPROP_TYPE_BOOLEAN - - -// -// Device properties that were set by the driver package that was installed -// on the device. -// -DEFINE_PROPERTYKEY(PKEY_DrvPkg_Model, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 2); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_DrvPkg_VendorWebSite, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 3); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_DrvPkg_DetailedDescription, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 4); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_DrvPkg_DocumentationLink, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 5); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_DrvPkg_Icon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 6); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_DrvPkg_BrandingIcon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 7); // DEVPROP_TYPE_STRING_LIST - -// -// Device setup class properties -// These PKEYs correspond to the old setupapi SPCRP_XXX properties -// -DEFINE_PROPERTYKEY(PKEY_DeviceClass_UpperFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 19); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_DeviceClass_LowerFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 20); // DEVPROP_TYPE_STRING_LIST -DEFINE_PROPERTYKEY(PKEY_DeviceClass_Security, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR -DEFINE_PROPERTYKEY(PKEY_DeviceClass_SecuritySDS, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING -DEFINE_PROPERTYKEY(PKEY_DeviceClass_DevType, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 27); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_DeviceClass_Exclusive, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 28); // DEVPROP_TYPE_UINT32 -DEFINE_PROPERTYKEY(PKEY_DeviceClass_Characteristics, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 29); // DEVPROP_TYPE_UINT32 - -// -// Device setup class properties -// These PKEYs correspond to registry values under the device class GUID key -// -DEFINE_PROPERTYKEY(PKEY_DeviceClass_Name, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 2); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassName, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 3); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_DeviceClass_Icon, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 4); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassInstaller, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 5); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_DeviceClass_PropPageProvider, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 6); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoInstallClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 7); // DEVPROP_TYPE_BOOLEAN -DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoDisplayClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 8); // DEVPROP_TYPE_BOOLEAN -DEFINE_PROPERTYKEY(PKEY_DeviceClass_SilentInstall, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 9); // DEVPROP_TYPE_BOOLEAN -DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoUseClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 10); // DEVPROP_TYPE_BOOLEAN -DEFINE_PROPERTYKEY(PKEY_DeviceClass_DefaultService, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 11); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_DeviceClass_IconPath, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 12); // DEVPROP_TYPE_STRING_LIST - -// -// Other Device setup class properties -// -DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassCoInstallers, 0x713d1703, 0xa2e2, 0x49f5, 0x92, 0x14, 0x56, 0x47, 0x2e, 0xf3, 0xda, 0x5c, 2); // DEVPROP_TYPE_STRING_LIST - -// -// Device interface properties -// -DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 2); // DEVPROP_TYPE_STRING -DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Enabled, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 3); // DEVPROP_TYPE_BOOLEAN -DEFINE_PROPERTYKEY(PKEY_DeviceInterface_ClassGuid, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 4); // DEVPROP_TYPE_GUID - -// -// Device interface class properties -// -DEFINE_PROPERTYKEY(PKEY_DeviceInterfaceClass_DefaultInterface, 0x14c83a99, 0x0b3f, 0x44b7, 0xbe, 0x4c, 0xa1, 0x78, 0xd3, 0x99, 0x05, 0x64, 2); // DEVPROP_TYPE_STRING - - - - diff --git a/Externals/portaudio/src/hostapi/wasapi/mingw-include/ksmedia.h b/Externals/portaudio/src/hostapi/wasapi/mingw-include/ksmedia.h index 2242c1e03a..f029b017f4 100644 --- a/Externals/portaudio/src/hostapi/wasapi/mingw-include/ksmedia.h +++ b/Externals/portaudio/src/hostapi/wasapi/mingw-include/ksmedia.h @@ -417,6 +417,12 @@ DEFINE_GUIDSTRUCT("6994AD04-93EF-11D0-A3CC-00A0C9223196",KSCATEGORY_AUDIO); DEFINE_GUIDSTRUCT("6994AD05-93EF-11D0-A3CC-00A0C9223196",KSCATEGORY_VIDEO); #define KSCATEGORY_VIDEO DEFINE_GUIDNAMED(KSCATEGORY_VIDEO) +/* Added for Vista and later */ +#define STATIC_KSCATEGORY_REALTIME \ + 0xEB115FFCL, 0x10C8, 0x4964, 0x83, 0x1D, 0x6D, 0xCB, 0x02, 0xE6, 0xF2, 0x3F +DEFINE_GUIDSTRUCT("EB115FFC-10C8-4964-831D-6DCB02E6F23F", KSCATEGORY_REALTIME); +#define KSCATEGORY_REALTIME DEFINE_GUIDNAMED(KSCATEGORY_REALTIME) + #define STATIC_KSCATEGORY_TEXT \ 0x6994AD06L,0x93EF,0x11D0,0xA3,0xCC,0x00,0xA0,0xC9,0x22,0x31,0x96 DEFINE_GUIDSTRUCT("6994AD06-93EF-11D0-A3CC-00A0C9223196",KSCATEGORY_TEXT); @@ -979,7 +985,15 @@ DEFINE_GUIDSTRUCT("A855A48C-2F78-4729-9051-1968746B9EEF",KSPROPSETID_RtAudio); #define KSPROPSETID_RtAudio DEFINE_GUIDNAMED(KSPROPSETID_RtAudio) typedef enum { - KSPROPERTY_RTAUDIO_GETPOSITIONFUNCTION + KSPROPERTY_RTAUDIO_GETPOSITIONFUNCTION, + /* Added for Vista and later */ + KSPROPERTY_RTAUDIO_BUFFER, + KSPROPERTY_RTAUDIO_HWLATENCY, + KSPROPERTY_RTAUDIO_POSITIONREGISTER, + KSPROPERTY_RTAUDIO_CLOCKREGISTER, + KSPROPERTY_RTAUDIO_BUFFER_WITH_NOTIFICATION, + KSPROPERTY_RTAUDIO_REGISTER_NOTIFICATION_EVENT, + KSPROPERTY_RTAUDIO_UNREGISTER_NOTIFICATION_EVENT } KSPROPERTY_RTAUDIO; #define STATIC_KSPROPSETID_DrmAudioStream \ @@ -4547,5 +4561,50 @@ typedef struct _tagKSJACK_DESCRIPTION2 DWORD JackCapabilities; } KSJACK_DESCRIPTION2, *PKSJACK_DESCRIPTION2; +/* Additional structs for Windows Vista and later */ +typedef struct _tagKSRTAUDIO_BUFFER_PROPERTY { + KSPROPERTY Property; + PVOID BaseAddress; + ULONG RequestedBufferSize; +} KSRTAUDIO_BUFFER_PROPERTY, *PKSRTAUDIO_BUFFER_PROPERTY; + +typedef struct _tagKSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION { + KSPROPERTY Property; + PVOID BaseAddress; + ULONG RequestedBufferSize; + ULONG NotificationCount; +} KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION, *PKSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION; + +typedef struct _tagKSRTAUDIO_BUFFER { + PVOID BufferAddress; + ULONG ActualBufferSize; + BOOL CallMemoryBarrier; +} KSRTAUDIO_BUFFER, *PKSRTAUDIO_BUFFER; + +typedef struct _tagKSRTAUDIO_HWLATENCY { + ULONG FifoSize; + ULONG ChipsetDelay; + ULONG CodecDelay; +} KSRTAUDIO_HWLATENCY, *PKSRTAUDIO_HWLATENCY; + +typedef struct _tagKSRTAUDIO_HWREGISTER_PROPERTY { + KSPROPERTY Property; + PVOID BaseAddress; +} KSRTAUDIO_HWREGISTER_PROPERTY, *PKSRTAUDIO_HWREGISTER_PROPERTY; + +typedef struct _tagKSRTAUDIO_HWREGISTER { + PVOID Register; + ULONG Width; + ULONGLONG Numerator; + ULONGLONG Denominator; + ULONG Accuracy; +} KSRTAUDIO_HWREGISTER, *PKSRTAUDIO_HWREGISTER; + +typedef struct _tagKSRTAUDIO_NOTIFICATION_EVENT_PROPERTY { + KSPROPERTY Property; + HANDLE NotificationEvent; +} KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY, *PKSRTAUDIO_NOTIFICATION_EVENT_PROPERTY; + + #endif /* _KSMEDIA_ */ diff --git a/Externals/portaudio/src/hostapi/wasapi/mingw-include/propidl.h b/Externals/portaudio/src/hostapi/wasapi/mingw-include/propidl.h deleted file mode 100644 index 96298650b1..0000000000 --- a/Externals/portaudio/src/hostapi/wasapi/mingw-include/propidl.h +++ /dev/null @@ -1,1275 +0,0 @@ - - -/* this ALWAYS GENERATED file contains the definitions for the interfaces */ - - - /* File created by MIDL compiler version 7.00.0499 */ -/* Compiler settings for propidl.idl: - Oicf, W1, Zp8, env=Win32 (32b run) - protocol : dce , ms_ext, c_ext, robust - error checks: allocation ref bounds_check enum stub_data - VC __declspec() decoration level: - __declspec(uuid()), __declspec(selectany), __declspec(novtable) - DECLSPEC_UUID(), MIDL_INTERFACE() -*/ -//@@MIDL_FILE_HEADING( ) - -#pragma warning( disable: 4049 ) /* more than 64k source lines */ - - -/* verify that the version is high enough to compile this file*/ -#ifndef __REQUIRED_RPCNDR_H_VERSION__ -#define __REQUIRED_RPCNDR_H_VERSION__ 500 -#endif - -/* verify that the version is high enough to compile this file*/ -#ifndef __REQUIRED_RPCSAL_H_VERSION__ -#define __REQUIRED_RPCSAL_H_VERSION__ 100 -#endif - -#include "rpc.h" -#include "rpcndr.h" - -#ifndef __RPCNDR_H_VERSION__ -#error this stub requires an updated version of -#endif // __RPCNDR_H_VERSION__ - -#ifndef COM_NO_WINDOWS_H -#include "windows.h" -#include "ole2.h" -#endif /*COM_NO_WINDOWS_H*/ - -#ifndef __propidl_h__ -#define __propidl_h__ - -#if __GNUC__ >=3 -#pragma GCC system_header -#endif - -#define interface struct -#include "sal.h" -#include "rpcsal.h" - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -#pragma once -#endif - -/* Forward Declarations */ - -#ifndef __IPropertyStorage_FWD_DEFINED__ -#define __IPropertyStorage_FWD_DEFINED__ -typedef interface IPropertyStorage IPropertyStorage; -#endif /* __IPropertyStorage_FWD_DEFINED__ */ - - -#ifndef __IPropertySetStorage_FWD_DEFINED__ -#define __IPropertySetStorage_FWD_DEFINED__ -typedef interface IPropertySetStorage IPropertySetStorage; -#endif /* __IPropertySetStorage_FWD_DEFINED__ */ - - -#ifndef __IEnumSTATPROPSTG_FWD_DEFINED__ -#define __IEnumSTATPROPSTG_FWD_DEFINED__ -typedef interface IEnumSTATPROPSTG IEnumSTATPROPSTG; -#endif /* __IEnumSTATPROPSTG_FWD_DEFINED__ */ - - -#ifndef __IEnumSTATPROPSETSTG_FWD_DEFINED__ -#define __IEnumSTATPROPSETSTG_FWD_DEFINED__ -typedef interface IEnumSTATPROPSETSTG IEnumSTATPROPSETSTG; -#endif /* __IEnumSTATPROPSETSTG_FWD_DEFINED__ */ - - -/* header files for imported files */ -#include "objidl.h" -#include "oaidl.h" - -#ifdef __cplusplus -extern "C"{ -#endif - - -/* interface __MIDL_itf_propidl_0000_0000 */ -/* [local] */ - -//+------------------------------------------------------------------------- -// -// Microsoft Windows -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//-------------------------------------------------------------------------- -#if ( _MSC_VER >= 800 ) -#if _MSC_VER >= 1200 -#pragma warning(push) -#endif -#pragma warning(disable:4201) /* Nameless struct/union */ -#pragma warning(disable:4237) /* obsolete member named 'bool' */ -#endif -#if ( _MSC_VER >= 1020 ) -#pragma once -#endif - - - -typedef struct tagVersionedStream - { - GUID guidVersion; - IStream *pStream; - } VERSIONEDSTREAM; - -typedef struct tagVersionedStream *LPVERSIONEDSTREAM; - - -// Flags for IPropertySetStorage::Create -#define PROPSETFLAG_DEFAULT ( 0 ) - -#define PROPSETFLAG_NONSIMPLE ( 1 ) - -#define PROPSETFLAG_ANSI ( 2 ) - -// (This flag is only supported on StgCreatePropStg & StgOpenPropStg -#define PROPSETFLAG_UNBUFFERED ( 4 ) - -// (This flag causes a version-1 property set to be created -#define PROPSETFLAG_CASE_SENSITIVE ( 8 ) - - -// Flags for the reservied PID_BEHAVIOR property -#define PROPSET_BEHAVIOR_CASE_SENSITIVE ( 1 ) - -#ifdef MIDL_PASS -// This is the PROPVARIANT definition for marshaling. -typedef struct tag_inner_PROPVARIANT PROPVARIANT; - -#else -// This is the standard C layout of the PROPVARIANT. -typedef struct tagPROPVARIANT PROPVARIANT; -#endif -typedef struct tagCAC - { - ULONG cElems; - CHAR *pElems; - } CAC; -#ifdef WIN64 -typedef struct tagCAUB - { - ULONG cElems; - UCHAR *pElems; - } CAUB; - -typedef struct tagCAI - { - ULONG cElems; - SHORT *pElems; - } CAI; - -typedef struct tagCAUI - { - ULONG cElems; - USHORT *pElems; - } CAUI; - -typedef struct tagCAL - { - ULONG cElems; - LONG *pElems; - } CAL; - -typedef struct tagCAUL - { - ULONG cElems; - ULONG *pElems; - } CAUL; - -typedef struct tagCAFLT - { - ULONG cElems; - FLOAT *pElems; - } CAFLT; - -typedef struct tagCADBL - { - ULONG cElems; - DOUBLE *pElems; - } CADBL; - -typedef struct tagCACY - { - ULONG cElems; - CY *pElems; - } CACY; - -typedef struct tagCADATE - { - ULONG cElems; - DATE *pElems; - } CADATE; - -typedef struct tagCABSTR - { - ULONG cElems; - BSTR *pElems; - } CABSTR; - -typedef struct tagCABSTRBLOB - { - ULONG cElems; - BSTRBLOB *pElems; - } CABSTRBLOB; - -typedef struct tagCABOOL - { - ULONG cElems; - VARIANT_BOOL *pElems; - } CABOOL; - -typedef struct tagCASCODE - { - ULONG cElems; - SCODE *pElems; - } CASCODE; - -typedef struct tagCAPROPVARIANT - { - ULONG cElems; - PROPVARIANT *pElems; - } CAPROPVARIANT; - -typedef struct tagCAH - { - ULONG cElems; - LARGE_INTEGER *pElems; - } CAH; - -typedef struct tagCAUH - { - ULONG cElems; - ULARGE_INTEGER *pElems; - } CAUH; - -typedef struct tagCALPSTR - { - ULONG cElems; - LPSTR *pElems; - } CALPSTR; - -typedef struct tagCALPWSTR - { - ULONG cElems; - LPWSTR *pElems; - } CALPWSTR; - -typedef struct tagCAFILETIME - { - ULONG cElems; - FILETIME *pElems; - } CAFILETIME; - -typedef struct tagCACLIPDATA - { - ULONG cElems; - CLIPDATA *pElems; - } CACLIPDATA; - -typedef struct tagCACLSID - { - ULONG cElems; - CLSID *pElems; - } CACLSID; -#endif -#ifdef MIDL_PASS -// This is the PROPVARIANT padding layout for marshaling. -typedef BYTE PROPVAR_PAD1; - -typedef BYTE PROPVAR_PAD2; - -typedef ULONG PROPVAR_PAD3; - -#else -// This is the standard C layout of the structure. -typedef WORD PROPVAR_PAD1; -typedef WORD PROPVAR_PAD2; -typedef WORD PROPVAR_PAD3; -#define tag_inner_PROPVARIANT -#endif -#ifdef WIN64 -#ifndef MIDL_PASS -struct tagPROPVARIANT { - union { -#endif -struct tag_inner_PROPVARIANT - { - VARTYPE vt; - PROPVAR_PAD1 wReserved1; - PROPVAR_PAD2 wReserved2; - PROPVAR_PAD3 wReserved3; - /* [switch_type] */ union - { - /* Empty union arm */ - CHAR cVal; - UCHAR bVal; - SHORT iVal; - USHORT uiVal; - LONG lVal; - ULONG ulVal; - INT intVal; - UINT uintVal; - LARGE_INTEGER hVal; - ULARGE_INTEGER uhVal; - FLOAT fltVal; - DOUBLE dblVal; - VARIANT_BOOL boolVal; - //_VARIANT_BOOL bool; - SCODE scode; - CY cyVal; - DATE date; - FILETIME filetime; - CLSID *puuid; - CLIPDATA *pclipdata; - BSTR bstrVal; - BSTRBLOB bstrblobVal; - BLOB blob; - LPSTR pszVal; - LPWSTR pwszVal; - IUnknown *punkVal; - IDispatch *pdispVal; - IStream *pStream; - IStorage *pStorage; - LPVERSIONEDSTREAM pVersionedStream; - LPSAFEARRAY parray; - CAC cac; - CAUB caub; - CAI cai; - CAUI caui; - CAL cal; - CAUL caul; - CAH cah; - CAUH cauh; - CAFLT caflt; - CADBL cadbl; - CABOOL cabool; - CASCODE cascode; - CACY cacy; - CADATE cadate; - CAFILETIME cafiletime; - CACLSID cauuid; - CACLIPDATA caclipdata; - CABSTR cabstr; - CABSTRBLOB cabstrblob; - CALPSTR calpstr; - CALPWSTR calpwstr; - CAPROPVARIANT capropvar; - CHAR *pcVal; - UCHAR *pbVal; - SHORT *piVal; - USHORT *puiVal; - LONG *plVal; - ULONG *pulVal; - INT *pintVal; - UINT *puintVal; - FLOAT *pfltVal; - DOUBLE *pdblVal; - VARIANT_BOOL *pboolVal; - DECIMAL *pdecVal; - SCODE *pscode; - CY *pcyVal; - DATE *pdate; - BSTR *pbstrVal; - IUnknown **ppunkVal; - IDispatch **ppdispVal; - LPSAFEARRAY *pparray; - PROPVARIANT *pvarVal; - } ; - } ; -#ifndef MIDL_PASS - DECIMAL decVal; - }; -}; -#endif -#endif -#ifdef MIDL_PASS -// This is the LPPROPVARIANT definition for marshaling. -typedef struct tag_inner_PROPVARIANT *LPPROPVARIANT; - -typedef const PROPVARIANT *REFPROPVARIANT; - -#else - -// This is the standard C layout of the PROPVARIANT. -#ifdef WIN64 -typedef struct tagPROPVARIANT * LPPROPVARIANT; -#endif - -#ifndef _REFPROPVARIANT_DEFINED -#define _REFPROPVARIANT_DEFINED -#ifdef __cplusplus -#define REFPROPVARIANT const PROPVARIANT & -#else -#define REFPROPVARIANT const PROPVARIANT * __MIDL_CONST -#endif -#endif - -#endif // MIDL_PASS - -// Reserved global Property IDs -#define PID_DICTIONARY ( 0 ) - -#define PID_CODEPAGE ( 0x1 ) - -#define PID_FIRST_USABLE ( 0x2 ) - -#define PID_FIRST_NAME_DEFAULT ( 0xfff ) - -#define PID_LOCALE ( 0x80000000 ) - -#define PID_MODIFY_TIME ( 0x80000001 ) - -#define PID_SECURITY ( 0x80000002 ) - -#define PID_BEHAVIOR ( 0x80000003 ) - -#define PID_ILLEGAL ( 0xffffffff ) - -// Range which is read-only to downlevel implementations -#define PID_MIN_READONLY ( 0x80000000 ) - -#define PID_MAX_READONLY ( 0xbfffffff ) - -// Property IDs for the DiscardableInformation Property Set - -#define PIDDI_THUMBNAIL 0x00000002L // VT_BLOB - -// Property IDs for the SummaryInformation Property Set - -#define PIDSI_TITLE 0x00000002L // VT_LPSTR -#define PIDSI_SUBJECT 0x00000003L // VT_LPSTR -#define PIDSI_AUTHOR 0x00000004L // VT_LPSTR -#define PIDSI_KEYWORDS 0x00000005L // VT_LPSTR -#define PIDSI_COMMENTS 0x00000006L // VT_LPSTR -#define PIDSI_TEMPLATE 0x00000007L // VT_LPSTR -#define PIDSI_LASTAUTHOR 0x00000008L // VT_LPSTR -#define PIDSI_REVNUMBER 0x00000009L // VT_LPSTR -#define PIDSI_EDITTIME 0x0000000aL // VT_FILETIME (UTC) -#define PIDSI_LASTPRINTED 0x0000000bL // VT_FILETIME (UTC) -#define PIDSI_CREATE_DTM 0x0000000cL // VT_FILETIME (UTC) -#define PIDSI_LASTSAVE_DTM 0x0000000dL // VT_FILETIME (UTC) -#define PIDSI_PAGECOUNT 0x0000000eL // VT_I4 -#define PIDSI_WORDCOUNT 0x0000000fL // VT_I4 -#define PIDSI_CHARCOUNT 0x00000010L // VT_I4 -#define PIDSI_THUMBNAIL 0x00000011L // VT_CF -#define PIDSI_APPNAME 0x00000012L // VT_LPSTR -#define PIDSI_DOC_SECURITY 0x00000013L // VT_I4 - -// Property IDs for the DocSummaryInformation Property Set - -#define PIDDSI_CATEGORY 0x00000002 // VT_LPSTR -#define PIDDSI_PRESFORMAT 0x00000003 // VT_LPSTR -#define PIDDSI_BYTECOUNT 0x00000004 // VT_I4 -#define PIDDSI_LINECOUNT 0x00000005 // VT_I4 -#define PIDDSI_PARCOUNT 0x00000006 // VT_I4 -#define PIDDSI_SLIDECOUNT 0x00000007 // VT_I4 -#define PIDDSI_NOTECOUNT 0x00000008 // VT_I4 -#define PIDDSI_HIDDENCOUNT 0x00000009 // VT_I4 -#define PIDDSI_MMCLIPCOUNT 0x0000000A // VT_I4 -#define PIDDSI_SCALE 0x0000000B // VT_BOOL -#define PIDDSI_HEADINGPAIR 0x0000000C // VT_VARIANT | VT_VECTOR -#define PIDDSI_DOCPARTS 0x0000000D // VT_LPSTR | VT_VECTOR -#define PIDDSI_MANAGER 0x0000000E // VT_LPSTR -#define PIDDSI_COMPANY 0x0000000F // VT_LPSTR -#define PIDDSI_LINKSDIRTY 0x00000010 // VT_BOOL - - -// FMTID_MediaFileSummaryInfo - Property IDs - -#define PIDMSI_EDITOR 0x00000002L // VT_LPWSTR -#define PIDMSI_SUPPLIER 0x00000003L // VT_LPWSTR -#define PIDMSI_SOURCE 0x00000004L // VT_LPWSTR -#define PIDMSI_SEQUENCE_NO 0x00000005L // VT_LPWSTR -#define PIDMSI_PROJECT 0x00000006L // VT_LPWSTR -#define PIDMSI_STATUS 0x00000007L // VT_UI4 -#define PIDMSI_OWNER 0x00000008L // VT_LPWSTR -#define PIDMSI_RATING 0x00000009L // VT_LPWSTR -#define PIDMSI_PRODUCTION 0x0000000AL // VT_FILETIME (UTC) -#define PIDMSI_COPYRIGHT 0x0000000BL // VT_LPWSTR - -// PIDMSI_STATUS value definitions - -enum PIDMSI_STATUS_VALUE - { PIDMSI_STATUS_NORMAL = 0, - PIDMSI_STATUS_NEW = ( PIDMSI_STATUS_NORMAL + 1 ) , - PIDMSI_STATUS_PRELIM = ( PIDMSI_STATUS_NEW + 1 ) , - PIDMSI_STATUS_DRAFT = ( PIDMSI_STATUS_PRELIM + 1 ) , - PIDMSI_STATUS_INPROGRESS = ( PIDMSI_STATUS_DRAFT + 1 ) , - PIDMSI_STATUS_EDIT = ( PIDMSI_STATUS_INPROGRESS + 1 ) , - PIDMSI_STATUS_REVIEW = ( PIDMSI_STATUS_EDIT + 1 ) , - PIDMSI_STATUS_PROOF = ( PIDMSI_STATUS_REVIEW + 1 ) , - PIDMSI_STATUS_FINAL = ( PIDMSI_STATUS_PROOF + 1 ) , - PIDMSI_STATUS_OTHER = 0x7fff - } ; -#define PRSPEC_INVALID ( 0xffffffff ) - -#define PRSPEC_LPWSTR ( 0 ) - -#define PRSPEC_PROPID ( 1 ) - -#ifdef WIN64 -typedef struct tagPROPSPEC - { - ULONG ulKind; - /* [switch_type] */ union - { - PROPID propid; - LPOLESTR lpwstr; - /* Empty union arm */ - } ; - } PROPSPEC; - -typedef struct tagSTATPROPSTG - { - LPOLESTR lpwstrName; - PROPID propid; - VARTYPE vt; - } STATPROPSTG; -#endif - -// Macros for parsing the OS Version of the Property Set Header -#define PROPSETHDR_OSVER_KIND(dwOSVer) HIWORD( (dwOSVer) ) -#define PROPSETHDR_OSVER_MAJOR(dwOSVer) LOBYTE(LOWORD( (dwOSVer) )) -#define PROPSETHDR_OSVER_MINOR(dwOSVer) HIBYTE(LOWORD( (dwOSVer) )) -#define PROPSETHDR_OSVERSION_UNKNOWN 0xFFFFFFFF -#ifdef WIN64 -typedef struct tagSTATPROPSETSTG - { - FMTID fmtid; - CLSID clsid; - DWORD grfFlags; - FILETIME mtime; - FILETIME ctime; - FILETIME atime; - DWORD dwOSVersion; - } STATPROPSETSTG; -#endif - - -extern RPC_IF_HANDLE __MIDL_itf_propidl_0000_0000_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_propidl_0000_0000_v0_0_s_ifspec; - -#ifndef __IPropertyStorage_INTERFACE_DEFINED__ -#define __IPropertyStorage_INTERFACE_DEFINED__ - -/* interface IPropertyStorage */ -/* [unique][uuid][object] */ - - -EXTERN_C const IID IID_IPropertyStorage; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("00000138-0000-0000-C000-000000000046") - IPropertyStorage : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE ReadMultiple( - /* [in] */ ULONG cpspec, - /* [size_is][in] */ __RPC__in_ecount_full(cpspec) const PROPSPEC rgpspec[ ], - /* [size_is][out] */ __RPC__out_ecount_full(cpspec) PROPVARIANT rgpropvar[ ]) = 0; - - virtual HRESULT STDMETHODCALLTYPE WriteMultiple( - /* [in] */ ULONG cpspec, - /* [size_is][in] */ __RPC__in_ecount_full(cpspec) const PROPSPEC rgpspec[ ], - /* [size_is][in] */ __RPC__in_ecount_full(cpspec) const PROPVARIANT rgpropvar[ ], - /* [in] */ PROPID propidNameFirst) = 0; - - virtual HRESULT STDMETHODCALLTYPE DeleteMultiple( - /* [in] */ ULONG cpspec, - /* [size_is][in] */ __RPC__in_ecount_full(cpspec) const PROPSPEC rgpspec[ ]) = 0; - - virtual HRESULT STDMETHODCALLTYPE ReadPropertyNames( - /* [in] */ ULONG cpropid, - /* [size_is][in] */ __RPC__in_ecount_full(cpropid) const PROPID rgpropid[ ], - /* [size_is][out] */ __RPC__out_ecount_full(cpropid) LPOLESTR rglpwstrName[ ]) = 0; - - virtual HRESULT STDMETHODCALLTYPE WritePropertyNames( - /* [in] */ ULONG cpropid, - /* [size_is][in] */ __RPC__in_ecount_full(cpropid) const PROPID rgpropid[ ], - /* [size_is][in] */ __RPC__in_ecount_full(cpropid) const LPOLESTR rglpwstrName[ ]) = 0; - - virtual HRESULT STDMETHODCALLTYPE DeletePropertyNames( - /* [in] */ ULONG cpropid, - /* [size_is][in] */ __RPC__in_ecount_full(cpropid) const PROPID rgpropid[ ]) = 0; - - virtual HRESULT STDMETHODCALLTYPE Commit( - /* [in] */ DWORD grfCommitFlags) = 0; - - virtual HRESULT STDMETHODCALLTYPE Revert( void) = 0; - - virtual HRESULT STDMETHODCALLTYPE Enum( - /* [out] */ __RPC__deref_out_opt IEnumSTATPROPSTG **ppenum) = 0; - - virtual HRESULT STDMETHODCALLTYPE SetTimes( - /* [in] */ __RPC__in const FILETIME *pctime, - /* [in] */ __RPC__in const FILETIME *patime, - /* [in] */ __RPC__in const FILETIME *pmtime) = 0; - - virtual HRESULT STDMETHODCALLTYPE SetClass( - /* [in] */ __RPC__in REFCLSID clsid) = 0; - - virtual HRESULT STDMETHODCALLTYPE Stat( - /* [out] */ __RPC__out STATPROPSETSTG *pstatpsstg) = 0; - - }; - -#else /* C style interface */ - -// typedef struct IPropertyStorageVtbl -// { -// BEGIN_INTERFACE -// -// HRESULT ( STDMETHODCALLTYPE *QueryInterface )( -// IPropertyStorage * This, -// /* [in] */ __RPC__in REFIID riid, -// /* [iid_is][out] */ -// __RPC__deref_out void **ppvObject); -// -// ULONG ( STDMETHODCALLTYPE *AddRef )( -// IPropertyStorage * This); -// -// ULONG ( STDMETHODCALLTYPE *Release )( -// IPropertyStorage * This); -// -// HRESULT ( STDMETHODCALLTYPE *ReadMultiple )( -// IPropertyStorage * This, -// /* [in] */ ULONG cpspec, -// /* [size_is][in] */ __RPC__in_ecount_full(cpspec) const PROPSPEC rgpspec[ ], -// /* [size_is][out] */ __RPC__out_ecount_full(cpspec) PROPVARIANT rgpropvar[ ]); -// -// HRESULT ( STDMETHODCALLTYPE *WriteMultiple )( -// IPropertyStorage * This, -// /* [in] */ ULONG cpspec, -// /* [size_is][in] */ __RPC__in_ecount_full(cpspec) const PROPSPEC rgpspec[ ], -// /* [size_is][in] */ __RPC__in_ecount_full(cpspec) const PROPVARIANT rgpropvar[ ], -// /* [in] */ PROPID propidNameFirst); -// -// HRESULT ( STDMETHODCALLTYPE *DeleteMultiple )( -// IPropertyStorage * This, -// /* [in] */ ULONG cpspec, -// /* [size_is][in] */ __RPC__in_ecount_full(cpspec) const PROPSPEC rgpspec[ ]); -// -// HRESULT ( STDMETHODCALLTYPE *ReadPropertyNames )( -// IPropertyStorage * This, -// /* [in] */ ULONG cpropid, -// /* [size_is][in] */ __RPC__in_ecount_full(cpropid) const PROPID rgpropid[ ], -// /* [size_is][out] */ __RPC__out_ecount_full(cpropid) LPOLESTR rglpwstrName[ ]); -// -// HRESULT ( STDMETHODCALLTYPE *WritePropertyNames )( -// IPropertyStorage * This, -// /* [in] */ ULONG cpropid, -// /* [size_is][in] */ __RPC__in_ecount_full(cpropid) const PROPID rgpropid[ ], -// /* [size_is][in] */ __RPC__in_ecount_full(cpropid) const LPOLESTR rglpwstrName[ ]); -// -// HRESULT ( STDMETHODCALLTYPE *DeletePropertyNames )( -// IPropertyStorage * This, -// /* [in] */ ULONG cpropid, -// /* [size_is][in] */ __RPC__in_ecount_full(cpropid) const PROPID rgpropid[ ]); -// -// HRESULT ( STDMETHODCALLTYPE *Commit )( -// IPropertyStorage * This, -// /* [in] */ DWORD grfCommitFlags); -// -// HRESULT ( STDMETHODCALLTYPE *Revert )( -// IPropertyStorage * This); -// -// HRESULT ( STDMETHODCALLTYPE *Enum )( -// IPropertyStorage * This, -// /* [out] */ __RPC__deref_out_opt IEnumSTATPROPSTG **ppenum); -// -// HRESULT ( STDMETHODCALLTYPE *SetTimes )( -// IPropertyStorage * This, -// /* [in] */ __RPC__in const FILETIME *pctime, -// /* [in] */ __RPC__in const FILETIME *patime, -// /* [in] */ __RPC__in const FILETIME *pmtime); -// -// HRESULT ( STDMETHODCALLTYPE *SetClass )( -// IPropertyStorage * This, -// /* [in] */ __RPC__in REFCLSID clsid); -// -// HRESULT ( STDMETHODCALLTYPE *Stat )( -// IPropertyStorage * This, -// /* [out] */ __RPC__out STATPROPSETSTG *pstatpsstg); -// -// END_INTERFACE -// } IPropertyStorageVtbl; -// -// interface IPropertyStorage -// { -// CONST_VTBL struct IPropertyStorageVtbl *lpVtbl; -// }; - - - -#ifdef COBJMACROS - - -#define IPropertyStorage_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) - -#define IPropertyStorage_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) - -#define IPropertyStorage_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) - - -#define IPropertyStorage_ReadMultiple(This,cpspec,rgpspec,rgpropvar) \ - ( (This)->lpVtbl -> ReadMultiple(This,cpspec,rgpspec,rgpropvar) ) - -#define IPropertyStorage_WriteMultiple(This,cpspec,rgpspec,rgpropvar,propidNameFirst) \ - ( (This)->lpVtbl -> WriteMultiple(This,cpspec,rgpspec,rgpropvar,propidNameFirst) ) - -#define IPropertyStorage_DeleteMultiple(This,cpspec,rgpspec) \ - ( (This)->lpVtbl -> DeleteMultiple(This,cpspec,rgpspec) ) - -#define IPropertyStorage_ReadPropertyNames(This,cpropid,rgpropid,rglpwstrName) \ - ( (This)->lpVtbl -> ReadPropertyNames(This,cpropid,rgpropid,rglpwstrName) ) - -#define IPropertyStorage_WritePropertyNames(This,cpropid,rgpropid,rglpwstrName) \ - ( (This)->lpVtbl -> WritePropertyNames(This,cpropid,rgpropid,rglpwstrName) ) - -#define IPropertyStorage_DeletePropertyNames(This,cpropid,rgpropid) \ - ( (This)->lpVtbl -> DeletePropertyNames(This,cpropid,rgpropid) ) - -#define IPropertyStorage_Commit(This,grfCommitFlags) \ - ( (This)->lpVtbl -> Commit(This,grfCommitFlags) ) - -#define IPropertyStorage_Revert(This) \ - ( (This)->lpVtbl -> Revert(This) ) - -#define IPropertyStorage_Enum(This,ppenum) \ - ( (This)->lpVtbl -> Enum(This,ppenum) ) - -#define IPropertyStorage_SetTimes(This,pctime,patime,pmtime) \ - ( (This)->lpVtbl -> SetTimes(This,pctime,patime,pmtime) ) - -#define IPropertyStorage_SetClass(This,clsid) \ - ( (This)->lpVtbl -> SetClass(This,clsid) ) - -#define IPropertyStorage_Stat(This,pstatpsstg) \ - ( (This)->lpVtbl -> Stat(This,pstatpsstg) ) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - - -#endif /* __IPropertyStorage_INTERFACE_DEFINED__ */ - - -#ifndef __IPropertySetStorage_INTERFACE_DEFINED__ -#define __IPropertySetStorage_INTERFACE_DEFINED__ - -/* interface IPropertySetStorage */ -/* [unique][uuid][object] */ - -typedef /* [unique] */ __RPC_unique_pointer IPropertySetStorage *LPPROPERTYSETSTORAGE; - - -EXTERN_C const IID IID_IPropertySetStorage; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("0000013A-0000-0000-C000-000000000046") - IPropertySetStorage : public IUnknown - { - public: - virtual HRESULT STDMETHODCALLTYPE Create( - /* [in] */ __RPC__in REFFMTID rfmtid, - /* [unique][in] */ __RPC__in_opt const CLSID *pclsid, - /* [in] */ DWORD grfFlags, - /* [in] */ DWORD grfMode, - /* [out] */ __RPC__deref_out_opt IPropertyStorage **ppprstg) = 0; - - virtual HRESULT STDMETHODCALLTYPE Open( - /* [in] */ __RPC__in REFFMTID rfmtid, - /* [in] */ DWORD grfMode, - /* [out] */ __RPC__deref_out_opt IPropertyStorage **ppprstg) = 0; - - virtual HRESULT STDMETHODCALLTYPE Delete( - /* [in] */ __RPC__in REFFMTID rfmtid) = 0; - - virtual HRESULT STDMETHODCALLTYPE Enum( - /* [out] */ __RPC__deref_out_opt IEnumSTATPROPSETSTG **ppenum) = 0; - - }; - -#else /* C style interface */ - -// typedef struct IPropertySetStorageVtbl -// { -// BEGIN_INTERFACE -// -// HRESULT ( STDMETHODCALLTYPE *QueryInterface )( -// IPropertySetStorage * This, -// /* [in] */ __RPC__in REFIID riid, -// /* [iid_is][out] */ -// __RPC__deref_out void **ppvObject); -// -// ULONG ( STDMETHODCALLTYPE *AddRef )( -// IPropertySetStorage * This); -// -// ULONG ( STDMETHODCALLTYPE *Release )( -// IPropertySetStorage * This); -// -// HRESULT ( STDMETHODCALLTYPE *Create )( -// IPropertySetStorage * This, -// /* [in] */ __RPC__in REFFMTID rfmtid, -// /* [unique][in] */ __RPC__in_opt const CLSID *pclsid, -// /* [in] */ DWORD grfFlags, -// /* [in] */ DWORD grfMode, -// /* [out] */ __RPC__deref_out_opt IPropertyStorage **ppprstg); -// -// HRESULT ( STDMETHODCALLTYPE *Open )( -// IPropertySetStorage * This, -// /* [in] */ __RPC__in REFFMTID rfmtid, -// /* [in] */ DWORD grfMode, -// /* [out] */ __RPC__deref_out_opt IPropertyStorage **ppprstg); -// -// HRESULT ( STDMETHODCALLTYPE *Delete )( -// IPropertySetStorage * This, -// /* [in] */ __RPC__in REFFMTID rfmtid); -// -// HRESULT ( STDMETHODCALLTYPE *Enum )( -// IPropertySetStorage * This, -// /* [out] */ __RPC__deref_out_opt IEnumSTATPROPSETSTG **ppenum); -// -// END_INTERFACE -// } IPropertySetStorageVtbl; -// -// interface IPropertySetStorage -// { -// CONST_VTBL struct IPropertySetStorageVtbl *lpVtbl; -// }; - - - -#ifdef COBJMACROS - - -#define IPropertySetStorage_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) - -#define IPropertySetStorage_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) - -#define IPropertySetStorage_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) - - -#define IPropertySetStorage_Create(This,rfmtid,pclsid,grfFlags,grfMode,ppprstg) \ - ( (This)->lpVtbl -> Create(This,rfmtid,pclsid,grfFlags,grfMode,ppprstg) ) - -#define IPropertySetStorage_Open(This,rfmtid,grfMode,ppprstg) \ - ( (This)->lpVtbl -> Open(This,rfmtid,grfMode,ppprstg) ) - -#define IPropertySetStorage_Delete(This,rfmtid) \ - ( (This)->lpVtbl -> Delete(This,rfmtid) ) - -#define IPropertySetStorage_Enum(This,ppenum) \ - ( (This)->lpVtbl -> Enum(This,ppenum) ) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - - -#endif /* __IPropertySetStorage_INTERFACE_DEFINED__ */ - - -#ifndef __IEnumSTATPROPSTG_INTERFACE_DEFINED__ -#define __IEnumSTATPROPSTG_INTERFACE_DEFINED__ - -/* interface IEnumSTATPROPSTG */ -/* [unique][uuid][object] */ - -//typedef /* [unique] */ __RPC_unique_pointer IEnumSTATPROPSTG *LPENUMSTATPROPSTG; - - -EXTERN_C const IID IID_IEnumSTATPROPSTG; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("00000139-0000-0000-C000-000000000046") - IEnumSTATPROPSTG : public IUnknown - { - public: - virtual /* [local] */ HRESULT STDMETHODCALLTYPE Next( - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ STATPROPSTG *rgelt, - /* [out] */ ULONG *pceltFetched) = 0; - - virtual HRESULT STDMETHODCALLTYPE Skip( - /* [in] */ ULONG celt) = 0; - - virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0; - - virtual HRESULT STDMETHODCALLTYPE Clone( - /* [out] */ __RPC__deref_out_opt IEnumSTATPROPSTG **ppenum) = 0; - - }; - -#else /* C style interface */ - -// typedef struct IEnumSTATPROPSTGVtbl -// { -// BEGIN_INTERFACE -// -// HRESULT ( STDMETHODCALLTYPE *QueryInterface )( -// IEnumSTATPROPSTG * This, -// /* [in] */ __RPC__in REFIID riid, -// /* [iid_is][out] */ -// __RPC__deref_out void **ppvObject); -// -// ULONG ( STDMETHODCALLTYPE *AddRef )( -// IEnumSTATPROPSTG * This); -// -// ULONG ( STDMETHODCALLTYPE *Release )( -// IEnumSTATPROPSTG * This); -// -// /* [local] */ HRESULT ( STDMETHODCALLTYPE *Next )( -// IEnumSTATPROPSTG * This, -// /* [in] */ ULONG celt, -// /* [length_is][size_is][out] */ STATPROPSTG *rgelt, -// /* [out] */ ULONG *pceltFetched); -// -// HRESULT ( STDMETHODCALLTYPE *Skip )( -// IEnumSTATPROPSTG * This, -// /* [in] */ ULONG celt); -// -// HRESULT ( STDMETHODCALLTYPE *Reset )( -// IEnumSTATPROPSTG * This); -// -// HRESULT ( STDMETHODCALLTYPE *Clone )( -// IEnumSTATPROPSTG * This, -// /* [out] */ __RPC__deref_out_opt IEnumSTATPROPSTG **ppenum); -// -// END_INTERFACE -// } IEnumSTATPROPSTGVtbl; -// -// interface IEnumSTATPROPSTG -// { -// CONST_VTBL struct IEnumSTATPROPSTGVtbl *lpVtbl; -// }; - - - -#ifdef COBJMACROS - - -#define IEnumSTATPROPSTG_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) - -#define IEnumSTATPROPSTG_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) - -#define IEnumSTATPROPSTG_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) - - -#define IEnumSTATPROPSTG_Next(This,celt,rgelt,pceltFetched) \ - ( (This)->lpVtbl -> Next(This,celt,rgelt,pceltFetched) ) - -#define IEnumSTATPROPSTG_Skip(This,celt) \ - ( (This)->lpVtbl -> Skip(This,celt) ) - -#define IEnumSTATPROPSTG_Reset(This) \ - ( (This)->lpVtbl -> Reset(This) ) - -#define IEnumSTATPROPSTG_Clone(This,ppenum) \ - ( (This)->lpVtbl -> Clone(This,ppenum) ) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE IEnumSTATPROPSTG_RemoteNext_Proxy( - IEnumSTATPROPSTG * This, - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) STATPROPSTG *rgelt, - /* [out] */ __RPC__out ULONG *pceltFetched); - - -void __RPC_STUB IEnumSTATPROPSTG_RemoteNext_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IEnumSTATPROPSTG_INTERFACE_DEFINED__ */ - - -#ifndef __IEnumSTATPROPSETSTG_INTERFACE_DEFINED__ -#define __IEnumSTATPROPSETSTG_INTERFACE_DEFINED__ - -/* interface IEnumSTATPROPSETSTG */ -/* [unique][uuid][object] */ - -typedef /* [unique] */ __RPC_unique_pointer IEnumSTATPROPSETSTG *LPENUMSTATPROPSETSTG; - - -EXTERN_C const IID IID_IEnumSTATPROPSETSTG; - -#if defined(__cplusplus) && !defined(CINTERFACE) - - MIDL_INTERFACE("0000013B-0000-0000-C000-000000000046") - IEnumSTATPROPSETSTG : public IUnknown - { - public: - virtual /* [local] */ HRESULT STDMETHODCALLTYPE Next( - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ STATPROPSETSTG *rgelt, - /* [out] */ ULONG *pceltFetched) = 0; - - virtual HRESULT STDMETHODCALLTYPE Skip( - /* [in] */ ULONG celt) = 0; - - virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0; - - virtual HRESULT STDMETHODCALLTYPE Clone( - /* [out] */ __RPC__deref_out_opt IEnumSTATPROPSETSTG **ppenum) = 0; - - }; - -#else /* C style interface */ - -// typedef struct IEnumSTATPROPSETSTGVtbl -// { -// BEGIN_INTERFACE -// -// HRESULT ( STDMETHODCALLTYPE *QueryInterface )( -// IEnumSTATPROPSETSTG * This, -// /* [in] */ __RPC__in REFIID riid, -// /* [iid_is][out] */ -// __RPC__deref_out void **ppvObject); -// -// ULONG ( STDMETHODCALLTYPE *AddRef )( -// IEnumSTATPROPSETSTG * This); -// -// ULONG ( STDMETHODCALLTYPE *Release )( -// IEnumSTATPROPSETSTG * This); -// -// /* [local] */ HRESULT ( STDMETHODCALLTYPE *Next )( -// IEnumSTATPROPSETSTG * This, -// /* [in] */ ULONG celt, -// /* [length_is][size_is][out] */ STATPROPSETSTG *rgelt, -// /* [out] */ ULONG *pceltFetched); -// -// HRESULT ( STDMETHODCALLTYPE *Skip )( -// IEnumSTATPROPSETSTG * This, -// /* [in] */ ULONG celt); -// -// HRESULT ( STDMETHODCALLTYPE *Reset )( -// IEnumSTATPROPSETSTG * This); -// -// HRESULT ( STDMETHODCALLTYPE *Clone )( -// IEnumSTATPROPSETSTG * This, -// /* [out] */ __RPC__deref_out_opt IEnumSTATPROPSETSTG **ppenum); -// -// END_INTERFACE -// } IEnumSTATPROPSETSTGVtbl; -// -// interface IEnumSTATPROPSETSTG -// { -// CONST_VTBL struct IEnumSTATPROPSETSTGVtbl *lpVtbl; -// }; - - - -#ifdef COBJMACROS - - -#define IEnumSTATPROPSETSTG_QueryInterface(This,riid,ppvObject) \ - ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) - -#define IEnumSTATPROPSETSTG_AddRef(This) \ - ( (This)->lpVtbl -> AddRef(This) ) - -#define IEnumSTATPROPSETSTG_Release(This) \ - ( (This)->lpVtbl -> Release(This) ) - - -#define IEnumSTATPROPSETSTG_Next(This,celt,rgelt,pceltFetched) \ - ( (This)->lpVtbl -> Next(This,celt,rgelt,pceltFetched) ) - -#define IEnumSTATPROPSETSTG_Skip(This,celt) \ - ( (This)->lpVtbl -> Skip(This,celt) ) - -#define IEnumSTATPROPSETSTG_Reset(This) \ - ( (This)->lpVtbl -> Reset(This) ) - -#define IEnumSTATPROPSETSTG_Clone(This,ppenum) \ - ( (This)->lpVtbl -> Clone(This,ppenum) ) - -#endif /* COBJMACROS */ - - -#endif /* C style interface */ - - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE IEnumSTATPROPSETSTG_RemoteNext_Proxy( - IEnumSTATPROPSETSTG * This, - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) STATPROPSETSTG *rgelt, - /* [out] */ __RPC__out ULONG *pceltFetched); - - -void __RPC_STUB IEnumSTATPROPSETSTG_RemoteNext_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase); - - - -#endif /* __IEnumSTATPROPSETSTG_INTERFACE_DEFINED__ */ - - -/* interface __MIDL_itf_propidl_0000_0004 */ -/* [local] */ - -typedef /* [unique] */ __RPC_unique_pointer IPropertyStorage *LPPROPERTYSTORAGE; - -WINOLEAPI PropVariantCopy ( PROPVARIANT * pvarDest, const PROPVARIANT * pvarSrc ); -WINOLEAPI PropVariantClear ( PROPVARIANT * pvar ); -WINOLEAPI FreePropVariantArray ( ULONG cVariants, PROPVARIANT * rgvars ); - -#define _PROPVARIANTINIT_DEFINED_ -# ifdef __cplusplus -inline void PropVariantInit ( PROPVARIANT * pvar ) -{ - memset ( pvar, 0, sizeof(PROPVARIANT) ); -} -# else -# define PropVariantInit(pvar) memset ( (pvar), 0, sizeof(PROPVARIANT) ) -# endif - - -#ifndef _STGCREATEPROPSTG_DEFINED_ -WINOLEAPI StgCreatePropStg( IUnknown* pUnk, REFFMTID fmtid, const CLSID *pclsid, DWORD grfFlags, DWORD dwReserved, IPropertyStorage **ppPropStg ); -WINOLEAPI StgOpenPropStg( IUnknown* pUnk, REFFMTID fmtid, DWORD grfFlags, DWORD dwReserved, IPropertyStorage **ppPropStg ); -WINOLEAPI StgCreatePropSetStg( IStorage *pStorage, DWORD dwReserved, IPropertySetStorage **ppPropSetStg); - -#define CCH_MAX_PROPSTG_NAME 31 -__checkReturn WINOLEAPI FmtIdToPropStgName( const FMTID *pfmtid, __out_ecount(CCH_MAX_PROPSTG_NAME+1) LPOLESTR oszName ); -WINOLEAPI PropStgNameToFmtId( __in __nullterminated const LPOLESTR oszName, FMTID *pfmtid ); -#endif -#ifndef _SERIALIZEDPROPERTYVALUE_DEFINED_ -#define _SERIALIZEDPROPERTYVALUE_DEFINED_ -typedef struct tagSERIALIZEDPROPERTYVALUE // prop -{ - DWORD dwType; - BYTE rgb[1]; -} SERIALIZEDPROPERTYVALUE; -#endif - -EXTERN_C SERIALIZEDPROPERTYVALUE* __stdcall -StgConvertVariantToProperty( - __in const PROPVARIANT* pvar, - USHORT CodePage, - __out_bcount_opt(*pcb) SERIALIZEDPROPERTYVALUE* pprop, - __inout ULONG* pcb, - PROPID pid, - __reserved BOOLEAN fReserved, - __out_opt ULONG* pcIndirect); - -#ifdef __cplusplus -class PMemoryAllocator; - -EXTERN_C BOOLEAN __stdcall -StgConvertPropertyToVariant( - __in const SERIALIZEDPROPERTYVALUE* pprop, - USHORT CodePage, - __out PROPVARIANT* pvar, - __in PMemoryAllocator* pma); -#endif -#if _MSC_VER >= 1200 -#pragma warning(pop) -#else -#pragma warning(default:4201) /* Nameless struct/union */ -#pragma warning(default:4237) /* keywords bool, true, false, etc.. */ -#endif - - -extern RPC_IF_HANDLE __MIDL_itf_propidl_0000_0004_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_propidl_0000_0004_v0_0_s_ifspec; - -/* Additional Prototypes for ALL interfaces */ - -unsigned long __RPC_USER BSTR_UserSize( unsigned long *, unsigned long , BSTR * ); -unsigned char * __RPC_USER BSTR_UserMarshal( unsigned long *, unsigned char *, BSTR * ); -unsigned char * __RPC_USER BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * ); -void __RPC_USER BSTR_UserFree( unsigned long *, BSTR * ); - -unsigned long __RPC_USER LPSAFEARRAY_UserSize( unsigned long *, unsigned long , LPSAFEARRAY * ); -unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal( unsigned long *, unsigned char *, LPSAFEARRAY * ); -unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal(unsigned long *, unsigned char *, LPSAFEARRAY * ); -void __RPC_USER LPSAFEARRAY_UserFree( unsigned long *, LPSAFEARRAY * ); - -unsigned long __RPC_USER BSTR_UserSize64( unsigned long *, unsigned long , BSTR * ); -unsigned char * __RPC_USER BSTR_UserMarshal64( unsigned long *, unsigned char *, BSTR * ); -unsigned char * __RPC_USER BSTR_UserUnmarshal64(unsigned long *, unsigned char *, BSTR * ); -void __RPC_USER BSTR_UserFree64( unsigned long *, BSTR * ); - -unsigned long __RPC_USER LPSAFEARRAY_UserSize64( unsigned long *, unsigned long , LPSAFEARRAY * ); -unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal64( unsigned long *, unsigned char *, LPSAFEARRAY * ); -unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal64(unsigned long *, unsigned char *, LPSAFEARRAY * ); -void __RPC_USER LPSAFEARRAY_UserFree64( unsigned long *, LPSAFEARRAY * ); - -/* [local] */ HRESULT STDMETHODCALLTYPE IEnumSTATPROPSTG_Next_Proxy( - IEnumSTATPROPSTG * This, - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ STATPROPSTG *rgelt, - /* [out] */ ULONG *pceltFetched); - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE IEnumSTATPROPSTG_Next_Stub( - IEnumSTATPROPSTG * This, - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) STATPROPSTG *rgelt, - /* [out] */ __RPC__out ULONG *pceltFetched); - -/* [local] */ HRESULT STDMETHODCALLTYPE IEnumSTATPROPSETSTG_Next_Proxy( - IEnumSTATPROPSETSTG * This, - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ STATPROPSETSTG *rgelt, - /* [out] */ ULONG *pceltFetched); - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE IEnumSTATPROPSETSTG_Next_Stub( - IEnumSTATPROPSETSTG * This, - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ __RPC__out_ecount_part(celt, *pceltFetched) STATPROPSETSTG *rgelt, - /* [out] */ __RPC__out ULONG *pceltFetched); - - - -/* end of Additional Prototypes */ - -#ifdef __cplusplus -} -#endif - -#endif - - - diff --git a/Externals/portaudio/src/hostapi/wasapi/mingw-include/propkey.h b/Externals/portaudio/src/hostapi/wasapi/mingw-include/propkey.h deleted file mode 100644 index 69e71a5191..0000000000 --- a/Externals/portaudio/src/hostapi/wasapi/mingw-include/propkey.h +++ /dev/null @@ -1,4274 +0,0 @@ -//=========================================================================== -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//=========================================================================== - - -#ifndef _INC_PROPKEY -#define _INC_PROPKEY - -#ifndef DEFINE_API_PKEY -#define DEFINE_API_PKEY(name, managed_name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) \ - DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) -#endif - -#include - -#ifndef _WIN32_IE -#define _WIN32_IE 0x0501 -#else -#if (_WIN32_IE < 0x0400) && defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0500) -#error _WIN32_IE setting conflicts with _WIN32_WINNT setting -#endif -#endif - - -//----------------------------------------------------------------------------- -// Audio properties - -// Name: System.Audio.ChannelCount -- PKEY_Audio_ChannelCount -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_AudioSummaryInformation) 64440490-4C8B-11D1-8B70-080036B11A03, 7 (PIDASI_CHANNEL_COUNT) -// -// Indicates the channel count for the audio file. Values: 1 (mono), 2 (stereo). -DEFINE_PROPERTYKEY(PKEY_Audio_ChannelCount, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 7); - -// Possible discrete values for PKEY_Audio_ChannelCount are: -#define AUDIO_CHANNELCOUNT_MONO 1ul -#define AUDIO_CHANNELCOUNT_STEREO 2ul - -// Name: System.Audio.Compression -- PKEY_Audio_Compression -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_AudioSummaryInformation) 64440490-4C8B-11D1-8B70-080036B11A03, 10 (PIDASI_COMPRESSION) -// -// -DEFINE_PROPERTYKEY(PKEY_Audio_Compression, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 10); - -// Name: System.Audio.EncodingBitrate -- PKEY_Audio_EncodingBitrate -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_AudioSummaryInformation) 64440490-4C8B-11D1-8B70-080036B11A03, 4 (PIDASI_AVG_DATA_RATE) -// -// Indicates the average data rate in Hz for the audio file in "bits per second". -DEFINE_PROPERTYKEY(PKEY_Audio_EncodingBitrate, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 4); - -// Name: System.Audio.Format -- PKEY_Audio_Format -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) Legacy code may treat this as VT_BSTR. -// FormatID: (FMTID_AudioSummaryInformation) 64440490-4C8B-11D1-8B70-080036B11A03, 2 (PIDASI_FORMAT) -// -// Indicates the format of the audio file. -DEFINE_PROPERTYKEY(PKEY_Audio_Format, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 2); - -// Name: System.Audio.IsVariableBitRate -- PKEY_Audio_IsVariableBitRate -// Type: Boolean -- VT_BOOL -// FormatID: E6822FEE-8C17-4D62-823C-8E9CFCBD1D5C, 100 -DEFINE_PROPERTYKEY(PKEY_Audio_IsVariableBitRate, 0xE6822FEE, 0x8C17, 0x4D62, 0x82, 0x3C, 0x8E, 0x9C, 0xFC, 0xBD, 0x1D, 0x5C, 100); - -// Name: System.Audio.PeakValue -- PKEY_Audio_PeakValue -// Type: UInt32 -- VT_UI4 -// FormatID: 2579E5D0-1116-4084-BD9A-9B4F7CB4DF5E, 100 -DEFINE_PROPERTYKEY(PKEY_Audio_PeakValue, 0x2579E5D0, 0x1116, 0x4084, 0xBD, 0x9A, 0x9B, 0x4F, 0x7C, 0xB4, 0xDF, 0x5E, 100); - -// Name: System.Audio.SampleRate -- PKEY_Audio_SampleRate -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_AudioSummaryInformation) 64440490-4C8B-11D1-8B70-080036B11A03, 5 (PIDASI_SAMPLE_RATE) -// -// Indicates the audio sample rate for the audio file in "samples per second". -DEFINE_PROPERTYKEY(PKEY_Audio_SampleRate, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 5); - -// Name: System.Audio.SampleSize -- PKEY_Audio_SampleSize -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_AudioSummaryInformation) 64440490-4C8B-11D1-8B70-080036B11A03, 6 (PIDASI_SAMPLE_SIZE) -// -// Indicates the audio sample size for the audio file in "bits per sample". -DEFINE_PROPERTYKEY(PKEY_Audio_SampleSize, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 6); - -// Name: System.Audio.StreamName -- PKEY_Audio_StreamName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_AudioSummaryInformation) 64440490-4C8B-11D1-8B70-080036B11A03, 9 (PIDASI_STREAM_NAME) -// -// -DEFINE_PROPERTYKEY(PKEY_Audio_StreamName, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 9); - -// Name: System.Audio.StreamNumber -- PKEY_Audio_StreamNumber -// Type: UInt16 -- VT_UI2 -// FormatID: (FMTID_AudioSummaryInformation) 64440490-4C8B-11D1-8B70-080036B11A03, 8 (PIDASI_STREAM_NUMBER) -// -// -DEFINE_PROPERTYKEY(PKEY_Audio_StreamNumber, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 8); - - - -//----------------------------------------------------------------------------- -// Calendar properties - -// Name: System.Calendar.Duration -- PKEY_Calendar_Duration -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 293CA35A-09AA-4DD2-B180-1FE245728A52, 100 -// -// The duration as specified in a string. -DEFINE_PROPERTYKEY(PKEY_Calendar_Duration, 0x293CA35A, 0x09AA, 0x4DD2, 0xB1, 0x80, 0x1F, 0xE2, 0x45, 0x72, 0x8A, 0x52, 100); - -// Name: System.Calendar.IsOnline -- PKEY_Calendar_IsOnline -// Type: Boolean -- VT_BOOL -// FormatID: BFEE9149-E3E2-49A7-A862-C05988145CEC, 100 -// -// Identifies if the event is an online event. -DEFINE_PROPERTYKEY(PKEY_Calendar_IsOnline, 0xBFEE9149, 0xE3E2, 0x49A7, 0xA8, 0x62, 0xC0, 0x59, 0x88, 0x14, 0x5C, 0xEC, 100); - -// Name: System.Calendar.IsRecurring -- PKEY_Calendar_IsRecurring -// Type: Boolean -- VT_BOOL -// FormatID: 315B9C8D-80A9-4EF9-AE16-8E746DA51D70, 100 -DEFINE_PROPERTYKEY(PKEY_Calendar_IsRecurring, 0x315B9C8D, 0x80A9, 0x4EF9, 0xAE, 0x16, 0x8E, 0x74, 0x6D, 0xA5, 0x1D, 0x70, 100); - -// Name: System.Calendar.Location -- PKEY_Calendar_Location -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: F6272D18-CECC-40B1-B26A-3911717AA7BD, 100 -DEFINE_PROPERTYKEY(PKEY_Calendar_Location, 0xF6272D18, 0xCECC, 0x40B1, 0xB2, 0x6A, 0x39, 0x11, 0x71, 0x7A, 0xA7, 0xBD, 100); - -// Name: System.Calendar.OptionalAttendeeAddresses -- PKEY_Calendar_OptionalAttendeeAddresses -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: D55BAE5A-3892-417A-A649-C6AC5AAAEAB3, 100 -DEFINE_PROPERTYKEY(PKEY_Calendar_OptionalAttendeeAddresses, 0xD55BAE5A, 0x3892, 0x417A, 0xA6, 0x49, 0xC6, 0xAC, 0x5A, 0xAA, 0xEA, 0xB3, 100); - -// Name: System.Calendar.OptionalAttendeeNames -- PKEY_Calendar_OptionalAttendeeNames -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: 09429607-582D-437F-84C3-DE93A2B24C3C, 100 -DEFINE_PROPERTYKEY(PKEY_Calendar_OptionalAttendeeNames, 0x09429607, 0x582D, 0x437F, 0x84, 0xC3, 0xDE, 0x93, 0xA2, 0xB2, 0x4C, 0x3C, 100); - -// Name: System.Calendar.OrganizerAddress -- PKEY_Calendar_OrganizerAddress -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 744C8242-4DF5-456C-AB9E-014EFB9021E3, 100 -// -// Address of the organizer organizing the event. -DEFINE_PROPERTYKEY(PKEY_Calendar_OrganizerAddress, 0x744C8242, 0x4DF5, 0x456C, 0xAB, 0x9E, 0x01, 0x4E, 0xFB, 0x90, 0x21, 0xE3, 100); - -// Name: System.Calendar.OrganizerName -- PKEY_Calendar_OrganizerName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: AAA660F9-9865-458E-B484-01BC7FE3973E, 100 -// -// Name of the organizer organizing the event. -DEFINE_PROPERTYKEY(PKEY_Calendar_OrganizerName, 0xAAA660F9, 0x9865, 0x458E, 0xB4, 0x84, 0x01, 0xBC, 0x7F, 0xE3, 0x97, 0x3E, 100); - -// Name: System.Calendar.ReminderTime -- PKEY_Calendar_ReminderTime -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 72FC5BA4-24F9-4011-9F3F-ADD27AFAD818, 100 -DEFINE_PROPERTYKEY(PKEY_Calendar_ReminderTime, 0x72FC5BA4, 0x24F9, 0x4011, 0x9F, 0x3F, 0xAD, 0xD2, 0x7A, 0xFA, 0xD8, 0x18, 100); - -// Name: System.Calendar.RequiredAttendeeAddresses -- PKEY_Calendar_RequiredAttendeeAddresses -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: 0BA7D6C3-568D-4159-AB91-781A91FB71E5, 100 -DEFINE_PROPERTYKEY(PKEY_Calendar_RequiredAttendeeAddresses, 0x0BA7D6C3, 0x568D, 0x4159, 0xAB, 0x91, 0x78, 0x1A, 0x91, 0xFB, 0x71, 0xE5, 100); - -// Name: System.Calendar.RequiredAttendeeNames -- PKEY_Calendar_RequiredAttendeeNames -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: B33AF30B-F552-4584-936C-CB93E5CDA29F, 100 -DEFINE_PROPERTYKEY(PKEY_Calendar_RequiredAttendeeNames, 0xB33AF30B, 0xF552, 0x4584, 0x93, 0x6C, 0xCB, 0x93, 0xE5, 0xCD, 0xA2, 0x9F, 100); - -// Name: System.Calendar.Resources -- PKEY_Calendar_Resources -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: 00F58A38-C54B-4C40-8696-97235980EAE1, 100 -DEFINE_PROPERTYKEY(PKEY_Calendar_Resources, 0x00F58A38, 0xC54B, 0x4C40, 0x86, 0x96, 0x97, 0x23, 0x59, 0x80, 0xEA, 0xE1, 100); - -// Name: System.Calendar.ShowTimeAs -- PKEY_Calendar_ShowTimeAs -// Type: UInt16 -- VT_UI2 -// FormatID: 5BF396D4-5EB2-466F-BDE9-2FB3F2361D6E, 100 -// -// -DEFINE_PROPERTYKEY(PKEY_Calendar_ShowTimeAs, 0x5BF396D4, 0x5EB2, 0x466F, 0xBD, 0xE9, 0x2F, 0xB3, 0xF2, 0x36, 0x1D, 0x6E, 100); - -// Possible discrete values for PKEY_Calendar_ShowTimeAs are: -#define CALENDAR_SHOWTIMEAS_FREE 0u -#define CALENDAR_SHOWTIMEAS_TENTATIVE 1u -#define CALENDAR_SHOWTIMEAS_BUSY 2u -#define CALENDAR_SHOWTIMEAS_OOF 3u - -// Name: System.Calendar.ShowTimeAsText -- PKEY_Calendar_ShowTimeAsText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 53DA57CF-62C0-45C4-81DE-7610BCEFD7F5, 100 -// -// This is the user-friendly form of System.Calendar.ShowTimeAs. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Calendar_ShowTimeAsText, 0x53DA57CF, 0x62C0, 0x45C4, 0x81, 0xDE, 0x76, 0x10, 0xBC, 0xEF, 0xD7, 0xF5, 100); - -//----------------------------------------------------------------------------- -// Communication properties - - - -// Name: System.Communication.AccountName -- PKEY_Communication_AccountName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 9 -// -// Account Name -DEFINE_PROPERTYKEY(PKEY_Communication_AccountName, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 9); - -// Name: System.Communication.Suffix -- PKEY_Communication_Suffix -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 807B653A-9E91-43EF-8F97-11CE04EE20C5, 100 -DEFINE_PROPERTYKEY(PKEY_Communication_Suffix, 0x807B653A, 0x9E91, 0x43EF, 0x8F, 0x97, 0x11, 0xCE, 0x04, 0xEE, 0x20, 0xC5, 100); - -// Name: System.Communication.TaskStatus -- PKEY_Communication_TaskStatus -// Type: UInt16 -- VT_UI2 -// FormatID: BE1A72C6-9A1D-46B7-AFE7-AFAF8CEF4999, 100 -DEFINE_PROPERTYKEY(PKEY_Communication_TaskStatus, 0xBE1A72C6, 0x9A1D, 0x46B7, 0xAF, 0xE7, 0xAF, 0xAF, 0x8C, 0xEF, 0x49, 0x99, 100); - -// Possible discrete values for PKEY_Communication_TaskStatus are: -#define TASKSTATUS_NOTSTARTED 0u -#define TASKSTATUS_INPROGRESS 1u -#define TASKSTATUS_COMPLETE 2u -#define TASKSTATUS_WAITING 3u -#define TASKSTATUS_DEFERRED 4u - -// Name: System.Communication.TaskStatusText -- PKEY_Communication_TaskStatusText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: A6744477-C237-475B-A075-54F34498292A, 100 -// -// This is the user-friendly form of System.Communication.TaskStatus. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Communication_TaskStatusText, 0xA6744477, 0xC237, 0x475B, 0xA0, 0x75, 0x54, 0xF3, 0x44, 0x98, 0x29, 0x2A, 100); - -//----------------------------------------------------------------------------- -// Computer properties - - - -// Name: System.Computer.DecoratedFreeSpace -- PKEY_Computer_DecoratedFreeSpace -// Type: Multivalue UInt64 -- VT_VECTOR | VT_UI8 (For variants: VT_ARRAY | VT_UI8) -// FormatID: (FMTID_Volume) 9B174B35-40FF-11D2-A27E-00C04FC30871, 7 (Filesystem Volume Properties) -// -// Free space and total space: "%s free of %s" -DEFINE_PROPERTYKEY(PKEY_Computer_DecoratedFreeSpace, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71, 7); - -//----------------------------------------------------------------------------- -// Contact properties - - - -// Name: System.Contact.Anniversary -- PKEY_Contact_Anniversary -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 9AD5BADB-CEA7-4470-A03D-B84E51B9949E, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_Anniversary, 0x9AD5BADB, 0xCEA7, 0x4470, 0xA0, 0x3D, 0xB8, 0x4E, 0x51, 0xB9, 0x94, 0x9E, 100); - -// Name: System.Contact.AssistantName -- PKEY_Contact_AssistantName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: CD102C9C-5540-4A88-A6F6-64E4981C8CD1, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_AssistantName, 0xCD102C9C, 0x5540, 0x4A88, 0xA6, 0xF6, 0x64, 0xE4, 0x98, 0x1C, 0x8C, 0xD1, 100); - -// Name: System.Contact.AssistantTelephone -- PKEY_Contact_AssistantTelephone -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 9A93244D-A7AD-4FF8-9B99-45EE4CC09AF6, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_AssistantTelephone, 0x9A93244D, 0xA7AD, 0x4FF8, 0x9B, 0x99, 0x45, 0xEE, 0x4C, 0xC0, 0x9A, 0xF6, 100); - -// Name: System.Contact.Birthday -- PKEY_Contact_Birthday -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 47 -DEFINE_PROPERTYKEY(PKEY_Contact_Birthday, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 47); - -// Name: System.Contact.BusinessAddress -- PKEY_Contact_BusinessAddress -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 730FB6DD-CF7C-426B-A03F-BD166CC9EE24, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_BusinessAddress, 0x730FB6DD, 0xCF7C, 0x426B, 0xA0, 0x3F, 0xBD, 0x16, 0x6C, 0xC9, 0xEE, 0x24, 100); - -// Name: System.Contact.BusinessAddressCity -- PKEY_Contact_BusinessAddressCity -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 402B5934-EC5A-48C3-93E6-85E86A2D934E, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_BusinessAddressCity, 0x402B5934, 0xEC5A, 0x48C3, 0x93, 0xE6, 0x85, 0xE8, 0x6A, 0x2D, 0x93, 0x4E, 100); - -// Name: System.Contact.BusinessAddressCountry -- PKEY_Contact_BusinessAddressCountry -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: B0B87314-FCF6-4FEB-8DFF-A50DA6AF561C, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_BusinessAddressCountry, 0xB0B87314, 0xFCF6, 0x4FEB, 0x8D, 0xFF, 0xA5, 0x0D, 0xA6, 0xAF, 0x56, 0x1C, 100); - -// Name: System.Contact.BusinessAddressPostalCode -- PKEY_Contact_BusinessAddressPostalCode -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: E1D4A09E-D758-4CD1-B6EC-34A8B5A73F80, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_BusinessAddressPostalCode, 0xE1D4A09E, 0xD758, 0x4CD1, 0xB6, 0xEC, 0x34, 0xA8, 0xB5, 0xA7, 0x3F, 0x80, 100); - -// Name: System.Contact.BusinessAddressPostOfficeBox -- PKEY_Contact_BusinessAddressPostOfficeBox -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: BC4E71CE-17F9-48D5-BEE9-021DF0EA5409, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_BusinessAddressPostOfficeBox, 0xBC4E71CE, 0x17F9, 0x48D5, 0xBE, 0xE9, 0x02, 0x1D, 0xF0, 0xEA, 0x54, 0x09, 100); - -// Name: System.Contact.BusinessAddressState -- PKEY_Contact_BusinessAddressState -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 446F787F-10C4-41CB-A6C4-4D0343551597, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_BusinessAddressState, 0x446F787F, 0x10C4, 0x41CB, 0xA6, 0xC4, 0x4D, 0x03, 0x43, 0x55, 0x15, 0x97, 100); - -// Name: System.Contact.BusinessAddressStreet -- PKEY_Contact_BusinessAddressStreet -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: DDD1460F-C0BF-4553-8CE4-10433C908FB0, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_BusinessAddressStreet, 0xDDD1460F, 0xC0BF, 0x4553, 0x8C, 0xE4, 0x10, 0x43, 0x3C, 0x90, 0x8F, 0xB0, 100); - -// Name: System.Contact.BusinessFaxNumber -- PKEY_Contact_BusinessFaxNumber -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 91EFF6F3-2E27-42CA-933E-7C999FBE310B, 100 -// -// Business fax number of the contact. -DEFINE_PROPERTYKEY(PKEY_Contact_BusinessFaxNumber, 0x91EFF6F3, 0x2E27, 0x42CA, 0x93, 0x3E, 0x7C, 0x99, 0x9F, 0xBE, 0x31, 0x0B, 100); - -// Name: System.Contact.BusinessHomePage -- PKEY_Contact_BusinessHomePage -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 56310920-2491-4919-99CE-EADB06FAFDB2, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_BusinessHomePage, 0x56310920, 0x2491, 0x4919, 0x99, 0xCE, 0xEA, 0xDB, 0x06, 0xFA, 0xFD, 0xB2, 100); - -// Name: System.Contact.BusinessTelephone -- PKEY_Contact_BusinessTelephone -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 6A15E5A0-0A1E-4CD7-BB8C-D2F1B0C929BC, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_BusinessTelephone, 0x6A15E5A0, 0x0A1E, 0x4CD7, 0xBB, 0x8C, 0xD2, 0xF1, 0xB0, 0xC9, 0x29, 0xBC, 100); - -// Name: System.Contact.CallbackTelephone -- PKEY_Contact_CallbackTelephone -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: BF53D1C3-49E0-4F7F-8567-5A821D8AC542, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_CallbackTelephone, 0xBF53D1C3, 0x49E0, 0x4F7F, 0x85, 0x67, 0x5A, 0x82, 0x1D, 0x8A, 0xC5, 0x42, 100); - -// Name: System.Contact.CarTelephone -- PKEY_Contact_CarTelephone -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 8FDC6DEA-B929-412B-BA90-397A257465FE, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_CarTelephone, 0x8FDC6DEA, 0xB929, 0x412B, 0xBA, 0x90, 0x39, 0x7A, 0x25, 0x74, 0x65, 0xFE, 100); - -// Name: System.Contact.Children -- PKEY_Contact_Children -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: D4729704-8EF1-43EF-9024-2BD381187FD5, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_Children, 0xD4729704, 0x8EF1, 0x43EF, 0x90, 0x24, 0x2B, 0xD3, 0x81, 0x18, 0x7F, 0xD5, 100); - -// Name: System.Contact.CompanyMainTelephone -- PKEY_Contact_CompanyMainTelephone -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 8589E481-6040-473D-B171-7FA89C2708ED, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_CompanyMainTelephone, 0x8589E481, 0x6040, 0x473D, 0xB1, 0x71, 0x7F, 0xA8, 0x9C, 0x27, 0x08, 0xED, 100); - -// Name: System.Contact.Department -- PKEY_Contact_Department -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: FC9F7306-FF8F-4D49-9FB6-3FFE5C0951EC, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_Department, 0xFC9F7306, 0xFF8F, 0x4D49, 0x9F, 0xB6, 0x3F, 0xFE, 0x5C, 0x09, 0x51, 0xEC, 100); - -// Name: System.Contact.EmailAddress -- PKEY_Contact_EmailAddress -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: F8FA7FA3-D12B-4785-8A4E-691A94F7A3E7, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_EmailAddress, 0xF8FA7FA3, 0xD12B, 0x4785, 0x8A, 0x4E, 0x69, 0x1A, 0x94, 0xF7, 0xA3, 0xE7, 100); - -// Name: System.Contact.EmailAddress2 -- PKEY_Contact_EmailAddress2 -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 38965063-EDC8-4268-8491-B7723172CF29, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_EmailAddress2, 0x38965063, 0xEDC8, 0x4268, 0x84, 0x91, 0xB7, 0x72, 0x31, 0x72, 0xCF, 0x29, 100); - -// Name: System.Contact.EmailAddress3 -- PKEY_Contact_EmailAddress3 -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 644D37B4-E1B3-4BAD-B099-7E7C04966ACA, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_EmailAddress3, 0x644D37B4, 0xE1B3, 0x4BAD, 0xB0, 0x99, 0x7E, 0x7C, 0x04, 0x96, 0x6A, 0xCA, 100); - -// Name: System.Contact.EmailAddresses -- PKEY_Contact_EmailAddresses -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: 84D8F337-981D-44B3-9615-C7596DBA17E3, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_EmailAddresses, 0x84D8F337, 0x981D, 0x44B3, 0x96, 0x15, 0xC7, 0x59, 0x6D, 0xBA, 0x17, 0xE3, 100); - -// Name: System.Contact.EmailName -- PKEY_Contact_EmailName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: CC6F4F24-6083-4BD4-8754-674D0DE87AB8, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_EmailName, 0xCC6F4F24, 0x6083, 0x4BD4, 0x87, 0x54, 0x67, 0x4D, 0x0D, 0xE8, 0x7A, 0xB8, 100); - -// Name: System.Contact.FileAsName -- PKEY_Contact_FileAsName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: F1A24AA7-9CA7-40F6-89EC-97DEF9FFE8DB, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_FileAsName, 0xF1A24AA7, 0x9CA7, 0x40F6, 0x89, 0xEC, 0x97, 0xDE, 0xF9, 0xFF, 0xE8, 0xDB, 100); - -// Name: System.Contact.FirstName -- PKEY_Contact_FirstName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 14977844-6B49-4AAD-A714-A4513BF60460, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_FirstName, 0x14977844, 0x6B49, 0x4AAD, 0xA7, 0x14, 0xA4, 0x51, 0x3B, 0xF6, 0x04, 0x60, 100); - -// Name: System.Contact.FullName -- PKEY_Contact_FullName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 635E9051-50A5-4BA2-B9DB-4ED056C77296, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_FullName, 0x635E9051, 0x50A5, 0x4BA2, 0xB9, 0xDB, 0x4E, 0xD0, 0x56, 0xC7, 0x72, 0x96, 100); - -// Name: System.Contact.Gender -- PKEY_Contact_Gender -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 3C8CEE58-D4F0-4CF9-B756-4E5D24447BCD, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_Gender, 0x3C8CEE58, 0xD4F0, 0x4CF9, 0xB7, 0x56, 0x4E, 0x5D, 0x24, 0x44, 0x7B, 0xCD, 100); - -// Name: System.Contact.Hobbies -- PKEY_Contact_Hobbies -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: 5DC2253F-5E11-4ADF-9CFE-910DD01E3E70, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_Hobbies, 0x5DC2253F, 0x5E11, 0x4ADF, 0x9C, 0xFE, 0x91, 0x0D, 0xD0, 0x1E, 0x3E, 0x70, 100); - -// Name: System.Contact.HomeAddress -- PKEY_Contact_HomeAddress -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 98F98354-617A-46B8-8560-5B1B64BF1F89, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_HomeAddress, 0x98F98354, 0x617A, 0x46B8, 0x85, 0x60, 0x5B, 0x1B, 0x64, 0xBF, 0x1F, 0x89, 100); - -// Name: System.Contact.HomeAddressCity -- PKEY_Contact_HomeAddressCity -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 65 -DEFINE_PROPERTYKEY(PKEY_Contact_HomeAddressCity, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 65); - -// Name: System.Contact.HomeAddressCountry -- PKEY_Contact_HomeAddressCountry -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 08A65AA1-F4C9-43DD-9DDF-A33D8E7EAD85, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_HomeAddressCountry, 0x08A65AA1, 0xF4C9, 0x43DD, 0x9D, 0xDF, 0xA3, 0x3D, 0x8E, 0x7E, 0xAD, 0x85, 100); - -// Name: System.Contact.HomeAddressPostalCode -- PKEY_Contact_HomeAddressPostalCode -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 8AFCC170-8A46-4B53-9EEE-90BAE7151E62, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_HomeAddressPostalCode, 0x8AFCC170, 0x8A46, 0x4B53, 0x9E, 0xEE, 0x90, 0xBA, 0xE7, 0x15, 0x1E, 0x62, 100); - -// Name: System.Contact.HomeAddressPostOfficeBox -- PKEY_Contact_HomeAddressPostOfficeBox -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 7B9F6399-0A3F-4B12-89BD-4ADC51C918AF, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_HomeAddressPostOfficeBox, 0x7B9F6399, 0x0A3F, 0x4B12, 0x89, 0xBD, 0x4A, 0xDC, 0x51, 0xC9, 0x18, 0xAF, 100); - -// Name: System.Contact.HomeAddressState -- PKEY_Contact_HomeAddressState -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C89A23D0-7D6D-4EB8-87D4-776A82D493E5, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_HomeAddressState, 0xC89A23D0, 0x7D6D, 0x4EB8, 0x87, 0xD4, 0x77, 0x6A, 0x82, 0xD4, 0x93, 0xE5, 100); - -// Name: System.Contact.HomeAddressStreet -- PKEY_Contact_HomeAddressStreet -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 0ADEF160-DB3F-4308-9A21-06237B16FA2A, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_HomeAddressStreet, 0x0ADEF160, 0xDB3F, 0x4308, 0x9A, 0x21, 0x06, 0x23, 0x7B, 0x16, 0xFA, 0x2A, 100); - -// Name: System.Contact.HomeFaxNumber -- PKEY_Contact_HomeFaxNumber -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 660E04D6-81AB-4977-A09F-82313113AB26, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_HomeFaxNumber, 0x660E04D6, 0x81AB, 0x4977, 0xA0, 0x9F, 0x82, 0x31, 0x31, 0x13, 0xAB, 0x26, 100); - -// Name: System.Contact.HomeTelephone -- PKEY_Contact_HomeTelephone -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 20 -DEFINE_PROPERTYKEY(PKEY_Contact_HomeTelephone, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 20); - -// Name: System.Contact.IMAddress -- PKEY_Contact_IMAddress -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: D68DBD8A-3374-4B81-9972-3EC30682DB3D, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_IMAddress, 0xD68DBD8A, 0x3374, 0x4B81, 0x99, 0x72, 0x3E, 0xC3, 0x06, 0x82, 0xDB, 0x3D, 100); - -// Name: System.Contact.Initials -- PKEY_Contact_Initials -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: F3D8F40D-50CB-44A2-9718-40CB9119495D, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_Initials, 0xF3D8F40D, 0x50CB, 0x44A2, 0x97, 0x18, 0x40, 0xCB, 0x91, 0x19, 0x49, 0x5D, 100); - -// Name: System.Contact.JA.CompanyNamePhonetic -- PKEY_Contact_JA_CompanyNamePhonetic -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 897B3694-FE9E-43E6-8066-260F590C0100, 2 -// -// -DEFINE_PROPERTYKEY(PKEY_Contact_JA_CompanyNamePhonetic, 0x897B3694, 0xFE9E, 0x43E6, 0x80, 0x66, 0x26, 0x0F, 0x59, 0x0C, 0x01, 0x00, 2); - -// Name: System.Contact.JA.FirstNamePhonetic -- PKEY_Contact_JA_FirstNamePhonetic -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 897B3694-FE9E-43E6-8066-260F590C0100, 3 -// -// -DEFINE_PROPERTYKEY(PKEY_Contact_JA_FirstNamePhonetic, 0x897B3694, 0xFE9E, 0x43E6, 0x80, 0x66, 0x26, 0x0F, 0x59, 0x0C, 0x01, 0x00, 3); - -// Name: System.Contact.JA.LastNamePhonetic -- PKEY_Contact_JA_LastNamePhonetic -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 897B3694-FE9E-43E6-8066-260F590C0100, 4 -// -// -DEFINE_PROPERTYKEY(PKEY_Contact_JA_LastNamePhonetic, 0x897B3694, 0xFE9E, 0x43E6, 0x80, 0x66, 0x26, 0x0F, 0x59, 0x0C, 0x01, 0x00, 4); - -// Name: System.Contact.JobTitle -- PKEY_Contact_JobTitle -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 6 -DEFINE_PROPERTYKEY(PKEY_Contact_JobTitle, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 6); - -// Name: System.Contact.Label -- PKEY_Contact_Label -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 97B0AD89-DF49-49CC-834E-660974FD755B, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_Label, 0x97B0AD89, 0xDF49, 0x49CC, 0x83, 0x4E, 0x66, 0x09, 0x74, 0xFD, 0x75, 0x5B, 100); - -// Name: System.Contact.LastName -- PKEY_Contact_LastName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 8F367200-C270-457C-B1D4-E07C5BCD90C7, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_LastName, 0x8F367200, 0xC270, 0x457C, 0xB1, 0xD4, 0xE0, 0x7C, 0x5B, 0xCD, 0x90, 0xC7, 100); - -// Name: System.Contact.MailingAddress -- PKEY_Contact_MailingAddress -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C0AC206A-827E-4650-95AE-77E2BB74FCC9, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_MailingAddress, 0xC0AC206A, 0x827E, 0x4650, 0x95, 0xAE, 0x77, 0xE2, 0xBB, 0x74, 0xFC, 0xC9, 100); - -// Name: System.Contact.MiddleName -- PKEY_Contact_MiddleName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 71 -DEFINE_PROPERTYKEY(PKEY_Contact_MiddleName, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 71); - -// Name: System.Contact.MobileTelephone -- PKEY_Contact_MobileTelephone -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 35 -DEFINE_PROPERTYKEY(PKEY_Contact_MobileTelephone, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 35); - -// Name: System.Contact.NickName -- PKEY_Contact_NickName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 74 -DEFINE_PROPERTYKEY(PKEY_Contact_NickName, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 74); - -// Name: System.Contact.OfficeLocation -- PKEY_Contact_OfficeLocation -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 7 -DEFINE_PROPERTYKEY(PKEY_Contact_OfficeLocation, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 7); - -// Name: System.Contact.OtherAddress -- PKEY_Contact_OtherAddress -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 508161FA-313B-43D5-83A1-C1ACCF68622C, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_OtherAddress, 0x508161FA, 0x313B, 0x43D5, 0x83, 0xA1, 0xC1, 0xAC, 0xCF, 0x68, 0x62, 0x2C, 100); - -// Name: System.Contact.OtherAddressCity -- PKEY_Contact_OtherAddressCity -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 6E682923-7F7B-4F0C-A337-CFCA296687BF, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_OtherAddressCity, 0x6E682923, 0x7F7B, 0x4F0C, 0xA3, 0x37, 0xCF, 0xCA, 0x29, 0x66, 0x87, 0xBF, 100); - -// Name: System.Contact.OtherAddressCountry -- PKEY_Contact_OtherAddressCountry -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 8F167568-0AAE-4322-8ED9-6055B7B0E398, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_OtherAddressCountry, 0x8F167568, 0x0AAE, 0x4322, 0x8E, 0xD9, 0x60, 0x55, 0xB7, 0xB0, 0xE3, 0x98, 100); - -// Name: System.Contact.OtherAddressPostalCode -- PKEY_Contact_OtherAddressPostalCode -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 95C656C1-2ABF-4148-9ED3-9EC602E3B7CD, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_OtherAddressPostalCode, 0x95C656C1, 0x2ABF, 0x4148, 0x9E, 0xD3, 0x9E, 0xC6, 0x02, 0xE3, 0xB7, 0xCD, 100); - -// Name: System.Contact.OtherAddressPostOfficeBox -- PKEY_Contact_OtherAddressPostOfficeBox -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 8B26EA41-058F-43F6-AECC-4035681CE977, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_OtherAddressPostOfficeBox, 0x8B26EA41, 0x058F, 0x43F6, 0xAE, 0xCC, 0x40, 0x35, 0x68, 0x1C, 0xE9, 0x77, 100); - -// Name: System.Contact.OtherAddressState -- PKEY_Contact_OtherAddressState -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 71B377D6-E570-425F-A170-809FAE73E54E, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_OtherAddressState, 0x71B377D6, 0xE570, 0x425F, 0xA1, 0x70, 0x80, 0x9F, 0xAE, 0x73, 0xE5, 0x4E, 100); - -// Name: System.Contact.OtherAddressStreet -- PKEY_Contact_OtherAddressStreet -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: FF962609-B7D6-4999-862D-95180D529AEA, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_OtherAddressStreet, 0xFF962609, 0xB7D6, 0x4999, 0x86, 0x2D, 0x95, 0x18, 0x0D, 0x52, 0x9A, 0xEA, 100); - -// Name: System.Contact.PagerTelephone -- PKEY_Contact_PagerTelephone -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: D6304E01-F8F5-4F45-8B15-D024A6296789, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_PagerTelephone, 0xD6304E01, 0xF8F5, 0x4F45, 0x8B, 0x15, 0xD0, 0x24, 0xA6, 0x29, 0x67, 0x89, 100); - -// Name: System.Contact.PersonalTitle -- PKEY_Contact_PersonalTitle -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 69 -DEFINE_PROPERTYKEY(PKEY_Contact_PersonalTitle, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 69); - -// Name: System.Contact.PrimaryAddressCity -- PKEY_Contact_PrimaryAddressCity -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C8EA94F0-A9E3-4969-A94B-9C62A95324E0, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_PrimaryAddressCity, 0xC8EA94F0, 0xA9E3, 0x4969, 0xA9, 0x4B, 0x9C, 0x62, 0xA9, 0x53, 0x24, 0xE0, 100); - -// Name: System.Contact.PrimaryAddressCountry -- PKEY_Contact_PrimaryAddressCountry -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: E53D799D-0F3F-466E-B2FF-74634A3CB7A4, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_PrimaryAddressCountry, 0xE53D799D, 0x0F3F, 0x466E, 0xB2, 0xFF, 0x74, 0x63, 0x4A, 0x3C, 0xB7, 0xA4, 100); - -// Name: System.Contact.PrimaryAddressPostalCode -- PKEY_Contact_PrimaryAddressPostalCode -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 18BBD425-ECFD-46EF-B612-7B4A6034EDA0, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_PrimaryAddressPostalCode, 0x18BBD425, 0xECFD, 0x46EF, 0xB6, 0x12, 0x7B, 0x4A, 0x60, 0x34, 0xED, 0xA0, 100); - -// Name: System.Contact.PrimaryAddressPostOfficeBox -- PKEY_Contact_PrimaryAddressPostOfficeBox -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: DE5EF3C7-46E1-484E-9999-62C5308394C1, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_PrimaryAddressPostOfficeBox, 0xDE5EF3C7, 0x46E1, 0x484E, 0x99, 0x99, 0x62, 0xC5, 0x30, 0x83, 0x94, 0xC1, 100); - -// Name: System.Contact.PrimaryAddressState -- PKEY_Contact_PrimaryAddressState -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: F1176DFE-7138-4640-8B4C-AE375DC70A6D, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_PrimaryAddressState, 0xF1176DFE, 0x7138, 0x4640, 0x8B, 0x4C, 0xAE, 0x37, 0x5D, 0xC7, 0x0A, 0x6D, 100); - -// Name: System.Contact.PrimaryAddressStreet -- PKEY_Contact_PrimaryAddressStreet -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 63C25B20-96BE-488F-8788-C09C407AD812, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_PrimaryAddressStreet, 0x63C25B20, 0x96BE, 0x488F, 0x87, 0x88, 0xC0, 0x9C, 0x40, 0x7A, 0xD8, 0x12, 100); - -// Name: System.Contact.PrimaryEmailAddress -- PKEY_Contact_PrimaryEmailAddress -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 48 -DEFINE_PROPERTYKEY(PKEY_Contact_PrimaryEmailAddress, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 48); - -// Name: System.Contact.PrimaryTelephone -- PKEY_Contact_PrimaryTelephone -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 25 -DEFINE_PROPERTYKEY(PKEY_Contact_PrimaryTelephone, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 25); - -// Name: System.Contact.Profession -- PKEY_Contact_Profession -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 7268AF55-1CE4-4F6E-A41F-B6E4EF10E4A9, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_Profession, 0x7268AF55, 0x1CE4, 0x4F6E, 0xA4, 0x1F, 0xB6, 0xE4, 0xEF, 0x10, 0xE4, 0xA9, 100); - -// Name: System.Contact.SpouseName -- PKEY_Contact_SpouseName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 9D2408B6-3167-422B-82B0-F583B7A7CFE3, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_SpouseName, 0x9D2408B6, 0x3167, 0x422B, 0x82, 0xB0, 0xF5, 0x83, 0xB7, 0xA7, 0xCF, 0xE3, 100); - -// Name: System.Contact.Suffix -- PKEY_Contact_Suffix -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 176DC63C-2688-4E89-8143-A347800F25E9, 73 -DEFINE_PROPERTYKEY(PKEY_Contact_Suffix, 0x176DC63C, 0x2688, 0x4E89, 0x81, 0x43, 0xA3, 0x47, 0x80, 0x0F, 0x25, 0xE9, 73); - -// Name: System.Contact.TelexNumber -- PKEY_Contact_TelexNumber -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C554493C-C1F7-40C1-A76C-EF8C0614003E, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_TelexNumber, 0xC554493C, 0xC1F7, 0x40C1, 0xA7, 0x6C, 0xEF, 0x8C, 0x06, 0x14, 0x00, 0x3E, 100); - -// Name: System.Contact.TTYTDDTelephone -- PKEY_Contact_TTYTDDTelephone -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: AAF16BAC-2B55-45E6-9F6D-415EB94910DF, 100 -DEFINE_PROPERTYKEY(PKEY_Contact_TTYTDDTelephone, 0xAAF16BAC, 0x2B55, 0x45E6, 0x9F, 0x6D, 0x41, 0x5E, 0xB9, 0x49, 0x10, 0xDF, 100); - -// Name: System.Contact.WebPage -- PKEY_Contact_WebPage -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 18 -DEFINE_PROPERTYKEY(PKEY_Contact_WebPage, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 18); - -//----------------------------------------------------------------------------- -// Core properties - - - -// Name: System.AcquisitionID -- PKEY_AcquisitionID -// Type: Int32 -- VT_I4 -// FormatID: 65A98875-3C80-40AB-ABBC-EFDAF77DBEE2, 100 -// -// Hash to determine acquisition session. -DEFINE_PROPERTYKEY(PKEY_AcquisitionID, 0x65A98875, 0x3C80, 0x40AB, 0xAB, 0xBC, 0xEF, 0xDA, 0xF7, 0x7D, 0xBE, 0xE2, 100); - -// Name: System.ApplicationName -- PKEY_ApplicationName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) Legacy code may treat this as VT_LPSTR. -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 18 (PIDSI_APPNAME) -// -// -DEFINE_PROPERTYKEY(PKEY_ApplicationName, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 18); - -// Name: System.Author -- PKEY_Author -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) Legacy code may treat this as VT_LPSTR. -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 4 (PIDSI_AUTHOR) -// -// -DEFINE_PROPERTYKEY(PKEY_Author, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 4); - -// Name: System.Capacity -- PKEY_Capacity -// Type: UInt64 -- VT_UI8 -// FormatID: (FMTID_Volume) 9B174B35-40FF-11D2-A27E-00C04FC30871, 3 (PID_VOLUME_CAPACITY) (Filesystem Volume Properties) -// -// The amount of total space in bytes. -DEFINE_PROPERTYKEY(PKEY_Capacity, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71, 3); - -// Name: System.Category -- PKEY_Category -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 2 (PIDDSI_CATEGORY) -// -// Legacy code treats this as VT_LPSTR. -DEFINE_PROPERTYKEY(PKEY_Category, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 2); - -// Name: System.Comment -- PKEY_Comment -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) Legacy code may treat this as VT_LPSTR. -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 6 (PIDSI_COMMENTS) -// -// Comments. -DEFINE_PROPERTYKEY(PKEY_Comment, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 6); - -// Name: System.Company -- PKEY_Company -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 15 (PIDDSI_COMPANY) -// -// The company or publisher. -DEFINE_PROPERTYKEY(PKEY_Company, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 15); - -// Name: System.ComputerName -- PKEY_ComputerName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 5 (PID_COMPUTERNAME) -// -// -DEFINE_PROPERTYKEY(PKEY_ComputerName, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 5); - -// Name: System.ContainedItems -- PKEY_ContainedItems -// Type: Multivalue Guid -- VT_VECTOR | VT_CLSID (For variants: VT_ARRAY | VT_CLSID) -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 29 -// -// The list of type of items, this item contains. For example, this item contains urls, attachments etc. -// This is represented as a vector array of GUIDs where each GUID represents certain type. -DEFINE_PROPERTYKEY(PKEY_ContainedItems, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 29); - -// Name: System.ContentStatus -- PKEY_ContentStatus -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 27 -DEFINE_PROPERTYKEY(PKEY_ContentStatus, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 27); - -// Name: System.ContentType -- PKEY_ContentType -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 26 -DEFINE_PROPERTYKEY(PKEY_ContentType, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 26); - -// Name: System.Copyright -- PKEY_Copyright -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 11 (PIDMSI_COPYRIGHT) -// -// -DEFINE_PROPERTYKEY(PKEY_Copyright, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 11); - -// Name: System.DateAccessed -- PKEY_DateAccessed -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: (FMTID_Storage) B725F130-47EF-101A-A5F1-02608C9EEBAC, 16 (PID_STG_ACCESSTIME) -// -// The time of the last access to the item. The Indexing Service friendly name is 'access'. -DEFINE_PROPERTYKEY(PKEY_DateAccessed, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC, 16); - -// Name: System.DateAcquired -- PKEY_DateAcquired -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 2CBAA8F5-D81F-47CA-B17A-F8D822300131, 100 -// -// The time the file entered the system via acquisition. This is not the same as System.DateImported. -// Examples are when pictures are acquired from a camera, or when music is purchased online. -DEFINE_PROPERTYKEY(PKEY_DateAcquired, 0x2CBAA8F5, 0xD81F, 0x47CA, 0xB1, 0x7A, 0xF8, 0xD8, 0x22, 0x30, 0x01, 0x31, 100); - -// Name: System.DateArchived -- PKEY_DateArchived -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 43F8D7B7-A444-4F87-9383-52271C9B915C, 100 -DEFINE_PROPERTYKEY(PKEY_DateArchived, 0x43F8D7B7, 0xA444, 0x4F87, 0x93, 0x83, 0x52, 0x27, 0x1C, 0x9B, 0x91, 0x5C, 100); - -// Name: System.DateCompleted -- PKEY_DateCompleted -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 72FAB781-ACDA-43E5-B155-B2434F85E678, 100 -DEFINE_PROPERTYKEY(PKEY_DateCompleted, 0x72FAB781, 0xACDA, 0x43E5, 0xB1, 0x55, 0xB2, 0x43, 0x4F, 0x85, 0xE6, 0x78, 100); - -// Name: System.DateCreated -- PKEY_DateCreated -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: (FMTID_Storage) B725F130-47EF-101A-A5F1-02608C9EEBAC, 15 (PID_STG_CREATETIME) -// -// The date and time the item was created. The Indexing Service friendly name is 'create'. -DEFINE_PROPERTYKEY(PKEY_DateCreated, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC, 15); - -// Name: System.DateImported -- PKEY_DateImported -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 18258 -// -// The time the file is imported into a separate database. This is not the same as System.DateAcquired. (Eg, 2003:05:22 13:55:04) -DEFINE_PROPERTYKEY(PKEY_DateImported, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 18258); - -// Name: System.DateModified -- PKEY_DateModified -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: (FMTID_Storage) B725F130-47EF-101A-A5F1-02608C9EEBAC, 14 (PID_STG_WRITETIME) -// -// The date and time of the last write to the item. The Indexing Service friendly name is 'write'. -DEFINE_PROPERTYKEY(PKEY_DateModified, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC, 14); - -// Name: System.DueDate -- PKEY_DueDate -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 3F8472B5-E0AF-4DB2-8071-C53FE76AE7CE, 100 -DEFINE_PROPERTYKEY(PKEY_DueDate, 0x3F8472B5, 0xE0AF, 0x4DB2, 0x80, 0x71, 0xC5, 0x3F, 0xE7, 0x6A, 0xE7, 0xCE, 100); - -// Name: System.EndDate -- PKEY_EndDate -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: C75FAA05-96FD-49E7-9CB4-9F601082D553, 100 -DEFINE_PROPERTYKEY(PKEY_EndDate, 0xC75FAA05, 0x96FD, 0x49E7, 0x9C, 0xB4, 0x9F, 0x60, 0x10, 0x82, 0xD5, 0x53, 100); - -// Name: System.FileAllocationSize -- PKEY_FileAllocationSize -// Type: UInt64 -- VT_UI8 -// FormatID: (FMTID_Storage) B725F130-47EF-101A-A5F1-02608C9EEBAC, 18 (PID_STG_ALLOCSIZE) -// -// -DEFINE_PROPERTYKEY(PKEY_FileAllocationSize, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC, 18); - -// Name: System.FileAttributes -- PKEY_FileAttributes -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_Storage) B725F130-47EF-101A-A5F1-02608C9EEBAC, 13 (PID_STG_ATTRIBUTES) -// -// This is the WIN32_FIND_DATA dwFileAttributes for the file-based item. -DEFINE_PROPERTYKEY(PKEY_FileAttributes, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC, 13); - -// Name: System.FileCount -- PKEY_FileCount -// Type: UInt64 -- VT_UI8 -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 12 -// -// -DEFINE_PROPERTYKEY(PKEY_FileCount, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 12); - -// Name: System.FileDescription -- PKEY_FileDescription -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSFMTID_VERSION) 0CEF7D53-FA64-11D1-A203-0000F81FEDEE, 3 (PIDVSI_FileDescription) -// -// This is a user-friendly description of the file. -DEFINE_PROPERTYKEY(PKEY_FileDescription, 0x0CEF7D53, 0xFA64, 0x11D1, 0xA2, 0x03, 0x00, 0x00, 0xF8, 0x1F, 0xED, 0xEE, 3); - -// Name: System.FileExtension -- PKEY_FileExtension -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: E4F10A3C-49E6-405D-8288-A23BD4EEAA6C, 100 -// -// This is the file extension of the file based item, including the leading period. -// -// If System.FileName is VT_EMPTY, then this property should be too. Otherwise, it should be derived -// appropriately by the data source from System.FileName. If System.FileName does not have a file -// extension, this value should be VT_EMPTY. -// -// To obtain the type of any item (including an item that is not a file), use System.ItemType. -// -// Example values: -// -// If the path is... The property value is... -// ----------------- ------------------------ -// "c:\foo\bar\hello.txt" ".txt" -// "\\server\share\mydir\goodnews.doc" ".doc" -// "\\server\share\numbers.xls" ".xls" -// "\\server\share\folder" VT_EMPTY -// "c:\foo\MyFolder" VT_EMPTY -// [desktop] VT_EMPTY -DEFINE_PROPERTYKEY(PKEY_FileExtension, 0xE4F10A3C, 0x49E6, 0x405D, 0x82, 0x88, 0xA2, 0x3B, 0xD4, 0xEE, 0xAA, 0x6C, 100); - -// Name: System.FileFRN -- PKEY_FileFRN -// Type: UInt64 -- VT_UI8 -// FormatID: (FMTID_Storage) B725F130-47EF-101A-A5F1-02608C9EEBAC, 21 (PID_STG_FRN) -// -// This is the unique file ID, also known as the File Reference Number. For a given file, this is the same value -// as is found in the structure variable FILE_ID_BOTH_DIR_INFO.FileId, via GetFileInformationByHandleEx(). -DEFINE_PROPERTYKEY(PKEY_FileFRN, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC, 21); - -// Name: System.FileName -- PKEY_FileName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 41CF5AE0-F75A-4806-BD87-59C7D9248EB9, 100 -// -// This is the file name (including extension) of the file. -// -// It is possible that the item might not exist on a filesystem (ie, it may not be opened -// using CreateFile). Nonetheless, if the item is represented as a file from the logical sense -// (and its name follows standard Win32 file-naming syntax), then the data source should emit this property. -// -// If an item is not a file, then the value for this property is VT_EMPTY. See -// System.ItemNameDisplay. -// -// This has the same value as System.ParsingName for items that are provided by the Shell's file folder. -// -// Example values: -// -// If the path is... The property value is... -// ----------------- ------------------------ -// "c:\foo\bar\hello.txt" "hello.txt" -// "\\server\share\mydir\goodnews.doc" "goodnews.doc" -// "\\server\share\numbers.xls" "numbers.xls" -// "c:\foo\MyFolder" "MyFolder" -// (email message) VT_EMPTY -// (song on portable device) "song.wma" -DEFINE_PROPERTYKEY(PKEY_FileName, 0x41CF5AE0, 0xF75A, 0x4806, 0xBD, 0x87, 0x59, 0xC7, 0xD9, 0x24, 0x8E, 0xB9, 100); - -// Name: System.FileOwner -- PKEY_FileOwner -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_Misc) 9B174B34-40FF-11D2-A27E-00C04FC30871, 4 (PID_MISC_OWNER) -// -// This is the owner of the file, according to the file system. -DEFINE_PROPERTYKEY(PKEY_FileOwner, 0x9B174B34, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71, 4); - -// Name: System.FileVersion -- PKEY_FileVersion -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSFMTID_VERSION) 0CEF7D53-FA64-11D1-A203-0000F81FEDEE, 4 (PIDVSI_FileVersion) -// -// -DEFINE_PROPERTYKEY(PKEY_FileVersion, 0x0CEF7D53, 0xFA64, 0x11D1, 0xA2, 0x03, 0x00, 0x00, 0xF8, 0x1F, 0xED, 0xEE, 4); - -// Name: System.FindData -- PKEY_FindData -// Type: Buffer -- VT_VECTOR | VT_UI1 (For variants: VT_ARRAY | VT_UI1) -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 0 (PID_FINDDATA) -// -// WIN32_FIND_DATAW in buffer of bytes. -DEFINE_PROPERTYKEY(PKEY_FindData, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 0); - -// Name: System.FlagColor -- PKEY_FlagColor -// Type: UInt16 -- VT_UI2 -// FormatID: 67DF94DE-0CA7-4D6F-B792-053A3E4F03CF, 100 -// -// -DEFINE_PROPERTYKEY(PKEY_FlagColor, 0x67DF94DE, 0x0CA7, 0x4D6F, 0xB7, 0x92, 0x05, 0x3A, 0x3E, 0x4F, 0x03, 0xCF, 100); - -// Possible discrete values for PKEY_FlagColor are: -#define FLAGCOLOR_PURPLE 1u -#define FLAGCOLOR_ORANGE 2u -#define FLAGCOLOR_GREEN 3u -#define FLAGCOLOR_YELLOW 4u -#define FLAGCOLOR_BLUE 5u -#define FLAGCOLOR_RED 6u - -// Name: System.FlagColorText -- PKEY_FlagColorText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 45EAE747-8E2A-40AE-8CBF-CA52ABA6152A, 100 -// -// This is the user-friendly form of System.FlagColor. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_FlagColorText, 0x45EAE747, 0x8E2A, 0x40AE, 0x8C, 0xBF, 0xCA, 0x52, 0xAB, 0xA6, 0x15, 0x2A, 100); - -// Name: System.FlagStatus -- PKEY_FlagStatus -// Type: Int32 -- VT_I4 -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 12 -// -// Status of Flag. Values: (0=none 1=white 2=Red). cdoPR_FLAG_STATUS -DEFINE_PROPERTYKEY(PKEY_FlagStatus, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 12); - -// Possible discrete values for PKEY_FlagStatus are: -#define FLAGSTATUS_NOTFLAGGED 0l -#define FLAGSTATUS_COMPLETED 1l -#define FLAGSTATUS_FOLLOWUP 2l - -// Name: System.FlagStatusText -- PKEY_FlagStatusText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: DC54FD2E-189D-4871-AA01-08C2F57A4ABC, 100 -// -// This is the user-friendly form of System.FlagStatus. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_FlagStatusText, 0xDC54FD2E, 0x189D, 0x4871, 0xAA, 0x01, 0x08, 0xC2, 0xF5, 0x7A, 0x4A, 0xBC, 100); - -// Name: System.FreeSpace -- PKEY_FreeSpace -// Type: UInt64 -- VT_UI8 -// FormatID: (FMTID_Volume) 9B174B35-40FF-11D2-A27E-00C04FC30871, 2 (PID_VOLUME_FREE) (Filesystem Volume Properties) -// -// The amount of free space in bytes. -DEFINE_PROPERTYKEY(PKEY_FreeSpace, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71, 2); - -// Name: System.Identity -- PKEY_Identity -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: A26F4AFC-7346-4299-BE47-EB1AE613139F, 100 -DEFINE_PROPERTYKEY(PKEY_Identity, 0xA26F4AFC, 0x7346, 0x4299, 0xBE, 0x47, 0xEB, 0x1A, 0xE6, 0x13, 0x13, 0x9F, 100); - -// Name: System.Importance -- PKEY_Importance -// Type: Int32 -- VT_I4 -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 11 -DEFINE_PROPERTYKEY(PKEY_Importance, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 11); - -// Possible range of values for PKEY_Importance are: -#define IMPORTANCE_LOW_MIN 0l -#define IMPORTANCE_LOW_SET 1l -#define IMPORTANCE_LOW_MAX 1l - -#define IMPORTANCE_NORMAL_MIN 2l -#define IMPORTANCE_NORMAL_SET 3l -#define IMPORTANCE_NORMAL_MAX 4l - -#define IMPORTANCE_HIGH_MIN 5l -#define IMPORTANCE_HIGH_SET 5l -#define IMPORTANCE_HIGH_MAX 5l - - -// Name: System.ImportanceText -- PKEY_ImportanceText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: A3B29791-7713-4E1D-BB40-17DB85F01831, 100 -// -// This is the user-friendly form of System.Importance. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_ImportanceText, 0xA3B29791, 0x7713, 0x4E1D, 0xBB, 0x40, 0x17, 0xDB, 0x85, 0xF0, 0x18, 0x31, 100); - -// Name: System.IsAttachment -- PKEY_IsAttachment -// Type: Boolean -- VT_BOOL -// FormatID: F23F425C-71A1-4FA8-922F-678EA4A60408, 100 -// -// Identifies if this item is an attachment. -DEFINE_PROPERTYKEY(PKEY_IsAttachment, 0xF23F425C, 0x71A1, 0x4FA8, 0x92, 0x2F, 0x67, 0x8E, 0xA4, 0xA6, 0x04, 0x08, 100); - -// Name: System.IsDeleted -- PKEY_IsDeleted -// Type: Boolean -- VT_BOOL -// FormatID: 5CDA5FC8-33EE-4FF3-9094-AE7BD8868C4D, 100 -DEFINE_PROPERTYKEY(PKEY_IsDeleted, 0x5CDA5FC8, 0x33EE, 0x4FF3, 0x90, 0x94, 0xAE, 0x7B, 0xD8, 0x86, 0x8C, 0x4D, 100); - -// Name: System.IsFlagged -- PKEY_IsFlagged -// Type: Boolean -- VT_BOOL -// FormatID: 5DA84765-E3FF-4278-86B0-A27967FBDD03, 100 -DEFINE_PROPERTYKEY(PKEY_IsFlagged, 0x5DA84765, 0xE3FF, 0x4278, 0x86, 0xB0, 0xA2, 0x79, 0x67, 0xFB, 0xDD, 0x03, 100); - -// Name: System.IsFlaggedComplete -- PKEY_IsFlaggedComplete -// Type: Boolean -- VT_BOOL -// FormatID: A6F360D2-55F9-48DE-B909-620E090A647C, 100 -DEFINE_PROPERTYKEY(PKEY_IsFlaggedComplete, 0xA6F360D2, 0x55F9, 0x48DE, 0xB9, 0x09, 0x62, 0x0E, 0x09, 0x0A, 0x64, 0x7C, 100); - -// Name: System.IsIncomplete -- PKEY_IsIncomplete -// Type: Boolean -- VT_BOOL -// FormatID: 346C8BD1-2E6A-4C45-89A4-61B78E8E700F, 100 -// -// Identifies if the message was not completely received for some error condition. -DEFINE_PROPERTYKEY(PKEY_IsIncomplete, 0x346C8BD1, 0x2E6A, 0x4C45, 0x89, 0xA4, 0x61, 0xB7, 0x8E, 0x8E, 0x70, 0x0F, 100); - -// Name: System.IsRead -- PKEY_IsRead -// Type: Boolean -- VT_BOOL -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 10 -// -// Has the item been read? -DEFINE_PROPERTYKEY(PKEY_IsRead, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 10); - -// Name: System.IsSendToTarget -- PKEY_IsSendToTarget -// Type: Boolean -- VT_BOOL -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 33 -// -// Provided by certain shell folders. Return TRUE if the folder is a valid Send To target. -DEFINE_PROPERTYKEY(PKEY_IsSendToTarget, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 33); - -// Name: System.IsShared -- PKEY_IsShared -// Type: Boolean -- VT_BOOL -// FormatID: EF884C5B-2BFE-41BB-AAE5-76EEDF4F9902, 100 -// -// Is this item shared? -DEFINE_PROPERTYKEY(PKEY_IsShared, 0xEF884C5B, 0x2BFE, 0x41BB, 0xAA, 0xE5, 0x76, 0xEE, 0xDF, 0x4F, 0x99, 0x02, 100); - -// Name: System.ItemAuthors -- PKEY_ItemAuthors -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: D0A04F0A-462A-48A4-BB2F-3706E88DBD7D, 100 -// -// This is the generic list of authors associated with an item. -// -// For example, the artist name for a track is the item author. -DEFINE_PROPERTYKEY(PKEY_ItemAuthors, 0xD0A04F0A, 0x462A, 0x48A4, 0xBB, 0x2F, 0x37, 0x06, 0xE8, 0x8D, 0xBD, 0x7D, 100); - -// Name: System.ItemDate -- PKEY_ItemDate -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: F7DB74B4-4287-4103-AFBA-F1B13DCD75CF, 100 -// -// This is the main date for an item. The date of interest. -// -// For example, for photos this maps to System.Photo.DateTaken. -DEFINE_PROPERTYKEY(PKEY_ItemDate, 0xF7DB74B4, 0x4287, 0x4103, 0xAF, 0xBA, 0xF1, 0xB1, 0x3D, 0xCD, 0x75, 0xCF, 100); - -// Name: System.ItemFolderNameDisplay -- PKEY_ItemFolderNameDisplay -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_Storage) B725F130-47EF-101A-A5F1-02608C9EEBAC, 2 (PID_STG_DIRECTORY) -// -// This is the user-friendly display name of the parent folder of an item. -// -// If System.ItemFolderPathDisplay is VT_EMPTY, then this property should be too. Otherwise, it -// should be derived appropriately by the data source from System.ItemFolderPathDisplay. -// -// Example values: -// -// If the path is... The property value is... -// ----------------- ------------------------ -// "c:\foo\bar\hello.txt" "bar" -// "\\server\share\mydir\goodnews.doc" "mydir" -// "\\server\share\numbers.xls" "share" -// "c:\foo\MyFolder" "foo" -// "/Mailbox Account/Inbox/'Re: Hello!'" "Inbox" -DEFINE_PROPERTYKEY(PKEY_ItemFolderNameDisplay, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC, 2); - -// Name: System.ItemFolderPathDisplay -- PKEY_ItemFolderPathDisplay -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 6 -// -// This is the user-friendly display path of the parent folder of an item. -// -// If System.ItemPathDisplay is VT_EMPTY, then this property should be too. Otherwise, it should -// be derived appropriately by the data source from System.ItemPathDisplay. -// -// Example values: -// -// If the path is... The property value is... -// ----------------- ------------------------ -// "c:\foo\bar\hello.txt" "c:\foo\bar" -// "\\server\share\mydir\goodnews.doc" "\\server\share\mydir" -// "\\server\share\numbers.xls" "\\server\share" -// "c:\foo\MyFolder" "c:\foo" -// "/Mailbox Account/Inbox/'Re: Hello!'" "/Mailbox Account/Inbox" -DEFINE_PROPERTYKEY(PKEY_ItemFolderPathDisplay, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 6); - -// Name: System.ItemFolderPathDisplayNarrow -- PKEY_ItemFolderPathDisplayNarrow -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: DABD30ED-0043-4789-A7F8-D013A4736622, 100 -// -// This is the user-friendly display path of the parent folder of an item. The format of the string -// should be tailored such that the folder name comes first, to optimize for a narrow viewing column. -// -// If the folder is a file folder, the value includes localized names if they are present. -// -// If System.ItemFolderPathDisplay is VT_EMPTY, then this property should be too. Otherwise, it should -// be derived appropriately by the data source from System.ItemFolderPathDisplay. -// -// Example values: -// -// If the path is... The property value is... -// ----------------- ------------------------ -// "c:\foo\bar\hello.txt" "bar (c:\foo)" -// "\\server\share\mydir\goodnews.doc" "mydir (\\server\share)" -// "\\server\share\numbers.xls" "share (\\server)" -// "c:\foo\MyFolder" "foo (c:\)" -// "/Mailbox Account/Inbox/'Re: Hello!'" "Inbox (/Mailbox Account)" -DEFINE_PROPERTYKEY(PKEY_ItemFolderPathDisplayNarrow, 0xDABD30ED, 0x0043, 0x4789, 0xA7, 0xF8, 0xD0, 0x13, 0xA4, 0x73, 0x66, 0x22, 100); - -// Name: System.ItemName -- PKEY_ItemName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 6B8DA074-3B5C-43BC-886F-0A2CDCE00B6F, 100 -// -// This is the base-name of the System.ItemNameDisplay. -// -// If the item is a file this property -// includes the extension in all cases, and will be localized if a localized name is available. -// -// If the item is a message, then the value of this property does not include the forwarding or -// reply prefixes (see System.ItemNamePrefix). -DEFINE_PROPERTYKEY(PKEY_ItemName, 0x6B8DA074, 0x3B5C, 0x43BC, 0x88, 0x6F, 0x0A, 0x2C, 0xDC, 0xE0, 0x0B, 0x6F, 100); - -// Name: System.ItemNameDisplay -- PKEY_ItemNameDisplay -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_Storage) B725F130-47EF-101A-A5F1-02608C9EEBAC, 10 (PID_STG_NAME) -// -// This is the display name in "most complete" form. This is the best effort unique representation -// of the name of an item that makes sense for end users to read. It is the concatentation of -// System.ItemNamePrefix and System.ItemName. -// -// If the item is a file this property -// includes the extension in all cases, and will be localized if a localized name is available. -// -// There are acceptable cases when System.FileName is not VT_EMPTY, yet the value of this property -// is completely different. Email messages are a key example. If the item is an email message, -// the item name is likely the subject. In that case, the value must be the concatenation of the -// System.ItemNamePrefix and System.ItemName. Since the value of System.ItemNamePrefix excludes -// any trailing whitespace, the concatenation must include a whitespace when generating System.ItemNameDisplay. -// -// Note that this property is not guaranteed to be unique, but the idea is to promote the most likely -// candidate that can be unique and also makes sense for end users. For example, for documents, you -// might think about using System.Title as the System.ItemNameDisplay, but in practice the title of -// the documents may not be useful or unique enough to be of value as the sole System.ItemNameDisplay. -// Instead, providing the value of System.FileName as the value of System.ItemNameDisplay is a better -// candidate. In Windows Mail, the emails are stored in the file system as .eml files and the -// System.FileName for those files are not human-friendly as they contain GUIDs. In this example, -// promoting System.Subject as System.ItemNameDisplay makes more sense. -// -// Compatibility notes: -// -// Shell folder implementations on Vista: use PKEY_ItemNameDisplay for the name column when -// you want Explorer to call ISF::GetDisplayNameOf(SHGDN_NORMAL) to get the value of the name. Use -// another PKEY (like PKEY_ItemName) when you want Explorer to call either the folder's property store or -// ISF2::GetDetailsEx in order to get the value of the name. -// -// Shell folder implementations on XP: the first column needs to be the name column, and Explorer -// will call ISF::GetDisplayNameOf to get the value of the name. The PKEY/SCID does not matter. -// -// Example values: -// -// File: "hello.txt" -// Message: "Re: Let's talk about Tom's argyle socks!" -// Device folder: "song.wma" -// Folder: "Documents" -DEFINE_PROPERTYKEY(PKEY_ItemNameDisplay, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC, 10); - -// Name: System.ItemNamePrefix -- PKEY_ItemNamePrefix -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: D7313FF1-A77A-401C-8C99-3DBDD68ADD36, 100 -// -// This is the prefix of an item, used for email messages. -// where the subject begins with "Re:" which is the prefix. -// -// If the item is a file, then the value of this property is VT_EMPTY. -// -// If the item is a message, then the value of this property is the forwarding or reply -// prefixes (including delimiting colon, but no whitespace), or VT_EMPTY if there is no prefix. -// -// Example values: -// -// System.ItemNamePrefix System.ItemName System.ItemNameDisplay -// --------------------- ------------------- ---------------------- -// VT_EMPTY "Great day" "Great day" -// "Re:" "Great day" "Re: Great day" -// "Fwd: " "Monthly budget" "Fwd: Monthly budget" -// VT_EMPTY "accounts.xls" "accounts.xls" -DEFINE_PROPERTYKEY(PKEY_ItemNamePrefix, 0xD7313FF1, 0xA77A, 0x401C, 0x8C, 0x99, 0x3D, 0xBD, 0xD6, 0x8A, 0xDD, 0x36, 100); - -// Name: System.ItemParticipants -- PKEY_ItemParticipants -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: D4D0AA16-9948-41A4-AA85-D97FF9646993, 100 -// -// This is the generic list of people associated with an item and who contributed -// to the item. -// -// For example, this is the combination of people in the To list, Cc list and -// sender of an email message. -DEFINE_PROPERTYKEY(PKEY_ItemParticipants, 0xD4D0AA16, 0x9948, 0x41A4, 0xAA, 0x85, 0xD9, 0x7F, 0xF9, 0x64, 0x69, 0x93, 100); - -// Name: System.ItemPathDisplay -- PKEY_ItemPathDisplay -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 7 -// -// This is the user-friendly display path to the item. -// -// If the item is a file or folder this property -// includes the extension in all cases, and will be localized if a localized name is available. -// -// For other items,this is the user-friendly equivalent, assuming the item exists in hierarchical storage. -// -// Unlike System.ItemUrl, this property value does not include the URL scheme. -// -// To parse an item path, use System.ItemUrl or System.ParsingPath. To reference shell -// namespace items using shell APIs, use System.ParsingPath. -// -// Example values: -// -// If the path is... The property value is... -// ----------------- ------------------------ -// "c:\foo\bar\hello.txt" "c:\foo\bar\hello.txt" -// "\\server\share\mydir\goodnews.doc" "\\server\share\mydir\goodnews.doc" -// "\\server\share\numbers.xls" "\\server\share\numbers.xls" -// "c:\foo\MyFolder" "c:\foo\MyFolder" -// "/Mailbox Account/Inbox/'Re: Hello!'" "/Mailbox Account/Inbox/'Re: Hello!'" -DEFINE_PROPERTYKEY(PKEY_ItemPathDisplay, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 7); - -// Name: System.ItemPathDisplayNarrow -- PKEY_ItemPathDisplayNarrow -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 8 -// -// This is the user-friendly display path to the item. The format of the string should be -// tailored such that the name comes first, to optimize for a narrow viewing column. -// -// If the item is a file, the value excludes the file extension, and includes localized names if they are present. -// If the item is a message, the value includes the System.ItemNamePrefix. -// -// To parse an item path, use System.ItemUrl or System.ParsingPath. -// -// Example values: -// -// If the path is... The property value is... -// ----------------- ------------------------ -// "c:\foo\bar\hello.txt" "hello (c:\foo\bar)" -// "\\server\share\mydir\goodnews.doc" "goodnews (\\server\share\mydir)" -// "\\server\share\folder" "folder (\\server\share)" -// "c:\foo\MyFolder" "MyFolder (c:\foo)" -// "/Mailbox Account/Inbox/'Re: Hello!'" "Re: Hello! (/Mailbox Account/Inbox)" -DEFINE_PROPERTYKEY(PKEY_ItemPathDisplayNarrow, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 8); - -// Name: System.ItemType -- PKEY_ItemType -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 11 -// -// This is the canonical type of the item and is intended to be programmatically -// parsed. -// -// If there is no canonical type, the value is VT_EMPTY. -// -// If the item is a file (ie, System.FileName is not VT_EMPTY), the value is the same as -// System.FileExtension. -// -// Use System.ItemTypeText when you want to display the type to end users in a view. (If -// the item is a file, passing the System.ItemType value to PSFormatForDisplay will -// result in the same value as System.ItemTypeText.) -// -// Example values: -// -// If the path is... The property value is... -// ----------------- ------------------------ -// "c:\foo\bar\hello.txt" ".txt" -// "\\server\share\mydir\goodnews.doc" ".doc" -// "\\server\share\folder" "Directory" -// "c:\foo\MyFolder" "Directory" -// [desktop] "Folder" -// "/Mailbox Account/Inbox/'Re: Hello!'" "MAPI/IPM.Message" -DEFINE_PROPERTYKEY(PKEY_ItemType, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 11); - -// Name: System.ItemTypeText -- PKEY_ItemTypeText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_Storage) B725F130-47EF-101A-A5F1-02608C9EEBAC, 4 (PID_STG_STORAGETYPE) -// -// This is the user friendly type name of the item. This is not intended to be -// programmatically parsed. -// -// If System.ItemType is VT_EMPTY, the value of this property is also VT_EMPTY. -// -// If the item is a file, the value of this property is the same as if you passed the -// file's System.ItemType value to PSFormatForDisplay. -// -// This property should not be confused with System.Kind, where System.Kind is a high-level -// user friendly kind name. For example, for a document, System.Kind = "Document" and -// System.Item.Type = ".doc" and System.Item.TypeText = "Microsoft Word Document" -// -// Example values: -// -// If the path is... The property value is... -// ----------------- ------------------------ -// "c:\foo\bar\hello.txt" "Text File" -// "\\server\share\mydir\goodnews.doc" "Microsoft Word Document" -// "\\server\share\folder" "File Folder" -// "c:\foo\MyFolder" "File Folder" -// "/Mailbox Account/Inbox/'Re: Hello!'" "Outlook E-Mail Message" -DEFINE_PROPERTYKEY(PKEY_ItemTypeText, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC, 4); - -// Name: System.ItemUrl -- PKEY_ItemUrl -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_Query) 49691C90-7E17-101A-A91C-08002B2ECDA9, 9 (PROPID_QUERY_VIRTUALPATH) -// -// This always represents a well formed URL that points to the item. -// -// To reference shell namespace items using shell APIs, use System.ParsingPath. -// -// Example values: -// -// Files: "file:///c:/foo/bar/hello.txt" -// "csc://{GUID}/..." -// Messages: "mapi://..." -DEFINE_PROPERTYKEY(PKEY_ItemUrl, 0x49691C90, 0x7E17, 0x101A, 0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9, 9); - -// Name: System.Keywords -- PKEY_Keywords -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) Legacy code may treat this as VT_LPSTR. -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 5 (PIDSI_KEYWORDS) -// -// The keywords for the item. Also referred to as tags. -DEFINE_PROPERTYKEY(PKEY_Keywords, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 5); - -// Name: System.Kind -- PKEY_Kind -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: 1E3EE840-BC2B-476C-8237-2ACD1A839B22, 3 -// -// System.Kind is used to map extensions to various .Search folders. -// Extensions are mapped to Kinds at HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\KindMap -// The list of kinds is not extensible. -DEFINE_PROPERTYKEY(PKEY_Kind, 0x1E3EE840, 0xBC2B, 0x476C, 0x82, 0x37, 0x2A, 0xCD, 0x1A, 0x83, 0x9B, 0x22, 3); - -// Possible discrete values for PKEY_Kind are: -#define KIND_CALENDAR L"calendar" -#define KIND_COMMUNICATION L"communication" -#define KIND_CONTACT L"contact" -#define KIND_DOCUMENT L"document" -#define KIND_EMAIL L"email" -#define KIND_FEED L"feed" -#define KIND_FOLDER L"folder" -#define KIND_GAME L"game" -#define KIND_INSTANTMESSAGE L"instantmessage" -#define KIND_JOURNAL L"journal" -#define KIND_LINK L"link" -#define KIND_MOVIE L"movie" -#define KIND_MUSIC L"music" -#define KIND_NOTE L"note" -#define KIND_PICTURE L"picture" -#define KIND_PROGRAM L"program" -#define KIND_RECORDEDTV L"recordedtv" -#define KIND_SEARCHFOLDER L"searchfolder" -#define KIND_TASK L"task" -#define KIND_VIDEO L"video" -#define KIND_WEBHISTORY L"webhistory" - -// Name: System.KindText -- PKEY_KindText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: F04BEF95-C585-4197-A2B7-DF46FDC9EE6D, 100 -// -// This is the user-friendly form of System.Kind. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_KindText, 0xF04BEF95, 0xC585, 0x4197, 0xA2, 0xB7, 0xDF, 0x46, 0xFD, 0xC9, 0xEE, 0x6D, 100); - -// Name: System.Language -- PKEY_Language -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 28 -// -// -DEFINE_PROPERTYKEY(PKEY_Language, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 28); - -// Name: System.MileageInformation -- PKEY_MileageInformation -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: FDF84370-031A-4ADD-9E91-0D775F1C6605, 100 -DEFINE_PROPERTYKEY(PKEY_MileageInformation, 0xFDF84370, 0x031A, 0x4ADD, 0x9E, 0x91, 0x0D, 0x77, 0x5F, 0x1C, 0x66, 0x05, 100); - -// Name: System.MIMEType -- PKEY_MIMEType -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 0B63E350-9CCC-11D0-BCDB-00805FCCCE04, 5 -// -// The MIME type. Eg, for EML files: 'message/rfc822'. -DEFINE_PROPERTYKEY(PKEY_MIMEType, 0x0B63E350, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04, 5); - -// Name: System.Null -- PKEY_Null -// Type: Null -- VT_NULL -// FormatID: 00000000-0000-0000-0000-000000000000, 0 -DEFINE_PROPERTYKEY(PKEY_Null, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0); - -// Name: System.OfflineAvailability -- PKEY_OfflineAvailability -// Type: UInt32 -- VT_UI4 -// FormatID: A94688B6-7D9F-4570-A648-E3DFC0AB2B3F, 100 -DEFINE_PROPERTYKEY(PKEY_OfflineAvailability, 0xA94688B6, 0x7D9F, 0x4570, 0xA6, 0x48, 0xE3, 0xDF, 0xC0, 0xAB, 0x2B, 0x3F, 100); - -// Possible discrete values for PKEY_OfflineAvailability are: -#define OFFLINEAVAILABILITY_NOT_AVAILABLE 0ul -#define OFFLINEAVAILABILITY_AVAILABLE 1ul -#define OFFLINEAVAILABILITY_ALWAYS_AVAILABLE 2ul - -// Name: System.OfflineStatus -- PKEY_OfflineStatus -// Type: UInt32 -- VT_UI4 -// FormatID: 6D24888F-4718-4BDA-AFED-EA0FB4386CD8, 100 -DEFINE_PROPERTYKEY(PKEY_OfflineStatus, 0x6D24888F, 0x4718, 0x4BDA, 0xAF, 0xED, 0xEA, 0x0F, 0xB4, 0x38, 0x6C, 0xD8, 100); - -// Possible discrete values for PKEY_OfflineStatus are: -#define OFFLINESTATUS_ONLINE 0ul -#define OFFLINESTATUS_OFFLINE 1ul -#define OFFLINESTATUS_OFFLINE_FORCED 2ul -#define OFFLINESTATUS_OFFLINE_SLOW 3ul -#define OFFLINESTATUS_OFFLINE_ERROR 4ul -#define OFFLINESTATUS_OFFLINE_ITEM_VERSION_CONFLICT 5ul -#define OFFLINESTATUS_OFFLINE_SUSPENDED 6ul - -// Name: System.OriginalFileName -- PKEY_OriginalFileName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSFMTID_VERSION) 0CEF7D53-FA64-11D1-A203-0000F81FEDEE, 6 -// -// -DEFINE_PROPERTYKEY(PKEY_OriginalFileName, 0x0CEF7D53, 0xFA64, 0x11D1, 0xA2, 0x03, 0x00, 0x00, 0xF8, 0x1F, 0xED, 0xEE, 6); - -// Name: System.ParentalRating -- PKEY_ParentalRating -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 21 (PIDMSI_PARENTAL_RATING) -// -// -DEFINE_PROPERTYKEY(PKEY_ParentalRating, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 21); - -// Name: System.ParentalRatingReason -- PKEY_ParentalRatingReason -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 10984E0A-F9F2-4321-B7EF-BAF195AF4319, 100 -DEFINE_PROPERTYKEY(PKEY_ParentalRatingReason, 0x10984E0A, 0xF9F2, 0x4321, 0xB7, 0xEF, 0xBA, 0xF1, 0x95, 0xAF, 0x43, 0x19, 100); - -// Name: System.ParentalRatingsOrganization -- PKEY_ParentalRatingsOrganization -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: A7FE0840-1344-46F0-8D37-52ED712A4BF9, 100 -DEFINE_PROPERTYKEY(PKEY_ParentalRatingsOrganization, 0xA7FE0840, 0x1344, 0x46F0, 0x8D, 0x37, 0x52, 0xED, 0x71, 0x2A, 0x4B, 0xF9, 100); - -// Name: System.ParsingBindContext -- PKEY_ParsingBindContext -// Type: Any -- VT_NULL Legacy code may treat this as VT_UNKNOWN. -// FormatID: DFB9A04D-362F-4CA3-B30B-0254B17B5B84, 100 -// -// used to get the IBindCtx for an item for parsing -DEFINE_PROPERTYKEY(PKEY_ParsingBindContext, 0xDFB9A04D, 0x362F, 0x4CA3, 0xB3, 0x0B, 0x02, 0x54, 0xB1, 0x7B, 0x5B, 0x84, 100); - -// Name: System.ParsingName -- PKEY_ParsingName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 24 -// -// The shell namespace name of an item relative to a parent folder. This name may be passed to -// IShellFolder::ParseDisplayName() of the parent shell folder. -DEFINE_PROPERTYKEY(PKEY_ParsingName, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 24); - -// Name: System.ParsingPath -- PKEY_ParsingPath -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 30 -// -// This is the shell namespace path to the item. This path may be passed to -// SHParseDisplayName to parse the path to the correct shell folder. -// -// If the item is a file, the value is identical to System.ItemPathDisplay. -// -// If the item cannot be accessed through the shell namespace, this value is VT_EMPTY. -DEFINE_PROPERTYKEY(PKEY_ParsingPath, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 30); - -// Name: System.PerceivedType -- PKEY_PerceivedType -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 9 -// -// The perceived type of a shell item, based upon its canonical type. -DEFINE_PROPERTYKEY(PKEY_PerceivedType, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 9); - -// For the enumerated values of PKEY_PerceivedType, see the PERCEIVED_TYPE_* values in shtypes.idl. - -// Name: System.PercentFull -- PKEY_PercentFull -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_Volume) 9B174B35-40FF-11D2-A27E-00C04FC30871, 5 (Filesystem Volume Properties) -// -// The amount filled as a percentage, multiplied by 100 (ie, the valid range is 0 through 100). -DEFINE_PROPERTYKEY(PKEY_PercentFull, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71, 5); - -// Name: System.Priority -- PKEY_Priority -// Type: UInt16 -- VT_UI2 -// FormatID: 9C1FCF74-2D97-41BA-B4AE-CB2E3661A6E4, 5 -// -// -DEFINE_PROPERTYKEY(PKEY_Priority, 0x9C1FCF74, 0x2D97, 0x41BA, 0xB4, 0xAE, 0xCB, 0x2E, 0x36, 0x61, 0xA6, 0xE4, 5); - -// Possible discrete values for PKEY_Priority are: -#define PRIORITY_PROP_LOW 0u -#define PRIORITY_PROP_NORMAL 1u -#define PRIORITY_PROP_HIGH 2u - -// Name: System.PriorityText -- PKEY_PriorityText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: D98BE98B-B86B-4095-BF52-9D23B2E0A752, 100 -// -// This is the user-friendly form of System.Priority. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_PriorityText, 0xD98BE98B, 0xB86B, 0x4095, 0xBF, 0x52, 0x9D, 0x23, 0xB2, 0xE0, 0xA7, 0x52, 100); - -// Name: System.Project -- PKEY_Project -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 39A7F922-477C-48DE-8BC8-B28441E342E3, 100 -DEFINE_PROPERTYKEY(PKEY_Project, 0x39A7F922, 0x477C, 0x48DE, 0x8B, 0xC8, 0xB2, 0x84, 0x41, 0xE3, 0x42, 0xE3, 100); - -// Name: System.ProviderItemID -- PKEY_ProviderItemID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: F21D9941-81F0-471A-ADEE-4E74B49217ED, 100 -// -// -DEFINE_PROPERTYKEY(PKEY_ProviderItemID, 0xF21D9941, 0x81F0, 0x471A, 0xAD, 0xEE, 0x4E, 0x74, 0xB4, 0x92, 0x17, 0xED, 100); - -// Name: System.Rating -- PKEY_Rating -// Type: UInt32 -- VT_UI4 -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 9 (PIDMSI_RATING) -// -// Indicates the users preference rating of an item on a scale of 0-99 (0 = unrated, 1-12 = One Star, -// 13-37 = Two Stars, 38-62 = Three Stars, 63-87 = Four Stars, 88-99 = Five Stars). -DEFINE_PROPERTYKEY(PKEY_Rating, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 9); - -// Use the following constants to convert between visual stars and the ratings value: -#define RATING_UNRATED_MIN 0ul -#define RATING_UNRATED_SET 0ul -#define RATING_UNRATED_MAX 0ul - -#define RATING_ONE_STAR_MIN 1ul -#define RATING_ONE_STAR_SET 1ul -#define RATING_ONE_STAR_MAX 12ul - -#define RATING_TWO_STARS_MIN 13ul -#define RATING_TWO_STARS_SET 25ul -#define RATING_TWO_STARS_MAX 37ul - -#define RATING_THREE_STARS_MIN 38ul -#define RATING_THREE_STARS_SET 50ul -#define RATING_THREE_STARS_MAX 62ul - -#define RATING_FOUR_STARS_MIN 63ul -#define RATING_FOUR_STARS_SET 75ul -#define RATING_FOUR_STARS_MAX 87ul - -#define RATING_FIVE_STARS_MIN 88ul -#define RATING_FIVE_STARS_SET 99ul -#define RATING_FIVE_STARS_MAX 99ul - - -// Name: System.RatingText -- PKEY_RatingText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 90197CA7-FD8F-4E8C-9DA3-B57E1E609295, 100 -// -// This is the user-friendly form of System.Rating. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_RatingText, 0x90197CA7, 0xFD8F, 0x4E8C, 0x9D, 0xA3, 0xB5, 0x7E, 0x1E, 0x60, 0x92, 0x95, 100); - -// Name: System.Sensitivity -- PKEY_Sensitivity -// Type: UInt16 -- VT_UI2 -// FormatID: F8D3F6AC-4874-42CB-BE59-AB454B30716A, 100 -// -// -DEFINE_PROPERTYKEY(PKEY_Sensitivity, 0xF8D3F6AC, 0x4874, 0x42CB, 0xBE, 0x59, 0xAB, 0x45, 0x4B, 0x30, 0x71, 0x6A, 100); - -// Possible discrete values for PKEY_Sensitivity are: -#define SENSITIVITY_PROP_NORMAL 0u -#define SENSITIVITY_PROP_PERSONAL 1u -#define SENSITIVITY_PROP_PRIVATE 2u -#define SENSITIVITY_PROP_CONFIDENTIAL 3u - -// Name: System.SensitivityText -- PKEY_SensitivityText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: D0C7F054-3F72-4725-8527-129A577CB269, 100 -// -// This is the user-friendly form of System.Sensitivity. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_SensitivityText, 0xD0C7F054, 0x3F72, 0x4725, 0x85, 0x27, 0x12, 0x9A, 0x57, 0x7C, 0xB2, 0x69, 100); - -// Name: System.SFGAOFlags -- PKEY_SFGAOFlags -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 25 -// -// IShellFolder::GetAttributesOf flags, with SFGAO_PKEYSFGAOMASK attributes masked out. -DEFINE_PROPERTYKEY(PKEY_SFGAOFlags, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 25); - -// Name: System.SharedWith -- PKEY_SharedWith -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: EF884C5B-2BFE-41BB-AAE5-76EEDF4F9902, 200 -// -// Who is the item shared with? -DEFINE_PROPERTYKEY(PKEY_SharedWith, 0xEF884C5B, 0x2BFE, 0x41BB, 0xAA, 0xE5, 0x76, 0xEE, 0xDF, 0x4F, 0x99, 0x02, 200); - -// Name: System.ShareUserRating -- PKEY_ShareUserRating -// Type: UInt32 -- VT_UI4 -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 12 (PIDMSI_SHARE_USER_RATING) -// -// -DEFINE_PROPERTYKEY(PKEY_ShareUserRating, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 12); - -// Name: System.Shell.OmitFromView -- PKEY_Shell_OmitFromView -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: DE35258C-C695-4CBC-B982-38B0AD24CED0, 2 -// -// Set this to a string value of 'True' to omit this item from shell views -DEFINE_PROPERTYKEY(PKEY_Shell_OmitFromView, 0xDE35258C, 0xC695, 0x4CBC, 0xB9, 0x82, 0x38, 0xB0, 0xAD, 0x24, 0xCE, 0xD0, 2); - -// Name: System.SimpleRating -- PKEY_SimpleRating -// Type: UInt32 -- VT_UI4 -// FormatID: A09F084E-AD41-489F-8076-AA5BE3082BCA, 100 -// -// Indicates the users preference rating of an item on a scale of 0-5 (0=unrated, 1=One Star, 2=Two Stars, 3=Three Stars, -// 4=Four Stars, 5=Five Stars) -DEFINE_PROPERTYKEY(PKEY_SimpleRating, 0xA09F084E, 0xAD41, 0x489F, 0x80, 0x76, 0xAA, 0x5B, 0xE3, 0x08, 0x2B, 0xCA, 100); - -// Name: System.Size -- PKEY_Size -// Type: UInt64 -- VT_UI8 -// FormatID: (FMTID_Storage) B725F130-47EF-101A-A5F1-02608C9EEBAC, 12 (PID_STG_SIZE) -// -// -DEFINE_PROPERTYKEY(PKEY_Size, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC, 12); - -// Name: System.SoftwareUsed -- PKEY_SoftwareUsed -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 305 -// -// PropertyTagSoftwareUsed -DEFINE_PROPERTYKEY(PKEY_SoftwareUsed, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 305); - -// Name: System.SourceItem -- PKEY_SourceItem -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 668CDFA5-7A1B-4323-AE4B-E527393A1D81, 100 -DEFINE_PROPERTYKEY(PKEY_SourceItem, 0x668CDFA5, 0x7A1B, 0x4323, 0xAE, 0x4B, 0xE5, 0x27, 0x39, 0x3A, 0x1D, 0x81, 100); - -// Name: System.StartDate -- PKEY_StartDate -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 48FD6EC8-8A12-4CDF-A03E-4EC5A511EDDE, 100 -DEFINE_PROPERTYKEY(PKEY_StartDate, 0x48FD6EC8, 0x8A12, 0x4CDF, 0xA0, 0x3E, 0x4E, 0xC5, 0xA5, 0x11, 0xED, 0xDE, 100); - -// Name: System.Status -- PKEY_Status -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_IntSite) 000214A1-0000-0000-C000-000000000046, 9 -DEFINE_PROPERTYKEY(PKEY_Status, 0x000214A1, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 9); - -// Name: System.Subject -- PKEY_Subject -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 3 (PIDSI_SUBJECT) -// -// -DEFINE_PROPERTYKEY(PKEY_Subject, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 3); - -// Name: System.Thumbnail -- PKEY_Thumbnail -// Type: Clipboard -- VT_CF -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 17 (PIDSI_THUMBNAIL) -// -// A data that represents the thumbnail in VT_CF format. -DEFINE_PROPERTYKEY(PKEY_Thumbnail, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 17); - -// Name: System.ThumbnailCacheId -- PKEY_ThumbnailCacheId -// Type: UInt64 -- VT_UI8 -// FormatID: 446D16B1-8DAD-4870-A748-402EA43D788C, 100 -// -// Unique value that can be used as a key to cache thumbnails. The value changes when the name, volume, or data modified -// of an item changes. -DEFINE_PROPERTYKEY(PKEY_ThumbnailCacheId, 0x446D16B1, 0x8DAD, 0x4870, 0xA7, 0x48, 0x40, 0x2E, 0xA4, 0x3D, 0x78, 0x8C, 100); - -// Name: System.ThumbnailStream -- PKEY_ThumbnailStream -// Type: Stream -- VT_STREAM -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 27 -// -// Data that represents the thumbnail in VT_STREAM format that GDI+/WindowsCodecs supports (jpg, png, etc). -DEFINE_PROPERTYKEY(PKEY_ThumbnailStream, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 27); - -// Name: System.Title -- PKEY_Title -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) Legacy code may treat this as VT_LPSTR. -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 2 (PIDSI_TITLE) -// -// Title of item. -DEFINE_PROPERTYKEY(PKEY_Title, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 2); - -// Name: System.TotalFileSize -- PKEY_TotalFileSize -// Type: UInt64 -- VT_UI8 -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 14 -// -// -DEFINE_PROPERTYKEY(PKEY_TotalFileSize, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 14); - -// Name: System.Trademarks -- PKEY_Trademarks -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSFMTID_VERSION) 0CEF7D53-FA64-11D1-A203-0000F81FEDEE, 9 (PIDVSI_Trademarks) -// -// -DEFINE_PROPERTYKEY(PKEY_Trademarks, 0x0CEF7D53, 0xFA64, 0x11D1, 0xA2, 0x03, 0x00, 0x00, 0xF8, 0x1F, 0xED, 0xEE, 9); - -//----------------------------------------------------------------------------- -// Document properties - - - -// Name: System.Document.ByteCount -- PKEY_Document_ByteCount -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 4 (PIDDSI_BYTECOUNT) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_ByteCount, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 4); - -// Name: System.Document.CharacterCount -- PKEY_Document_CharacterCount -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 16 (PIDSI_CHARCOUNT) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_CharacterCount, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 16); - -// Name: System.Document.ClientID -- PKEY_Document_ClientID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 276D7BB0-5B34-4FB0-AA4B-158ED12A1809, 100 -DEFINE_PROPERTYKEY(PKEY_Document_ClientID, 0x276D7BB0, 0x5B34, 0x4FB0, 0xAA, 0x4B, 0x15, 0x8E, 0xD1, 0x2A, 0x18, 0x09, 100); - -// Name: System.Document.Contributor -- PKEY_Document_Contributor -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: F334115E-DA1B-4509-9B3D-119504DC7ABB, 100 -DEFINE_PROPERTYKEY(PKEY_Document_Contributor, 0xF334115E, 0xDA1B, 0x4509, 0x9B, 0x3D, 0x11, 0x95, 0x04, 0xDC, 0x7A, 0xBB, 100); - -// Name: System.Document.DateCreated -- PKEY_Document_DateCreated -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 12 (PIDSI_CREATE_DTM) -// -// This property is stored in the document, not obtained from the file system. -DEFINE_PROPERTYKEY(PKEY_Document_DateCreated, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 12); - -// Name: System.Document.DatePrinted -- PKEY_Document_DatePrinted -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 11 (PIDSI_LASTPRINTED) -// -// Legacy name: "DocLastPrinted". -DEFINE_PROPERTYKEY(PKEY_Document_DatePrinted, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 11); - -// Name: System.Document.DateSaved -- PKEY_Document_DateSaved -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 13 (PIDSI_LASTSAVE_DTM) -// -// Legacy name: "DocLastSavedTm". -DEFINE_PROPERTYKEY(PKEY_Document_DateSaved, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 13); - -// Name: System.Document.Division -- PKEY_Document_Division -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 1E005EE6-BF27-428B-B01C-79676ACD2870, 100 -DEFINE_PROPERTYKEY(PKEY_Document_Division, 0x1E005EE6, 0xBF27, 0x428B, 0xB0, 0x1C, 0x79, 0x67, 0x6A, 0xCD, 0x28, 0x70, 100); - -// Name: System.Document.DocumentID -- PKEY_Document_DocumentID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: E08805C8-E395-40DF-80D2-54F0D6C43154, 100 -DEFINE_PROPERTYKEY(PKEY_Document_DocumentID, 0xE08805C8, 0xE395, 0x40DF, 0x80, 0xD2, 0x54, 0xF0, 0xD6, 0xC4, 0x31, 0x54, 100); - -// Name: System.Document.HiddenSlideCount -- PKEY_Document_HiddenSlideCount -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 9 (PIDDSI_HIDDENCOUNT) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_HiddenSlideCount, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 9); - -// Name: System.Document.LastAuthor -- PKEY_Document_LastAuthor -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 8 (PIDSI_LASTAUTHOR) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_LastAuthor, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 8); - -// Name: System.Document.LineCount -- PKEY_Document_LineCount -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 5 (PIDDSI_LINECOUNT) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_LineCount, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 5); - -// Name: System.Document.Manager -- PKEY_Document_Manager -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 14 (PIDDSI_MANAGER) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_Manager, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 14); - -// Name: System.Document.MultimediaClipCount -- PKEY_Document_MultimediaClipCount -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 10 (PIDDSI_MMCLIPCOUNT) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_MultimediaClipCount, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 10); - -// Name: System.Document.NoteCount -- PKEY_Document_NoteCount -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 8 (PIDDSI_NOTECOUNT) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_NoteCount, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 8); - -// Name: System.Document.PageCount -- PKEY_Document_PageCount -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 14 (PIDSI_PAGECOUNT) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_PageCount, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 14); - -// Name: System.Document.ParagraphCount -- PKEY_Document_ParagraphCount -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 6 (PIDDSI_PARCOUNT) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_ParagraphCount, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 6); - -// Name: System.Document.PresentationFormat -- PKEY_Document_PresentationFormat -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 3 (PIDDSI_PRESFORMAT) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_PresentationFormat, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 3); - -// Name: System.Document.RevisionNumber -- PKEY_Document_RevisionNumber -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 9 (PIDSI_REVNUMBER) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_RevisionNumber, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 9); - -// Name: System.Document.Security -- PKEY_Document_Security -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 19 -// -// Access control information, from SummaryInfo propset -DEFINE_PROPERTYKEY(PKEY_Document_Security, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 19); - -// Name: System.Document.SlideCount -- PKEY_Document_SlideCount -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 7 (PIDDSI_SLIDECOUNT) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_SlideCount, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 7); - -// Name: System.Document.Template -- PKEY_Document_Template -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 7 (PIDSI_TEMPLATE) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_Template, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 7); - -// Name: System.Document.TotalEditingTime -- PKEY_Document_TotalEditingTime -// Type: UInt64 -- VT_UI8 -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 10 (PIDSI_EDITTIME) -// -// 100ns units, not milliseconds. VT_FILETIME for IPropertySetStorage handlers (legacy) -DEFINE_PROPERTYKEY(PKEY_Document_TotalEditingTime, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 10); - -// Name: System.Document.Version -- PKEY_Document_Version -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_DocumentSummaryInformation) D5CDD502-2E9C-101B-9397-08002B2CF9AE, 29 -DEFINE_PROPERTYKEY(PKEY_Document_Version, 0xD5CDD502, 0x2E9C, 0x101B, 0x93, 0x97, 0x08, 0x00, 0x2B, 0x2C, 0xF9, 0xAE, 29); - -// Name: System.Document.WordCount -- PKEY_Document_WordCount -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_SummaryInformation) F29F85E0-4FF9-1068-AB91-08002B27B3D9, 15 (PIDSI_WORDCOUNT) -// -// -DEFINE_PROPERTYKEY(PKEY_Document_WordCount, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 15); - - - -//----------------------------------------------------------------------------- -// DRM properties - -// Name: System.DRM.DatePlayExpires -- PKEY_DRM_DatePlayExpires -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: (FMTID_DRM) AEAC19E4-89AE-4508-B9B7-BB867ABEE2ED, 6 (PIDDRSI_PLAYEXPIRES) -// -// Indicates when play expires for digital rights management. -DEFINE_PROPERTYKEY(PKEY_DRM_DatePlayExpires, 0xAEAC19E4, 0x89AE, 0x4508, 0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED, 6); - -// Name: System.DRM.DatePlayStarts -- PKEY_DRM_DatePlayStarts -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: (FMTID_DRM) AEAC19E4-89AE-4508-B9B7-BB867ABEE2ED, 5 (PIDDRSI_PLAYSTARTS) -// -// Indicates when play starts for digital rights management. -DEFINE_PROPERTYKEY(PKEY_DRM_DatePlayStarts, 0xAEAC19E4, 0x89AE, 0x4508, 0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED, 5); - -// Name: System.DRM.Description -- PKEY_DRM_Description -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_DRM) AEAC19E4-89AE-4508-B9B7-BB867ABEE2ED, 3 (PIDDRSI_DESCRIPTION) -// -// Displays the description for digital rights management. -DEFINE_PROPERTYKEY(PKEY_DRM_Description, 0xAEAC19E4, 0x89AE, 0x4508, 0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED, 3); - -// Name: System.DRM.IsProtected -- PKEY_DRM_IsProtected -// Type: Boolean -- VT_BOOL -// FormatID: (FMTID_DRM) AEAC19E4-89AE-4508-B9B7-BB867ABEE2ED, 2 (PIDDRSI_PROTECTED) -// -// -DEFINE_PROPERTYKEY(PKEY_DRM_IsProtected, 0xAEAC19E4, 0x89AE, 0x4508, 0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED, 2); - -// Name: System.DRM.PlayCount -- PKEY_DRM_PlayCount -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_DRM) AEAC19E4-89AE-4508-B9B7-BB867ABEE2ED, 4 (PIDDRSI_PLAYCOUNT) -// -// Indicates the play count for digital rights management. -DEFINE_PROPERTYKEY(PKEY_DRM_PlayCount, 0xAEAC19E4, 0x89AE, 0x4508, 0xB9, 0xB7, 0xBB, 0x86, 0x7A, 0xBE, 0xE2, 0xED, 4); - -//----------------------------------------------------------------------------- -// GPS properties - -// Name: System.GPS.Altitude -- PKEY_GPS_Altitude -// Type: Double -- VT_R8 -// FormatID: 827EDB4F-5B73-44A7-891D-FDFFABEA35CA, 100 -// -// Indicates the altitude based on the reference in PKEY_GPS_AltitudeRef. Calculated from PKEY_GPS_AltitudeNumerator and -// PKEY_GPS_AltitudeDenominator -DEFINE_PROPERTYKEY(PKEY_GPS_Altitude, 0x827EDB4F, 0x5B73, 0x44A7, 0x89, 0x1D, 0xFD, 0xFF, 0xAB, 0xEA, 0x35, 0xCA, 100); - -// Name: System.GPS.AltitudeDenominator -- PKEY_GPS_AltitudeDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 78342DCB-E358-4145-AE9A-6BFE4E0F9F51, 100 -// -// Denominator of PKEY_GPS_Altitude -DEFINE_PROPERTYKEY(PKEY_GPS_AltitudeDenominator, 0x78342DCB, 0xE358, 0x4145, 0xAE, 0x9A, 0x6B, 0xFE, 0x4E, 0x0F, 0x9F, 0x51, 100); - -// Name: System.GPS.AltitudeNumerator -- PKEY_GPS_AltitudeNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 2DAD1EB7-816D-40D3-9EC3-C9773BE2AADE, 100 -// -// Numerator of PKEY_GPS_Altitude -DEFINE_PROPERTYKEY(PKEY_GPS_AltitudeNumerator, 0x2DAD1EB7, 0x816D, 0x40D3, 0x9E, 0xC3, 0xC9, 0x77, 0x3B, 0xE2, 0xAA, 0xDE, 100); - -// Name: System.GPS.AltitudeRef -- PKEY_GPS_AltitudeRef -// Type: Byte -- VT_UI1 -// FormatID: 46AC629D-75EA-4515-867F-6DC4321C5844, 100 -// -// Indicates the reference for the altitude property. (eg: above sea level, below sea level, absolute value) -DEFINE_PROPERTYKEY(PKEY_GPS_AltitudeRef, 0x46AC629D, 0x75EA, 0x4515, 0x86, 0x7F, 0x6D, 0xC4, 0x32, 0x1C, 0x58, 0x44, 100); - -// Name: System.GPS.AreaInformation -- PKEY_GPS_AreaInformation -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 972E333E-AC7E-49F1-8ADF-A70D07A9BCAB, 100 -// -// Represents the name of the GPS area -DEFINE_PROPERTYKEY(PKEY_GPS_AreaInformation, 0x972E333E, 0xAC7E, 0x49F1, 0x8A, 0xDF, 0xA7, 0x0D, 0x07, 0xA9, 0xBC, 0xAB, 100); - -// Name: System.GPS.Date -- PKEY_GPS_Date -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 3602C812-0F3B-45F0-85AD-603468D69423, 100 -// -// Date and time of the GPS record -DEFINE_PROPERTYKEY(PKEY_GPS_Date, 0x3602C812, 0x0F3B, 0x45F0, 0x85, 0xAD, 0x60, 0x34, 0x68, 0xD6, 0x94, 0x23, 100); - -// Name: System.GPS.DestBearing -- PKEY_GPS_DestBearing -// Type: Double -- VT_R8 -// FormatID: C66D4B3C-E888-47CC-B99F-9DCA3EE34DEA, 100 -// -// Indicates the bearing to the destination point. Calculated from PKEY_GPS_DestBearingNumerator and -// PKEY_GPS_DestBearingDenominator. -DEFINE_PROPERTYKEY(PKEY_GPS_DestBearing, 0xC66D4B3C, 0xE888, 0x47CC, 0xB9, 0x9F, 0x9D, 0xCA, 0x3E, 0xE3, 0x4D, 0xEA, 100); - -// Name: System.GPS.DestBearingDenominator -- PKEY_GPS_DestBearingDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 7ABCF4F8-7C3F-4988-AC91-8D2C2E97ECA5, 100 -// -// Denominator of PKEY_GPS_DestBearing -DEFINE_PROPERTYKEY(PKEY_GPS_DestBearingDenominator, 0x7ABCF4F8, 0x7C3F, 0x4988, 0xAC, 0x91, 0x8D, 0x2C, 0x2E, 0x97, 0xEC, 0xA5, 100); - -// Name: System.GPS.DestBearingNumerator -- PKEY_GPS_DestBearingNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: BA3B1DA9-86EE-4B5D-A2A4-A271A429F0CF, 100 -// -// Numerator of PKEY_GPS_DestBearing -DEFINE_PROPERTYKEY(PKEY_GPS_DestBearingNumerator, 0xBA3B1DA9, 0x86EE, 0x4B5D, 0xA2, 0xA4, 0xA2, 0x71, 0xA4, 0x29, 0xF0, 0xCF, 100); - -// Name: System.GPS.DestBearingRef -- PKEY_GPS_DestBearingRef -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 9AB84393-2A0F-4B75-BB22-7279786977CB, 100 -// -// Indicates the reference used for the giving the bearing to the destination point. (eg: true direction, magnetic direction) -DEFINE_PROPERTYKEY(PKEY_GPS_DestBearingRef, 0x9AB84393, 0x2A0F, 0x4B75, 0xBB, 0x22, 0x72, 0x79, 0x78, 0x69, 0x77, 0xCB, 100); - -// Name: System.GPS.DestDistance -- PKEY_GPS_DestDistance -// Type: Double -- VT_R8 -// FormatID: A93EAE04-6804-4F24-AC81-09B266452118, 100 -// -// Indicates the distance to the destination point. Calculated from PKEY_GPS_DestDistanceNumerator and -// PKEY_GPS_DestDistanceDenominator. -DEFINE_PROPERTYKEY(PKEY_GPS_DestDistance, 0xA93EAE04, 0x6804, 0x4F24, 0xAC, 0x81, 0x09, 0xB2, 0x66, 0x45, 0x21, 0x18, 100); - -// Name: System.GPS.DestDistanceDenominator -- PKEY_GPS_DestDistanceDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 9BC2C99B-AC71-4127-9D1C-2596D0D7DCB7, 100 -// -// Denominator of PKEY_GPS_DestDistance -DEFINE_PROPERTYKEY(PKEY_GPS_DestDistanceDenominator, 0x9BC2C99B, 0xAC71, 0x4127, 0x9D, 0x1C, 0x25, 0x96, 0xD0, 0xD7, 0xDC, 0xB7, 100); - -// Name: System.GPS.DestDistanceNumerator -- PKEY_GPS_DestDistanceNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 2BDA47DA-08C6-4FE1-80BC-A72FC517C5D0, 100 -// -// Numerator of PKEY_GPS_DestDistance -DEFINE_PROPERTYKEY(PKEY_GPS_DestDistanceNumerator, 0x2BDA47DA, 0x08C6, 0x4FE1, 0x80, 0xBC, 0xA7, 0x2F, 0xC5, 0x17, 0xC5, 0xD0, 100); - -// Name: System.GPS.DestDistanceRef -- PKEY_GPS_DestDistanceRef -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: ED4DF2D3-8695-450B-856F-F5C1C53ACB66, 100 -// -// Indicates the unit used to express the distance to the destination. (eg: kilometers, miles, knots) -DEFINE_PROPERTYKEY(PKEY_GPS_DestDistanceRef, 0xED4DF2D3, 0x8695, 0x450B, 0x85, 0x6F, 0xF5, 0xC1, 0xC5, 0x3A, 0xCB, 0x66, 100); - -// Name: System.GPS.DestLatitude -- PKEY_GPS_DestLatitude -// Type: Multivalue Double -- VT_VECTOR | VT_R8 (For variants: VT_ARRAY | VT_R8) -// FormatID: 9D1D7CC5-5C39-451C-86B3-928E2D18CC47, 100 -// -// Indicates the latitude of the destination point. This is an array of three values. Index 0 is the degrees, index 1 -// is the minutes, index 2 is the seconds. Each is calculated from the values in PKEY_GPS_DestLatitudeNumerator and -// PKEY_GPS_DestLatitudeDenominator. -DEFINE_PROPERTYKEY(PKEY_GPS_DestLatitude, 0x9D1D7CC5, 0x5C39, 0x451C, 0x86, 0xB3, 0x92, 0x8E, 0x2D, 0x18, 0xCC, 0x47, 100); - -// Name: System.GPS.DestLatitudeDenominator -- PKEY_GPS_DestLatitudeDenominator -// Type: Multivalue UInt32 -- VT_VECTOR | VT_UI4 (For variants: VT_ARRAY | VT_UI4) -// FormatID: 3A372292-7FCA-49A7-99D5-E47BB2D4E7AB, 100 -// -// Denominator of PKEY_GPS_DestLatitude -DEFINE_PROPERTYKEY(PKEY_GPS_DestLatitudeDenominator, 0x3A372292, 0x7FCA, 0x49A7, 0x99, 0xD5, 0xE4, 0x7B, 0xB2, 0xD4, 0xE7, 0xAB, 100); - -// Name: System.GPS.DestLatitudeNumerator -- PKEY_GPS_DestLatitudeNumerator -// Type: Multivalue UInt32 -- VT_VECTOR | VT_UI4 (For variants: VT_ARRAY | VT_UI4) -// FormatID: ECF4B6F6-D5A6-433C-BB92-4076650FC890, 100 -// -// Numerator of PKEY_GPS_DestLatitude -DEFINE_PROPERTYKEY(PKEY_GPS_DestLatitudeNumerator, 0xECF4B6F6, 0xD5A6, 0x433C, 0xBB, 0x92, 0x40, 0x76, 0x65, 0x0F, 0xC8, 0x90, 100); - -// Name: System.GPS.DestLatitudeRef -- PKEY_GPS_DestLatitudeRef -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: CEA820B9-CE61-4885-A128-005D9087C192, 100 -// -// Indicates whether the latitude destination point is north or south latitude -DEFINE_PROPERTYKEY(PKEY_GPS_DestLatitudeRef, 0xCEA820B9, 0xCE61, 0x4885, 0xA1, 0x28, 0x00, 0x5D, 0x90, 0x87, 0xC1, 0x92, 100); - -// Name: System.GPS.DestLongitude -- PKEY_GPS_DestLongitude -// Type: Multivalue Double -- VT_VECTOR | VT_R8 (For variants: VT_ARRAY | VT_R8) -// FormatID: 47A96261-CB4C-4807-8AD3-40B9D9DBC6BC, 100 -// -// Indicates the latitude of the destination point. This is an array of three values. Index 0 is the degrees, index 1 -// is the minutes, index 2 is the seconds. Each is calculated from the values in PKEY_GPS_DestLongitudeNumerator and -// PKEY_GPS_DestLongitudeDenominator. -DEFINE_PROPERTYKEY(PKEY_GPS_DestLongitude, 0x47A96261, 0xCB4C, 0x4807, 0x8A, 0xD3, 0x40, 0xB9, 0xD9, 0xDB, 0xC6, 0xBC, 100); - -// Name: System.GPS.DestLongitudeDenominator -- PKEY_GPS_DestLongitudeDenominator -// Type: Multivalue UInt32 -- VT_VECTOR | VT_UI4 (For variants: VT_ARRAY | VT_UI4) -// FormatID: 425D69E5-48AD-4900-8D80-6EB6B8D0AC86, 100 -// -// Denominator of PKEY_GPS_DestLongitude -DEFINE_PROPERTYKEY(PKEY_GPS_DestLongitudeDenominator, 0x425D69E5, 0x48AD, 0x4900, 0x8D, 0x80, 0x6E, 0xB6, 0xB8, 0xD0, 0xAC, 0x86, 100); - -// Name: System.GPS.DestLongitudeNumerator -- PKEY_GPS_DestLongitudeNumerator -// Type: Multivalue UInt32 -- VT_VECTOR | VT_UI4 (For variants: VT_ARRAY | VT_UI4) -// FormatID: A3250282-FB6D-48D5-9A89-DBCACE75CCCF, 100 -// -// Numerator of PKEY_GPS_DestLongitude -DEFINE_PROPERTYKEY(PKEY_GPS_DestLongitudeNumerator, 0xA3250282, 0xFB6D, 0x48D5, 0x9A, 0x89, 0xDB, 0xCA, 0xCE, 0x75, 0xCC, 0xCF, 100); - -// Name: System.GPS.DestLongitudeRef -- PKEY_GPS_DestLongitudeRef -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 182C1EA6-7C1C-4083-AB4B-AC6C9F4ED128, 100 -// -// Indicates whether the longitude destination point is east or west longitude -DEFINE_PROPERTYKEY(PKEY_GPS_DestLongitudeRef, 0x182C1EA6, 0x7C1C, 0x4083, 0xAB, 0x4B, 0xAC, 0x6C, 0x9F, 0x4E, 0xD1, 0x28, 100); - -// Name: System.GPS.Differential -- PKEY_GPS_Differential -// Type: UInt16 -- VT_UI2 -// FormatID: AAF4EE25-BD3B-4DD7-BFC4-47F77BB00F6D, 100 -// -// Indicates whether differential correction was applied to the GPS receiver -DEFINE_PROPERTYKEY(PKEY_GPS_Differential, 0xAAF4EE25, 0xBD3B, 0x4DD7, 0xBF, 0xC4, 0x47, 0xF7, 0x7B, 0xB0, 0x0F, 0x6D, 100); - -// Name: System.GPS.DOP -- PKEY_GPS_DOP -// Type: Double -- VT_R8 -// FormatID: 0CF8FB02-1837-42F1-A697-A7017AA289B9, 100 -// -// Indicates the GPS DOP (data degree of precision). Calculated from PKEY_GPS_DOPNumerator and PKEY_GPS_DOPDenominator -DEFINE_PROPERTYKEY(PKEY_GPS_DOP, 0x0CF8FB02, 0x1837, 0x42F1, 0xA6, 0x97, 0xA7, 0x01, 0x7A, 0xA2, 0x89, 0xB9, 100); - -// Name: System.GPS.DOPDenominator -- PKEY_GPS_DOPDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: A0BE94C5-50BA-487B-BD35-0654BE8881ED, 100 -// -// Denominator of PKEY_GPS_DOP -DEFINE_PROPERTYKEY(PKEY_GPS_DOPDenominator, 0xA0BE94C5, 0x50BA, 0x487B, 0xBD, 0x35, 0x06, 0x54, 0xBE, 0x88, 0x81, 0xED, 100); - -// Name: System.GPS.DOPNumerator -- PKEY_GPS_DOPNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 47166B16-364F-4AA0-9F31-E2AB3DF449C3, 100 -// -// Numerator of PKEY_GPS_DOP -DEFINE_PROPERTYKEY(PKEY_GPS_DOPNumerator, 0x47166B16, 0x364F, 0x4AA0, 0x9F, 0x31, 0xE2, 0xAB, 0x3D, 0xF4, 0x49, 0xC3, 100); - -// Name: System.GPS.ImgDirection -- PKEY_GPS_ImgDirection -// Type: Double -- VT_R8 -// FormatID: 16473C91-D017-4ED9-BA4D-B6BAA55DBCF8, 100 -// -// Indicates direction of the image when it was captured. Calculated from PKEY_GPS_ImgDirectionNumerator and -// PKEY_GPS_ImgDirectionDenominator. -DEFINE_PROPERTYKEY(PKEY_GPS_ImgDirection, 0x16473C91, 0xD017, 0x4ED9, 0xBA, 0x4D, 0xB6, 0xBA, 0xA5, 0x5D, 0xBC, 0xF8, 100); - -// Name: System.GPS.ImgDirectionDenominator -- PKEY_GPS_ImgDirectionDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 10B24595-41A2-4E20-93C2-5761C1395F32, 100 -// -// Denominator of PKEY_GPS_ImgDirection -DEFINE_PROPERTYKEY(PKEY_GPS_ImgDirectionDenominator, 0x10B24595, 0x41A2, 0x4E20, 0x93, 0xC2, 0x57, 0x61, 0xC1, 0x39, 0x5F, 0x32, 100); - -// Name: System.GPS.ImgDirectionNumerator -- PKEY_GPS_ImgDirectionNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: DC5877C7-225F-45F7-BAC7-E81334B6130A, 100 -// -// Numerator of PKEY_GPS_ImgDirection -DEFINE_PROPERTYKEY(PKEY_GPS_ImgDirectionNumerator, 0xDC5877C7, 0x225F, 0x45F7, 0xBA, 0xC7, 0xE8, 0x13, 0x34, 0xB6, 0x13, 0x0A, 100); - -// Name: System.GPS.ImgDirectionRef -- PKEY_GPS_ImgDirectionRef -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: A4AAA5B7-1AD0-445F-811A-0F8F6E67F6B5, 100 -// -// Indicates reference for giving the direction of the image when it was captured. (eg: true direction, magnetic direction) -DEFINE_PROPERTYKEY(PKEY_GPS_ImgDirectionRef, 0xA4AAA5B7, 0x1AD0, 0x445F, 0x81, 0x1A, 0x0F, 0x8F, 0x6E, 0x67, 0xF6, 0xB5, 100); - -// Name: System.GPS.Latitude -- PKEY_GPS_Latitude -// Type: Multivalue Double -- VT_VECTOR | VT_R8 (For variants: VT_ARRAY | VT_R8) -// FormatID: 8727CFFF-4868-4EC6-AD5B-81B98521D1AB, 100 -// -// Indicates the latitude. This is an array of three values. Index 0 is the degrees, index 1 is the minutes, index 2 -// is the seconds. Each is calculated from the values in PKEY_GPS_LatitudeNumerator and PKEY_GPS_LatitudeDenominator. -DEFINE_PROPERTYKEY(PKEY_GPS_Latitude, 0x8727CFFF, 0x4868, 0x4EC6, 0xAD, 0x5B, 0x81, 0xB9, 0x85, 0x21, 0xD1, 0xAB, 100); - -// Name: System.GPS.LatitudeDenominator -- PKEY_GPS_LatitudeDenominator -// Type: Multivalue UInt32 -- VT_VECTOR | VT_UI4 (For variants: VT_ARRAY | VT_UI4) -// FormatID: 16E634EE-2BFF-497B-BD8A-4341AD39EEB9, 100 -// -// Denominator of PKEY_GPS_Latitude -DEFINE_PROPERTYKEY(PKEY_GPS_LatitudeDenominator, 0x16E634EE, 0x2BFF, 0x497B, 0xBD, 0x8A, 0x43, 0x41, 0xAD, 0x39, 0xEE, 0xB9, 100); - -// Name: System.GPS.LatitudeNumerator -- PKEY_GPS_LatitudeNumerator -// Type: Multivalue UInt32 -- VT_VECTOR | VT_UI4 (For variants: VT_ARRAY | VT_UI4) -// FormatID: 7DDAAAD1-CCC8-41AE-B750-B2CB8031AEA2, 100 -// -// Numerator of PKEY_GPS_Latitude -DEFINE_PROPERTYKEY(PKEY_GPS_LatitudeNumerator, 0x7DDAAAD1, 0xCCC8, 0x41AE, 0xB7, 0x50, 0xB2, 0xCB, 0x80, 0x31, 0xAE, 0xA2, 100); - -// Name: System.GPS.LatitudeRef -- PKEY_GPS_LatitudeRef -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 029C0252-5B86-46C7-ACA0-2769FFC8E3D4, 100 -// -// Indicates whether latitude is north or south latitude -DEFINE_PROPERTYKEY(PKEY_GPS_LatitudeRef, 0x029C0252, 0x5B86, 0x46C7, 0xAC, 0xA0, 0x27, 0x69, 0xFF, 0xC8, 0xE3, 0xD4, 100); - -// Name: System.GPS.Longitude -- PKEY_GPS_Longitude -// Type: Multivalue Double -- VT_VECTOR | VT_R8 (For variants: VT_ARRAY | VT_R8) -// FormatID: C4C4DBB2-B593-466B-BBDA-D03D27D5E43A, 100 -// -// Indicates the longitude. This is an array of three values. Index 0 is the degrees, index 1 is the minutes, index 2 -// is the seconds. Each is calculated from the values in PKEY_GPS_LongitudeNumerator and PKEY_GPS_LongitudeDenominator. -DEFINE_PROPERTYKEY(PKEY_GPS_Longitude, 0xC4C4DBB2, 0xB593, 0x466B, 0xBB, 0xDA, 0xD0, 0x3D, 0x27, 0xD5, 0xE4, 0x3A, 100); - -// Name: System.GPS.LongitudeDenominator -- PKEY_GPS_LongitudeDenominator -// Type: Multivalue UInt32 -- VT_VECTOR | VT_UI4 (For variants: VT_ARRAY | VT_UI4) -// FormatID: BE6E176C-4534-4D2C-ACE5-31DEDAC1606B, 100 -// -// Denominator of PKEY_GPS_Longitude -DEFINE_PROPERTYKEY(PKEY_GPS_LongitudeDenominator, 0xBE6E176C, 0x4534, 0x4D2C, 0xAC, 0xE5, 0x31, 0xDE, 0xDA, 0xC1, 0x60, 0x6B, 100); - -// Name: System.GPS.LongitudeNumerator -- PKEY_GPS_LongitudeNumerator -// Type: Multivalue UInt32 -- VT_VECTOR | VT_UI4 (For variants: VT_ARRAY | VT_UI4) -// FormatID: 02B0F689-A914-4E45-821D-1DDA452ED2C4, 100 -// -// Numerator of PKEY_GPS_Longitude -DEFINE_PROPERTYKEY(PKEY_GPS_LongitudeNumerator, 0x02B0F689, 0xA914, 0x4E45, 0x82, 0x1D, 0x1D, 0xDA, 0x45, 0x2E, 0xD2, 0xC4, 100); - -// Name: System.GPS.LongitudeRef -- PKEY_GPS_LongitudeRef -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 33DCF22B-28D5-464C-8035-1EE9EFD25278, 100 -// -// Indicates whether longitude is east or west longitude -DEFINE_PROPERTYKEY(PKEY_GPS_LongitudeRef, 0x33DCF22B, 0x28D5, 0x464C, 0x80, 0x35, 0x1E, 0xE9, 0xEF, 0xD2, 0x52, 0x78, 100); - -// Name: System.GPS.MapDatum -- PKEY_GPS_MapDatum -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 2CA2DAE6-EDDC-407D-BEF1-773942ABFA95, 100 -// -// Indicates the geodetic survey data used by the GPS receiver -DEFINE_PROPERTYKEY(PKEY_GPS_MapDatum, 0x2CA2DAE6, 0xEDDC, 0x407D, 0xBE, 0xF1, 0x77, 0x39, 0x42, 0xAB, 0xFA, 0x95, 100); - -// Name: System.GPS.MeasureMode -- PKEY_GPS_MeasureMode -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: A015ED5D-AAEA-4D58-8A86-3C586920EA0B, 100 -// -// Indicates the GPS measurement mode. (eg: 2-dimensional, 3-dimensional) -DEFINE_PROPERTYKEY(PKEY_GPS_MeasureMode, 0xA015ED5D, 0xAAEA, 0x4D58, 0x8A, 0x86, 0x3C, 0x58, 0x69, 0x20, 0xEA, 0x0B, 100); - -// Name: System.GPS.ProcessingMethod -- PKEY_GPS_ProcessingMethod -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 59D49E61-840F-4AA9-A939-E2099B7F6399, 100 -// -// Indicates the name of the method used for location finding -DEFINE_PROPERTYKEY(PKEY_GPS_ProcessingMethod, 0x59D49E61, 0x840F, 0x4AA9, 0xA9, 0x39, 0xE2, 0x09, 0x9B, 0x7F, 0x63, 0x99, 100); - -// Name: System.GPS.Satellites -- PKEY_GPS_Satellites -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 467EE575-1F25-4557-AD4E-B8B58B0D9C15, 100 -// -// Indicates the GPS satellites used for measurements -DEFINE_PROPERTYKEY(PKEY_GPS_Satellites, 0x467EE575, 0x1F25, 0x4557, 0xAD, 0x4E, 0xB8, 0xB5, 0x8B, 0x0D, 0x9C, 0x15, 100); - -// Name: System.GPS.Speed -- PKEY_GPS_Speed -// Type: Double -- VT_R8 -// FormatID: DA5D0862-6E76-4E1B-BABD-70021BD25494, 100 -// -// Indicates the speed of the GPS receiver movement. Calculated from PKEY_GPS_SpeedNumerator and -// PKEY_GPS_SpeedDenominator. -DEFINE_PROPERTYKEY(PKEY_GPS_Speed, 0xDA5D0862, 0x6E76, 0x4E1B, 0xBA, 0xBD, 0x70, 0x02, 0x1B, 0xD2, 0x54, 0x94, 100); - -// Name: System.GPS.SpeedDenominator -- PKEY_GPS_SpeedDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 7D122D5A-AE5E-4335-8841-D71E7CE72F53, 100 -// -// Denominator of PKEY_GPS_Speed -DEFINE_PROPERTYKEY(PKEY_GPS_SpeedDenominator, 0x7D122D5A, 0xAE5E, 0x4335, 0x88, 0x41, 0xD7, 0x1E, 0x7C, 0xE7, 0x2F, 0x53, 100); - -// Name: System.GPS.SpeedNumerator -- PKEY_GPS_SpeedNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: ACC9CE3D-C213-4942-8B48-6D0820F21C6D, 100 -// -// Numerator of PKEY_GPS_Speed -DEFINE_PROPERTYKEY(PKEY_GPS_SpeedNumerator, 0xACC9CE3D, 0xC213, 0x4942, 0x8B, 0x48, 0x6D, 0x08, 0x20, 0xF2, 0x1C, 0x6D, 100); - -// Name: System.GPS.SpeedRef -- PKEY_GPS_SpeedRef -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: ECF7F4C9-544F-4D6D-9D98-8AD79ADAF453, 100 -// -// Indicates the unit used to express the speed of the GPS receiver movement. (eg: kilometers per hour, -// miles per hour, knots). -DEFINE_PROPERTYKEY(PKEY_GPS_SpeedRef, 0xECF7F4C9, 0x544F, 0x4D6D, 0x9D, 0x98, 0x8A, 0xD7, 0x9A, 0xDA, 0xF4, 0x53, 100); - -// Name: System.GPS.Status -- PKEY_GPS_Status -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 125491F4-818F-46B2-91B5-D537753617B2, 100 -// -// Indicates the status of the GPS receiver when the image was recorded. (eg: measurement in progress, -// measurement interoperability). -DEFINE_PROPERTYKEY(PKEY_GPS_Status, 0x125491F4, 0x818F, 0x46B2, 0x91, 0xB5, 0xD5, 0x37, 0x75, 0x36, 0x17, 0xB2, 100); - -// Name: System.GPS.Track -- PKEY_GPS_Track -// Type: Double -- VT_R8 -// FormatID: 76C09943-7C33-49E3-9E7E-CDBA872CFADA, 100 -// -// Indicates the direction of the GPS receiver movement. Calculated from PKEY_GPS_TrackNumerator and -// PKEY_GPS_TrackDenominator. -DEFINE_PROPERTYKEY(PKEY_GPS_Track, 0x76C09943, 0x7C33, 0x49E3, 0x9E, 0x7E, 0xCD, 0xBA, 0x87, 0x2C, 0xFA, 0xDA, 100); - -// Name: System.GPS.TrackDenominator -- PKEY_GPS_TrackDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: C8D1920C-01F6-40C0-AC86-2F3A4AD00770, 100 -// -// Denominator of PKEY_GPS_Track -DEFINE_PROPERTYKEY(PKEY_GPS_TrackDenominator, 0xC8D1920C, 0x01F6, 0x40C0, 0xAC, 0x86, 0x2F, 0x3A, 0x4A, 0xD0, 0x07, 0x70, 100); - -// Name: System.GPS.TrackNumerator -- PKEY_GPS_TrackNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 702926F4-44A6-43E1-AE71-45627116893B, 100 -// -// Numerator of PKEY_GPS_Track -DEFINE_PROPERTYKEY(PKEY_GPS_TrackNumerator, 0x702926F4, 0x44A6, 0x43E1, 0xAE, 0x71, 0x45, 0x62, 0x71, 0x16, 0x89, 0x3B, 100); - -// Name: System.GPS.TrackRef -- PKEY_GPS_TrackRef -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 35DBE6FE-44C3-4400-AAAE-D2C799C407E8, 100 -// -// Indicates reference for the direction of the GPS receiver movement. (eg: true direction, magnetic direction) -DEFINE_PROPERTYKEY(PKEY_GPS_TrackRef, 0x35DBE6FE, 0x44C3, 0x4400, 0xAA, 0xAE, 0xD2, 0xC7, 0x99, 0xC4, 0x07, 0xE8, 100); - -// Name: System.GPS.VersionID -- PKEY_GPS_VersionID -// Type: Buffer -- VT_VECTOR | VT_UI1 (For variants: VT_ARRAY | VT_UI1) -// FormatID: 22704DA4-C6B2-4A99-8E56-F16DF8C92599, 100 -// -// Indicates the version of the GPS information -DEFINE_PROPERTYKEY(PKEY_GPS_VersionID, 0x22704DA4, 0xC6B2, 0x4A99, 0x8E, 0x56, 0xF1, 0x6D, 0xF8, 0xC9, 0x25, 0x99, 100); - -//----------------------------------------------------------------------------- -// Image properties - - - -// Name: System.Image.BitDepth -- PKEY_Image_BitDepth -// Type: UInt32 -- VT_UI4 -// FormatID: (PSGUID_IMAGESUMMARYINFORMATION) 6444048F-4C8B-11D1-8B70-080036B11A03, 7 (PIDISI_BITDEPTH) -// -// -DEFINE_PROPERTYKEY(PKEY_Image_BitDepth, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 7); - -// Name: System.Image.ColorSpace -- PKEY_Image_ColorSpace -// Type: UInt16 -- VT_UI2 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 40961 -// -// PropertyTagExifColorSpace -DEFINE_PROPERTYKEY(PKEY_Image_ColorSpace, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 40961); - -// Possible discrete values for PKEY_Image_ColorSpace are: -#define IMAGE_COLORSPACE_SRGB 1u -#define IMAGE_COLORSPACE_UNCALIBRATED 0xFFFFu - -// Name: System.Image.CompressedBitsPerPixel -- PKEY_Image_CompressedBitsPerPixel -// Type: Double -- VT_R8 -// FormatID: 364B6FA9-37AB-482A-BE2B-AE02F60D4318, 100 -// -// Calculated from PKEY_Image_CompressedBitsPerPixelNumerator and PKEY_Image_CompressedBitsPerPixelDenominator. -DEFINE_PROPERTYKEY(PKEY_Image_CompressedBitsPerPixel, 0x364B6FA9, 0x37AB, 0x482A, 0xBE, 0x2B, 0xAE, 0x02, 0xF6, 0x0D, 0x43, 0x18, 100); - -// Name: System.Image.CompressedBitsPerPixelDenominator -- PKEY_Image_CompressedBitsPerPixelDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 1F8844E1-24AD-4508-9DFD-5326A415CE02, 100 -// -// Denominator of PKEY_Image_CompressedBitsPerPixel. -DEFINE_PROPERTYKEY(PKEY_Image_CompressedBitsPerPixelDenominator, 0x1F8844E1, 0x24AD, 0x4508, 0x9D, 0xFD, 0x53, 0x26, 0xA4, 0x15, 0xCE, 0x02, 100); - -// Name: System.Image.CompressedBitsPerPixelNumerator -- PKEY_Image_CompressedBitsPerPixelNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: D21A7148-D32C-4624-8900-277210F79C0F, 100 -// -// Numerator of PKEY_Image_CompressedBitsPerPixel. -DEFINE_PROPERTYKEY(PKEY_Image_CompressedBitsPerPixelNumerator, 0xD21A7148, 0xD32C, 0x4624, 0x89, 0x00, 0x27, 0x72, 0x10, 0xF7, 0x9C, 0x0F, 100); - -// Name: System.Image.Compression -- PKEY_Image_Compression -// Type: UInt16 -- VT_UI2 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 259 -// -// Indicates the image compression level. PropertyTagCompression. -DEFINE_PROPERTYKEY(PKEY_Image_Compression, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 259); - -// Possible discrete values for PKEY_Image_Compression are: -#define IMAGE_COMPRESSION_UNCOMPRESSED 1u -#define IMAGE_COMPRESSION_CCITT_T3 2u -#define IMAGE_COMPRESSION_CCITT_T4 3u -#define IMAGE_COMPRESSION_CCITT_T6 4u -#define IMAGE_COMPRESSION_LZW 5u -#define IMAGE_COMPRESSION_JPEG 6u -#define IMAGE_COMPRESSION_PACKBITS 32773u - -// Name: System.Image.CompressionText -- PKEY_Image_CompressionText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 3F08E66F-2F44-4BB9-A682-AC35D2562322, 100 -// -// This is the user-friendly form of System.Image.Compression. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Image_CompressionText, 0x3F08E66F, 0x2F44, 0x4BB9, 0xA6, 0x82, 0xAC, 0x35, 0xD2, 0x56, 0x23, 0x22, 100); - -// Name: System.Image.Dimensions -- PKEY_Image_Dimensions -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_IMAGESUMMARYINFORMATION) 6444048F-4C8B-11D1-8B70-080036B11A03, 13 (PIDISI_DIMENSIONS) -// -// Indicates the dimensions of the image. -DEFINE_PROPERTYKEY(PKEY_Image_Dimensions, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 13); - -// Name: System.Image.HorizontalResolution -- PKEY_Image_HorizontalResolution -// Type: Double -- VT_R8 -// FormatID: (PSGUID_IMAGESUMMARYINFORMATION) 6444048F-4C8B-11D1-8B70-080036B11A03, 5 (PIDISI_RESOLUTIONX) -// -// -DEFINE_PROPERTYKEY(PKEY_Image_HorizontalResolution, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 5); - -// Name: System.Image.HorizontalSize -- PKEY_Image_HorizontalSize -// Type: UInt32 -- VT_UI4 -// FormatID: (PSGUID_IMAGESUMMARYINFORMATION) 6444048F-4C8B-11D1-8B70-080036B11A03, 3 (PIDISI_CX) -// -// -DEFINE_PROPERTYKEY(PKEY_Image_HorizontalSize, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 3); - -// Name: System.Image.ImageID -- PKEY_Image_ImageID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 10DABE05-32AA-4C29-BF1A-63E2D220587F, 100 -DEFINE_PROPERTYKEY(PKEY_Image_ImageID, 0x10DABE05, 0x32AA, 0x4C29, 0xBF, 0x1A, 0x63, 0xE2, 0xD2, 0x20, 0x58, 0x7F, 100); - -// Name: System.Image.ResolutionUnit -- PKEY_Image_ResolutionUnit -// Type: Int16 -- VT_I2 -// FormatID: 19B51FA6-1F92-4A5C-AB48-7DF0ABD67444, 100 -DEFINE_PROPERTYKEY(PKEY_Image_ResolutionUnit, 0x19B51FA6, 0x1F92, 0x4A5C, 0xAB, 0x48, 0x7D, 0xF0, 0xAB, 0xD6, 0x74, 0x44, 100); - -// Name: System.Image.VerticalResolution -- PKEY_Image_VerticalResolution -// Type: Double -- VT_R8 -// FormatID: (PSGUID_IMAGESUMMARYINFORMATION) 6444048F-4C8B-11D1-8B70-080036B11A03, 6 (PIDISI_RESOLUTIONY) -// -// -DEFINE_PROPERTYKEY(PKEY_Image_VerticalResolution, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 6); - -// Name: System.Image.VerticalSize -- PKEY_Image_VerticalSize -// Type: UInt32 -- VT_UI4 -// FormatID: (PSGUID_IMAGESUMMARYINFORMATION) 6444048F-4C8B-11D1-8B70-080036B11A03, 4 (PIDISI_CY) -// -// -DEFINE_PROPERTYKEY(PKEY_Image_VerticalSize, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 4); - - - -//----------------------------------------------------------------------------- -// Journal properties - -// Name: System.Journal.Contacts -- PKEY_Journal_Contacts -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: DEA7C82C-1D89-4A66-9427-A4E3DEBABCB1, 100 -DEFINE_PROPERTYKEY(PKEY_Journal_Contacts, 0xDEA7C82C, 0x1D89, 0x4A66, 0x94, 0x27, 0xA4, 0xE3, 0xDE, 0xBA, 0xBC, 0xB1, 100); - -// Name: System.Journal.EntryType -- PKEY_Journal_EntryType -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 95BEB1FC-326D-4644-B396-CD3ED90E6DDF, 100 -DEFINE_PROPERTYKEY(PKEY_Journal_EntryType, 0x95BEB1FC, 0x326D, 0x4644, 0xB3, 0x96, 0xCD, 0x3E, 0xD9, 0x0E, 0x6D, 0xDF, 100); - -//----------------------------------------------------------------------------- -// Link properties - - - -// Name: System.Link.Comment -- PKEY_Link_Comment -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_LINK) B9B4B3FC-2B51-4A42-B5D8-324146AFCF25, 5 -DEFINE_PROPERTYKEY(PKEY_Link_Comment, 0xB9B4B3FC, 0x2B51, 0x4A42, 0xB5, 0xD8, 0x32, 0x41, 0x46, 0xAF, 0xCF, 0x25, 5); - -// Name: System.Link.DateVisited -- PKEY_Link_DateVisited -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 5CBF2787-48CF-4208-B90E-EE5E5D420294, 23 (PKEYs relating to URLs. Used by IE History.) -DEFINE_PROPERTYKEY(PKEY_Link_DateVisited, 0x5CBF2787, 0x48CF, 0x4208, 0xB9, 0x0E, 0xEE, 0x5E, 0x5D, 0x42, 0x02, 0x94, 23); - -// Name: System.Link.Description -- PKEY_Link_Description -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 5CBF2787-48CF-4208-B90E-EE5E5D420294, 21 (PKEYs relating to URLs. Used by IE History.) -DEFINE_PROPERTYKEY(PKEY_Link_Description, 0x5CBF2787, 0x48CF, 0x4208, 0xB9, 0x0E, 0xEE, 0x5E, 0x5D, 0x42, 0x02, 0x94, 21); - -// Name: System.Link.Status -- PKEY_Link_Status -// Type: Int32 -- VT_I4 -// FormatID: (PSGUID_LINK) B9B4B3FC-2B51-4A42-B5D8-324146AFCF25, 3 (PID_LINK_TARGET_TYPE) -// -// -DEFINE_PROPERTYKEY(PKEY_Link_Status, 0xB9B4B3FC, 0x2B51, 0x4A42, 0xB5, 0xD8, 0x32, 0x41, 0x46, 0xAF, 0xCF, 0x25, 3); - -// Possible discrete values for PKEY_Link_Status are: -#define LINK_STATUS_RESOLVED 1l -#define LINK_STATUS_BROKEN 2l - -// Name: System.Link.TargetExtension -- PKEY_Link_TargetExtension -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: 7A7D76F4-B630-4BD7-95FF-37CC51A975C9, 2 -// -// The file extension of the link target. See System.File.Extension -DEFINE_PROPERTYKEY(PKEY_Link_TargetExtension, 0x7A7D76F4, 0xB630, 0x4BD7, 0x95, 0xFF, 0x37, 0xCC, 0x51, 0xA9, 0x75, 0xC9, 2); - -// Name: System.Link.TargetParsingPath -- PKEY_Link_TargetParsingPath -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_LINK) B9B4B3FC-2B51-4A42-B5D8-324146AFCF25, 2 (PID_LINK_TARGET) -// -// This is the shell namespace path to the target of the link item. This path may be passed to -// SHParseDisplayName to parse the path to the correct shell folder. -// -// If the target item is a file, the value is identical to System.ItemPathDisplay. -// -// If the target item cannot be accessed through the shell namespace, this value is VT_EMPTY. -DEFINE_PROPERTYKEY(PKEY_Link_TargetParsingPath, 0xB9B4B3FC, 0x2B51, 0x4A42, 0xB5, 0xD8, 0x32, 0x41, 0x46, 0xAF, 0xCF, 0x25, 2); - -// Name: System.Link.TargetSFGAOFlags -- PKEY_Link_TargetSFGAOFlags -// Type: UInt32 -- VT_UI4 -// FormatID: (PSGUID_LINK) B9B4B3FC-2B51-4A42-B5D8-324146AFCF25, 8 -// -// IShellFolder::GetAttributesOf flags for the target of a link, with SFGAO_PKEYSFGAOMASK -// attributes masked out. -DEFINE_PROPERTYKEY(PKEY_Link_TargetSFGAOFlags, 0xB9B4B3FC, 0x2B51, 0x4A42, 0xB5, 0xD8, 0x32, 0x41, 0x46, 0xAF, 0xCF, 0x25, 8); - -//----------------------------------------------------------------------------- -// Media properties - - - -// Name: System.Media.AuthorUrl -- PKEY_Media_AuthorUrl -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 32 (PIDMSI_AUTHOR_URL) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_AuthorUrl, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 32); - -// Name: System.Media.AverageLevel -- PKEY_Media_AverageLevel -// Type: UInt32 -- VT_UI4 -// FormatID: 09EDD5B6-B301-43C5-9990-D00302EFFD46, 100 -DEFINE_PROPERTYKEY(PKEY_Media_AverageLevel, 0x09EDD5B6, 0xB301, 0x43C5, 0x99, 0x90, 0xD0, 0x03, 0x02, 0xEF, 0xFD, 0x46, 100); - -// Name: System.Media.ClassPrimaryID -- PKEY_Media_ClassPrimaryID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 13 (PIDMSI_CLASS_PRIMARY_ID) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_ClassPrimaryID, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 13); - -// Name: System.Media.ClassSecondaryID -- PKEY_Media_ClassSecondaryID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 14 (PIDMSI_CLASS_SECONDARY_ID) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_ClassSecondaryID, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 14); - -// Name: System.Media.CollectionGroupID -- PKEY_Media_CollectionGroupID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 24 (PIDMSI_COLLECTION_GROUP_ID) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_CollectionGroupID, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 24); - -// Name: System.Media.CollectionID -- PKEY_Media_CollectionID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 25 (PIDMSI_COLLECTION_ID) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_CollectionID, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 25); - -// Name: System.Media.ContentDistributor -- PKEY_Media_ContentDistributor -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 18 (PIDMSI_CONTENTDISTRIBUTOR) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_ContentDistributor, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 18); - -// Name: System.Media.ContentID -- PKEY_Media_ContentID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 26 (PIDMSI_CONTENT_ID) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_ContentID, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 26); - -// Name: System.Media.CreatorApplication -- PKEY_Media_CreatorApplication -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 27 (PIDMSI_TOOL_NAME) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_CreatorApplication, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 27); - -// Name: System.Media.CreatorApplicationVersion -- PKEY_Media_CreatorApplicationVersion -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 28 (PIDMSI_TOOL_VERSION) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_CreatorApplicationVersion, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 28); - -// Name: System.Media.DateEncoded -- PKEY_Media_DateEncoded -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 2E4B640D-5019-46D8-8881-55414CC5CAA0, 100 -// -// DateTime is in UTC (in the doc, not file system). -DEFINE_PROPERTYKEY(PKEY_Media_DateEncoded, 0x2E4B640D, 0x5019, 0x46D8, 0x88, 0x81, 0x55, 0x41, 0x4C, 0xC5, 0xCA, 0xA0, 100); - -// Name: System.Media.DateReleased -- PKEY_Media_DateReleased -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: DE41CC29-6971-4290-B472-F59F2E2F31E2, 100 -DEFINE_PROPERTYKEY(PKEY_Media_DateReleased, 0xDE41CC29, 0x6971, 0x4290, 0xB4, 0x72, 0xF5, 0x9F, 0x2E, 0x2F, 0x31, 0xE2, 100); - -// Name: System.Media.Duration -- PKEY_Media_Duration -// Type: UInt64 -- VT_UI8 -// FormatID: (FMTID_AudioSummaryInformation) 64440490-4C8B-11D1-8B70-080036B11A03, 3 (PIDASI_TIMELENGTH) -// -// 100ns units, not milliseconds -DEFINE_PROPERTYKEY(PKEY_Media_Duration, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 3); - -// Name: System.Media.DVDID -- PKEY_Media_DVDID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 15 (PIDMSI_DVDID) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_DVDID, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 15); - -// Name: System.Media.EncodedBy -- PKEY_Media_EncodedBy -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 36 (PIDMSI_ENCODED_BY) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_EncodedBy, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 36); - -// Name: System.Media.EncodingSettings -- PKEY_Media_EncodingSettings -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 37 (PIDMSI_ENCODING_SETTINGS) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_EncodingSettings, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 37); - -// Name: System.Media.FrameCount -- PKEY_Media_FrameCount -// Type: UInt32 -- VT_UI4 -// FormatID: (PSGUID_IMAGESUMMARYINFORMATION) 6444048F-4C8B-11D1-8B70-080036B11A03, 12 (PIDISI_FRAMECOUNT) -// -// Indicates the frame count for the image. -DEFINE_PROPERTYKEY(PKEY_Media_FrameCount, 0x6444048F, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 12); - -// Name: System.Media.MCDI -- PKEY_Media_MCDI -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 16 (PIDMSI_MCDI) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_MCDI, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 16); - -// Name: System.Media.MetadataContentProvider -- PKEY_Media_MetadataContentProvider -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 17 (PIDMSI_PROVIDER) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_MetadataContentProvider, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 17); - -// Name: System.Media.Producer -- PKEY_Media_Producer -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 22 (PIDMSI_PRODUCER) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_Producer, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 22); - -// Name: System.Media.PromotionUrl -- PKEY_Media_PromotionUrl -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 33 (PIDMSI_PROMOTION_URL) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_PromotionUrl, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 33); - -// Name: System.Media.ProtectionType -- PKEY_Media_ProtectionType -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 38 -// -// If media is protected, how is it protected? -DEFINE_PROPERTYKEY(PKEY_Media_ProtectionType, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 38); - -// Name: System.Media.ProviderRating -- PKEY_Media_ProviderRating -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 39 -// -// Rating (0 - 99) supplied by metadata provider -DEFINE_PROPERTYKEY(PKEY_Media_ProviderRating, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 39); - -// Name: System.Media.ProviderStyle -- PKEY_Media_ProviderStyle -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 40 -// -// Style of music or video, supplied by metadata provider -DEFINE_PROPERTYKEY(PKEY_Media_ProviderStyle, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 40); - -// Name: System.Media.Publisher -- PKEY_Media_Publisher -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 30 (PIDMSI_PUBLISHER) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_Publisher, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 30); - -// Name: System.Media.SubscriptionContentId -- PKEY_Media_SubscriptionContentId -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 9AEBAE7A-9644-487D-A92C-657585ED751A, 100 -DEFINE_PROPERTYKEY(PKEY_Media_SubscriptionContentId, 0x9AEBAE7A, 0x9644, 0x487D, 0xA9, 0x2C, 0x65, 0x75, 0x85, 0xED, 0x75, 0x1A, 100); - -// Name: System.Media.SubTitle -- PKEY_Media_SubTitle -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 38 (PIDSI_MUSIC_SUB_TITLE) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_SubTitle, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 38); - -// Name: System.Media.UniqueFileIdentifier -- PKEY_Media_UniqueFileIdentifier -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 35 (PIDMSI_UNIQUE_FILE_IDENTIFIER) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_UniqueFileIdentifier, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 35); - -// Name: System.Media.UserNoAutoInfo -- PKEY_Media_UserNoAutoInfo -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 41 -// -// If true, do NOT alter this file's metadata. Set by user. -DEFINE_PROPERTYKEY(PKEY_Media_UserNoAutoInfo, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 41); - -// Name: System.Media.UserWebUrl -- PKEY_Media_UserWebUrl -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 34 (PIDMSI_USER_WEB_URL) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_UserWebUrl, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 34); - -// Name: System.Media.Writer -- PKEY_Media_Writer -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 23 (PIDMSI_WRITER) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_Writer, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 23); - -// Name: System.Media.Year -- PKEY_Media_Year -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 5 (PIDSI_MUSIC_YEAR) -// -// -DEFINE_PROPERTYKEY(PKEY_Media_Year, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 5); - -//----------------------------------------------------------------------------- -// Message properties - - - -// Name: System.Message.AttachmentContents -- PKEY_Message_AttachmentContents -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 3143BF7C-80A8-4854-8880-E2E40189BDD0, 100 -DEFINE_PROPERTYKEY(PKEY_Message_AttachmentContents, 0x3143BF7C, 0x80A8, 0x4854, 0x88, 0x80, 0xE2, 0xE4, 0x01, 0x89, 0xBD, 0xD0, 100); - -// Name: System.Message.AttachmentNames -- PKEY_Message_AttachmentNames -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 21 -// -// The names of the attachments in a message -DEFINE_PROPERTYKEY(PKEY_Message_AttachmentNames, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 21); - -// Name: System.Message.BccAddress -- PKEY_Message_BccAddress -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 2 -// -// Addresses in Bcc: field -DEFINE_PROPERTYKEY(PKEY_Message_BccAddress, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 2); - -// Name: System.Message.BccName -- PKEY_Message_BccName -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 3 -// -// person names in Bcc: field -DEFINE_PROPERTYKEY(PKEY_Message_BccName, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 3); - -// Name: System.Message.CcAddress -- PKEY_Message_CcAddress -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 4 -// -// Addresses in Cc: field -DEFINE_PROPERTYKEY(PKEY_Message_CcAddress, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 4); - -// Name: System.Message.CcName -- PKEY_Message_CcName -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 5 -// -// person names in Cc: field -DEFINE_PROPERTYKEY(PKEY_Message_CcName, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 5); - -// Name: System.Message.ConversationID -- PKEY_Message_ConversationID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: DC8F80BD-AF1E-4289-85B6-3DFC1B493992, 100 -DEFINE_PROPERTYKEY(PKEY_Message_ConversationID, 0xDC8F80BD, 0xAF1E, 0x4289, 0x85, 0xB6, 0x3D, 0xFC, 0x1B, 0x49, 0x39, 0x92, 100); - -// Name: System.Message.ConversationIndex -- PKEY_Message_ConversationIndex -// Type: Buffer -- VT_VECTOR | VT_UI1 (For variants: VT_ARRAY | VT_UI1) -// FormatID: DC8F80BD-AF1E-4289-85B6-3DFC1B493992, 101 -// -// -DEFINE_PROPERTYKEY(PKEY_Message_ConversationIndex, 0xDC8F80BD, 0xAF1E, 0x4289, 0x85, 0xB6, 0x3D, 0xFC, 0x1B, 0x49, 0x39, 0x92, 101); - -// Name: System.Message.DateReceived -- PKEY_Message_DateReceived -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 20 -// -// Date and Time communication was received -DEFINE_PROPERTYKEY(PKEY_Message_DateReceived, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 20); - -// Name: System.Message.DateSent -- PKEY_Message_DateSent -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 19 -// -// Date and Time communication was sent -DEFINE_PROPERTYKEY(PKEY_Message_DateSent, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 19); - -// Name: System.Message.FromAddress -- PKEY_Message_FromAddress -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 13 -DEFINE_PROPERTYKEY(PKEY_Message_FromAddress, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 13); - -// Name: System.Message.FromName -- PKEY_Message_FromName -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 14 -// -// Address in from field as person name -DEFINE_PROPERTYKEY(PKEY_Message_FromName, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 14); - -// Name: System.Message.HasAttachments -- PKEY_Message_HasAttachments -// Type: Boolean -- VT_BOOL -// FormatID: 9C1FCF74-2D97-41BA-B4AE-CB2E3661A6E4, 8 -// -// -DEFINE_PROPERTYKEY(PKEY_Message_HasAttachments, 0x9C1FCF74, 0x2D97, 0x41BA, 0xB4, 0xAE, 0xCB, 0x2E, 0x36, 0x61, 0xA6, 0xE4, 8); - -// Name: System.Message.IsFwdOrReply -- PKEY_Message_IsFwdOrReply -// Type: Int32 -- VT_I4 -// FormatID: 9A9BC088-4F6D-469E-9919-E705412040F9, 100 -DEFINE_PROPERTYKEY(PKEY_Message_IsFwdOrReply, 0x9A9BC088, 0x4F6D, 0x469E, 0x99, 0x19, 0xE7, 0x05, 0x41, 0x20, 0x40, 0xF9, 100); - -// Name: System.Message.MessageClass -- PKEY_Message_MessageClass -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: CD9ED458-08CE-418F-A70E-F912C7BB9C5C, 103 -// -// What type of outlook msg this is (meeting, task, mail, etc.) -DEFINE_PROPERTYKEY(PKEY_Message_MessageClass, 0xCD9ED458, 0x08CE, 0x418F, 0xA7, 0x0E, 0xF9, 0x12, 0xC7, 0xBB, 0x9C, 0x5C, 103); - -// Name: System.Message.SenderAddress -- PKEY_Message_SenderAddress -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 0BE1C8E7-1981-4676-AE14-FDD78F05A6E7, 100 -DEFINE_PROPERTYKEY(PKEY_Message_SenderAddress, 0x0BE1C8E7, 0x1981, 0x4676, 0xAE, 0x14, 0xFD, 0xD7, 0x8F, 0x05, 0xA6, 0xE7, 100); - -// Name: System.Message.SenderName -- PKEY_Message_SenderName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 0DA41CFA-D224-4A18-AE2F-596158DB4B3A, 100 -DEFINE_PROPERTYKEY(PKEY_Message_SenderName, 0x0DA41CFA, 0xD224, 0x4A18, 0xAE, 0x2F, 0x59, 0x61, 0x58, 0xDB, 0x4B, 0x3A, 100); - -// Name: System.Message.Store -- PKEY_Message_Store -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 15 -// -// The store (aka protocol handler) FILE, MAIL, OUTLOOKEXPRESS -DEFINE_PROPERTYKEY(PKEY_Message_Store, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 15); - -// Name: System.Message.ToAddress -- PKEY_Message_ToAddress -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 16 -// -// Addresses in To: field -DEFINE_PROPERTYKEY(PKEY_Message_ToAddress, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 16); - -// Name: System.Message.ToDoTitle -- PKEY_Message_ToDoTitle -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: BCCC8A3C-8CEF-42E5-9B1C-C69079398BC7, 100 -DEFINE_PROPERTYKEY(PKEY_Message_ToDoTitle, 0xBCCC8A3C, 0x8CEF, 0x42E5, 0x9B, 0x1C, 0xC6, 0x90, 0x79, 0x39, 0x8B, 0xC7, 100); - -// Name: System.Message.ToName -- PKEY_Message_ToName -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD, 17 -// -// Person names in To: field -DEFINE_PROPERTYKEY(PKEY_Message_ToName, 0xE3E0584C, 0xB788, 0x4A5A, 0xBB, 0x20, 0x7F, 0x5A, 0x44, 0xC9, 0xAC, 0xDD, 17); - -//----------------------------------------------------------------------------- -// Music properties - -// Name: System.Music.AlbumArtist -- PKEY_Music_AlbumArtist -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 13 (PIDSI_MUSIC_ALBUM_ARTIST) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_AlbumArtist, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 13); - -// Name: System.Music.AlbumTitle -- PKEY_Music_AlbumTitle -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 4 (PIDSI_MUSIC_ALBUM) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_AlbumTitle, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 4); - -// Name: System.Music.Artist -- PKEY_Music_Artist -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 2 (PIDSI_MUSIC_ARTIST) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_Artist, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 2); - -// Name: System.Music.BeatsPerMinute -- PKEY_Music_BeatsPerMinute -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 35 (PIDSI_MUSIC_BEATS_PER_MINUTE) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_BeatsPerMinute, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 35); - -// Name: System.Music.Composer -- PKEY_Music_Composer -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 19 (PIDMSI_COMPOSER) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_Composer, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 19); - -// Name: System.Music.Conductor -- PKEY_Music_Conductor -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 36 (PIDSI_MUSIC_CONDUCTOR) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_Conductor, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 36); - -// Name: System.Music.ContentGroupDescription -- PKEY_Music_ContentGroupDescription -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 33 (PIDSI_MUSIC_CONTENT_GROUP_DESCRIPTION) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_ContentGroupDescription, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 33); - -// Name: System.Music.Genre -- PKEY_Music_Genre -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 11 (PIDSI_MUSIC_GENRE) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_Genre, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 11); - -// Name: System.Music.InitialKey -- PKEY_Music_InitialKey -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 34 (PIDSI_MUSIC_INITIAL_KEY) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_InitialKey, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 34); - -// Name: System.Music.Lyrics -- PKEY_Music_Lyrics -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 12 (PIDSI_MUSIC_LYRICS) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_Lyrics, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 12); - -// Name: System.Music.Mood -- PKEY_Music_Mood -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 39 (PIDSI_MUSIC_MOOD) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_Mood, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 39); - -// Name: System.Music.PartOfSet -- PKEY_Music_PartOfSet -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 37 (PIDSI_MUSIC_PART_OF_SET) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_PartOfSet, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 37); - -// Name: System.Music.Period -- PKEY_Music_Period -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 31 (PIDMSI_PERIOD) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_Period, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 31); - -// Name: System.Music.SynchronizedLyrics -- PKEY_Music_SynchronizedLyrics -// Type: Blob -- VT_BLOB -// FormatID: 6B223B6A-162E-4AA9-B39F-05D678FC6D77, 100 -DEFINE_PROPERTYKEY(PKEY_Music_SynchronizedLyrics, 0x6B223B6A, 0x162E, 0x4AA9, 0xB3, 0x9F, 0x05, 0xD6, 0x78, 0xFC, 0x6D, 0x77, 100); - -// Name: System.Music.TrackNumber -- PKEY_Music_TrackNumber -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_MUSIC) 56A3372E-CE9C-11D2-9F0E-006097C686F6, 7 (PIDSI_MUSIC_TRACK) -// -// -DEFINE_PROPERTYKEY(PKEY_Music_TrackNumber, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 7); - - - -//----------------------------------------------------------------------------- -// Note properties - -// Name: System.Note.Color -- PKEY_Note_Color -// Type: UInt16 -- VT_UI2 -// FormatID: 4776CAFA-BCE4-4CB1-A23E-265E76D8EB11, 100 -DEFINE_PROPERTYKEY(PKEY_Note_Color, 0x4776CAFA, 0xBCE4, 0x4CB1, 0xA2, 0x3E, 0x26, 0x5E, 0x76, 0xD8, 0xEB, 0x11, 100); - -// Possible discrete values for PKEY_Note_Color are: -#define NOTE_COLOR_BLUE 0u -#define NOTE_COLOR_GREEN 1u -#define NOTE_COLOR_PINK 2u -#define NOTE_COLOR_YELLOW 3u -#define NOTE_COLOR_WHITE 4u -#define NOTE_COLOR_LIGHTGREEN 5u - -// Name: System.Note.ColorText -- PKEY_Note_ColorText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 46B4E8DE-CDB2-440D-885C-1658EB65B914, 100 -// -// This is the user-friendly form of System.Note.Color. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Note_ColorText, 0x46B4E8DE, 0xCDB2, 0x440D, 0x88, 0x5C, 0x16, 0x58, 0xEB, 0x65, 0xB9, 0x14, 100); - -//----------------------------------------------------------------------------- -// Photo properties - - - -// Name: System.Photo.Aperture -- PKEY_Photo_Aperture -// Type: Double -- VT_R8 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 37378 -// -// PropertyTagExifAperture. Calculated from PKEY_Photo_ApertureNumerator and PKEY_Photo_ApertureDenominator -DEFINE_PROPERTYKEY(PKEY_Photo_Aperture, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 37378); - -// Name: System.Photo.ApertureDenominator -- PKEY_Photo_ApertureDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: E1A9A38B-6685-46BD-875E-570DC7AD7320, 100 -// -// Denominator of PKEY_Photo_Aperture -DEFINE_PROPERTYKEY(PKEY_Photo_ApertureDenominator, 0xE1A9A38B, 0x6685, 0x46BD, 0x87, 0x5E, 0x57, 0x0D, 0xC7, 0xAD, 0x73, 0x20, 100); - -// Name: System.Photo.ApertureNumerator -- PKEY_Photo_ApertureNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 0337ECEC-39FB-4581-A0BD-4C4CC51E9914, 100 -// -// Numerator of PKEY_Photo_Aperture -DEFINE_PROPERTYKEY(PKEY_Photo_ApertureNumerator, 0x0337ECEC, 0x39FB, 0x4581, 0xA0, 0xBD, 0x4C, 0x4C, 0xC5, 0x1E, 0x99, 0x14, 100); - -// Name: System.Photo.Brightness -- PKEY_Photo_Brightness -// Type: Double -- VT_R8 -// FormatID: 1A701BF6-478C-4361-83AB-3701BB053C58, 100 (PropertyTagExifBrightness) -// -// This is the brightness of the photo. -// -// Calculated from PKEY_Photo_BrightnessNumerator and PKEY_Photo_BrightnessDenominator. -// -// The units are "APEX", normally in the range of -99.99 to 99.99. If the numerator of -// the recorded value is FFFFFFFF.H, "Unknown" should be indicated. -DEFINE_PROPERTYKEY(PKEY_Photo_Brightness, 0x1A701BF6, 0x478C, 0x4361, 0x83, 0xAB, 0x37, 0x01, 0xBB, 0x05, 0x3C, 0x58, 100); - -// Name: System.Photo.BrightnessDenominator -- PKEY_Photo_BrightnessDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 6EBE6946-2321-440A-90F0-C043EFD32476, 100 -// -// Denominator of PKEY_Photo_Brightness -DEFINE_PROPERTYKEY(PKEY_Photo_BrightnessDenominator, 0x6EBE6946, 0x2321, 0x440A, 0x90, 0xF0, 0xC0, 0x43, 0xEF, 0xD3, 0x24, 0x76, 100); - -// Name: System.Photo.BrightnessNumerator -- PKEY_Photo_BrightnessNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 9E7D118F-B314-45A0-8CFB-D654B917C9E9, 100 -// -// Numerator of PKEY_Photo_Brightness -DEFINE_PROPERTYKEY(PKEY_Photo_BrightnessNumerator, 0x9E7D118F, 0xB314, 0x45A0, 0x8C, 0xFB, 0xD6, 0x54, 0xB9, 0x17, 0xC9, 0xE9, 100); - -// Name: System.Photo.CameraManufacturer -- PKEY_Photo_CameraManufacturer -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 271 (PropertyTagEquipMake) -// -// -DEFINE_PROPERTYKEY(PKEY_Photo_CameraManufacturer, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 271); - -// Name: System.Photo.CameraModel -- PKEY_Photo_CameraModel -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 272 (PropertyTagEquipModel) -// -// -DEFINE_PROPERTYKEY(PKEY_Photo_CameraModel, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 272); - -// Name: System.Photo.CameraSerialNumber -- PKEY_Photo_CameraSerialNumber -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 273 -// -// Serial number of camera that produced this photo -DEFINE_PROPERTYKEY(PKEY_Photo_CameraSerialNumber, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 273); - -// Name: System.Photo.Contrast -- PKEY_Photo_Contrast -// Type: UInt32 -- VT_UI4 -// FormatID: 2A785BA9-8D23-4DED-82E6-60A350C86A10, 100 -// -// This indicates the direction of contrast processing applied by the camera -// when the image was shot. -DEFINE_PROPERTYKEY(PKEY_Photo_Contrast, 0x2A785BA9, 0x8D23, 0x4DED, 0x82, 0xE6, 0x60, 0xA3, 0x50, 0xC8, 0x6A, 0x10, 100); - -// Possible discrete values for PKEY_Photo_Contrast are: -#define PHOTO_CONTRAST_NORMAL 0ul -#define PHOTO_CONTRAST_SOFT 1ul -#define PHOTO_CONTRAST_HARD 2ul - -// Name: System.Photo.ContrastText -- PKEY_Photo_ContrastText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 59DDE9F2-5253-40EA-9A8B-479E96C6249A, 100 -// -// This is the user-friendly form of System.Photo.Contrast. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Photo_ContrastText, 0x59DDE9F2, 0x5253, 0x40EA, 0x9A, 0x8B, 0x47, 0x9E, 0x96, 0xC6, 0x24, 0x9A, 100); - -// Name: System.Photo.DateTaken -- PKEY_Photo_DateTaken -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 36867 -// -// PropertyTagExifDTOrig -DEFINE_PROPERTYKEY(PKEY_Photo_DateTaken, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 36867); - -// Name: System.Photo.DigitalZoom -- PKEY_Photo_DigitalZoom -// Type: Double -- VT_R8 -// FormatID: F85BF840-A925-4BC2-B0C4-8E36B598679E, 100 -// -// PropertyTagExifDigitalZoom. Calculated from PKEY_Photo_DigitalZoomNumerator and PKEY_Photo_DigitalZoomDenominator -DEFINE_PROPERTYKEY(PKEY_Photo_DigitalZoom, 0xF85BF840, 0xA925, 0x4BC2, 0xB0, 0xC4, 0x8E, 0x36, 0xB5, 0x98, 0x67, 0x9E, 100); - -// Name: System.Photo.DigitalZoomDenominator -- PKEY_Photo_DigitalZoomDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 745BAF0E-E5C1-4CFB-8A1B-D031A0A52393, 100 -// -// Denominator of PKEY_Photo_DigitalZoom -DEFINE_PROPERTYKEY(PKEY_Photo_DigitalZoomDenominator, 0x745BAF0E, 0xE5C1, 0x4CFB, 0x8A, 0x1B, 0xD0, 0x31, 0xA0, 0xA5, 0x23, 0x93, 100); - -// Name: System.Photo.DigitalZoomNumerator -- PKEY_Photo_DigitalZoomNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 16CBB924-6500-473B-A5BE-F1599BCBE413, 100 -// -// Numerator of PKEY_Photo_DigitalZoom -DEFINE_PROPERTYKEY(PKEY_Photo_DigitalZoomNumerator, 0x16CBB924, 0x6500, 0x473B, 0xA5, 0xBE, 0xF1, 0x59, 0x9B, 0xCB, 0xE4, 0x13, 100); - -// Name: System.Photo.Event -- PKEY_Photo_Event -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 18248 -// -// The event at which the photo was taken -DEFINE_PROPERTYKEY(PKEY_Photo_Event, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 18248); - -// Name: System.Photo.EXIFVersion -- PKEY_Photo_EXIFVersion -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: D35F743A-EB2E-47F2-A286-844132CB1427, 100 -// -// The EXIF version. -DEFINE_PROPERTYKEY(PKEY_Photo_EXIFVersion, 0xD35F743A, 0xEB2E, 0x47F2, 0xA2, 0x86, 0x84, 0x41, 0x32, 0xCB, 0x14, 0x27, 100); - -// Name: System.Photo.ExposureBias -- PKEY_Photo_ExposureBias -// Type: Double -- VT_R8 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 37380 -// -// PropertyTagExifExposureBias. Calculated from PKEY_Photo_ExposureBiasNumerator and PKEY_Photo_ExposureBiasDenominator -DEFINE_PROPERTYKEY(PKEY_Photo_ExposureBias, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 37380); - -// Name: System.Photo.ExposureBiasDenominator -- PKEY_Photo_ExposureBiasDenominator -// Type: Int32 -- VT_I4 -// FormatID: AB205E50-04B7-461C-A18C-2F233836E627, 100 -// -// Denominator of PKEY_Photo_ExposureBias -DEFINE_PROPERTYKEY(PKEY_Photo_ExposureBiasDenominator, 0xAB205E50, 0x04B7, 0x461C, 0xA1, 0x8C, 0x2F, 0x23, 0x38, 0x36, 0xE6, 0x27, 100); - -// Name: System.Photo.ExposureBiasNumerator -- PKEY_Photo_ExposureBiasNumerator -// Type: Int32 -- VT_I4 -// FormatID: 738BF284-1D87-420B-92CF-5834BF6EF9ED, 100 -// -// Numerator of PKEY_Photo_ExposureBias -DEFINE_PROPERTYKEY(PKEY_Photo_ExposureBiasNumerator, 0x738BF284, 0x1D87, 0x420B, 0x92, 0xCF, 0x58, 0x34, 0xBF, 0x6E, 0xF9, 0xED, 100); - -// Name: System.Photo.ExposureIndex -- PKEY_Photo_ExposureIndex -// Type: Double -- VT_R8 -// FormatID: 967B5AF8-995A-46ED-9E11-35B3C5B9782D, 100 -// -// PropertyTagExifExposureIndex. Calculated from PKEY_Photo_ExposureIndexNumerator and PKEY_Photo_ExposureIndexDenominator -DEFINE_PROPERTYKEY(PKEY_Photo_ExposureIndex, 0x967B5AF8, 0x995A, 0x46ED, 0x9E, 0x11, 0x35, 0xB3, 0xC5, 0xB9, 0x78, 0x2D, 100); - -// Name: System.Photo.ExposureIndexDenominator -- PKEY_Photo_ExposureIndexDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 93112F89-C28B-492F-8A9D-4BE2062CEE8A, 100 -// -// Denominator of PKEY_Photo_ExposureIndex -DEFINE_PROPERTYKEY(PKEY_Photo_ExposureIndexDenominator, 0x93112F89, 0xC28B, 0x492F, 0x8A, 0x9D, 0x4B, 0xE2, 0x06, 0x2C, 0xEE, 0x8A, 100); - -// Name: System.Photo.ExposureIndexNumerator -- PKEY_Photo_ExposureIndexNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: CDEDCF30-8919-44DF-8F4C-4EB2FFDB8D89, 100 -// -// Numerator of PKEY_Photo_ExposureIndex -DEFINE_PROPERTYKEY(PKEY_Photo_ExposureIndexNumerator, 0xCDEDCF30, 0x8919, 0x44DF, 0x8F, 0x4C, 0x4E, 0xB2, 0xFF, 0xDB, 0x8D, 0x89, 100); - -// Name: System.Photo.ExposureProgram -- PKEY_Photo_ExposureProgram -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 34850 (PropertyTagExifExposureProg) -// -// -DEFINE_PROPERTYKEY(PKEY_Photo_ExposureProgram, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 34850); - -// Possible discrete values for PKEY_Photo_ExposureProgram are: -#define PHOTO_EXPOSUREPROGRAM_UNKNOWN 0ul -#define PHOTO_EXPOSUREPROGRAM_MANUAL 1ul -#define PHOTO_EXPOSUREPROGRAM_NORMAL 2ul -#define PHOTO_EXPOSUREPROGRAM_APERTURE 3ul -#define PHOTO_EXPOSUREPROGRAM_SHUTTER 4ul -#define PHOTO_EXPOSUREPROGRAM_CREATIVE 5ul -#define PHOTO_EXPOSUREPROGRAM_ACTION 6ul -#define PHOTO_EXPOSUREPROGRAM_PORTRAIT 7ul -#define PHOTO_EXPOSUREPROGRAM_LANDSCAPE 8ul - -// Name: System.Photo.ExposureProgramText -- PKEY_Photo_ExposureProgramText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: FEC690B7-5F30-4646-AE47-4CAAFBA884A3, 100 -// -// This is the user-friendly form of System.Photo.ExposureProgram. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Photo_ExposureProgramText, 0xFEC690B7, 0x5F30, 0x4646, 0xAE, 0x47, 0x4C, 0xAA, 0xFB, 0xA8, 0x84, 0xA3, 100); - -// Name: System.Photo.ExposureTime -- PKEY_Photo_ExposureTime -// Type: Double -- VT_R8 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 33434 -// -// PropertyTagExifExposureTime. Calculated from PKEY_Photo_ExposureTimeNumerator and PKEY_Photo_ExposureTimeDenominator -DEFINE_PROPERTYKEY(PKEY_Photo_ExposureTime, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 33434); - -// Name: System.Photo.ExposureTimeDenominator -- PKEY_Photo_ExposureTimeDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 55E98597-AD16-42E0-B624-21599A199838, 100 -// -// Denominator of PKEY_Photo_ExposureTime -DEFINE_PROPERTYKEY(PKEY_Photo_ExposureTimeDenominator, 0x55E98597, 0xAD16, 0x42E0, 0xB6, 0x24, 0x21, 0x59, 0x9A, 0x19, 0x98, 0x38, 100); - -// Name: System.Photo.ExposureTimeNumerator -- PKEY_Photo_ExposureTimeNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 257E44E2-9031-4323-AC38-85C552871B2E, 100 -// -// Numerator of PKEY_Photo_ExposureTime -DEFINE_PROPERTYKEY(PKEY_Photo_ExposureTimeNumerator, 0x257E44E2, 0x9031, 0x4323, 0xAC, 0x38, 0x85, 0xC5, 0x52, 0x87, 0x1B, 0x2E, 100); - -// Name: System.Photo.Flash -- PKEY_Photo_Flash -// Type: Byte -- VT_UI1 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 37385 -// -// PropertyTagExifFlash -DEFINE_PROPERTYKEY(PKEY_Photo_Flash, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 37385); - -// Possible discrete values for PKEY_Photo_Flash are: -#define PHOTO_FLASH_NONE 0 -#define PHOTO_FLASH_FLASH 1 -#define PHOTO_FLASH_WITHOUTSTROBE 5 -#define PHOTO_FLASH_WITHSTROBE 7 - -// Name: System.Photo.FlashEnergy -- PKEY_Photo_FlashEnergy -// Type: Double -- VT_R8 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 41483 -// -// PropertyTagExifFlashEnergy. Calculated from PKEY_Photo_FlashEnergyNumerator and PKEY_Photo_FlashEnergyDenominator -DEFINE_PROPERTYKEY(PKEY_Photo_FlashEnergy, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 41483); - -// Name: System.Photo.FlashEnergyDenominator -- PKEY_Photo_FlashEnergyDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: D7B61C70-6323-49CD-A5FC-C84277162C97, 100 -// -// Denominator of PKEY_Photo_FlashEnergy -DEFINE_PROPERTYKEY(PKEY_Photo_FlashEnergyDenominator, 0xD7B61C70, 0x6323, 0x49CD, 0xA5, 0xFC, 0xC8, 0x42, 0x77, 0x16, 0x2C, 0x97, 100); - -// Name: System.Photo.FlashEnergyNumerator -- PKEY_Photo_FlashEnergyNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: FCAD3D3D-0858-400F-AAA3-2F66CCE2A6BC, 100 -// -// Numerator of PKEY_Photo_FlashEnergy -DEFINE_PROPERTYKEY(PKEY_Photo_FlashEnergyNumerator, 0xFCAD3D3D, 0x0858, 0x400F, 0xAA, 0xA3, 0x2F, 0x66, 0xCC, 0xE2, 0xA6, 0xBC, 100); - -// Name: System.Photo.FlashManufacturer -- PKEY_Photo_FlashManufacturer -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: AABAF6C9-E0C5-4719-8585-57B103E584FE, 100 -DEFINE_PROPERTYKEY(PKEY_Photo_FlashManufacturer, 0xAABAF6C9, 0xE0C5, 0x4719, 0x85, 0x85, 0x57, 0xB1, 0x03, 0xE5, 0x84, 0xFE, 100); - -// Name: System.Photo.FlashModel -- PKEY_Photo_FlashModel -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: FE83BB35-4D1A-42E2-916B-06F3E1AF719E, 100 -DEFINE_PROPERTYKEY(PKEY_Photo_FlashModel, 0xFE83BB35, 0x4D1A, 0x42E2, 0x91, 0x6B, 0x06, 0xF3, 0xE1, 0xAF, 0x71, 0x9E, 100); - -// Name: System.Photo.FlashText -- PKEY_Photo_FlashText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 6B8B68F6-200B-47EA-8D25-D8050F57339F, 100 -// -// This is the user-friendly form of System.Photo.Flash. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Photo_FlashText, 0x6B8B68F6, 0x200B, 0x47EA, 0x8D, 0x25, 0xD8, 0x05, 0x0F, 0x57, 0x33, 0x9F, 100); - -// Name: System.Photo.FNumber -- PKEY_Photo_FNumber -// Type: Double -- VT_R8 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 33437 -// -// PropertyTagExifFNumber. Calculated from PKEY_Photo_FNumberNumerator and PKEY_Photo_FNumberDenominator -DEFINE_PROPERTYKEY(PKEY_Photo_FNumber, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 33437); - -// Name: System.Photo.FNumberDenominator -- PKEY_Photo_FNumberDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: E92A2496-223B-4463-A4E3-30EABBA79D80, 100 -// -// Denominator of PKEY_Photo_FNumber -DEFINE_PROPERTYKEY(PKEY_Photo_FNumberDenominator, 0xE92A2496, 0x223B, 0x4463, 0xA4, 0xE3, 0x30, 0xEA, 0xBB, 0xA7, 0x9D, 0x80, 100); - -// Name: System.Photo.FNumberNumerator -- PKEY_Photo_FNumberNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 1B97738A-FDFC-462F-9D93-1957E08BE90C, 100 -// -// Numerator of PKEY_Photo_FNumber -DEFINE_PROPERTYKEY(PKEY_Photo_FNumberNumerator, 0x1B97738A, 0xFDFC, 0x462F, 0x9D, 0x93, 0x19, 0x57, 0xE0, 0x8B, 0xE9, 0x0C, 100); - -// Name: System.Photo.FocalLength -- PKEY_Photo_FocalLength -// Type: Double -- VT_R8 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 37386 -// -// PropertyTagExifFocalLength. Calculated from PKEY_Photo_FocalLengthNumerator and PKEY_Photo_FocalLengthDenominator -DEFINE_PROPERTYKEY(PKEY_Photo_FocalLength, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 37386); - -// Name: System.Photo.FocalLengthDenominator -- PKEY_Photo_FocalLengthDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 305BC615-DCA1-44A5-9FD4-10C0BA79412E, 100 -// -// Denominator of PKEY_Photo_FocalLength -DEFINE_PROPERTYKEY(PKEY_Photo_FocalLengthDenominator, 0x305BC615, 0xDCA1, 0x44A5, 0x9F, 0xD4, 0x10, 0xC0, 0xBA, 0x79, 0x41, 0x2E, 100); - -// Name: System.Photo.FocalLengthInFilm -- PKEY_Photo_FocalLengthInFilm -// Type: UInt16 -- VT_UI2 -// FormatID: A0E74609-B84D-4F49-B860-462BD9971F98, 100 -DEFINE_PROPERTYKEY(PKEY_Photo_FocalLengthInFilm, 0xA0E74609, 0xB84D, 0x4F49, 0xB8, 0x60, 0x46, 0x2B, 0xD9, 0x97, 0x1F, 0x98, 100); - -// Name: System.Photo.FocalLengthNumerator -- PKEY_Photo_FocalLengthNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 776B6B3B-1E3D-4B0C-9A0E-8FBAF2A8492A, 100 -// -// Numerator of PKEY_Photo_FocalLength -DEFINE_PROPERTYKEY(PKEY_Photo_FocalLengthNumerator, 0x776B6B3B, 0x1E3D, 0x4B0C, 0x9A, 0x0E, 0x8F, 0xBA, 0xF2, 0xA8, 0x49, 0x2A, 100); - -// Name: System.Photo.FocalPlaneXResolution -- PKEY_Photo_FocalPlaneXResolution -// Type: Double -- VT_R8 -// FormatID: CFC08D97-C6F7-4484-89DD-EBEF4356FE76, 100 -// -// PropertyTagExifFocalXRes. Calculated from PKEY_Photo_FocalPlaneXResolutionNumerator and -// PKEY_Photo_FocalPlaneXResolutionDenominator. -DEFINE_PROPERTYKEY(PKEY_Photo_FocalPlaneXResolution, 0xCFC08D97, 0xC6F7, 0x4484, 0x89, 0xDD, 0xEB, 0xEF, 0x43, 0x56, 0xFE, 0x76, 100); - -// Name: System.Photo.FocalPlaneXResolutionDenominator -- PKEY_Photo_FocalPlaneXResolutionDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 0933F3F5-4786-4F46-A8E8-D64DD37FA521, 100 -// -// Denominator of PKEY_Photo_FocalPlaneXResolution -DEFINE_PROPERTYKEY(PKEY_Photo_FocalPlaneXResolutionDenominator, 0x0933F3F5, 0x4786, 0x4F46, 0xA8, 0xE8, 0xD6, 0x4D, 0xD3, 0x7F, 0xA5, 0x21, 100); - -// Name: System.Photo.FocalPlaneXResolutionNumerator -- PKEY_Photo_FocalPlaneXResolutionNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: DCCB10AF-B4E2-4B88-95F9-031B4D5AB490, 100 -// -// Numerator of PKEY_Photo_FocalPlaneXResolution -DEFINE_PROPERTYKEY(PKEY_Photo_FocalPlaneXResolutionNumerator, 0xDCCB10AF, 0xB4E2, 0x4B88, 0x95, 0xF9, 0x03, 0x1B, 0x4D, 0x5A, 0xB4, 0x90, 100); - -// Name: System.Photo.FocalPlaneYResolution -- PKEY_Photo_FocalPlaneYResolution -// Type: Double -- VT_R8 -// FormatID: 4FFFE4D0-914F-4AC4-8D6F-C9C61DE169B1, 100 -// -// PropertyTagExifFocalYRes. Calculated from PKEY_Photo_FocalPlaneYResolutionNumerator and -// PKEY_Photo_FocalPlaneYResolutionDenominator. -DEFINE_PROPERTYKEY(PKEY_Photo_FocalPlaneYResolution, 0x4FFFE4D0, 0x914F, 0x4AC4, 0x8D, 0x6F, 0xC9, 0xC6, 0x1D, 0xE1, 0x69, 0xB1, 100); - -// Name: System.Photo.FocalPlaneYResolutionDenominator -- PKEY_Photo_FocalPlaneYResolutionDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 1D6179A6-A876-4031-B013-3347B2B64DC8, 100 -// -// Denominator of PKEY_Photo_FocalPlaneYResolution -DEFINE_PROPERTYKEY(PKEY_Photo_FocalPlaneYResolutionDenominator, 0x1D6179A6, 0xA876, 0x4031, 0xB0, 0x13, 0x33, 0x47, 0xB2, 0xB6, 0x4D, 0xC8, 100); - -// Name: System.Photo.FocalPlaneYResolutionNumerator -- PKEY_Photo_FocalPlaneYResolutionNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: A2E541C5-4440-4BA8-867E-75CFC06828CD, 100 -// -// Numerator of PKEY_Photo_FocalPlaneYResolution -DEFINE_PROPERTYKEY(PKEY_Photo_FocalPlaneYResolutionNumerator, 0xA2E541C5, 0x4440, 0x4BA8, 0x86, 0x7E, 0x75, 0xCF, 0xC0, 0x68, 0x28, 0xCD, 100); - -// Name: System.Photo.GainControl -- PKEY_Photo_GainControl -// Type: Double -- VT_R8 -// FormatID: FA304789-00C7-4D80-904A-1E4DCC7265AA, 100 (PropertyTagExifGainControl) -// -// This indicates the degree of overall image gain adjustment. -// -// Calculated from PKEY_Photo_GainControlNumerator and PKEY_Photo_GainControlDenominator. -DEFINE_PROPERTYKEY(PKEY_Photo_GainControl, 0xFA304789, 0x00C7, 0x4D80, 0x90, 0x4A, 0x1E, 0x4D, 0xCC, 0x72, 0x65, 0xAA, 100); - -// Possible discrete values for PKEY_Photo_GainControl are: -#define PHOTO_GAINCONTROL_NONE 0.0 -#define PHOTO_GAINCONTROL_LOWGAINUP 1.0 -#define PHOTO_GAINCONTROL_HIGHGAINUP 2.0 -#define PHOTO_GAINCONTROL_LOWGAINDOWN 3.0 -#define PHOTO_GAINCONTROL_HIGHGAINDOWN 4.0 - -// Name: System.Photo.GainControlDenominator -- PKEY_Photo_GainControlDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 42864DFD-9DA4-4F77-BDED-4AAD7B256735, 100 -// -// Denominator of PKEY_Photo_GainControl -DEFINE_PROPERTYKEY(PKEY_Photo_GainControlDenominator, 0x42864DFD, 0x9DA4, 0x4F77, 0xBD, 0xED, 0x4A, 0xAD, 0x7B, 0x25, 0x67, 0x35, 100); - -// Name: System.Photo.GainControlNumerator -- PKEY_Photo_GainControlNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 8E8ECF7C-B7B8-4EB8-A63F-0EE715C96F9E, 100 -// -// Numerator of PKEY_Photo_GainControl -DEFINE_PROPERTYKEY(PKEY_Photo_GainControlNumerator, 0x8E8ECF7C, 0xB7B8, 0x4EB8, 0xA6, 0x3F, 0x0E, 0xE7, 0x15, 0xC9, 0x6F, 0x9E, 100); - -// Name: System.Photo.GainControlText -- PKEY_Photo_GainControlText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C06238B2-0BF9-4279-A723-25856715CB9D, 100 -// -// This is the user-friendly form of System.Photo.GainControl. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Photo_GainControlText, 0xC06238B2, 0x0BF9, 0x4279, 0xA7, 0x23, 0x25, 0x85, 0x67, 0x15, 0xCB, 0x9D, 100); - -// Name: System.Photo.ISOSpeed -- PKEY_Photo_ISOSpeed -// Type: UInt16 -- VT_UI2 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 34855 -// -// PropertyTagExifISOSpeed -DEFINE_PROPERTYKEY(PKEY_Photo_ISOSpeed, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 34855); - -// Name: System.Photo.LensManufacturer -- PKEY_Photo_LensManufacturer -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: E6DDCAF7-29C5-4F0A-9A68-D19412EC7090, 100 -DEFINE_PROPERTYKEY(PKEY_Photo_LensManufacturer, 0xE6DDCAF7, 0x29C5, 0x4F0A, 0x9A, 0x68, 0xD1, 0x94, 0x12, 0xEC, 0x70, 0x90, 100); - -// Name: System.Photo.LensModel -- PKEY_Photo_LensModel -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: E1277516-2B5F-4869-89B1-2E585BD38B7A, 100 -DEFINE_PROPERTYKEY(PKEY_Photo_LensModel, 0xE1277516, 0x2B5F, 0x4869, 0x89, 0xB1, 0x2E, 0x58, 0x5B, 0xD3, 0x8B, 0x7A, 100); - -// Name: System.Photo.LightSource -- PKEY_Photo_LightSource -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 37384 -// -// PropertyTagExifLightSource -DEFINE_PROPERTYKEY(PKEY_Photo_LightSource, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 37384); - -// Possible discrete values for PKEY_Photo_LightSource are: -#define PHOTO_LIGHTSOURCE_UNKNOWN 0ul -#define PHOTO_LIGHTSOURCE_DAYLIGHT 1ul -#define PHOTO_LIGHTSOURCE_FLUORESCENT 2ul -#define PHOTO_LIGHTSOURCE_TUNGSTEN 3ul -#define PHOTO_LIGHTSOURCE_STANDARD_A 17ul -#define PHOTO_LIGHTSOURCE_STANDARD_B 18ul -#define PHOTO_LIGHTSOURCE_STANDARD_C 19ul -#define PHOTO_LIGHTSOURCE_D55 20ul -#define PHOTO_LIGHTSOURCE_D65 21ul -#define PHOTO_LIGHTSOURCE_D75 22ul - -// Name: System.Photo.MakerNote -- PKEY_Photo_MakerNote -// Type: Buffer -- VT_VECTOR | VT_UI1 (For variants: VT_ARRAY | VT_UI1) -// FormatID: FA303353-B659-4052-85E9-BCAC79549B84, 100 -DEFINE_PROPERTYKEY(PKEY_Photo_MakerNote, 0xFA303353, 0xB659, 0x4052, 0x85, 0xE9, 0xBC, 0xAC, 0x79, 0x54, 0x9B, 0x84, 100); - -// Name: System.Photo.MakerNoteOffset -- PKEY_Photo_MakerNoteOffset -// Type: UInt64 -- VT_UI8 -// FormatID: 813F4124-34E6-4D17-AB3E-6B1F3C2247A1, 100 -DEFINE_PROPERTYKEY(PKEY_Photo_MakerNoteOffset, 0x813F4124, 0x34E6, 0x4D17, 0xAB, 0x3E, 0x6B, 0x1F, 0x3C, 0x22, 0x47, 0xA1, 100); - -// Name: System.Photo.MaxAperture -- PKEY_Photo_MaxAperture -// Type: Double -- VT_R8 -// FormatID: 08F6D7C2-E3F2-44FC-AF1E-5AA5C81A2D3E, 100 -// -// Calculated from PKEY_Photo_MaxApertureNumerator and PKEY_Photo_MaxApertureDenominator -DEFINE_PROPERTYKEY(PKEY_Photo_MaxAperture, 0x08F6D7C2, 0xE3F2, 0x44FC, 0xAF, 0x1E, 0x5A, 0xA5, 0xC8, 0x1A, 0x2D, 0x3E, 100); - -// Name: System.Photo.MaxApertureDenominator -- PKEY_Photo_MaxApertureDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: C77724D4-601F-46C5-9B89-C53F93BCEB77, 100 -// -// Denominator of PKEY_Photo_MaxAperture -DEFINE_PROPERTYKEY(PKEY_Photo_MaxApertureDenominator, 0xC77724D4, 0x601F, 0x46C5, 0x9B, 0x89, 0xC5, 0x3F, 0x93, 0xBC, 0xEB, 0x77, 100); - -// Name: System.Photo.MaxApertureNumerator -- PKEY_Photo_MaxApertureNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: C107E191-A459-44C5-9AE6-B952AD4B906D, 100 -// -// Numerator of PKEY_Photo_MaxAperture -DEFINE_PROPERTYKEY(PKEY_Photo_MaxApertureNumerator, 0xC107E191, 0xA459, 0x44C5, 0x9A, 0xE6, 0xB9, 0x52, 0xAD, 0x4B, 0x90, 0x6D, 100); - -// Name: System.Photo.MeteringMode -- PKEY_Photo_MeteringMode -// Type: UInt16 -- VT_UI2 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 37383 -// -// PropertyTagExifMeteringMode -DEFINE_PROPERTYKEY(PKEY_Photo_MeteringMode, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 37383); - -// Possible discrete values for PKEY_Photo_MeteringMode are: -#define PHOTO_METERINGMODE_UNKNOWN 0u -#define PHOTO_METERINGMODE_AVERAGE 1u -#define PHOTO_METERINGMODE_CENTER 2u -#define PHOTO_METERINGMODE_SPOT 3u -#define PHOTO_METERINGMODE_MULTISPOT 4u -#define PHOTO_METERINGMODE_PATTERN 5u -#define PHOTO_METERINGMODE_PARTIAL 6u - -// Name: System.Photo.MeteringModeText -- PKEY_Photo_MeteringModeText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: F628FD8C-7BA8-465A-A65B-C5AA79263A9E, 100 -// -// This is the user-friendly form of System.Photo.MeteringMode. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Photo_MeteringModeText, 0xF628FD8C, 0x7BA8, 0x465A, 0xA6, 0x5B, 0xC5, 0xAA, 0x79, 0x26, 0x3A, 0x9E, 100); - -// Name: System.Photo.Orientation -- PKEY_Photo_Orientation -// Type: UInt16 -- VT_UI2 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 274 (PropertyTagOrientation) -// -// This is the image orientation viewed in terms of rows and columns. -DEFINE_PROPERTYKEY(PKEY_Photo_Orientation, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 274); - -// Possible discrete values for PKEY_Photo_Orientation are: -#define PHOTO_ORIENTATION_NORMAL 1u -#define PHOTO_ORIENTATION_FLIPHORIZONTAL 2u -#define PHOTO_ORIENTATION_ROTATE180 3u -#define PHOTO_ORIENTATION_FLIPVERTICAL 4u -#define PHOTO_ORIENTATION_TRANSPOSE 5u -#define PHOTO_ORIENTATION_ROTATE270 6u -#define PHOTO_ORIENTATION_TRANSVERSE 7u -#define PHOTO_ORIENTATION_ROTATE90 8u - -// Name: System.Photo.OrientationText -- PKEY_Photo_OrientationText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: A9EA193C-C511-498A-A06B-58E2776DCC28, 100 -// -// This is the user-friendly form of System.Photo.Orientation. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Photo_OrientationText, 0xA9EA193C, 0xC511, 0x498A, 0xA0, 0x6B, 0x58, 0xE2, 0x77, 0x6D, 0xCC, 0x28, 100); - -// Name: System.Photo.PhotometricInterpretation -- PKEY_Photo_PhotometricInterpretation -// Type: UInt16 -- VT_UI2 -// FormatID: 341796F1-1DF9-4B1C-A564-91BDEFA43877, 100 -// -// This is the pixel composition. In JPEG compressed data, a JPEG marker is used -// instead of this property. -DEFINE_PROPERTYKEY(PKEY_Photo_PhotometricInterpretation, 0x341796F1, 0x1DF9, 0x4B1C, 0xA5, 0x64, 0x91, 0xBD, 0xEF, 0xA4, 0x38, 0x77, 100); - -// Possible discrete values for PKEY_Photo_PhotometricInterpretation are: -#define PHOTO_PHOTOMETRIC_RGB 2u -#define PHOTO_PHOTOMETRIC_YCBCR 6u - -// Name: System.Photo.PhotometricInterpretationText -- PKEY_Photo_PhotometricInterpretationText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 821437D6-9EAB-4765-A589-3B1CBBD22A61, 100 -// -// This is the user-friendly form of System.Photo.PhotometricInterpretation. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Photo_PhotometricInterpretationText, 0x821437D6, 0x9EAB, 0x4765, 0xA5, 0x89, 0x3B, 0x1C, 0xBB, 0xD2, 0x2A, 0x61, 100); - -// Name: System.Photo.ProgramMode -- PKEY_Photo_ProgramMode -// Type: UInt32 -- VT_UI4 -// FormatID: 6D217F6D-3F6A-4825-B470-5F03CA2FBE9B, 100 -// -// This is the class of the program used by the camera to set exposure when the -// picture is taken. -DEFINE_PROPERTYKEY(PKEY_Photo_ProgramMode, 0x6D217F6D, 0x3F6A, 0x4825, 0xB4, 0x70, 0x5F, 0x03, 0xCA, 0x2F, 0xBE, 0x9B, 100); - -// Possible discrete values for PKEY_Photo_ProgramMode are: -#define PHOTO_PROGRAMMODE_NOTDEFINED 0ul -#define PHOTO_PROGRAMMODE_MANUAL 1ul -#define PHOTO_PROGRAMMODE_NORMAL 2ul -#define PHOTO_PROGRAMMODE_APERTURE 3ul -#define PHOTO_PROGRAMMODE_SHUTTER 4ul -#define PHOTO_PROGRAMMODE_CREATIVE 5ul -#define PHOTO_PROGRAMMODE_ACTION 6ul -#define PHOTO_PROGRAMMODE_PORTRAIT 7ul -#define PHOTO_PROGRAMMODE_LANDSCAPE 8ul - -// Name: System.Photo.ProgramModeText -- PKEY_Photo_ProgramModeText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 7FE3AA27-2648-42F3-89B0-454E5CB150C3, 100 -// -// This is the user-friendly form of System.Photo.ProgramMode. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Photo_ProgramModeText, 0x7FE3AA27, 0x2648, 0x42F3, 0x89, 0xB0, 0x45, 0x4E, 0x5C, 0xB1, 0x50, 0xC3, 100); - -// Name: System.Photo.RelatedSoundFile -- PKEY_Photo_RelatedSoundFile -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 318A6B45-087F-4DC2-B8CC-05359551FC9E, 100 -DEFINE_PROPERTYKEY(PKEY_Photo_RelatedSoundFile, 0x318A6B45, 0x087F, 0x4DC2, 0xB8, 0xCC, 0x05, 0x35, 0x95, 0x51, 0xFC, 0x9E, 100); - -// Name: System.Photo.Saturation -- PKEY_Photo_Saturation -// Type: UInt32 -- VT_UI4 -// FormatID: 49237325-A95A-4F67-B211-816B2D45D2E0, 100 -// -// This indicates the direction of saturation processing applied by the camera when -// the image was shot. -DEFINE_PROPERTYKEY(PKEY_Photo_Saturation, 0x49237325, 0xA95A, 0x4F67, 0xB2, 0x11, 0x81, 0x6B, 0x2D, 0x45, 0xD2, 0xE0, 100); - -// Possible discrete values for PKEY_Photo_Saturation are: -#define PHOTO_SATURATION_NORMAL 0ul -#define PHOTO_SATURATION_LOW 1ul -#define PHOTO_SATURATION_HIGH 2ul - -// Name: System.Photo.SaturationText -- PKEY_Photo_SaturationText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 61478C08-B600-4A84-BBE4-E99C45F0A072, 100 -// -// This is the user-friendly form of System.Photo.Saturation. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Photo_SaturationText, 0x61478C08, 0xB600, 0x4A84, 0xBB, 0xE4, 0xE9, 0x9C, 0x45, 0xF0, 0xA0, 0x72, 100); - -// Name: System.Photo.Sharpness -- PKEY_Photo_Sharpness -// Type: UInt32 -- VT_UI4 -// FormatID: FC6976DB-8349-4970-AE97-B3C5316A08F0, 100 -// -// This indicates the direction of sharpness processing applied by the camera when -// the image was shot. -DEFINE_PROPERTYKEY(PKEY_Photo_Sharpness, 0xFC6976DB, 0x8349, 0x4970, 0xAE, 0x97, 0xB3, 0xC5, 0x31, 0x6A, 0x08, 0xF0, 100); - -// Possible discrete values for PKEY_Photo_Sharpness are: -#define PHOTO_SHARPNESS_NORMAL 0ul -#define PHOTO_SHARPNESS_SOFT 1ul -#define PHOTO_SHARPNESS_HARD 2ul - -// Name: System.Photo.SharpnessText -- PKEY_Photo_SharpnessText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 51EC3F47-DD50-421D-8769-334F50424B1E, 100 -// -// This is the user-friendly form of System.Photo.Sharpness. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Photo_SharpnessText, 0x51EC3F47, 0xDD50, 0x421D, 0x87, 0x69, 0x33, 0x4F, 0x50, 0x42, 0x4B, 0x1E, 100); - -// Name: System.Photo.ShutterSpeed -- PKEY_Photo_ShutterSpeed -// Type: Double -- VT_R8 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 37377 -// -// PropertyTagExifShutterSpeed. Calculated from PKEY_Photo_ShutterSpeedNumerator and PKEY_Photo_ShutterSpeedDenominator -DEFINE_PROPERTYKEY(PKEY_Photo_ShutterSpeed, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 37377); - -// Name: System.Photo.ShutterSpeedDenominator -- PKEY_Photo_ShutterSpeedDenominator -// Type: Int32 -- VT_I4 -// FormatID: E13D8975-81C7-4948-AE3F-37CAE11E8FF7, 100 -// -// Denominator of PKEY_Photo_ShutterSpeed -DEFINE_PROPERTYKEY(PKEY_Photo_ShutterSpeedDenominator, 0xE13D8975, 0x81C7, 0x4948, 0xAE, 0x3F, 0x37, 0xCA, 0xE1, 0x1E, 0x8F, 0xF7, 100); - -// Name: System.Photo.ShutterSpeedNumerator -- PKEY_Photo_ShutterSpeedNumerator -// Type: Int32 -- VT_I4 -// FormatID: 16EA4042-D6F4-4BCA-8349-7C78D30FB333, 100 -// -// Numerator of PKEY_Photo_ShutterSpeed -DEFINE_PROPERTYKEY(PKEY_Photo_ShutterSpeedNumerator, 0x16EA4042, 0xD6F4, 0x4BCA, 0x83, 0x49, 0x7C, 0x78, 0xD3, 0x0F, 0xB3, 0x33, 100); - -// Name: System.Photo.SubjectDistance -- PKEY_Photo_SubjectDistance -// Type: Double -- VT_R8 -// FormatID: (FMTID_ImageProperties) 14B81DA1-0135-4D31-96D9-6CBFC9671A99, 37382 -// -// PropertyTagExifSubjectDist. Calculated from PKEY_Photo_SubjectDistanceNumerator and PKEY_Photo_SubjectDistanceDenominator -DEFINE_PROPERTYKEY(PKEY_Photo_SubjectDistance, 0x14B81DA1, 0x0135, 0x4D31, 0x96, 0xD9, 0x6C, 0xBF, 0xC9, 0x67, 0x1A, 0x99, 37382); - -// Name: System.Photo.SubjectDistanceDenominator -- PKEY_Photo_SubjectDistanceDenominator -// Type: UInt32 -- VT_UI4 -// FormatID: 0C840A88-B043-466D-9766-D4B26DA3FA77, 100 -// -// Denominator of PKEY_Photo_SubjectDistance -DEFINE_PROPERTYKEY(PKEY_Photo_SubjectDistanceDenominator, 0x0C840A88, 0xB043, 0x466D, 0x97, 0x66, 0xD4, 0xB2, 0x6D, 0xA3, 0xFA, 0x77, 100); - -// Name: System.Photo.SubjectDistanceNumerator -- PKEY_Photo_SubjectDistanceNumerator -// Type: UInt32 -- VT_UI4 -// FormatID: 8AF4961C-F526-43E5-AA81-DB768219178D, 100 -// -// Numerator of PKEY_Photo_SubjectDistance -DEFINE_PROPERTYKEY(PKEY_Photo_SubjectDistanceNumerator, 0x8AF4961C, 0xF526, 0x43E5, 0xAA, 0x81, 0xDB, 0x76, 0x82, 0x19, 0x17, 0x8D, 100); - -// Name: System.Photo.TranscodedForSync -- PKEY_Photo_TranscodedForSync -// Type: Boolean -- VT_BOOL -// FormatID: 9A8EBB75-6458-4E82-BACB-35C0095B03BB, 100 -DEFINE_PROPERTYKEY(PKEY_Photo_TranscodedForSync, 0x9A8EBB75, 0x6458, 0x4E82, 0xBA, 0xCB, 0x35, 0xC0, 0x09, 0x5B, 0x03, 0xBB, 100); - -// Name: System.Photo.WhiteBalance -- PKEY_Photo_WhiteBalance -// Type: UInt32 -- VT_UI4 -// FormatID: EE3D3D8A-5381-4CFA-B13B-AAF66B5F4EC9, 100 -// -// This indicates the white balance mode set when the image was shot. -DEFINE_PROPERTYKEY(PKEY_Photo_WhiteBalance, 0xEE3D3D8A, 0x5381, 0x4CFA, 0xB1, 0x3B, 0xAA, 0xF6, 0x6B, 0x5F, 0x4E, 0xC9, 100); - -// Possible discrete values for PKEY_Photo_WhiteBalance are: -#define PHOTO_WHITEBALANCE_AUTO 0ul -#define PHOTO_WHITEBALANCE_MANUAL 1ul - -// Name: System.Photo.WhiteBalanceText -- PKEY_Photo_WhiteBalanceText -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 6336B95E-C7A7-426D-86FD-7AE3D39C84B4, 100 -// -// This is the user-friendly form of System.Photo.WhiteBalance. Not intended to be parsed -// programmatically. -DEFINE_PROPERTYKEY(PKEY_Photo_WhiteBalanceText, 0x6336B95E, 0xC7A7, 0x426D, 0x86, 0xFD, 0x7A, 0xE3, 0xD3, 0x9C, 0x84, 0xB4, 100); - -//----------------------------------------------------------------------------- -// PropGroup properties - -// Name: System.PropGroup.Advanced -- PKEY_PropGroup_Advanced -// Type: Null -- VT_NULL -// FormatID: 900A403B-097B-4B95-8AE2-071FDAEEB118, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Advanced, 0x900A403B, 0x097B, 0x4B95, 0x8A, 0xE2, 0x07, 0x1F, 0xDA, 0xEE, 0xB1, 0x18, 100); - -// Name: System.PropGroup.Audio -- PKEY_PropGroup_Audio -// Type: Null -- VT_NULL -// FormatID: 2804D469-788F-48AA-8570-71B9C187E138, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Audio, 0x2804D469, 0x788F, 0x48AA, 0x85, 0x70, 0x71, 0xB9, 0xC1, 0x87, 0xE1, 0x38, 100); - -// Name: System.PropGroup.Calendar -- PKEY_PropGroup_Calendar -// Type: Null -- VT_NULL -// FormatID: 9973D2B5-BFD8-438A-BA94-5349B293181A, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Calendar, 0x9973D2B5, 0xBFD8, 0x438A, 0xBA, 0x94, 0x53, 0x49, 0xB2, 0x93, 0x18, 0x1A, 100); - -// Name: System.PropGroup.Camera -- PKEY_PropGroup_Camera -// Type: Null -- VT_NULL -// FormatID: DE00DE32-547E-4981-AD4B-542F2E9007D8, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Camera, 0xDE00DE32, 0x547E, 0x4981, 0xAD, 0x4B, 0x54, 0x2F, 0x2E, 0x90, 0x07, 0xD8, 100); - -// Name: System.PropGroup.Contact -- PKEY_PropGroup_Contact -// Type: Null -- VT_NULL -// FormatID: DF975FD3-250A-4004-858F-34E29A3E37AA, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Contact, 0xDF975FD3, 0x250A, 0x4004, 0x85, 0x8F, 0x34, 0xE2, 0x9A, 0x3E, 0x37, 0xAA, 100); - -// Name: System.PropGroup.Content -- PKEY_PropGroup_Content -// Type: Null -- VT_NULL -// FormatID: D0DAB0BA-368A-4050-A882-6C010FD19A4F, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Content, 0xD0DAB0BA, 0x368A, 0x4050, 0xA8, 0x82, 0x6C, 0x01, 0x0F, 0xD1, 0x9A, 0x4F, 100); - -// Name: System.PropGroup.Description -- PKEY_PropGroup_Description -// Type: Null -- VT_NULL -// FormatID: 8969B275-9475-4E00-A887-FF93B8B41E44, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Description, 0x8969B275, 0x9475, 0x4E00, 0xA8, 0x87, 0xFF, 0x93, 0xB8, 0xB4, 0x1E, 0x44, 100); - -// Name: System.PropGroup.FileSystem -- PKEY_PropGroup_FileSystem -// Type: Null -- VT_NULL -// FormatID: E3A7D2C1-80FC-4B40-8F34-30EA111BDC2E, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_FileSystem, 0xE3A7D2C1, 0x80FC, 0x4B40, 0x8F, 0x34, 0x30, 0xEA, 0x11, 0x1B, 0xDC, 0x2E, 100); - -// Name: System.PropGroup.General -- PKEY_PropGroup_General -// Type: Null -- VT_NULL -// FormatID: CC301630-B192-4C22-B372-9F4C6D338E07, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_General, 0xCC301630, 0xB192, 0x4C22, 0xB3, 0x72, 0x9F, 0x4C, 0x6D, 0x33, 0x8E, 0x07, 100); - -// Name: System.PropGroup.GPS -- PKEY_PropGroup_GPS -// Type: Null -- VT_NULL -// FormatID: F3713ADA-90E3-4E11-AAE5-FDC17685B9BE, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_GPS, 0xF3713ADA, 0x90E3, 0x4E11, 0xAA, 0xE5, 0xFD, 0xC1, 0x76, 0x85, 0xB9, 0xBE, 100); - -// Name: System.PropGroup.Image -- PKEY_PropGroup_Image -// Type: Null -- VT_NULL -// FormatID: E3690A87-0FA8-4A2A-9A9F-FCE8827055AC, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Image, 0xE3690A87, 0x0FA8, 0x4A2A, 0x9A, 0x9F, 0xFC, 0xE8, 0x82, 0x70, 0x55, 0xAC, 100); - -// Name: System.PropGroup.Media -- PKEY_PropGroup_Media -// Type: Null -- VT_NULL -// FormatID: 61872CF7-6B5E-4B4B-AC2D-59DA84459248, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Media, 0x61872CF7, 0x6B5E, 0x4B4B, 0xAC, 0x2D, 0x59, 0xDA, 0x84, 0x45, 0x92, 0x48, 100); - -// Name: System.PropGroup.MediaAdvanced -- PKEY_PropGroup_MediaAdvanced -// Type: Null -- VT_NULL -// FormatID: 8859A284-DE7E-4642-99BA-D431D044B1EC, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_MediaAdvanced, 0x8859A284, 0xDE7E, 0x4642, 0x99, 0xBA, 0xD4, 0x31, 0xD0, 0x44, 0xB1, 0xEC, 100); - -// Name: System.PropGroup.Message -- PKEY_PropGroup_Message -// Type: Null -- VT_NULL -// FormatID: 7FD7259D-16B4-4135-9F97-7C96ECD2FA9E, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Message, 0x7FD7259D, 0x16B4, 0x4135, 0x9F, 0x97, 0x7C, 0x96, 0xEC, 0xD2, 0xFA, 0x9E, 100); - -// Name: System.PropGroup.Music -- PKEY_PropGroup_Music -// Type: Null -- VT_NULL -// FormatID: 68DD6094-7216-40F1-A029-43FE7127043F, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Music, 0x68DD6094, 0x7216, 0x40F1, 0xA0, 0x29, 0x43, 0xFE, 0x71, 0x27, 0x04, 0x3F, 100); - -// Name: System.PropGroup.Origin -- PKEY_PropGroup_Origin -// Type: Null -- VT_NULL -// FormatID: 2598D2FB-5569-4367-95DF-5CD3A177E1A5, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Origin, 0x2598D2FB, 0x5569, 0x4367, 0x95, 0xDF, 0x5C, 0xD3, 0xA1, 0x77, 0xE1, 0xA5, 100); - -// Name: System.PropGroup.PhotoAdvanced -- PKEY_PropGroup_PhotoAdvanced -// Type: Null -- VT_NULL -// FormatID: 0CB2BF5A-9EE7-4A86-8222-F01E07FDADAF, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_PhotoAdvanced, 0x0CB2BF5A, 0x9EE7, 0x4A86, 0x82, 0x22, 0xF0, 0x1E, 0x07, 0xFD, 0xAD, 0xAF, 100); - -// Name: System.PropGroup.RecordedTV -- PKEY_PropGroup_RecordedTV -// Type: Null -- VT_NULL -// FormatID: E7B33238-6584-4170-A5C0-AC25EFD9DA56, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_RecordedTV, 0xE7B33238, 0x6584, 0x4170, 0xA5, 0xC0, 0xAC, 0x25, 0xEF, 0xD9, 0xDA, 0x56, 100); - -// Name: System.PropGroup.Video -- PKEY_PropGroup_Video -// Type: Null -- VT_NULL -// FormatID: BEBE0920-7671-4C54-A3EB-49FDDFC191EE, 100 -DEFINE_PROPERTYKEY(PKEY_PropGroup_Video, 0xBEBE0920, 0x7671, 0x4C54, 0xA3, 0xEB, 0x49, 0xFD, 0xDF, 0xC1, 0x91, 0xEE, 100); - -//----------------------------------------------------------------------------- -// PropList properties - - - -// Name: System.PropList.ConflictPrompt -- PKEY_PropList_ConflictPrompt -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C9944A21-A406-48FE-8225-AEC7E24C211B, 11 -// -// The list of properties to show in the file operation conflict resolution dialog. Properties with empty -// values will not be displayed. Register under the regvalue of "ConflictPrompt". -DEFINE_PROPERTYKEY(PKEY_PropList_ConflictPrompt, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B, 11); - -// Name: System.PropList.ExtendedTileInfo -- PKEY_PropList_ExtendedTileInfo -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C9944A21-A406-48FE-8225-AEC7E24C211B, 9 -// -// The list of properties to show in the listview on extended tiles. Register under the regvalue of -// "ExtendedTileInfo". -DEFINE_PROPERTYKEY(PKEY_PropList_ExtendedTileInfo, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B, 9); - -// Name: System.PropList.FileOperationPrompt -- PKEY_PropList_FileOperationPrompt -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C9944A21-A406-48FE-8225-AEC7E24C211B, 10 -// -// The list of properties to show in the file operation confirmation dialog. Properties with empty values -// will not be displayed. If this list is not specified, then the InfoTip property list is used instead. -// Register under the regvalue of "FileOperationPrompt". -DEFINE_PROPERTYKEY(PKEY_PropList_FileOperationPrompt, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B, 10); - -// Name: System.PropList.FullDetails -- PKEY_PropList_FullDetails -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C9944A21-A406-48FE-8225-AEC7E24C211B, 2 -// -// The list of all the properties to show in the details page. Property groups can be included in this list -// in order to more easily organize the UI. Register under the regvalue of "FullDetails". -DEFINE_PROPERTYKEY(PKEY_PropList_FullDetails, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B, 2); - -// Name: System.PropList.InfoTip -- PKEY_PropList_InfoTip -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C9944A21-A406-48FE-8225-AEC7E24C211B, 4 (PID_PROPLIST_INFOTIP) -// -// The list of properties to show in the infotip. Properties with empty values will not be displayed. Register -// under the regvalue of "InfoTip". -DEFINE_PROPERTYKEY(PKEY_PropList_InfoTip, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B, 4); - -// Name: System.PropList.NonPersonal -- PKEY_PropList_NonPersonal -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 49D1091F-082E-493F-B23F-D2308AA9668C, 100 -// -// The list of properties that are considered 'non-personal'. When told to remove all non-personal properties -// from a given file, the system will leave these particular properties untouched. Register under the regvalue -// of "NonPersonal". -DEFINE_PROPERTYKEY(PKEY_PropList_NonPersonal, 0x49D1091F, 0x082E, 0x493F, 0xB2, 0x3F, 0xD2, 0x30, 0x8A, 0xA9, 0x66, 0x8C, 100); - -// Name: System.PropList.PreviewDetails -- PKEY_PropList_PreviewDetails -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C9944A21-A406-48FE-8225-AEC7E24C211B, 8 -// -// The list of properties to display in the preview pane. Register under the regvalue of "PreviewDetails". -DEFINE_PROPERTYKEY(PKEY_PropList_PreviewDetails, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B, 8); - -// Name: System.PropList.PreviewTitle -- PKEY_PropList_PreviewTitle -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C9944A21-A406-48FE-8225-AEC7E24C211B, 6 -// -// The one or two properties to display in the preview pane title section. The optional second property is -// displayed as a subtitle. Register under the regvalue of "PreviewTitle". -DEFINE_PROPERTYKEY(PKEY_PropList_PreviewTitle, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B, 6); - -// Name: System.PropList.QuickTip -- PKEY_PropList_QuickTip -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C9944A21-A406-48FE-8225-AEC7E24C211B, 5 (PID_PROPLIST_QUICKTIP) -// -// The list of properties to show in the infotip when the item is on a slow network. Properties with empty -// values will not be displayed. Register under the regvalue of "QuickTip". -DEFINE_PROPERTYKEY(PKEY_PropList_QuickTip, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B, 5); - -// Name: System.PropList.TileInfo -- PKEY_PropList_TileInfo -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: C9944A21-A406-48FE-8225-AEC7E24C211B, 3 (PID_PROPLIST_TILEINFO) -// -// The list of properties to show in the listview on tiles. Register under the regvalue of "TileInfo". -DEFINE_PROPERTYKEY(PKEY_PropList_TileInfo, 0xC9944A21, 0xA406, 0x48FE, 0x82, 0x25, 0xAE, 0xC7, 0xE2, 0x4C, 0x21, 0x1B, 3); - -// Name: System.PropList.XPDetailsPanel -- PKEY_PropList_XPDetailsPanel -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_WebView) F2275480-F782-4291-BD94-F13693513AEC, 0 (PID_DISPLAY_PROPERTIES) -// -// The list of properties to display in the XP webview details panel. Obsolete. -DEFINE_PROPERTYKEY(PKEY_PropList_XPDetailsPanel, 0xF2275480, 0xF782, 0x4291, 0xBD, 0x94, 0xF1, 0x36, 0x93, 0x51, 0x3A, 0xEC, 0); - -//----------------------------------------------------------------------------- -// RecordedTV properties - - - -// Name: System.RecordedTV.ChannelNumber -- PKEY_RecordedTV_ChannelNumber -// Type: UInt32 -- VT_UI4 -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 7 -// -// Example: 42 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_ChannelNumber, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 7); - -// Name: System.RecordedTV.Credits -- PKEY_RecordedTV_Credits -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 4 -// -// Example: "Don Messick/Frank Welker/Casey Kasem/Heather North/Nicole Jaffe;;;" -DEFINE_PROPERTYKEY(PKEY_RecordedTV_Credits, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 4); - -// Name: System.RecordedTV.DateContentExpires -- PKEY_RecordedTV_DateContentExpires -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 15 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_DateContentExpires, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 15); - -// Name: System.RecordedTV.EpisodeName -- PKEY_RecordedTV_EpisodeName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 2 -// -// Example: "Nowhere to Hyde" -DEFINE_PROPERTYKEY(PKEY_RecordedTV_EpisodeName, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 2); - -// Name: System.RecordedTV.IsATSCContent -- PKEY_RecordedTV_IsATSCContent -// Type: Boolean -- VT_BOOL -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 16 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_IsATSCContent, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 16); - -// Name: System.RecordedTV.IsClosedCaptioningAvailable -- PKEY_RecordedTV_IsClosedCaptioningAvailable -// Type: Boolean -- VT_BOOL -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 12 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_IsClosedCaptioningAvailable, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 12); - -// Name: System.RecordedTV.IsDTVContent -- PKEY_RecordedTV_IsDTVContent -// Type: Boolean -- VT_BOOL -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 17 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_IsDTVContent, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 17); - -// Name: System.RecordedTV.IsHDContent -- PKEY_RecordedTV_IsHDContent -// Type: Boolean -- VT_BOOL -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 18 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_IsHDContent, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 18); - -// Name: System.RecordedTV.IsRepeatBroadcast -- PKEY_RecordedTV_IsRepeatBroadcast -// Type: Boolean -- VT_BOOL -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 13 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_IsRepeatBroadcast, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 13); - -// Name: System.RecordedTV.IsSAP -- PKEY_RecordedTV_IsSAP -// Type: Boolean -- VT_BOOL -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 14 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_IsSAP, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 14); - -// Name: System.RecordedTV.NetworkAffiliation -- PKEY_RecordedTV_NetworkAffiliation -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 2C53C813-FB63-4E22-A1AB-0B331CA1E273, 100 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_NetworkAffiliation, 0x2C53C813, 0xFB63, 0x4E22, 0xA1, 0xAB, 0x0B, 0x33, 0x1C, 0xA1, 0xE2, 0x73, 100); - -// Name: System.RecordedTV.OriginalBroadcastDate -- PKEY_RecordedTV_OriginalBroadcastDate -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 4684FE97-8765-4842-9C13-F006447B178C, 100 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_OriginalBroadcastDate, 0x4684FE97, 0x8765, 0x4842, 0x9C, 0x13, 0xF0, 0x06, 0x44, 0x7B, 0x17, 0x8C, 100); - -// Name: System.RecordedTV.ProgramDescription -- PKEY_RecordedTV_ProgramDescription -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 3 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_ProgramDescription, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 3); - -// Name: System.RecordedTV.RecordingTime -- PKEY_RecordedTV_RecordingTime -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: A5477F61-7A82-4ECA-9DDE-98B69B2479B3, 100 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_RecordingTime, 0xA5477F61, 0x7A82, 0x4ECA, 0x9D, 0xDE, 0x98, 0xB6, 0x9B, 0x24, 0x79, 0xB3, 100); - -// Name: System.RecordedTV.StationCallSign -- PKEY_RecordedTV_StationCallSign -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 6D748DE2-8D38-4CC3-AC60-F009B057C557, 5 -// -// Example: "TOONP" -DEFINE_PROPERTYKEY(PKEY_RecordedTV_StationCallSign, 0x6D748DE2, 0x8D38, 0x4CC3, 0xAC, 0x60, 0xF0, 0x09, 0xB0, 0x57, 0xC5, 0x57, 5); - -// Name: System.RecordedTV.StationName -- PKEY_RecordedTV_StationName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 1B5439E7-EBA1-4AF8-BDD7-7AF1D4549493, 100 -DEFINE_PROPERTYKEY(PKEY_RecordedTV_StationName, 0x1B5439E7, 0xEBA1, 0x4AF8, 0xBD, 0xD7, 0x7A, 0xF1, 0xD4, 0x54, 0x94, 0x93, 100); - -//----------------------------------------------------------------------------- -// Search properties - - - -// Name: System.Search.AutoSummary -- PKEY_Search_AutoSummary -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 560C36C0-503A-11CF-BAA1-00004C752A9A, 2 -// -// General Summary of the document. -DEFINE_PROPERTYKEY(PKEY_Search_AutoSummary, 0x560C36C0, 0x503A, 0x11CF, 0xBA, 0xA1, 0x00, 0x00, 0x4C, 0x75, 0x2A, 0x9A, 2); - -// Name: System.Search.ContainerHash -- PKEY_Search_ContainerHash -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: BCEEE283-35DF-4D53-826A-F36A3EEFC6BE, 100 -// -// Hash code used to identify attachments to be deleted based on a common container url -DEFINE_PROPERTYKEY(PKEY_Search_ContainerHash, 0xBCEEE283, 0x35DF, 0x4D53, 0x82, 0x6A, 0xF3, 0x6A, 0x3E, 0xEF, 0xC6, 0xBE, 100); - -// Name: System.Search.Contents -- PKEY_Search_Contents -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_Storage) B725F130-47EF-101A-A5F1-02608C9EEBAC, 19 (PID_STG_CONTENTS) -// -// The contents of the item. This property is for query restrictions only; it cannot be retrieved in a -// query result. The Indexing Service friendly name is 'contents'. -DEFINE_PROPERTYKEY(PKEY_Search_Contents, 0xB725F130, 0x47EF, 0x101A, 0xA5, 0xF1, 0x02, 0x60, 0x8C, 0x9E, 0xEB, 0xAC, 19); - -// Name: System.Search.EntryID -- PKEY_Search_EntryID -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_Query) 49691C90-7E17-101A-A91C-08002B2ECDA9, 5 (PROPID_QUERY_WORKID) -// -// The entry ID for an item within a given catalog in the Windows Search Index. -// This value may be recycled, and therefore is not considered unique over time. -DEFINE_PROPERTYKEY(PKEY_Search_EntryID, 0x49691C90, 0x7E17, 0x101A, 0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9, 5); - -// Name: System.Search.GatherTime -- PKEY_Search_GatherTime -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 0B63E350-9CCC-11D0-BCDB-00805FCCCE04, 8 -// -// The Datetime that the Windows Search Gatherer process last pushed properties of this document to the Windows Search Gatherer Plugins. -DEFINE_PROPERTYKEY(PKEY_Search_GatherTime, 0x0B63E350, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04, 8); - -// Name: System.Search.IsClosedDirectory -- PKEY_Search_IsClosedDirectory -// Type: Boolean -- VT_BOOL -// FormatID: 0B63E343-9CCC-11D0-BCDB-00805FCCCE04, 23 -// -// If this property is emitted with a value of TRUE, then it indicates that this URL's last modified time applies to all of it's children, and if this URL is deleted then all of it's children are deleted as well. For example, this would be emitted as TRUE when emitting the URL of an email so that all attachments are tied to the last modified time of that email. -DEFINE_PROPERTYKEY(PKEY_Search_IsClosedDirectory, 0x0B63E343, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04, 23); - -// Name: System.Search.IsFullyContained -- PKEY_Search_IsFullyContained -// Type: Boolean -- VT_BOOL -// FormatID: 0B63E343-9CCC-11D0-BCDB-00805FCCCE04, 24 -// -// Any child URL of a URL which has System.Search.IsClosedDirectory=TRUE must emit System.Search.IsFullyContained=TRUE. This ensures that the URL is not deleted at the end of a crawl because it hasn't been visited (which is the normal mechanism for detecting deletes). For example an email attachment would emit this property -DEFINE_PROPERTYKEY(PKEY_Search_IsFullyContained, 0x0B63E343, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04, 24); - -// Name: System.Search.QueryFocusedSummary -- PKEY_Search_QueryFocusedSummary -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 560C36C0-503A-11CF-BAA1-00004C752A9A, 3 -// -// Query Focused Summary of the document. -DEFINE_PROPERTYKEY(PKEY_Search_QueryFocusedSummary, 0x560C36C0, 0x503A, 0x11CF, 0xBA, 0xA1, 0x00, 0x00, 0x4C, 0x75, 0x2A, 0x9A, 3); - -// Name: System.Search.Rank -- PKEY_Search_Rank -// Type: Int32 -- VT_I4 -// FormatID: (FMTID_Query) 49691C90-7E17-101A-A91C-08002B2ECDA9, 3 (PROPID_QUERY_RANK) -// -// Relevance rank of row. Ranges from 0-1000. Larger numbers = better matches. Query-time only, not -// defined in Search schema, retrievable but not searchable. -DEFINE_PROPERTYKEY(PKEY_Search_Rank, 0x49691C90, 0x7E17, 0x101A, 0xA9, 0x1C, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9, 3); - -// Name: System.Search.Store -- PKEY_Search_Store -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: A06992B3-8CAF-4ED7-A547-B259E32AC9FC, 100 -// -// The identifier for the protocol handler that produced this item. (E.g. MAPI, CSC, FILE etc.) -DEFINE_PROPERTYKEY(PKEY_Search_Store, 0xA06992B3, 0x8CAF, 0x4ED7, 0xA5, 0x47, 0xB2, 0x59, 0xE3, 0x2A, 0xC9, 0xFC, 100); - -// Name: System.Search.UrlToIndex -- PKEY_Search_UrlToIndex -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 0B63E343-9CCC-11D0-BCDB-00805FCCCE04, 2 -// -// This property should be emitted by a container IFilter for each child URL within the container. The children will eventually be crawled by the indexer if they are within scope. -DEFINE_PROPERTYKEY(PKEY_Search_UrlToIndex, 0x0B63E343, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04, 2); - -// Name: System.Search.UrlToIndexWithModificationTime -- PKEY_Search_UrlToIndexWithModificationTime -// Type: Multivalue Any -- VT_VECTOR | VT_NULL (For variants: VT_ARRAY | VT_NULL) -// FormatID: 0B63E343-9CCC-11D0-BCDB-00805FCCCE04, 12 -// -// This property is the same as System.Search.UrlToIndex except that it includes the time the URL was last modified. This is an optimization for the indexer as it doesn't have to call back into the protocol handler to ask for this information to determine if the content needs to be indexed again. The property is a vector with two elements, a VT_LPWSTR with the URL and a VT_FILETIME for the last modified time. -DEFINE_PROPERTYKEY(PKEY_Search_UrlToIndexWithModificationTime, 0x0B63E343, 0x9CCC, 0x11D0, 0xBC, 0xDB, 0x00, 0x80, 0x5F, 0xCC, 0xCE, 0x04, 12); - -//----------------------------------------------------------------------------- -// Shell properties - - - -// Name: System.DescriptionID -- PKEY_DescriptionID -// Type: Buffer -- VT_VECTOR | VT_UI1 (For variants: VT_ARRAY | VT_UI1) -// FormatID: (FMTID_ShellDetails) 28636AA6-953D-11D2-B5D6-00C04FD918D0, 2 (PID_DESCRIPTIONID) -// -// The contents of a SHDESCRIPTIONID structure as a buffer of bytes. -DEFINE_PROPERTYKEY(PKEY_DescriptionID, 0x28636AA6, 0x953D, 0x11D2, 0xB5, 0xD6, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xD0, 2); - -// Name: System.Link.TargetSFGAOFlagsStrings -- PKEY_Link_TargetSFGAOFlagsStrings -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: D6942081-D53B-443D-AD47-5E059D9CD27A, 3 -// -// Expresses the SFGAO flags of a link as string values and is used as a query optimization. See -// PKEY_Shell_SFGAOFlagsStrings for possible values of this. -DEFINE_PROPERTYKEY(PKEY_Link_TargetSFGAOFlagsStrings, 0xD6942081, 0xD53B, 0x443D, 0xAD, 0x47, 0x5E, 0x05, 0x9D, 0x9C, 0xD2, 0x7A, 3); - -// Name: System.Link.TargetUrl -- PKEY_Link_TargetUrl -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 5CBF2787-48CF-4208-B90E-EE5E5D420294, 2 (PKEYs relating to URLs. Used by IE History.) -DEFINE_PROPERTYKEY(PKEY_Link_TargetUrl, 0x5CBF2787, 0x48CF, 0x4208, 0xB9, 0x0E, 0xEE, 0x5E, 0x5D, 0x42, 0x02, 0x94, 2); - -// Name: System.Shell.SFGAOFlagsStrings -- PKEY_Shell_SFGAOFlagsStrings -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: D6942081-D53B-443D-AD47-5E059D9CD27A, 2 -// -// Expresses the SFGAO flags as string values and is used as a query optimization. -DEFINE_PROPERTYKEY(PKEY_Shell_SFGAOFlagsStrings, 0xD6942081, 0xD53B, 0x443D, 0xAD, 0x47, 0x5E, 0x05, 0x9D, 0x9C, 0xD2, 0x7A, 2); - -// Possible discrete values for PKEY_Shell_SFGAOFlagsStrings are: -#define SFGAOSTR_FILESYS L"filesys" // SFGAO_FILESYSTEM -#define SFGAOSTR_FILEANC L"fileanc" // SFGAO_FILESYSANCESTOR -#define SFGAOSTR_STORAGEANC L"storageanc" // SFGAO_STORAGEANCESTOR -#define SFGAOSTR_STREAM L"stream" // SFGAO_STREAM -#define SFGAOSTR_LINK L"link" // SFGAO_LINK -#define SFGAOSTR_HIDDEN L"hidden" // SFGAO_HIDDEN -#define SFGAOSTR_FOLDER L"folder" // SFGAO_FOLDER -#define SFGAOSTR_NONENUM L"nonenum" // SFGAO_NONENUMERATED -#define SFGAOSTR_BROWSABLE L"browsable" // SFGAO_BROWSABLE - -//----------------------------------------------------------------------------- -// Software properties - - - -// Name: System.Software.DateLastUsed -- PKEY_Software_DateLastUsed -// Type: DateTime -- VT_FILETIME (For variants: VT_DATE) -// FormatID: 841E4F90-FF59-4D16-8947-E81BBFFAB36D, 16 -// -// -DEFINE_PROPERTYKEY(PKEY_Software_DateLastUsed, 0x841E4F90, 0xFF59, 0x4D16, 0x89, 0x47, 0xE8, 0x1B, 0xBF, 0xFA, 0xB3, 0x6D, 16); - -// Name: System.Software.ProductName -- PKEY_Software_ProductName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (PSFMTID_VERSION) 0CEF7D53-FA64-11D1-A203-0000F81FEDEE, 7 -// -// -DEFINE_PROPERTYKEY(PKEY_Software_ProductName, 0x0CEF7D53, 0xFA64, 0x11D1, 0xA2, 0x03, 0x00, 0x00, 0xF8, 0x1F, 0xED, 0xEE, 7); - -//----------------------------------------------------------------------------- -// Sync properties - - - -// Name: System.Sync.Comments -- PKEY_Sync_Comments -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 7BD5533E-AF15-44DB-B8C8-BD6624E1D032, 13 -DEFINE_PROPERTYKEY(PKEY_Sync_Comments, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32, 13); - -// Name: System.Sync.ConflictDescription -- PKEY_Sync_ConflictDescription -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: CE50C159-2FB8-41FD-BE68-D3E042E274BC, 4 -DEFINE_PROPERTYKEY(PKEY_Sync_ConflictDescription, 0xCE50C159, 0x2FB8, 0x41FD, 0xBE, 0x68, 0xD3, 0xE0, 0x42, 0xE2, 0x74, 0xBC, 4); - -// Name: System.Sync.ConflictFirstLocation -- PKEY_Sync_ConflictFirstLocation -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: CE50C159-2FB8-41FD-BE68-D3E042E274BC, 6 -DEFINE_PROPERTYKEY(PKEY_Sync_ConflictFirstLocation, 0xCE50C159, 0x2FB8, 0x41FD, 0xBE, 0x68, 0xD3, 0xE0, 0x42, 0xE2, 0x74, 0xBC, 6); - -// Name: System.Sync.ConflictSecondLocation -- PKEY_Sync_ConflictSecondLocation -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: CE50C159-2FB8-41FD-BE68-D3E042E274BC, 7 -DEFINE_PROPERTYKEY(PKEY_Sync_ConflictSecondLocation, 0xCE50C159, 0x2FB8, 0x41FD, 0xBE, 0x68, 0xD3, 0xE0, 0x42, 0xE2, 0x74, 0xBC, 7); - -// Name: System.Sync.HandlerCollectionID -- PKEY_Sync_HandlerCollectionID -// Type: Guid -- VT_CLSID -// FormatID: 7BD5533E-AF15-44DB-B8C8-BD6624E1D032, 2 -DEFINE_PROPERTYKEY(PKEY_Sync_HandlerCollectionID, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32, 2); - -// Name: System.Sync.HandlerID -- PKEY_Sync_HandlerID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 7BD5533E-AF15-44DB-B8C8-BD6624E1D032, 3 -DEFINE_PROPERTYKEY(PKEY_Sync_HandlerID, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32, 3); - -// Name: System.Sync.HandlerName -- PKEY_Sync_HandlerName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: CE50C159-2FB8-41FD-BE68-D3E042E274BC, 2 -DEFINE_PROPERTYKEY(PKEY_Sync_HandlerName, 0xCE50C159, 0x2FB8, 0x41FD, 0xBE, 0x68, 0xD3, 0xE0, 0x42, 0xE2, 0x74, 0xBC, 2); - -// Name: System.Sync.HandlerType -- PKEY_Sync_HandlerType -// Type: UInt32 -- VT_UI4 -// FormatID: 7BD5533E-AF15-44DB-B8C8-BD6624E1D032, 8 -// -// -DEFINE_PROPERTYKEY(PKEY_Sync_HandlerType, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32, 8); - -// Possible discrete values for PKEY_Sync_HandlerType are: -#define SYNC_HANDLERTYPE_OTHER 0ul -#define SYNC_HANDLERTYPE_PROGRAMS 1ul -#define SYNC_HANDLERTYPE_DEVICES 2ul -#define SYNC_HANDLERTYPE_FOLDERS 3ul -#define SYNC_HANDLERTYPE_WEBSERVICES 4ul -#define SYNC_HANDLERTYPE_COMPUTERS 5ul - -// Name: System.Sync.HandlerTypeLabel -- PKEY_Sync_HandlerTypeLabel -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 7BD5533E-AF15-44DB-B8C8-BD6624E1D032, 9 -// -// -DEFINE_PROPERTYKEY(PKEY_Sync_HandlerTypeLabel, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32, 9); - -// Name: System.Sync.ItemID -- PKEY_Sync_ItemID -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 7BD5533E-AF15-44DB-B8C8-BD6624E1D032, 6 -DEFINE_PROPERTYKEY(PKEY_Sync_ItemID, 0x7BD5533E, 0xAF15, 0x44DB, 0xB8, 0xC8, 0xBD, 0x66, 0x24, 0xE1, 0xD0, 0x32, 6); - -// Name: System.Sync.ItemName -- PKEY_Sync_ItemName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: CE50C159-2FB8-41FD-BE68-D3E042E274BC, 3 -DEFINE_PROPERTYKEY(PKEY_Sync_ItemName, 0xCE50C159, 0x2FB8, 0x41FD, 0xBE, 0x68, 0xD3, 0xE0, 0x42, 0xE2, 0x74, 0xBC, 3); - -//----------------------------------------------------------------------------- -// Task properties - -// Name: System.Task.BillingInformation -- PKEY_Task_BillingInformation -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: D37D52C6-261C-4303-82B3-08B926AC6F12, 100 -DEFINE_PROPERTYKEY(PKEY_Task_BillingInformation, 0xD37D52C6, 0x261C, 0x4303, 0x82, 0xB3, 0x08, 0xB9, 0x26, 0xAC, 0x6F, 0x12, 100); - -// Name: System.Task.CompletionStatus -- PKEY_Task_CompletionStatus -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 084D8A0A-E6D5-40DE-BF1F-C8820E7C877C, 100 -DEFINE_PROPERTYKEY(PKEY_Task_CompletionStatus, 0x084D8A0A, 0xE6D5, 0x40DE, 0xBF, 0x1F, 0xC8, 0x82, 0x0E, 0x7C, 0x87, 0x7C, 100); - -// Name: System.Task.Owner -- PKEY_Task_Owner -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: 08C7CC5F-60F2-4494-AD75-55E3E0B5ADD0, 100 -DEFINE_PROPERTYKEY(PKEY_Task_Owner, 0x08C7CC5F, 0x60F2, 0x4494, 0xAD, 0x75, 0x55, 0xE3, 0xE0, 0xB5, 0xAD, 0xD0, 100); - - - -//----------------------------------------------------------------------------- -// Video properties - -// Name: System.Video.Compression -- PKEY_Video_Compression -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 10 (PIDVSI_COMPRESSION) -// -// Indicates the level of compression for the video stream. "Compression". -DEFINE_PROPERTYKEY(PKEY_Video_Compression, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 10); - -// Name: System.Video.Director -- PKEY_Video_Director -// Type: Multivalue String -- VT_VECTOR | VT_LPWSTR (For variants: VT_ARRAY | VT_BSTR) -// FormatID: (PSGUID_MEDIAFILESUMMARYINFORMATION) 64440492-4C8B-11D1-8B70-080036B11A03, 20 (PIDMSI_DIRECTOR) -// -// -DEFINE_PROPERTYKEY(PKEY_Video_Director, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 20); - -// Name: System.Video.EncodingBitrate -- PKEY_Video_EncodingBitrate -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 8 (PIDVSI_DATA_RATE) -// -// Indicates the data rate in "bits per second" for the video stream. "DataRate". -DEFINE_PROPERTYKEY(PKEY_Video_EncodingBitrate, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 8); - -// Name: System.Video.FourCC -- PKEY_Video_FourCC -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 44 -// -// Indicates the 4CC for the video stream. -DEFINE_PROPERTYKEY(PKEY_Video_FourCC, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 44); - -// Name: System.Video.FrameHeight -- PKEY_Video_FrameHeight -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 4 -// -// Indicates the frame height for the video stream. -DEFINE_PROPERTYKEY(PKEY_Video_FrameHeight, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 4); - -// Name: System.Video.FrameRate -- PKEY_Video_FrameRate -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 6 (PIDVSI_FRAME_RATE) -// -// Indicates the frame rate in "frames per millisecond" for the video stream. "FrameRate". -DEFINE_PROPERTYKEY(PKEY_Video_FrameRate, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 6); - -// Name: System.Video.FrameWidth -- PKEY_Video_FrameWidth -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 3 -// -// Indicates the frame width for the video stream. -DEFINE_PROPERTYKEY(PKEY_Video_FrameWidth, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 3); - -// Name: System.Video.HorizontalAspectRatio -- PKEY_Video_HorizontalAspectRatio -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 42 -// -// Indicates the horizontal portion of the aspect ratio. The X portion of XX:YY, -// like 16:9. -DEFINE_PROPERTYKEY(PKEY_Video_HorizontalAspectRatio, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 42); - -// Name: System.Video.SampleSize -- PKEY_Video_SampleSize -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 9 (PIDVSI_SAMPLE_SIZE) -// -// Indicates the sample size in bits for the video stream. "SampleSize". -DEFINE_PROPERTYKEY(PKEY_Video_SampleSize, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 9); - -// Name: System.Video.StreamName -- PKEY_Video_StreamName -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 2 (PIDVSI_STREAM_NAME) -// -// Indicates the name for the video stream. "StreamName". -DEFINE_PROPERTYKEY(PKEY_Video_StreamName, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 2); - -// Name: System.Video.StreamNumber -- PKEY_Video_StreamNumber -// Type: UInt16 -- VT_UI2 -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 11 (PIDVSI_STREAM_NUMBER) -// -// "Stream Number". -DEFINE_PROPERTYKEY(PKEY_Video_StreamNumber, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 11); - -// Name: System.Video.TotalBitrate -- PKEY_Video_TotalBitrate -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 43 (PIDVSI_TOTAL_BITRATE) -// -// Indicates the total data rate in "bits per second" for all video and audio streams. -DEFINE_PROPERTYKEY(PKEY_Video_TotalBitrate, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 43); - -// Name: System.Video.VerticalAspectRatio -- PKEY_Video_VerticalAspectRatio -// Type: UInt32 -- VT_UI4 -// FormatID: (FMTID_VideoSummaryInformation) 64440491-4C8B-11D1-8B70-080036B11A03, 45 -// -// Indicates the vertical portion of the aspect ratio. The Y portion of -// XX:YY, like 16:9. -DEFINE_PROPERTYKEY(PKEY_Video_VerticalAspectRatio, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 45); - - - -//----------------------------------------------------------------------------- -// Volume properties - -// Name: System.Volume.FileSystem -- PKEY_Volume_FileSystem -// Type: String -- VT_LPWSTR (For variants: VT_BSTR) -// FormatID: (FMTID_Volume) 9B174B35-40FF-11D2-A27E-00C04FC30871, 4 (PID_VOLUME_FILESYSTEM) (Filesystem Volume Properties) -// -// Indicates the filesystem of the volume. -DEFINE_PROPERTYKEY(PKEY_Volume_FileSystem, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71, 4); - -// Name: System.Volume.IsMappedDrive -- PKEY_Volume_IsMappedDrive -// Type: Boolean -- VT_BOOL -// FormatID: 149C0B69-2C2D-48FC-808F-D318D78C4636, 2 -DEFINE_PROPERTYKEY(PKEY_Volume_IsMappedDrive, 0x149C0B69, 0x2C2D, 0x48FC, 0x80, 0x8F, 0xD3, 0x18, 0xD7, 0x8C, 0x46, 0x36, 2); - -// Name: System.Volume.IsRoot -- PKEY_Volume_IsRoot -// Type: Boolean -- VT_BOOL -// FormatID: (FMTID_Volume) 9B174B35-40FF-11D2-A27E-00C04FC30871, 10 (Filesystem Volume Properties) -// -// -DEFINE_PROPERTYKEY(PKEY_Volume_IsRoot, 0x9B174B35, 0x40FF, 0x11D2, 0xA2, 0x7E, 0x00, 0xC0, 0x4F, 0xC3, 0x08, 0x71, 10); - -#endif /* _INC_PROPKEY */ - - diff --git a/Externals/portaudio/src/hostapi/wasapi/mingw-include/sdkddkver.h b/Externals/portaudio/src/hostapi/wasapi/mingw-include/sdkddkver.h deleted file mode 100644 index bc9008659a..0000000000 --- a/Externals/portaudio/src/hostapi/wasapi/mingw-include/sdkddkver.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - -Copyright (c) Microsoft Corporation. All rights reserved. - -Module Name: - - sdkddkver.h - -Abstract: - - Master include file for versioning windows SDK/DDK. - -*/ - -#ifndef _INC_SDKDDKVER -#define _INC_SDKDDKVER - -#pragma once - -// -// _WIN32_WINNT version constants -// -#define _WIN32_WINNT_NT4 0x0400 -#define _WIN32_WINNT_WIN2K 0x0500 -#define _WIN32_WINNT_WINXP 0x0501 -#define _WIN32_WINNT_WS03 0x0502 -#define _WIN32_WINNT_LONGHORN 0x0600 - -// -// _WIN32_IE_ version constants -// -#define _WIN32_IE_IE20 0x0200 -#define _WIN32_IE_IE30 0x0300 -#define _WIN32_IE_IE302 0x0302 -#define _WIN32_IE_IE40 0x0400 -#define _WIN32_IE_IE401 0x0401 -#define _WIN32_IE_IE50 0x0500 -#define _WIN32_IE_IE501 0x0501 -#define _WIN32_IE_IE55 0x0550 -#define _WIN32_IE_IE60 0x0600 -#define _WIN32_IE_IE60SP1 0x0601 -#define _WIN32_IE_IE60SP2 0x0603 -#define _WIN32_IE_IE70 0x0700 - -// -// IE <-> OS version mapping -// -// NT4 supports IE versions 2.0 -> 6.0 SP1 -#define _WIN32_IE_NT4 _WIN32_IE_IE20 -#define _WIN32_IE_NT4SP1 _WIN32_IE_IE20 -#define _WIN32_IE_NT4SP2 _WIN32_IE_IE20 -#define _WIN32_IE_NT4SP3 _WIN32_IE_IE302 -#define _WIN32_IE_NT4SP4 _WIN32_IE_IE401 -#define _WIN32_IE_NT4SP5 _WIN32_IE_IE401 -#define _WIN32_IE_NT4SP6 _WIN32_IE_IE50 -// Win98 supports IE versions 4.01 -> 6.0 SP1 -#define _WIN32_IE_WIN98 _WIN32_IE_IE401 -// Win98SE supports IE versions 5.0 -> 6.0 SP1 -#define _WIN32_IE_WIN98SE _WIN32_IE_IE50 -// WinME supports IE versions 5.5 -> 6.0 SP1 -#define _WIN32_IE_WINME _WIN32_IE_IE55 -// Win2k supports IE versions 5.01 -> 6.0 SP1 -#define _WIN32_IE_WIN2K _WIN32_IE_IE501 -#define _WIN32_IE_WIN2KSP1 _WIN32_IE_IE501 -#define _WIN32_IE_WIN2KSP2 _WIN32_IE_IE501 -#define _WIN32_IE_WIN2KSP3 _WIN32_IE_IE501 -#define _WIN32_IE_WIN2KSP4 _WIN32_IE_IE501 -#define _WIN32_IE_XP _WIN32_IE_IE60 -#define _WIN32_IE_XPSP1 _WIN32_IE_IE60SP1 -#define _WIN32_IE_XPSP2 _WIN32_IE_IE60SP2 -#define _WIN32_IE_WS03 0x0602 -#define _WIN32_IE_WS03SP1 _WIN32_IE_IE60SP2 -#define _WIN32_IE_LONGHORN _WIN32_IE_IE70 - - -// -// NTDDI version constants -// -#define NTDDI_WIN2K 0x05000000 -#define NTDDI_WIN2KSP1 0x05000100 -#define NTDDI_WIN2KSP2 0x05000200 -#define NTDDI_WIN2KSP3 0x05000300 -#define NTDDI_WIN2KSP4 0x05000400 - -#define NTDDI_WINXP 0x05010000 -#define NTDDI_WINXPSP1 0x05010100 -#define NTDDI_WINXPSP2 0x05010200 - -#define NTDDI_WS03 0x05020000 -#define NTDDI_WS03SP1 0x05020100 - -#define NTDDI_LONGHORN 0x06000000 - -// -// masks for version macros -// -#define OSVERSION_MASK 0xFFFF0000 -#define SPVERSION_MASK 0x0000FF00 -#define SUBVERSION_MASK 0x000000FF - - -// -// macros to extract various version fields from the NTDDI version -// -#define OSVER(Version) ((Version) & OSVERSION_MASK) -#define SPVER(Version) (((Version) & SPVERSION_MASK) >> 8) -#define SUBVER(Version) (((Version) & SUBVERSION_MASK) ) - - -#if defined(DECLSPEC_DEPRECATED_DDK) - -// deprecate in 2k or later -#if (NTDDI_VERSION >= NTDDI_WIN2K) -#define DECLSPEC_DEPRECATED_DDK_WIN2K DECLSPEC_DEPRECATED_DDK -#else -#define DECLSPEC_DEPRECATED_DDK_WIN2K -#endif - -// deprecate in XP or later -#if (NTDDI_VERSION >= NTDDI_WINXP) -#define DECLSPEC_DEPRECATED_DDK_WINXP DECLSPEC_DEPRECATED_DDK -#else -#define DECLSPEC_DEPRECATED_DDK_WINXP -#endif - -// deprecate in WS03 or later -#if (NTDDI_VERSION >= NTDDI_WS03) -#define DECLSPEC_DEPRECATED_DDK_WIN2003 DECLSPEC_DEPRECATED_DDK -#else -#define DECLSPEC_DEPRECATED_DDK_WIN2003 -#endif - -// deprecate in WS03 or later -#if (NTDDI_VERSION >= NTDDI_LONGHORN) -#define DECLSPEC_DEPRECATED_DDK_LONGHORN DECLSPEC_DEPRECATED_DDK -#else -#define DECLSPEC_DEPRECATED_DDK_LONGHORN -#endif - -#endif // defined(DECLSPEC_DEPRECATED_DDK) - - -// -// if versions aren't already defined, default to most current -// - -#define NTDDI_VERSION_FROM_WIN32_WINNT2(ver) ver##0000 -#define NTDDI_VERSION_FROM_WIN32_WINNT(ver) NTDDI_VERSION_FROM_WIN32_WINNT2(ver) - -#if !defined(_WIN32_WINNT) && !defined(_CHICAGO_) -#define _WIN32_WINNT 0x0600 -#endif - -#ifndef NTDDI_VERSION -#ifdef _WIN32_WINNT -// set NTDDI_VERSION based on _WIN32_WINNT -#define NTDDI_VERSION NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT) -#else -#define NTDDI_VERSION 0x06000000 -#endif -#endif - -#ifndef WINVER -#ifdef _WIN32_WINNT -// set WINVER based on _WIN32_WINNT -#define WINVER _WIN32_WINNT -#else -#define WINVER 0x0600 -#endif -#endif - -#ifndef _WIN32_IE -#ifdef _WIN32_WINNT -// set _WIN32_IE based on _WIN32_WINNT -#if (_WIN32_WINNT <= _WIN32_WINNT_NT4) -#define _WIN32_IE _WIN32_IE_IE50 -#elif (_WIN32_WINNT <= _WIN32_WINNT_WIN2K) -#define _WIN32_IE _WIN32_IE_IE501 -#elif (_WIN32_WINNT <= _WIN32_WINNT_WINXP) -#define _WIN32_IE _WIN32_IE_IE60 -#elif (_WIN32_WINNT <= _WIN32_WINNT_WS03) -#define _WIN32_IE 0x0602 -#else -#define _WIN32_IE 0x0700 -#endif -#else -#define _WIN32_IE 0x0700 -#endif -#endif - -// -// Sanity check for compatible versions -// -#if defined(_WIN32_WINNT) && !defined(MIDL_PASS) && !defined(RC_INVOKED) - -#if (defined(WINVER) && (WINVER < 0x0400) && (_WIN32_WINNT > 0x0400)) -#error WINVER setting conflicts with _WIN32_WINNT setting -#endif - -#if (((OSVERSION_MASK & NTDDI_VERSION) == NTDDI_WIN2K) && (_WIN32_WINNT != _WIN32_WINNT_WIN2K)) -#error NTDDI_VERSION setting conflicts with _WIN32_WINNT setting -#endif - -#if (((OSVERSION_MASK & NTDDI_VERSION) == NTDDI_WINXP) && (_WIN32_WINNT != _WIN32_WINNT_WINXP)) -#error NTDDI_VERSION setting conflicts with _WIN32_WINNT setting -#endif - -#if (((OSVERSION_MASK & NTDDI_VERSION) == NTDDI_WS03) && (_WIN32_WINNT != _WIN32_WINNT_WS03)) -#error NTDDI_VERSION setting conflicts with _WIN32_WINNT setting -#endif - -#if (((OSVERSION_MASK & NTDDI_VERSION) == NTDDI_LONGHORN) && (_WIN32_WINNT != _WIN32_WINNT_LONGHORN)) -#error NTDDI_VERSION setting conflicts with _WIN32_WINNT setting -#endif - -#if ((_WIN32_WINNT < _WIN32_WINNT_WIN2K) && (_WIN32_IE > _WIN32_IE_IE60SP1)) -#error _WIN32_WINNT settings conflicts with _WIN32_IE setting -#endif - -#endif // defined(_WIN32_WINNT) && !defined(MIDL_PASS) && !defined(_WINRESRC_) - - -#endif // !_INC_SDKDDKVER - - diff --git a/Externals/portaudio/src/hostapi/wasapi/mingw-include/shtypes.h b/Externals/portaudio/src/hostapi/wasapi/mingw-include/shtypes.h deleted file mode 100644 index 5221d060f5..0000000000 --- a/Externals/portaudio/src/hostapi/wasapi/mingw-include/shtypes.h +++ /dev/null @@ -1,468 +0,0 @@ - - -/* this ALWAYS GENERATED file contains the definitions for the interfaces */ - - - /* File created by MIDL compiler version 7.00.0499 */ -/* Compiler settings for shtypes.idl: - Oicf, W1, Zp8, env=Win32 (32b run) - protocol : dce , ms_ext, c_ext, robust - error checks: allocation ref bounds_check enum stub_data - VC __declspec() decoration level: - __declspec(uuid()), __declspec(selectany), __declspec(novtable) - DECLSPEC_UUID(), MIDL_INTERFACE() -*/ -//@@MIDL_FILE_HEADING( ) - -#pragma warning( disable: 4049 ) /* more than 64k source lines */ - - -/* verify that the version is high enough to compile this file*/ -#ifndef __REQUIRED_RPCNDR_H_VERSION__ -#define __REQUIRED_RPCNDR_H_VERSION__ 500 -#endif - -/* verify that the version is high enough to compile this file*/ -#ifndef __REQUIRED_RPCSAL_H_VERSION__ -#define __REQUIRED_RPCSAL_H_VERSION__ 100 -#endif - -#include "rpc.h" -#include "rpcndr.h" - -#ifndef __RPCNDR_H_VERSION__ -#error this stub requires an updated version of -#endif // __RPCNDR_H_VERSION__ - - -#ifndef __shtypes_h__ -#define __shtypes_h__ - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -#pragma once -#endif - -/* Forward Declarations */ - -/* header files for imported files */ -#include "wtypes.h" - -#ifdef __cplusplus -extern "C"{ -#endif - - -/* interface __MIDL_itf_shtypes_0000_0000 */ -/* [local] */ - -//+------------------------------------------------------------------------- -// -// Microsoft Windows -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//-------------------------------------------------------------------------- -//=========================================================================== -// -// Object identifiers in the explorer's name space (ItemID and IDList) -// -// All the items that the user can browse with the explorer (such as files, -// directories, servers, work-groups, etc.) has an identifier which is unique -// among items within the parent folder. Those identifiers are called item -// IDs (SHITEMID). Since all its parent folders have their own item IDs, -// any items can be uniquely identified by a list of item IDs, which is called -// an ID list (ITEMIDLIST). -// -// ID lists are almost always allocated by the task allocator (see some -// description below as well as OLE 2.0 SDK) and may be passed across -// some of shell interfaces (such as IShellFolder). Each item ID in an ID list -// is only meaningful to its parent folder (which has generated it), and all -// the clients must treat it as an opaque binary data except the first two -// bytes, which indicates the size of the item ID. -// -// When a shell extension -- which implements the IShellFolder interace -- -// generates an item ID, it may put any information in it, not only the data -// with that it needs to identifies the item, but also some additional -// information, which would help implementing some other functions efficiently. -// For example, the shell's IShellFolder implementation of file system items -// stores the primary (long) name of a file or a directory as the item -// identifier, but it also stores its alternative (short) name, size and date -// etc. -// -// When an ID list is passed to one of shell APIs (such as SHGetPathFromIDList), -// it is always an absolute path -- relative from the root of the name space, -// which is the desktop folder. When an ID list is passed to one of IShellFolder -// member function, it is always a relative path from the folder (unless it -// is explicitly specified). -// -//=========================================================================== -// -// SHITEMID -- Item ID (mkid) -// USHORT cb; // Size of the ID (including cb itself) -// BYTE abID[]; // The item ID (variable length) -// -#include -typedef struct _SHITEMID - { - USHORT cb; - BYTE abID[ 1 ]; - } SHITEMID; - -#include -#if defined(_M_IX86) -#define __unaligned -#endif // __unaligned -typedef SHITEMID __unaligned *LPSHITEMID; - -typedef const SHITEMID __unaligned *LPCSHITEMID; - -// -// ITEMIDLIST -- List if item IDs (combined with 0-terminator) -// -#include -typedef struct _ITEMIDLIST - { - SHITEMID mkid; - } ITEMIDLIST; - -#if defined(STRICT_TYPED_ITEMIDS) && defined(__cplusplus) -typedef struct _ITEMIDLIST_RELATIVE : ITEMIDLIST {} ITEMIDLIST_RELATIVE; -typedef struct _ITEMID_CHILD : ITEMIDLIST_RELATIVE {} ITEMID_CHILD; -typedef struct _ITEMIDLIST_ABSOLUTE : ITEMIDLIST_RELATIVE {} ITEMIDLIST_ABSOLUTE; -#else // !(defined(STRICT_TYPED_ITEMIDS) && defined(__cplusplus)) -typedef ITEMIDLIST ITEMIDLIST_RELATIVE; - -typedef ITEMIDLIST ITEMID_CHILD; - -typedef ITEMIDLIST ITEMIDLIST_ABSOLUTE; - -#endif // defined(STRICT_TYPED_ITEMIDS) && defined(__cplusplus) -#include -typedef /* [unique] */ __RPC_unique_pointer BYTE_BLOB *wirePIDL; - -typedef /* [wire_marshal] */ ITEMIDLIST __unaligned *LPITEMIDLIST; - -typedef /* [wire_marshal] */ const ITEMIDLIST __unaligned *LPCITEMIDLIST; - -#if defined(STRICT_TYPED_ITEMIDS) && defined(__cplusplus) -typedef /* [wire_marshal] */ ITEMIDLIST_ABSOLUTE *PIDLIST_ABSOLUTE; - -typedef /* [wire_marshal] */ const ITEMIDLIST_ABSOLUTE *PCIDLIST_ABSOLUTE; - -typedef /* [wire_marshal] */ const ITEMIDLIST_ABSOLUTE __unaligned *PCUIDLIST_ABSOLUTE; - -typedef /* [wire_marshal] */ ITEMIDLIST_RELATIVE *PIDLIST_RELATIVE; - -typedef /* [wire_marshal] */ const ITEMIDLIST_RELATIVE *PCIDLIST_RELATIVE; - -typedef /* [wire_marshal] */ ITEMIDLIST_RELATIVE __unaligned *PUIDLIST_RELATIVE; - -typedef /* [wire_marshal] */ const ITEMIDLIST_RELATIVE __unaligned *PCUIDLIST_RELATIVE; - -typedef /* [wire_marshal] */ ITEMID_CHILD *PITEMID_CHILD; - -typedef /* [wire_marshal] */ const ITEMID_CHILD *PCITEMID_CHILD; - -typedef /* [wire_marshal] */ ITEMID_CHILD __unaligned *PUITEMID_CHILD; - -typedef /* [wire_marshal] */ const ITEMID_CHILD __unaligned *PCUITEMID_CHILD; - -typedef const PCUITEMID_CHILD *PCUITEMID_CHILD_ARRAY; - -typedef const PCUIDLIST_RELATIVE *PCUIDLIST_RELATIVE_ARRAY; - -typedef const PCIDLIST_ABSOLUTE *PCIDLIST_ABSOLUTE_ARRAY; - -typedef const PCUIDLIST_ABSOLUTE *PCUIDLIST_ABSOLUTE_ARRAY; - -#else // !(defined(STRICT_TYPED_ITEMIDS) && defined(__cplusplus)) -#define PIDLIST_ABSOLUTE LPITEMIDLIST -#define PCIDLIST_ABSOLUTE LPCITEMIDLIST -#define PCUIDLIST_ABSOLUTE LPCITEMIDLIST -#define PIDLIST_RELATIVE LPITEMIDLIST -#define PCIDLIST_RELATIVE LPCITEMIDLIST -#define PUIDLIST_RELATIVE LPITEMIDLIST -#define PCUIDLIST_RELATIVE LPCITEMIDLIST -#define PITEMID_CHILD LPITEMIDLIST -#define PCITEMID_CHILD LPCITEMIDLIST -#define PUITEMID_CHILD LPITEMIDLIST -#define PCUITEMID_CHILD LPCITEMIDLIST -#define PCUITEMID_CHILD_ARRAY LPCITEMIDLIST * -#define PCUIDLIST_RELATIVE_ARRAY LPCITEMIDLIST * -#define PCIDLIST_ABSOLUTE_ARRAY LPCITEMIDLIST * -#define PCUIDLIST_ABSOLUTE_ARRAY LPCITEMIDLIST * -#endif // defined(STRICT_TYPED_ITEMIDS) && defined(__cplusplus) -#ifdef MIDL_PASS -typedef struct _WIN32_FIND_DATAA - { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - CHAR cFileName[ 260 ]; - CHAR cAlternateFileName[ 14 ]; - } WIN32_FIND_DATAA; - -typedef struct _WIN32_FIND_DATAA *PWIN32_FIND_DATAA; - -typedef struct _WIN32_FIND_DATAA *LPWIN32_FIND_DATAA; - -typedef struct _WIN32_FIND_DATAW - { - DWORD dwFileAttributes; - FILETIME ftCreationTime; - FILETIME ftLastAccessTime; - FILETIME ftLastWriteTime; - DWORD nFileSizeHigh; - DWORD nFileSizeLow; - DWORD dwReserved0; - DWORD dwReserved1; - WCHAR cFileName[ 260 ]; - WCHAR cAlternateFileName[ 14 ]; - } WIN32_FIND_DATAW; - -typedef struct _WIN32_FIND_DATAW *PWIN32_FIND_DATAW; - -typedef struct _WIN32_FIND_DATAW *LPWIN32_FIND_DATAW; - -#endif // MIDL_PASS -//------------------------------------------------------------------------- -// -// struct STRRET -// -// structure for returning strings from IShellFolder member functions -// -//------------------------------------------------------------------------- -// -// uType indicate which union member to use -// STRRET_WSTR Use STRRET.pOleStr must be freed by caller of GetDisplayNameOf -// STRRET_OFFSET Use STRRET.uOffset Offset into SHITEMID for ANSI string -// STRRET_CSTR Use STRRET.cStr ANSI Buffer -// -typedef /* [v1_enum] */ -enum tagSTRRET_TYPE - { STRRET_WSTR = 0, - STRRET_OFFSET = 0x1, - STRRET_CSTR = 0x2 - } STRRET_TYPE; - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -#pragma warning(push) -#pragma warning(disable:4201) /* nonstandard extension used : nameless struct/union */ -#pragma once -#endif -#include -typedef struct _STRRET - { - UINT uType; - union - { - LPWSTR pOleStr; - UINT uOffset; - char cStr[ 260 ]; - } DUMMYUNIONNAME; - } STRRET; - -#include -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -#pragma warning(pop) -#endif -typedef STRRET *LPSTRRET; - -//------------------------------------------------------------------------- -// -// struct SHELLDETAILS -// -// structure for returning strings from IShellDetails -// -//------------------------------------------------------------------------- -// -// fmt; // LVCFMT_* value (header only) -// cxChar; // Number of 'average' characters (header only) -// str; // String information -// -#include -typedef struct _SHELLDETAILS - { - int fmt; - int cxChar; - STRRET str; - } SHELLDETAILS; - -typedef struct _SHELLDETAILS *LPSHELLDETAILS; - -#include - -#if (_WIN32_IE >= _WIN32_IE_IE60SP2) -typedef /* [v1_enum] */ -enum tagPERCEIVED - { PERCEIVED_TYPE_FIRST = -3, - PERCEIVED_TYPE_CUSTOM = -3, - PERCEIVED_TYPE_UNSPECIFIED = -2, - PERCEIVED_TYPE_FOLDER = -1, - PERCEIVED_TYPE_UNKNOWN = 0, - PERCEIVED_TYPE_TEXT = 1, - PERCEIVED_TYPE_IMAGE = 2, - PERCEIVED_TYPE_AUDIO = 3, - PERCEIVED_TYPE_VIDEO = 4, - PERCEIVED_TYPE_COMPRESSED = 5, - PERCEIVED_TYPE_DOCUMENT = 6, - PERCEIVED_TYPE_SYSTEM = 7, - PERCEIVED_TYPE_APPLICATION = 8, - PERCEIVED_TYPE_GAMEMEDIA = 9, - PERCEIVED_TYPE_CONTACTS = 10, - PERCEIVED_TYPE_LAST = 10 - } PERCEIVED; - -#define PERCEIVEDFLAG_UNDEFINED 0x0000 -#define PERCEIVEDFLAG_SOFTCODED 0x0001 -#define PERCEIVEDFLAG_HARDCODED 0x0002 -#define PERCEIVEDFLAG_NATIVESUPPORT 0x0004 -#define PERCEIVEDFLAG_GDIPLUS 0x0010 -#define PERCEIVEDFLAG_WMSDK 0x0020 -#define PERCEIVEDFLAG_ZIPFOLDER 0x0040 -typedef DWORD PERCEIVEDFLAG; - -#endif // _WIN32_IE_IE60SP2 - -#if (NTDDI_VERSION >= NTDDI_LONGHORN) -typedef struct _COMDLG_FILTERSPEC - { - LPCWSTR pszName; - LPCWSTR pszSpec; - } COMDLG_FILTERSPEC; - -typedef struct tagMACHINE_ID - { - char szName[ 16 ]; - } MACHINE_ID; - -typedef struct tagDOMAIN_RELATIVE_OBJECTID - { - GUID guidVolume; - GUID guidObject; - } DOMAIN_RELATIVE_OBJECTID; - -typedef GUID KNOWNFOLDERID; - -#if 0 -typedef KNOWNFOLDERID *REFKNOWNFOLDERID; - -#endif // 0 -#ifdef __cplusplus -#define REFKNOWNFOLDERID const KNOWNFOLDERID & -#else // !__cplusplus -#define REFKNOWNFOLDERID const KNOWNFOLDERID * __MIDL_CONST -#endif // __cplusplus -#endif // NTDDI_LONGHORN -typedef GUID FOLDERTYPEID; - -#if 0 -typedef FOLDERTYPEID *REFFOLDERTYPEID; - -#endif // 0 -#ifdef __cplusplus -#define REFFOLDERTYPEID const FOLDERTYPEID & -#else // !__cplusplus -#define REFFOLDERTYPEID const FOLDERTYPEID * __MIDL_CONST -#endif // __cplusplus -typedef GUID TASKOWNERID; - -#if 0 -typedef TASKOWNERID *REFTASKOWNERID; - -#endif // 0 -#ifdef __cplusplus -#define REFTASKOWNERID const TASKOWNERID & -#else // !__cplusplus -#define REFTASKOWNERID const TASKOWNERID * __MIDL_CONST -#endif // __cplusplus -#ifndef LF_FACESIZE -typedef struct tagLOGFONTA - { - LONG lfHeight; - LONG lfWidth; - LONG lfEscapement; - LONG lfOrientation; - LONG lfWeight; - BYTE lfItalic; - BYTE lfUnderline; - BYTE lfStrikeOut; - BYTE lfCharSet; - BYTE lfOutPrecision; - BYTE lfClipPrecision; - BYTE lfQuality; - BYTE lfPitchAndFamily; - CHAR lfFaceName[ 32 ]; - } LOGFONTA; - -typedef struct tagLOGFONTW - { - LONG lfHeight; - LONG lfWidth; - LONG lfEscapement; - LONG lfOrientation; - LONG lfWeight; - BYTE lfItalic; - BYTE lfUnderline; - BYTE lfStrikeOut; - BYTE lfCharSet; - BYTE lfOutPrecision; - BYTE lfClipPrecision; - BYTE lfQuality; - BYTE lfPitchAndFamily; - WCHAR lfFaceName[ 32 ]; - } LOGFONTW; - -typedef LOGFONTA LOGFONT; - -#endif // LF_FACESIZE -typedef /* [v1_enum] */ -enum tagSHCOLSTATE - { SHCOLSTATE_TYPE_STR = 0x1, - SHCOLSTATE_TYPE_INT = 0x2, - SHCOLSTATE_TYPE_DATE = 0x3, - SHCOLSTATE_TYPEMASK = 0xf, - SHCOLSTATE_ONBYDEFAULT = 0x10, - SHCOLSTATE_SLOW = 0x20, - SHCOLSTATE_EXTENDED = 0x40, - SHCOLSTATE_SECONDARYUI = 0x80, - SHCOLSTATE_HIDDEN = 0x100, - SHCOLSTATE_PREFER_VARCMP = 0x200, - SHCOLSTATE_PREFER_FMTCMP = 0x400, - SHCOLSTATE_NOSORTBYFOLDERNESS = 0x800, - SHCOLSTATE_VIEWONLY = 0x10000, - SHCOLSTATE_BATCHREAD = 0x20000, - SHCOLSTATE_NO_GROUPBY = 0x40000, - SHCOLSTATE_FIXED_WIDTH = 0x1000, - SHCOLSTATE_NODPISCALE = 0x2000, - SHCOLSTATE_FIXED_RATIO = 0x4000, - SHCOLSTATE_DISPLAYMASK = 0xf000 - } SHCOLSTATE; - -typedef DWORD SHCOLSTATEF; - -typedef PROPERTYKEY SHCOLUMNID; - -typedef const SHCOLUMNID *LPCSHCOLUMNID; - - - -extern RPC_IF_HANDLE __MIDL_itf_shtypes_0000_0000_v0_0_c_ifspec; -extern RPC_IF_HANDLE __MIDL_itf_shtypes_0000_0000_v0_0_s_ifspec; - -/* Additional Prototypes for ALL interfaces */ - -/* end of Additional Prototypes */ - -#ifdef __cplusplus -} -#endif - -#endif - - - diff --git a/Externals/portaudio/src/hostapi/wasapi/pa_win_wasapi.c b/Externals/portaudio/src/hostapi/wasapi/pa_win_wasapi.c index 0172e47144..b12b91ffff 100644 --- a/Externals/portaudio/src/hostapi/wasapi/pa_win_wasapi.c +++ b/Externals/portaudio/src/hostapi/wasapi/pa_win_wasapi.c @@ -42,12 +42,18 @@ @note pa_wasapi currently requires minimum VC 2005, and the latest Vista SDK */ -#define WIN32_LEAN_AND_MEAN // exclude rare headers #include #include #include #include -#include + +// WinRT +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + #define PA_WINRT + #define INITGUID +#endif + +// WASAPI #include // must be before other Wasapi headers #if defined(_MSC_VER) && (_MSC_VER >= 1400) #include @@ -61,9 +67,9 @@ #undef INITGUID #endif #ifndef __MWERKS__ -#include -#include -#endif /* __MWERKS__ */ + #include + #include +#endif #include "pa_util.h" #include "pa_allocation.h" @@ -74,10 +80,9 @@ #include "pa_win_wasapi.h" #include "pa_debugprint.h" #include "pa_ringbuffer.h" - #include "pa_win_coinitialize.h" -#ifndef NTDDI_VERSION +#if !defined(NTDDI_VERSION) #undef WINVER #undef _WIN32_WINNT @@ -160,6 +165,38 @@ #endif // NTDDI_VERSION +// Missing declarations for WinRT +#ifdef PA_WINRT + + #define DEVICE_STATE_ACTIVE 0x00000001 + + typedef enum _EDataFlow + { + eRender = 0, + eCapture = ( eRender + 1 ) , + eAll = ( eCapture + 1 ) , + EDataFlow_enum_count = ( eAll + 1 ) + } + EDataFlow; + + typedef enum _EndpointFormFactor + { + RemoteNetworkDevice = 0, + Speakers = ( RemoteNetworkDevice + 1 ) , + LineLevel = ( Speakers + 1 ) , + Headphones = ( LineLevel + 1 ) , + Microphone = ( Headphones + 1 ) , + Headset = ( Microphone + 1 ) , + Handset = ( Headset + 1 ) , + UnknownDigitalPassthrough = ( Handset + 1 ) , + SPDIF = ( UnknownDigitalPassthrough + 1 ) , + HDMI = ( SPDIF + 1 ) , + UnknownFormFactor = ( HDMI + 1 ) + } + EndpointFormFactor; + +#endif + #ifndef GUID_SECT #define GUID_SECT #endif @@ -174,6 +211,8 @@ // "1CB9AD4C-DBFA-4c32-B178-C2F568A703B2" PA_DEFINE_IID(IAudioClient, 1cb9ad4c, dbfa, 4c32, b1, 78, c2, f5, 68, a7, 03, b2); +// "726778CD-F60A-4EDA-82DE-E47610CD78AA" +PA_DEFINE_IID(IAudioClient2, 726778cd, f60a, 4eda, 82, de, e4, 76, 10, cd, 78, aa); // "1BE09788-6894-4089-8586-9A2A6C265AC5" PA_DEFINE_IID(IMMEndpoint, 1be09788, 6894, 4089, 85, 86, 9a, 2a, 6c, 26, 5a, c5); // "A95664D2-9614-4F35-A746-DE8DB63617E6" @@ -190,11 +229,28 @@ PA_DEFINE_IID(IDeviceTopology, 2A07407E, 6497, 4A18, 97, 87, 32, f7, 9b, d0 PA_DEFINE_IID(IPart, AE2DE0E4, 5BCA, 4F2D, aa, 46, 5d, 13, f8, fd, b3, a9); // *4509F757-2D46-4637-8E62-CE7DB944F57B* PA_DEFINE_IID(IKsJackDescription, 4509F757, 2D46, 4637, 8e, 62, ce, 7d, b9, 44, f5, 7b); + // Media formats: __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_ADPCM, 0x00000002, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); __DEFINE_GUID(pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +#ifdef __IAudioClient2_INTERFACE_DEFINED__ +typedef enum _pa_AUDCLNT_STREAMOPTIONS { + pa_AUDCLNT_STREAMOPTIONS_NONE = 0x00, + pa_AUDCLNT_STREAMOPTIONS_RAW = 0x01, + pa_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT = 0x02 +} pa_AUDCLNT_STREAMOPTIONS; +typedef struct _pa_AudioClientProperties { + UINT32 cbSize; + BOOL bIsOffload; + AUDIO_STREAM_CATEGORY eCategory; + pa_AUDCLNT_STREAMOPTIONS Options; +} pa_AudioClientProperties; +#define PA_AUDIOCLIENTPROPERTIES_SIZE_CATEGORY (sizeof(pa_AudioClientProperties) - sizeof(pa_AUDCLNT_STREAMOPTIONS)) +#define PA_AUDIOCLIENTPROPERTIES_SIZE_OPTIONS sizeof(pa_AudioClientProperties) +#endif // __IAudioClient2_INTERFACE_DEFINED__ + /* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */ #if !defined(__CYGWIN__) && !defined(_WIN32_WCE) #define CREATE_THREAD(PROC) (HANDLE)_beginthreadex( NULL, 0, (PROC), stream, 0, &stream->dwThreadId ) @@ -254,13 +310,13 @@ enum { WASAPI_PACKETS_PER_INPUT_BUFFER = 6 }; typedef void (*MixMonoToStereoF) (void *__to, void *__from, UINT32 count); // AVRT is the new "multimedia schedulling stuff" +#ifndef PA_WINRT typedef BOOL (WINAPI *FAvRtCreateThreadOrderingGroup) (PHANDLE,PLARGE_INTEGER,GUID*,PLARGE_INTEGER); typedef BOOL (WINAPI *FAvRtDeleteThreadOrderingGroup) (HANDLE); typedef BOOL (WINAPI *FAvRtWaitOnThreadOrderingGroup) (HANDLE); -typedef HANDLE (WINAPI *FAvSetMmThreadCharacteristics) (LPCTSTR,LPDWORD); +typedef HANDLE (WINAPI *FAvSetMmThreadCharacteristics) (LPCSTR,LPDWORD); typedef BOOL (WINAPI *FAvRevertMmThreadCharacteristics)(HANDLE); typedef BOOL (WINAPI *FAvSetMmThreadPriority) (HANDLE,AVRT_PRIORITY); - static HMODULE hDInputDLL = 0; FAvRtCreateThreadOrderingGroup pAvRtCreateThreadOrderingGroup = NULL; FAvRtDeleteThreadOrderingGroup pAvRtDeleteThreadOrderingGroup = NULL; @@ -268,6 +324,7 @@ FAvRtWaitOnThreadOrderingGroup pAvRtWaitOnThreadOrderingGroup = NULL; FAvSetMmThreadCharacteristics pAvSetMmThreadCharacteristics = NULL; FAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL; FAvSetMmThreadPriority pAvSetMmThreadPriority = NULL; +#endif #define _GetProc(fun, type, name) { \ fun = (type) GetProcAddress(hDInputDLL,name); \ @@ -333,7 +390,9 @@ static signed long GetStreamWriteAvailable( PaStream* stream ); typedef struct PaWasapiDeviceInfo { // Device +#ifndef PA_WINRT IMMDevice *device; +#endif // from GetId WCHAR szDeviceID[MAX_STR_LEN]; @@ -341,20 +400,17 @@ typedef struct PaWasapiDeviceInfo // from GetState DWORD state; - // Fields filled from IMMEndpoint'sGetDataFlow - EDataFlow flow; - // Fields filled from IAudioDevice (_prior_ to Initialize) // from GetDevicePeriod( REFERENCE_TIME DefaultDevicePeriod; REFERENCE_TIME MinimumDevicePeriod; - // from GetMixFormat - // WAVEFORMATEX *MixFormat;//needs to be CoTaskMemFree'd after use! - // Default format (setup through Control Panel by user) WAVEFORMATEXTENSIBLE DefaultFormat; + // Fields filled from IMMEndpoint'sGetDataFlow + EDataFlow flow; + // Formfactor EndpointFormFactor formFactor; } @@ -375,7 +431,9 @@ typedef struct PaWinUtilComInitializationResult comInitializationResult; //in case we later need the synch +#ifndef PA_WINRT IMMDeviceEnumerator *enumerator; +#endif //this is the REAL number of devices, whether they are usefull to PA or not! UINT32 deviceCount; @@ -410,7 +468,9 @@ PaWasapiAudioClientParams; typedef struct PaWasapiSubStream { IAudioClient *clientParent; +#ifndef PA_WINRT IStream *clientStream; +#endif IAudioClient *clientProc; WAVEFORMATEXTENSIBLE wavex; @@ -460,14 +520,18 @@ typedef struct PaWasapiStream // input PaWasapiSubStream in; IAudioCaptureClient *captureClientParent; +#ifndef PA_WINRT IStream *captureClientStream; +#endif IAudioCaptureClient *captureClient; IAudioEndpointVolume *inVol; // output PaWasapiSubStream out; IAudioRenderClient *renderClientParent; +#ifndef PA_WINRT IStream *renderClientStream; +#endif IAudioRenderClient *renderClient; IAudioEndpointVolume *outVol; @@ -506,14 +570,22 @@ typedef struct PaWasapiStream } PaWasapiStream; +// COM marshaling +static HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream); +static HRESULT MarshalStreamComPointers(PaWasapiStream *stream); +static HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream); +static HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream); +static void ReleaseUnmarshaledSubComPointers(PaWasapiSubStream *substream); +static void ReleaseUnmarshaledComPointers(PaWasapiStream *stream); + // Local stream methods -void _StreamOnStop(PaWasapiStream *stream); -void _StreamFinish(PaWasapiStream *stream); -void _StreamCleanup(PaWasapiStream *stream); -HRESULT _PollGetOutputFramesAvailable(PaWasapiStream *stream, UINT32 *available); -HRESULT _PollGetInputFramesAvailable(PaWasapiStream *stream, UINT32 *available); -void *PaWasapi_ReallocateMemory(void *ptr, size_t size); -void PaWasapi_FreeMemory(void *ptr); +static void _StreamOnStop(PaWasapiStream *stream); +static void _StreamFinish(PaWasapiStream *stream); +static void _StreamCleanup(PaWasapiStream *stream); +static HRESULT _PollGetOutputFramesAvailable(PaWasapiStream *stream, UINT32 *available); +static HRESULT _PollGetInputFramesAvailable(PaWasapiStream *stream, UINT32 *available); +static void *PaWasapi_ReallocateMemory(void *ptr, size_t size); +static void PaWasapi_FreeMemory(void *ptr); // Local statics @@ -740,6 +812,7 @@ static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32 long frame_bytes = nFrames * nBlockAlign; long packets; + (void)nSamplesPerSec; // align to packet size frame_bytes = pAlignFunc(frame_bytes, HDA_PACKET_SIZE); // use ALIGN_FWD if bigger but safer period is more desired @@ -786,6 +859,7 @@ static UINT32 GetFramesSleepTimeMicroseconds(UINT32 nFrames, UINT32 nSamplesPerS } // ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT static BOOL SetupAVRT() { hDInputDLL = LoadLibraryA("avrt.dll"); @@ -806,18 +880,23 @@ static BOOL SetupAVRT() pAvRevertMmThreadCharacteristics && pAvSetMmThreadPriority; } +#endif // ------------------------------------------------------------------------------------------ static void CloseAVRT() { +#ifndef PA_WINRT if (hDInputDLL != NULL) FreeLibrary(hDInputDLL); hDInputDLL = NULL; +#endif } // ------------------------------------------------------------------------------------------ static BOOL IsWow64() { +#ifndef PA_WINRT + // http://msdn.microsoft.com/en-us/library/ms684139(VS.85).aspx typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); @@ -830,7 +909,7 @@ static BOOL IsWow64() // and GetProcAddress to get a pointer to the function if available. fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( - GetModuleHandle(TEXT("kernel32")), TEXT("IsWow64Process")); + GetModuleHandleA("kernel32"), "IsWow64Process"); if (fnIsWow64Process == NULL) return FALSE; @@ -839,24 +918,63 @@ static BOOL IsWow64() return FALSE; return bIsWow64; + +#else + + return FALSE; + +#endif } // ------------------------------------------------------------------------------------------ typedef enum EWindowsVersion { - WINDOWS_UNKNOWN = 0, - WINDOWS_VISTA_SERVER2008 = (1 << 0), - WINDOWS_7_SERVER2008R2 = (1 << 1), - WINDOWS_FUTURE = (1 << 2) + WINDOWS_UNKNOWN = 0, + WINDOWS_VISTA_SERVER2008, + WINDOWS_7_SERVER2008R2, + WINDOWS_8_SERVER2012, + WINDOWS_8_1_SERVER2012R2, + WINDOWS_10_SERVER2016, + WINDOWS_FUTURE } EWindowsVersion; -// Defines Windows 7/Windows Server 2008 R2 and up (future versions) -#define WINDOWS_7_SERVER2008R2_AND_UP (WINDOWS_7_SERVER2008R2|WINDOWS_FUTURE) -// The function is limited to Vista/7 mostly as we need just to find out Vista/WOW64 combination -// in order to use WASAPI WOW64 workarounds. -static UINT32 GetWindowsVersion() +// Alternative way for checking Windows version (allows to check version on Windows 8.1 and up) +#ifndef PA_WINRT +static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) { - static UINT32 version = WINDOWS_UNKNOWN; + typedef ULONGLONG (NTAPI *LPFN_VERSETCONDITIONMASK)(ULONGLONG ConditionMask, DWORD TypeMask, BYTE Condition); + typedef BOOL (WINAPI *LPFN_VERIFYVERSIONINFO)(LPOSVERSIONINFOEXA lpVersionInformation, DWORD dwTypeMask, DWORDLONG dwlConditionMask); + + LPFN_VERSETCONDITIONMASK fnVerSetConditionMask; + LPFN_VERIFYVERSIONINFO fnVerifyVersionInfo; + OSVERSIONINFOEXA osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 }; + DWORDLONG dwlConditionMask; + + fnVerSetConditionMask = (LPFN_VERSETCONDITIONMASK)GetProcAddress(GetModuleHandleA("kernel32"), "VerSetConditionMask"); + fnVerifyVersionInfo = (LPFN_VERIFYVERSIONINFO)GetProcAddress(GetModuleHandleA("kernel32"), "VerifyVersionInfoA"); + + if ((fnVerSetConditionMask == NULL) || (fnVerifyVersionInfo == NULL)) + return FALSE; + + dwlConditionMask = fnVerSetConditionMask( + fnVerSetConditionMask( + fnVerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL), + VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + + osvi.dwMajorVersion = wMajorVersion; + osvi.dwMinorVersion = wMinorVersion; + osvi.wServicePackMajor = wServicePackMajor; + + return (fnVerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE); +} +#endif +// Get Windows version +static EWindowsVersion GetWindowsVersion() +{ +#ifndef PA_WINRT + static EWindowsVersion version = WINDOWS_UNKNOWN; if (version == WINDOWS_UNKNOWN) { @@ -868,48 +986,81 @@ static UINT32 GetWindowsVersion() typedef DWORD (WINAPI *LPFN_GETVERSION)(VOID); LPFN_GETVERSION fnGetVersion; - fnGetVersion = (LPFN_GETVERSION) GetProcAddress(GetModuleHandle(TEXT("kernel32")), TEXT("GetVersion")); - if (fnGetVersion == NULL) - return WINDOWS_UNKNOWN; - - dwVersion = fnGetVersion(); - - // Get the Windows version - dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); - dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); - - // Get the build number - if (dwVersion < 0x80000000) - dwBuild = (DWORD)(HIWORD(dwVersion)); - - switch (dwMajorVersion) + fnGetVersion = (LPFN_GETVERSION)GetProcAddress(GetModuleHandleA("kernel32"), "GetVersion"); + if (fnGetVersion != NULL) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - break; // skip lower - case 6: - switch (dwMinorVersion) + PRINT(("WASAPI: getting Windows version with GetVersion()\n")); + + dwVersion = fnGetVersion(); + + // Get the Windows version + dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion))); + dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion))); + + // Get the build number + if (dwVersion < 0x80000000) + dwBuild = (DWORD)(HIWORD(dwVersion)); + + switch (dwMajorVersion) { case 0: - version |= WINDOWS_VISTA_SERVER2008; - break; case 1: - version |= WINDOWS_7_SERVER2008R2; + case 2: + case 3: + case 4: + case 5: + break; // skip lower + case 6: + switch (dwMinorVersion) + { + case 0: version = WINDOWS_VISTA_SERVER2008; break; + case 1: version = WINDOWS_7_SERVER2008R2; break; + case 2: version = WINDOWS_8_SERVER2012; break; + case 3: version = WINDOWS_8_1_SERVER2012R2; break; + default: version = WINDOWS_FUTURE; break; + } + break; + case 10: + switch (dwMinorVersion) + { + case 0: version = WINDOWS_10_SERVER2016; break; + default: version = WINDOWS_FUTURE; break; + } break; default: - version |= WINDOWS_FUTURE; + version = WINDOWS_FUTURE; + break; } - break; - default: - version |= WINDOWS_FUTURE; } + else + { + PRINT(("WASAPI: getting Windows version with VerifyVersionInfo()\n")); + + if (IsWindowsVersionOrGreater(10, 0, 0)) + version = WINDOWS_10_SERVER2016; + else + if (IsWindowsVersionOrGreater(6, 3, 0)) + version = WINDOWS_8_1_SERVER2012R2; + else + if (IsWindowsVersionOrGreater(6, 2, 0)) + version = WINDOWS_8_SERVER2012; + else + if (IsWindowsVersionOrGreater(6, 1, 0)) + version = WINDOWS_7_SERVER2008R2; + else + if (IsWindowsVersionOrGreater(6, 0, 0)) + version = WINDOWS_VISTA_SERVER2008; + else + version = WINDOWS_FUTURE; + } + + PRINT(("WASAPI: Windows version = %d\n", version)); } return version; +#else + return WINDOWS_8_SERVER2012; +#endif } // ------------------------------------------------------------------------------------------ @@ -918,7 +1069,45 @@ static BOOL UseWOW64Workaround() // note: WOW64 bug is common to Windows Vista x64, thus we fall back to safe Poll-driven // method. Windows 7 x64 seems has WOW64 bug fixed. - return (IsWow64() && (GetWindowsVersion() & WINDOWS_VISTA_SERVER2008)); + return (IsWow64() && (GetWindowsVersion() == WINDOWS_VISTA_SERVER2008)); +} + +// ------------------------------------------------------------------------------------------ +static UINT32 GetAudioClientVersion() +{ + if (GetWindowsVersion() >= WINDOWS_10_SERVER2016) + return 3; + else + if (GetWindowsVersion() >= WINDOWS_8_SERVER2012) + return 2; + + return 1; +} + +// ------------------------------------------------------------------------------------------ +static const IID *GetAudioClientIID() +{ + static const IID *cli_iid = NULL; + if (cli_iid == NULL) + { + UINT32 cli_version = GetAudioClientVersion(); + if (cli_version <= 1) + { + cli_iid = &pa_IID_IAudioClient; + } + else + { + switch (cli_version) + { + case 3: cli_iid = &pa_IID_IAudioClient2; cli_version = 2; break; // use IAudioClient2 for Windows 10+ until IAudioClient3 functions are required + default: cli_iid = &pa_IID_IAudioClient2; cli_version = 2; break; + } + } + + PRINT(("WASAPI: IAudioClient version = %d\n", cli_version)); + } + + return cli_iid; } // ------------------------------------------------------------------------------------------ @@ -1043,6 +1232,186 @@ static MixMonoToStereoF _GetMonoToStereoMixer(PaSampleFormat format, EMixerDir d return NULL; } +// ------------------------------------------------------------------------------------------ +#ifdef PA_WINRT +typedef struct PaActivateAudioInterfaceCompletionHandler +{ + IActivateAudioInterfaceCompletionHandler parent; + volatile LONG refs; + volatile LONG done; + struct + { + const IID *iid; + void **obj; + } + in; + struct + { + HRESULT hr; + } + out; +} +PaActivateAudioInterfaceCompletionHandler; + +static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_QueryInterface)( + IActivateAudioInterfaceCompletionHandler *This, REFIID riid, void **ppvObject) +{ + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; + + // From MSDN: + // "The IAgileObject interface is a marker interface that indicates that an object + // is free threaded and can be called from any apartment." + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IAgileObject)) + { + IActivateAudioInterfaceCompletionHandler_AddRef((IActivateAudioInterfaceCompletionHandler *)handler); + (*ppvObject) = handler; + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_AddRef)( + IActivateAudioInterfaceCompletionHandler *This) +{ + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; + + return InterlockedIncrement(&handler->refs); +} + +static ULONG (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_Release)( + IActivateAudioInterfaceCompletionHandler *This) +{ + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; + ULONG refs; + + if ((refs = InterlockedDecrement(&handler->refs)) == 0) + { + PaUtil_FreeMemory(handler->parent.lpVtbl); + PaUtil_FreeMemory(handler); + } + + return refs; +} + +static HRESULT (STDMETHODCALLTYPE PaActivateAudioInterfaceCompletionHandler_ActivateCompleted)( + IActivateAudioInterfaceCompletionHandler *This, IActivateAudioInterfaceAsyncOperation *activateOperation) +{ + PaActivateAudioInterfaceCompletionHandler *handler = (PaActivateAudioInterfaceCompletionHandler *)This; + + HRESULT hr = S_OK; + HRESULT hrActivateResult = S_OK; + IUnknown *punkAudioInterface = NULL; + + // Check for a successful activation result + hr = IActivateAudioInterfaceAsyncOperation_GetActivateResult(activateOperation, &hrActivateResult, &punkAudioInterface); + if (SUCCEEDED(hr) && SUCCEEDED(hrActivateResult)) + { + // Get pointer to the requested audio interface + IUnknown_QueryInterface(punkAudioInterface, handler->in.iid, handler->in.obj); + if ((*handler->in.obj) == NULL) + hrActivateResult = E_FAIL; + } + SAFE_RELEASE(punkAudioInterface); + + if (SUCCEEDED(hr)) + handler->out.hr = hrActivateResult; + else + handler->out.hr = hr; + + // Got client object, stop busy waiting in ActivateAudioInterface + InterlockedExchange(&handler->done, TRUE); + + return hr; +} + +static IActivateAudioInterfaceCompletionHandler *CreateActivateAudioInterfaceCompletionHandler(const IID *iid, void **obj) +{ + PaActivateAudioInterfaceCompletionHandler *handler = PaUtil_AllocateMemory(sizeof(PaActivateAudioInterfaceCompletionHandler)); + ZeroMemory(handler, sizeof(*handler)); + handler->parent.lpVtbl = PaUtil_AllocateMemory(sizeof(*handler->parent.lpVtbl)); + handler->parent.lpVtbl->QueryInterface = &PaActivateAudioInterfaceCompletionHandler_QueryInterface; + handler->parent.lpVtbl->AddRef = &PaActivateAudioInterfaceCompletionHandler_AddRef; + handler->parent.lpVtbl->Release = &PaActivateAudioInterfaceCompletionHandler_Release; + handler->parent.lpVtbl->ActivateCompleted = &PaActivateAudioInterfaceCompletionHandler_ActivateCompleted; + handler->refs = 1; + handler->in.iid = iid; + handler->in.obj = obj; + return (IActivateAudioInterfaceCompletionHandler *)handler; +} +#endif + +// ------------------------------------------------------------------------------------------ +#ifdef PA_WINRT +static HRESULT ActivateAudioInterface_WINRT(const PaWasapiDeviceInfo *deviceInfo, const IID *iid, void **obj) +{ +#define PA_WASAPI_DEVICE_PATH_LEN 64 + + PaError result = paNoError; + HRESULT hr = S_OK; + IActivateAudioInterfaceAsyncOperation *asyncOp = NULL; + IActivateAudioInterfaceCompletionHandler *handler = CreateActivateAudioInterfaceCompletionHandler(iid, obj); + PaActivateAudioInterfaceCompletionHandler *handlerImpl = (PaActivateAudioInterfaceCompletionHandler *)handler; + OLECHAR devicePath[PA_WASAPI_DEVICE_PATH_LEN] = { 0 }; + + // Get device path in form L"{DEVICE_GUID}" + switch (deviceInfo->flow) + { + case eRender: + StringFromGUID2(&DEVINTERFACE_AUDIO_RENDER, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1); + break; + case eCapture: + StringFromGUID2(&DEVINTERFACE_AUDIO_CAPTURE, devicePath, PA_WASAPI_DEVICE_PATH_LEN - 1); + break; + default: + return S_FALSE; + } + + // Async operation will call back to IActivateAudioInterfaceCompletionHandler::ActivateCompleted + // which must be an agile interface implementation + hr = ActivateAudioInterfaceAsync(devicePath, iid, NULL, handler, &asyncOp); + IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + + // Wait in busy loop for async operation to complete + // Use Interlocked API here to ensure that ->done variable is read every time through the loop + while (SUCCEEDED(hr) && !InterlockedOr(&handlerImpl->done, 0)) + { + Sleep(1); + } + + hr = handlerImpl->out.hr; + +error: + + SAFE_RELEASE(asyncOp); + SAFE_RELEASE(handler); + + return hr; + +#undef PA_WASAPI_DEVICE_PATH_LEN +} +#endif + +// ------------------------------------------------------------------------------------------ +static HRESULT ActivateAudioInterface(const PaWasapiDeviceInfo *deviceInfo, IAudioClient **client) +{ +#ifndef PA_WINRT + return IMMDevice_Activate(deviceInfo->device, GetAudioClientIID(), CLSCTX_ALL, NULL, (void **)client); +#else + return ActivateAudioInterface_WINRT(deviceInfo, GetAudioClientIID(), (void **)client); +#endif +} + +// ------------------------------------------------------------------------------------------ +#ifdef PA_WINRT +static DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD dwMilliseconds, BOOL bAlertable) +{ + SetEvent(hObjectToSignal); + return WaitForSingleObjectEx(hObjectToWaitOn, dwMilliseconds, bAlertable); +} +#endif + // ------------------------------------------------------------------------------------------ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { @@ -1050,14 +1419,20 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd PaWasapiHostApiRepresentation *paWasapi; PaDeviceInfo *deviceInfoArray; HRESULT hr = S_OK; - IMMDeviceCollection* pEndPoints = NULL; UINT i; +#ifndef PA_WINRT + IMMDeviceCollection* pEndPoints = NULL; +#else + WAVEFORMATEX *mixFormat; +#endif +#ifndef PA_WINRT if (!SetupAVRT()) { PRINT(("WASAPI: No AVRT! (not VISTA?)")); return paNoError; } +#endif paWasapi = (PaWasapiHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaWasapiHostApiRepresentation) ); if (paWasapi == NULL) @@ -1065,6 +1440,8 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd result = paInsufficientMemory; goto error; } + + memset( paWasapi, 0, sizeof(PaWasapiHostApiRepresentation) ); /* ensure all fields are zeroed. especially paWasapi->allocations */ result = PaWinUtil_CoInitialize( paWASAPI, &paWasapi->comInitializationResult ); if( result != paNoError ) @@ -1087,6 +1464,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; +#ifndef PA_WINRT paWasapi->enumerator = NULL; hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &pa_IID_IMMDeviceEnumerator, (void **)&paWasapi->enumerator); @@ -1156,7 +1534,16 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd // [IF_FAILED_JUMP(hResult, error);] IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); +#else + paWasapi->deviceCount = 2; +#endif + paWasapi->devInfo = (PaWasapiDeviceInfo *)PaUtil_AllocateMemory(sizeof(PaWasapiDeviceInfo) * paWasapi->deviceCount); + if (paWasapi->devInfo == NULL) + { + result = paInsufficientMemory; + goto error; + } for (i = 0; i < paWasapi->deviceCount; ++i) memset(&paWasapi->devInfo[i], 0, sizeof(PaWasapiDeviceInfo)); @@ -1181,7 +1568,6 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd for (i = 0; i < paWasapi->deviceCount; ++i) { - DWORD state = 0; PaDeviceInfo *deviceInfo = &deviceInfoArray[i]; deviceInfo->structVersion = 2; deviceInfo->hostApi = hostApiIndex; @@ -1189,6 +1575,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd PA_DEBUG(("WASAPI: device idx: %02d\n", i)); PA_DEBUG(("WASAPI: ---------------\n")); + #ifndef PA_WINRT hr = IMMDeviceCollection_Item(pEndPoints, i, &paWasapi->devInfo[i].device); // We need to set the result to a value otherwise we will return paNoError // [IF_FAILED_JUMP(hResult, error);] @@ -1221,7 +1608,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd if (paWasapi->devInfo[i].state != DEVICE_STATE_ACTIVE) { - PRINT(("WASAPI device: %d is not currently available (state:%d)\n",i,state)); + PRINT(("WASAPI device: %d is not currently available (state:%d)\n", i, paWasapi->devInfo[i].state)); } { @@ -1248,9 +1635,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd goto error; } if (value.pwszVal) - wcstombs(deviceName, value.pwszVal, MAX_STR_LEN-1); + WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (int)wcslen(value.pwszVal), deviceName, MAX_STR_LEN - 1, 0, 0); else - _snprintf(deviceName, MAX_STR_LEN-1, "baddev%d", i); + _snprintf(deviceName, MAX_STR_LEN - 1, "baddev%d", i); deviceInfo->name = deviceName; PropVariantClear(&value); PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name)); @@ -1293,8 +1680,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd SAFE_RELEASE(pProperty); } - - + // Endpoint data { IMMEndpoint *endpoint = NULL; @@ -1305,28 +1691,75 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd SAFE_RELEASE(endpoint); } } + #endif // Getting a temporary IAudioClient for more fields // we make sure NOT to call Initialize yet! { - IAudioClient *tmpClient = NULL; + #ifdef PA_WINRT + // Set flow as ActivateAudioInterface depends on it and selects corresponding + // direction for the Audio Client + paWasapi->devInfo[i].flow = (i == 0 ? eRender : eCapture); + #endif - hr = IMMDevice_Activate(paWasapi->devInfo[i].device, &pa_IID_IAudioClient, - CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient); + // Create temp Audio Client instance to query additional details + IAudioClient *tmpClient = NULL; + hr = ActivateAudioInterface(&paWasapi->devInfo[i], &tmpClient); // We need to set the result to a value otherwise we will return paNoError // [IF_FAILED_JUMP(hResult, error);] IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + // Get latency hr = IAudioClient_GetDevicePeriod(tmpClient, &paWasapi->devInfo[i].DefaultDevicePeriod, &paWasapi->devInfo[i].MinimumDevicePeriod); - // We need to set the result to a value otherwise we will return paNoError - // [IF_FAILED_JUMP(hResult, error);] - IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); + if (FAILED(hr)) + { + PA_DEBUG(("WASAPI:%d| failed getting min/default periods by IAudioClient::GetDevicePeriod() with error[%08X], will use 30000/100000 hns\n", i, (UINT32)hr)); - //hr = tmpClient->GetMixFormat(&paWasapi->devInfo[i].MixFormat); + // assign WASAPI common values + paWasapi->devInfo[i].DefaultDevicePeriod = 100000; + paWasapi->devInfo[i].MinimumDevicePeriod = 30000; - // Release client + // ignore error, let continue further without failing with paInternalError + hr = S_OK; + } + + #ifdef PA_WINRT + // Get mix format which will treat as default device format + hr = IAudioClient_GetMixFormat(tmpClient, &mixFormat); + if (SUCCEEDED(hr)) + { + // Default device + if (i == 0) + (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; + else + (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; + + // State + paWasapi->devInfo[i].state = DEVICE_STATE_ACTIVE; + + // Default format + memcpy(&paWasapi->devInfo[i].DefaultFormat, mixFormat, min(sizeof(paWasapi->devInfo[i].DefaultFormat), sizeof(*mixFormat))); + CoTaskMemFree(mixFormat); + + // Form-factor + paWasapi->devInfo[i].formFactor = UnknownFormFactor; + + // Name + deviceInfo->name = (char *)PaUtil_GroupAllocateMemory(paWasapi->allocations, MAX_STR_LEN + 1); + if (deviceInfo->name == NULL) + { + SAFE_RELEASE(tmpClient); + result = paInsufficientMemory; + goto error; + } + _snprintf((char *)deviceInfo->name, MAX_STR_LEN - 1, "WASAPI_%s:%d", (i == 0 ? "Output" : "Input"), i); + PA_DEBUG(("WASAPI:%d| name[%s]\n", i, deviceInfo->name)); + } + #endif + + // Release tmp client SAFE_RELEASE(tmpClient); if (hr != S_OK) @@ -1340,7 +1773,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd goto error; } } - + // we can now fill in portaudio device data deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; @@ -1366,7 +1799,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd // We need to set the result to a value otherwise we will return paNoError result = paInternalError; //continue; // do not skip from list, allow to initialize - break; + break; } (*hostApi)->deviceInfos[i] = deviceInfo; @@ -1393,7 +1826,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd // findout if platform workaround is required paWasapi->useWOW64Workaround = UseWOW64Workaround(); +#ifndef PA_WINRT SAFE_RELEASE(pEndPoints); +#endif PRINT(("WASAPI: initialized ok\n")); @@ -1403,7 +1838,9 @@ error: PRINT(("WASAPI: failed %s error[%d|%s]\n", __FUNCTION__, result, Pa_GetErrorText(result))); +#ifndef PA_WINRT SAFE_RELEASE(pEndPoints); +#endif Terminate((PaUtilHostApiRepresentation *)paWasapi); @@ -1424,15 +1861,19 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi ) return; // Release IMMDeviceEnumerator +#ifndef PA_WINRT SAFE_RELEASE(paWasapi->enumerator); +#endif + // Release device info bound objects and device info itself for (i = 0; i < paWasapi->deviceCount; ++i) { PaWasapiDeviceInfo *info = &paWasapi->devInfo[i]; + #ifndef PA_WINRT SAFE_RELEASE(info->device); - - //if (info->MixFormat) - // CoTaskMemFree(info->MixFormat); + #else + (void)info; + #endif } PaUtil_FreeMemory(paWasapi->devInfo); @@ -1691,25 +2132,25 @@ static PaError MakeWaveFormatFromParams(WAVEFORMATEXTENSIBLE *wavex, const PaStr { switch (params->channelCount) { - case 1: wavex->dwChannelMask = KSAUDIO_SPEAKER_MONO; break; - case 2: wavex->dwChannelMask = KSAUDIO_SPEAKER_STEREO; break; - case 3: wavex->dwChannelMask = KSAUDIO_SPEAKER_STEREO|SPEAKER_LOW_FREQUENCY; break; - case 4: wavex->dwChannelMask = KSAUDIO_SPEAKER_QUAD; break; - case 5: wavex->dwChannelMask = KSAUDIO_SPEAKER_QUAD|SPEAKER_LOW_FREQUENCY; break; -#ifdef KSAUDIO_SPEAKER_5POINT1_SURROUND - case 6: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND; break; + case 1: wavex->dwChannelMask = PAWIN_SPEAKER_MONO; break; + case 2: wavex->dwChannelMask = PAWIN_SPEAKER_STEREO; break; + case 3: wavex->dwChannelMask = PAWIN_SPEAKER_STEREO|SPEAKER_LOW_FREQUENCY; break; + case 4: wavex->dwChannelMask = PAWIN_SPEAKER_QUAD; break; + case 5: wavex->dwChannelMask = PAWIN_SPEAKER_QUAD|SPEAKER_LOW_FREQUENCY; break; +#ifdef PAWIN_SPEAKER_5POINT1_SURROUND + case 6: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1_SURROUND; break; #else - case 6: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1; break; + case 6: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1; break; #endif -#ifdef KSAUDIO_SPEAKER_5POINT1_SURROUND - case 7: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND|SPEAKER_BACK_CENTER; break; +#ifdef PAWIN_SPEAKER_5POINT1_SURROUND + case 7: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1_SURROUND|SPEAKER_BACK_CENTER; break; #else - case 7: wavex->dwChannelMask = KSAUDIO_SPEAKER_5POINT1|SPEAKER_BACK_CENTER; break; + case 7: wavex->dwChannelMask = PAWIN_SPEAKER_5POINT1|SPEAKER_BACK_CENTER; break; #endif -#ifdef KSAUDIO_SPEAKER_7POINT1_SURROUND - case 8: wavex->dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND; break; +#ifdef PAWIN_SPEAKER_7POINT1_SURROUND + case 8: wavex->dwChannelMask = PAWIN_SPEAKER_7POINT1_SURROUND; break; #else - case 8: wavex->dwChannelMask = KSAUDIO_SPEAKER_7POINT1; break; + case 8: wavex->dwChannelMask = PAWIN_SPEAKER_7POINT1; break; #endif default: wavex->dwChannelMask = 0; @@ -1730,9 +2171,9 @@ static PaError MakeWaveFormatFromParams(WAVEFORMATEXTENSIBLE *wavex, const PaStr pwfext->Format.nChannels = (WORD)channelCount; pwfext->Format.nSamplesPerSec = (DWORD)sampleRate; if(channelCount == 1) - pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT; + pwfext->dwChannelMask = PAWIN_SPEAKER_DIRECTOUT; else - pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO; + pwfext->dwChannelMask = PAWIN_SPEAKER_STEREO; if(sampleFormat == paFloat32) { pwfext->Format.nBlockAlign = (WORD)(channelCount * 4); @@ -1777,6 +2218,7 @@ static PaError GetClosestFormat(IAudioClient *myClient, double sampleRate, WAVEFORMATEX *sharedClosestMatch = NULL; HRESULT hr = !S_OK; PaStreamParameters params = (*_params); + (void)output; /* It was not noticed that 24-bit Input producing no output while device accepts this format. To fix this issue let's ask for 32-bits and let PA converters convert host 32-bit data @@ -2015,8 +2457,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, if (inputStreamInfo && (inputStreamInfo->flags & paWinWasapiExclusive)) shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; - hr = IMMDevice_Activate(paWasapi->devInfo[inputParameters->device].device, - &pa_IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient); + hr = ActivateAudioInterface(&paWasapi->devInfo[inputParameters->device], &tmpClient); if (hr != S_OK) { LogHostError(hr); @@ -2041,8 +2482,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, if (outputStreamInfo && (outputStreamInfo->flags & paWinWasapiExclusive)) shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; - hr = IMMDevice_Activate(paWasapi->devInfo[outputParameters->device].device, - &pa_IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void **)&tmpClient); + hr = ActivateAudioInterface(&paWasapi->devInfo[outputParameters->device], &tmpClient); if (hr != S_OK) { LogHostError(hr); @@ -2120,22 +2560,32 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu const PaStreamParameters *params = &pSub->params.stream_params; UINT32 framesPerLatency = pSub->params.frames_per_buffer; double sampleRate = pSub->params.sample_rate; - BOOL blocking = pSub->params.blocking; + //BOOL blocking = pSub->params.blocking; BOOL fullDuplex = pSub->params.full_duplex; const UINT32 userFramesPerBuffer = framesPerLatency; IAudioClient *audioClient = NULL; + // Assume default failure due to some reason + (*pa_error) = paInvalidDevice; + // Validate parameters if (!pSub || !pInfo || !params) + { + (*pa_error) = paBadStreamPtr; return E_POINTER; + } if ((UINT32)sampleRate == 0) + { + (*pa_error) = paInvalidSampleRate; return E_INVALIDARG; + } // Get the audio client - hr = IMMDevice_Activate(pInfo->device, &pa_IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audioClient); + hr = ActivateAudioInterface(pInfo, &audioClient); if (hr != S_OK) { + (*pa_error) = paInsufficientMemory; LogHostError(hr); goto done; } @@ -2143,9 +2593,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu // Get closest format if ((error = GetClosestFormat(audioClient, sampleRate, params, pSub->shareMode, &pSub->wavex, output)) != paFormatIsSupported) { - if (pa_error) - (*pa_error) = error; - + (*pa_error) = error; LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT); goto done; // fail, format not supported } @@ -2163,6 +2611,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu pSub->monoMixer = _GetMonoToStereoMixer(WaveToPaFormat(&pSub->wavex), (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1_L)); if (pSub->monoMixer == NULL) { + (*pa_error) = paInvalidChannelCount; LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT); goto done; // fail, no mixer for format } @@ -2211,11 +2660,15 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu if (framesPerLatency == 0) framesPerLatency = MakeFramesFromHns(pInfo->DefaultDevicePeriod, pSub->wavex.Format.nSamplesPerSec); - //! Exclusive Input stream renders data in 6 packets, we must set then the size of - //! single packet, total buffer size, e.g. required latency will be PacketSize * 6 + // Exclusive Input stream renders data in 6 packets, we must set then the size of + // single packet, total buffer size, e.g. required latency will be PacketSize * 6 if (!output && (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE)) { - framesPerLatency /= WASAPI_PACKETS_PER_INPUT_BUFFER; + // Do it only for Polling mode + if ((pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0) + { + framesPerLatency /= WASAPI_PACKETS_PER_INPUT_BUFFER; + } } // Calculate aligned period @@ -2283,6 +2736,38 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu } } + // Set Raw mode (applicable only to IAudioClient2) +#ifdef __IAudioClient2_INTERFACE_DEFINED__ + if (GetAudioClientVersion() >= 2) + { + pa_AudioClientProperties audioProps = { 0 }; + audioProps.cbSize = sizeof(pa_AudioClientProperties); + audioProps.bIsOffload = FALSE; + audioProps.eCategory = (AUDIO_STREAM_CATEGORY)pSub->params.wasapi_params.streamCategory; + switch (pSub->params.wasapi_params.streamOption) + { + case eStreamOptionRaw: + if (GetWindowsVersion() >= WINDOWS_8_1_SERVER2012R2) + audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_RAW; + break; + case eStreamOptionMatchFormat: + if (GetWindowsVersion() >= WINDOWS_10_SERVER2016) + audioProps.Options = pa_AUDCLNT_STREAMOPTIONS_MATCH_FORMAT; + break; + } + + hr = IAudioClient2_SetClientProperties((IAudioClient2 *)audioClient, (AudioClientProperties *)&audioProps); + if (hr != S_OK) + { + PRINT(("WASAPI: IAudioClient2_SetClientProperties(Category = %d, Options = %d) failed with error = %08X\n", audioProps.eCategory, audioProps.Options, (UINT32)hr)); + } + else + { + PRINT(("WASAPI: IAudioClient2 set properties: IsOffload = %d, Category = %d, Options = %d\n", audioProps.bIsOffload, audioProps.eCategory, audioProps.Options)); + } + } +#endif + // Open the stream and associate it with an audio session hr = IAudioClient_Initialize(audioClient, pSub->shareMode, @@ -2311,9 +2796,10 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu SAFE_RELEASE(audioClient); // Create a new audio client - hr = IMMDevice_Activate(pInfo->device, &pa_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&audioClient); + hr = ActivateAudioInterface(pInfo, &audioClient); if (hr != S_OK) { + (*pa_error) = paInsufficientMemory; LogHostError(hr); goto done; } @@ -2341,9 +2827,10 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu SAFE_RELEASE(audioClient); // Create a new audio client - hr = IMMDevice_Activate(pInfo->device, &pa_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&audioClient); + hr = ActivateAudioInterface(pInfo, &audioClient); if (hr != S_OK) { + (*pa_error) = paInsufficientMemory; LogHostError(hr); goto done; } @@ -2369,6 +2856,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu hr = IAudioClient_GetBufferSize(audioClient, &frames); if (hr != S_OK) { + (*pa_error) = paInvalidDevice; LogHostError(hr); goto done; } @@ -2379,9 +2867,10 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu SAFE_RELEASE(audioClient); // Create a new audio client - hr = IMMDevice_Activate(pInfo->device, &pa_IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&audioClient); + hr = ActivateAudioInterface(pInfo, &audioClient); if (hr != S_OK) { + (*pa_error) = paInsufficientMemory; LogHostError(hr); goto done; } @@ -2389,9 +2878,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu // Get closest format if ((error = GetClosestFormat(audioClient, sampleRate, params, pSub->shareMode, &pSub->wavex, output)) != paFormatIsSupported) { - if (pa_error) - (*pa_error) = error; - + (*pa_error) = error; LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT); // fail, format not supported goto done; } @@ -2409,6 +2896,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu pSub->monoMixer = _GetMonoToStereoMixer(WaveToPaFormat(&pSub->wavex), (pInfo->flow == eRender ? MIX_DIR__1TO2 : MIX_DIR__2TO1_L)); if (pSub->monoMixer == NULL) { + (*pa_error) = paInvalidChannelCount; LogHostError(hr = AUDCLNT_E_UNSUPPORTED_FORMAT); goto done; // fail, no mixer for format } @@ -2427,6 +2915,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu NULL); if (hr != S_OK) { + (*pa_error) = paInvalidDevice; LogHostError(hr); goto done; } @@ -2434,6 +2923,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu else if (hr != S_OK) { + (*pa_error) = paInvalidDevice; LogHostError(hr); goto done; } @@ -2448,6 +2938,9 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec), fullDuplex); + // No error, client is succesfully created + (*pa_error) = paNoError; + done: // Clean up @@ -2469,7 +2962,7 @@ static PaError ActivateAudioClientOutput(PaWasapiStream *stream) hr = CreateAudioClient(stream, &stream->out, TRUE, &result); if (hr != S_OK) { - LogPaError(result = paInvalidDevice); + LogPaError(result); goto error; } LogWAVEFORMATEXTENSIBLE(&stream->out.wavex); @@ -2541,7 +3034,7 @@ static PaError ActivateAudioClientInput(PaWasapiStream *stream) hr = CreateAudioClient(stream, &stream->in, FALSE, &result); if (hr != S_OK) { - LogPaError(result = paInvalidDevice); + LogPaError(result); goto error; } LogWAVEFORMATEXTENSIBLE(&stream->in.wavex); @@ -2669,26 +3162,38 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; - inputStreamInfo = (PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo; info = &paWasapi->devInfo[inputParameters->device]; - stream->in.flags = (inputStreamInfo ? inputStreamInfo->flags : 0); - // Select Exclusive/Shared mode + // default Shared Mode stream->in.shareMode = AUDCLNT_SHAREMODE_SHARED; - if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiExclusive)) - { - // Boost thread priority - stream->nThreadPriority = eThreadPriorityProAudio; - // Make Exclusive - stream->in.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; - } - // If user provided explicit thread priority level, use it - if ((inputStreamInfo != NULL) && (inputStreamInfo->flags & paWinWasapiThreadPriority)) + // PaWasapiStreamInfo + if (inputParameters->hostApiSpecificStreamInfo != NULL) { - if ((inputStreamInfo->threadPriority > eThreadPriorityNone) && - (inputStreamInfo->threadPriority <= eThreadPriorityWindowManager)) - stream->nThreadPriority = inputStreamInfo->threadPriority; + memcpy(&stream->in.params.wasapi_params, inputParameters->hostApiSpecificStreamInfo, min(sizeof(stream->in.params.wasapi_params), ((PaWasapiStreamInfo *)inputParameters->hostApiSpecificStreamInfo)->size)); + stream->in.params.wasapi_params.size = sizeof(stream->in.params.wasapi_params); + + stream->in.params.stream_params.hostApiSpecificStreamInfo = &stream->in.params.wasapi_params; + inputStreamInfo = &stream->in.params.wasapi_params; + + stream->in.flags = inputStreamInfo->flags; + + // Exclusive Mode + if (inputStreamInfo->flags & paWinWasapiExclusive) + { + // Boost thread priority + stream->nThreadPriority = eThreadPriorityProAudio; + // Make Exclusive + stream->in.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; + } + + // explicit thread priority level + if (inputStreamInfo->flags & paWinWasapiThreadPriority) + { + if ((inputStreamInfo->threadPriority > eThreadPriorityNone) && + (inputStreamInfo->threadPriority <= eThreadPriorityWindowManager)) + stream->nThreadPriority = inputStreamInfo->threadPriority; + } } // Choose processing mode @@ -2708,11 +3213,6 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, // Fill parameters for Audio Client creation stream->in.params.device_info = info; stream->in.params.stream_params = (*inputParameters); - if (inputStreamInfo != NULL) - { - stream->in.params.wasapi_params = (*inputStreamInfo); - stream->in.params.stream_params.hostApiSpecificStreamInfo = &stream->in.params.wasapi_params; - } stream->in.params.frames_per_buffer = framesPerBuffer; stream->in.params.sample_rate = sampleRate; stream->in.params.blocking = (streamCallback == NULL); @@ -2789,26 +3289,38 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; - outputStreamInfo = (PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo; info = &paWasapi->devInfo[outputParameters->device]; - stream->out.flags = (outputStreamInfo ? outputStreamInfo->flags : 0); - // Select Exclusive/Shared mode + // default Shared Mode stream->out.shareMode = AUDCLNT_SHAREMODE_SHARED; - if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiExclusive)) - { - // Boost thread priority - stream->nThreadPriority = eThreadPriorityProAudio; - // Make Exclusive - stream->out.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; - } - // If user provided explicit thread priority level, use it - if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiThreadPriority)) + // set PaWasapiStreamInfo + if (outputParameters->hostApiSpecificStreamInfo != NULL) { - if ((outputStreamInfo->threadPriority > eThreadPriorityNone) && - (outputStreamInfo->threadPriority <= eThreadPriorityWindowManager)) - stream->nThreadPriority = outputStreamInfo->threadPriority; + memcpy(&stream->out.params.wasapi_params, outputParameters->hostApiSpecificStreamInfo, min(sizeof(stream->out.params.wasapi_params), ((PaWasapiStreamInfo *)outputParameters->hostApiSpecificStreamInfo)->size)); + stream->out.params.wasapi_params.size = sizeof(stream->out.params.wasapi_params); + + stream->out.params.stream_params.hostApiSpecificStreamInfo = &stream->out.params.wasapi_params; + outputStreamInfo = &stream->out.params.wasapi_params; + + stream->out.flags = outputStreamInfo->flags; + + // Exclusive Mode + if (outputStreamInfo->flags & paWinWasapiExclusive) + { + // Boost thread priority + stream->nThreadPriority = eThreadPriorityProAudio; + // Make Exclusive + stream->out.shareMode = AUDCLNT_SHAREMODE_EXCLUSIVE; + } + + // explicit thread priority level + if (outputStreamInfo->flags & paWinWasapiThreadPriority) + { + if ((outputStreamInfo->threadPriority > eThreadPriorityNone) && + (outputStreamInfo->threadPriority <= eThreadPriorityWindowManager)) + stream->nThreadPriority = outputStreamInfo->threadPriority; + } } // Choose processing mode @@ -2828,11 +3340,6 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, // Fill parameters for Audio Client creation stream->out.params.device_info = info; stream->out.params.stream_params = (*outputParameters); - if (inputStreamInfo != NULL) - { - stream->out.params.wasapi_params = (*outputStreamInfo); - stream->out.params.stream_params.hostApiSpecificStreamInfo = &stream->out.params.wasapi_params; - } stream->out.params.frames_per_buffer = framesPerBuffer; stream->out.params.sample_rate = sampleRate; stream->out.params.blocking = (streamCallback == NULL); @@ -3043,12 +3550,13 @@ static PaError CloseStream( PaStream* s ) // ------------------------------------------------------------------------------------------ HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream) { +#ifndef PA_WINRT HRESULT hResult = S_OK; HRESULT hFirstBadResult = S_OK; substream->clientProc = NULL; // IAudioClient - hResult = CoGetInterfaceAndReleaseStream(substream->clientStream, &pa_IID_IAudioClient, (LPVOID*)&substream->clientProc); + hResult = CoGetInterfaceAndReleaseStream(substream->clientStream, GetAudioClientIID(), (LPVOID*)&substream->clientProc); substream->clientStream = NULL; if (hResult != S_OK) { @@ -3056,11 +3564,17 @@ HRESULT UnmarshalSubStreamComPointers(PaWasapiSubStream *substream) } return hFirstBadResult; + +#else + (void)substream; + return S_OK; +#endif } // ------------------------------------------------------------------------------------------ HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream) { +#ifndef PA_WINRT HRESULT hResult = S_OK; HRESULT hFirstBadResult = S_OK; stream->captureClient = NULL; @@ -3105,6 +3619,33 @@ HRESULT UnmarshalStreamComPointers(PaWasapiStream *stream) } return hFirstBadResult; +#else + if (stream->in.clientParent != NULL) + { + stream->in.clientProc = stream->in.clientParent; + IAudioClient_AddRef(stream->in.clientParent); + } + + if (stream->out.clientParent != NULL) + { + stream->out.clientProc = stream->out.clientParent; + IAudioClient_AddRef(stream->out.clientParent); + } + + if (stream->renderClientParent != NULL) + { + stream->renderClient = stream->renderClientParent; + IAudioRenderClient_AddRef(stream->renderClientParent); + } + + if (stream->captureClientParent != NULL) + { + stream->captureClient = stream->captureClientParent; + IAudioCaptureClient_AddRef(stream->captureClientParent); + } + + return S_OK; +#endif } // ----------------------------------------------------------------------------------------- @@ -3128,11 +3669,12 @@ void ReleaseUnmarshaledComPointers(PaWasapiStream *stream) // ------------------------------------------------------------------------------------------ HRESULT MarshalSubStreamComPointers(PaWasapiSubStream *substream) { +#ifndef PA_WINRT HRESULT hResult; substream->clientStream = NULL; // IAudioClient - hResult = CoMarshalInterThreadInterfaceInStream(&pa_IID_IAudioClient, (LPUNKNOWN)substream->clientParent, &substream->clientStream); + hResult = CoMarshalInterThreadInterfaceInStream(GetAudioClientIID(), (LPUNKNOWN)substream->clientParent, &substream->clientStream); if (hResult != S_OK) goto marshal_sub_error; @@ -3144,11 +3686,16 @@ marshal_sub_error: UnmarshalSubStreamComPointers(substream); ReleaseUnmarshaledSubComPointers(substream); return hResult; +#else + (void)substream; + return S_OK; +#endif } // ------------------------------------------------------------------------------------------ HRESULT MarshalStreamComPointers(PaWasapiStream *stream) { +#ifndef PA_WINRT HRESULT hResult = S_OK; stream->captureClientStream = NULL; stream->in.clientStream = NULL; @@ -3189,6 +3736,10 @@ marshal_error: UnmarshalStreamComPointers(stream); ReleaseUnmarshaledComPointers(stream); return hResult; +#else + (void)stream; + return S_OK; +#endif } // ------------------------------------------------------------------------------------------ @@ -3460,7 +4011,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames ) // Limit desired to amount of requested frames desired = available; - if (desired > frames) + if ((UINT32)desired > frames) desired = frames; // Get pointers to read regions @@ -3873,6 +4424,7 @@ static void WaspiHostProcessingLoop( void *inputBuffer, long inputFrames, // ------------------------------------------------------------------------------------------ HANDLE MMCSS_activate(const char *name) { +#ifndef PA_WINRT DWORD task_idx = 0; HANDLE hTask = pAvSetMmThreadCharacteristics(name, &task_idx); if (hTask == NULL) @@ -3894,6 +4446,10 @@ HANDLE MMCSS_activate(const char *name) } return hTask; +#else + (void)name; + return NULL; +#endif } // ------------------------------------------------------------------------------------------ @@ -3902,10 +4458,12 @@ void MMCSS_deactivate(HANDLE hTask) if (!hTask) return; +#ifndef PA_WINRT if (pAvRevertMmThreadCharacteristics(hTask) == FALSE) { PRINT(("WASAPI: AvRevertMmThreadCharacteristics failed!\n")); } +#endif } // ------------------------------------------------------------------------------------------ @@ -3955,6 +4513,7 @@ PaError PaWasapi_ThreadPriorityRevert(void *hTask) PaError PaWasapi_GetJackCount(PaDeviceIndex nDevice, int *jcount) { +#ifndef PA_WINRT PaError ret; HRESULT hr = S_OK; PaDeviceIndex index; @@ -4024,9 +4583,15 @@ error: LogHostError(hr); return paNoError; +#else + (void)nDevice; + (void)jcount; + return paUnanticipatedHostError; +#endif } // ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connType) { switch (connType) @@ -4050,8 +4615,10 @@ static PaWasapiJackConnectionType ConvertJackConnectionTypeWASAPIToPA(int connTy } return eJackConnTypeUnknown; } +#endif // ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc) { switch (geoLoc) @@ -4076,8 +4643,10 @@ static PaWasapiJackGeoLocation ConvertJackGeoLocationWASAPIToPA(int geoLoc) } return eJackGeoLocUnk; } +#endif // ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc) { switch (genLoc) @@ -4093,8 +4662,10 @@ static PaWasapiJackGenLocation ConvertJackGenLocationWASAPIToPA(int genLoc) } return eJackGenLocPrimaryBox; } +#endif // ------------------------------------------------------------------------------------------ +#ifndef PA_WINRT static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portConn) { switch (portConn) @@ -4106,6 +4677,7 @@ static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portCo } return eJackPortConnJack; } +#endif // ------------------------------------------------------------------------------------------ // Described at: @@ -4113,6 +4685,7 @@ static PaWasapiJackPortConnection ConvertJackPortConnectionWASAPIToPA(int portCo PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription) { +#ifndef PA_WINRT PaError ret; HRESULT hr = S_OK; PaDeviceIndex index; @@ -4188,6 +4761,13 @@ error: LogHostError(hr); return ret; + +#else + (void)nDevice; + (void)jindex; + (void)pJackDescription; + return paUnanticipatedHostError; +#endif } // ------------------------------------------------------------------------------------------ @@ -4412,7 +4992,7 @@ PA_THREAD_FUNC ProcThreadEvent(void *param) if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE)) { PRINT(("WASAPI: failed ProcThreadEvent CoInitialize")); - return paUnanticipatedHostError; + return (UINT32)paUnanticipatedHostError; } if (hr != RPC_E_CHANGED_MODE) bThreadComInitialized = TRUE; @@ -4619,7 +5199,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) if (FAILED(hr) && (hr != RPC_E_CHANGED_MODE)) { PRINT(("WASAPI: failed ProcThreadPoll CoInitialize")); - return paUnanticipatedHostError; + return (UINT32)paUnanticipatedHostError; } if (hr != RPC_E_CHANGED_MODE) bThreadComInitialized = TRUE; @@ -4795,13 +5375,15 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) // output if (stream->bufferMode == paUtilFixedHostBufferSize) { - if (frames >= stream->out.framesPerBuffer) + while (frames >= stream->out.framesPerBuffer) { if ((hr = ProcessOutputBuffer(stream, processor, stream->out.framesPerBuffer)) != S_OK) { LogHostError(hr); goto thread_error; } + + frames -= stream->out.framesPerBuffer; } } else diff --git a/Externals/portaudio/src/hostapi/wasapi/readme.txt b/Externals/portaudio/src/hostapi/wasapi/readme.txt index 08fedeb074..0cfa0fa49d 100644 --- a/Externals/portaudio/src/hostapi/wasapi/readme.txt +++ b/Externals/portaudio/src/hostapi/wasapi/readme.txt @@ -2,24 +2,21 @@ * WASAPI API * ************** ----------------------------------------- -Microsoft Visual Studio 2005SP1/2008/10 ----------------------------------------- -No specific actions are needed to compile WASAPI API under Visual Studio. +------------------------------------------- +Microsoft Visual Studio 2005 SP1 and higher +------------------------------------------- +No specific action is required to compile WASAPI API under Visual Studio. You are only required to install min. Windows Vista SDK (v6.0A) prior -compilation. +the compilation. To compile with WASAPI specific functionality for Windows 8 +and higher the min. Windows 8 SDK is required. ---------------------------------------- -MinGW (GCC 32-bit)/ MinGW64 (GCC 64-bit) +MinGW (GCC 32/64-bit) ---------------------------------------- -To compile under MinGW you are required to include 'mingw-include' directory +To compile with MinGW you are required to include 'mingw-include' directory which contains necessary files with WASAPI API. These files are modified -in order to be compiled by MinGW compiler. These files are taken from -Windows Vista SDK (v6.0A). MinGW compilation is tested and proved to be -fully working under 32-bit and 64-bit modes. -MinGW (32-bit) tested: gcc version 4.4.0 (GCC) -MinGW64 (64-bit) tested: gcc version 4.4.4 20100226 (prerelease) (GCC) - -PortAudio -/Dmitry Kostjuchenko/ -04.03.2010 \ No newline at end of file +for the compatibility with MinGW compiler. These files are taken from +the Windows Vista SDK (v6.0A). MinGW compilation is tested and proved to be +fully working. +MinGW (32-bit) tested min. version: gcc version 4.4.0 (GCC) +MinGW64 (64-bit) tested min. version: gcc version 4.4.4 20100226 (prerelease) (GCC) \ No newline at end of file diff --git a/Externals/portaudio/src/hostapi/wdmks/pa_win_wdmks.c b/Externals/portaudio/src/hostapi/wdmks/pa_win_wdmks.c index 60a61e474b..70a48d8ffa 100644 --- a/Externals/portaudio/src/hostapi/wdmks/pa_win_wdmks.c +++ b/Externals/portaudio/src/hostapi/wdmks/pa_win_wdmks.c @@ -1,70 +1,75 @@ /* - * $Id: pa_win_wdmks.c 1606 2011-02-17 15:56:04Z rob_bielik $ - * PortAudio Windows WDM-KS interface - * - * Author: Andrew Baldwin - * Based on the Open Source API proposed by Ross Bencina - * Copyright (c) 1999-2004 Andrew Baldwin, Ross Bencina, Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ +* $Id$ +* PortAudio Windows WDM-KS interface +* +* Author: Andrew Baldwin, Robert Bielik (WaveRT) +* Based on the Open Source API proposed by Ross Bencina +* Copyright (c) 1999-2004 Andrew Baldwin, Ross Bencina, Phil Burk +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files +* (the "Software"), to deal in the Software without restriction, +* including without limitation the rights to use, copy, modify, merge, +* publish, distribute, sublicense, and/or sell copies of the Software, +* and to permit persons to whom the Software is furnished to do so, +* subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ /* - * The text above constitutes the entire PortAudio license; however, - * the PortAudio community also makes the following non-binding requests: - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. It is also - * requested that these non-binding requests be included along with the - * license above. - */ +* The text above constitutes the entire PortAudio license; however, +* the PortAudio community also makes the following non-binding requests: +* +* Any person wishing to distribute modifications to the Software is +* requested to send the modifications to the original developer so that +* they can be incorporated into the canonical version. It is also +* requested that these non-binding requests be included along with the +* license above. +*/ /** @file - @ingroup hostapi_src - @brief Portaudio WDM-KS host API. +@ingroup hostapi_src +@brief Portaudio WDM-KS host API. - @note This is the implementation of the Portaudio host API using the - Windows WDM/Kernel Streaming API in order to enable very low latency - playback and recording on all modern Windows platforms (e.g. 2K, XP) - Note: This API accesses the device drivers below the usual KMIXER - component which is normally used to enable multi-client mixing and - format conversion. That means that it will lock out all other users - of a device for the duration of active stream using those devices +@note This is the implementation of the Portaudio host API using the +Windows WDM/Kernel Streaming API in order to enable very low latency +playback and recording on all modern Windows platforms (e.g. 2K, XP, Vista, Win7) +Note: This API accesses the device drivers below the usual KMIXER +component which is normally used to enable multi-client mixing and +format conversion. That means that it will lock out all other users +of a device for the duration of active stream using those devices */ #include +#if (defined(_WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ +#pragma comment( lib, "setupapi.lib" ) +#endif + /* Debugging/tracing support */ #define PA_LOGE_ #define PA_LOGL_ #ifdef __GNUC__ - #include - #define _WIN32_WINNT 0x0501 - #define WINVER 0x0501 +#include +#define _WIN32_WINNT 0x0501 +#define WINVER 0x0501 #endif #include /* strlen() */ #include +#include /* iswspace() */ #include "pa_util.h" #include "pa_allocation.h" @@ -74,89 +79,204 @@ #include "pa_process.h" #include "portaudio.h" #include "pa_debugprint.h" +#include "pa_memorybarrier.h" +#include "pa_ringbuffer.h" +#include "pa_trace.h" +#include "pa_win_waveformat.h" + +#include "pa_win_wdmks.h" + +#ifndef DRV_QUERYDEVICEINTERFACE +#define DRV_QUERYDEVICEINTERFACE (DRV_RESERVED + 12) +#endif +#ifndef DRV_QUERYDEVICEINTERFACESIZE +#define DRV_QUERYDEVICEINTERFACESIZE (DRV_RESERVED + 13) +#endif #include +#ifndef __GNUC__ /* Fix for ticket #257: MinGW-w64: Inclusion of triggers multiple redefinition errors. */ #include +#endif #include +#include + +#ifdef _MSC_VER +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif + +/* The PA_HP_TRACE macro is used in RT parts, so it can be switched off without affecting +the rest of the debug tracing */ +#if 1 +#define PA_HP_TRACE(x) PaUtil_AddHighSpeedLogMessage x ; +#else +#define PA_HP_TRACE(x) +#endif + +/* A define that selects whether the resulting pin names are chosen from pin category +instead of the available pin names, who sometimes can be quite cheesy, like "Volume control". +Default is to use the pin category. +*/ +#ifndef PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES +#define PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES 1 +#endif + #ifdef __GNUC__ - #undef PA_LOGE_ - #define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__)) - #undef PA_LOGL_ - #define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__)) - /* These defines are set in order to allow the WIndows DirectX - * headers to compile with a GCC compiler such as MinGW - * NOTE: The headers may generate a few warning in GCC, but - * they should compile */ - #define _INC_MMSYSTEM - #define _INC_MMREG - #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */ - #define DEFINE_GUID_THUNK(name,guid) DEFINE_GUID(name,guid) - #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK( n, STATIC_##n ) - #if !defined( DEFINE_WAVEFORMATEX_GUID ) - #define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 - #endif - #define WAVE_FORMAT_ADPCM 0x0002 - #define WAVE_FORMAT_IEEE_FLOAT 0x0003 - #define WAVE_FORMAT_ALAW 0x0006 - #define WAVE_FORMAT_MULAW 0x0007 - #define WAVE_FORMAT_MPEG 0x0050 - #define WAVE_FORMAT_DRM 0x0009 - #define DYNAMIC_GUID_THUNK(l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} - #define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data) +#undef PA_LOGE_ +#define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__)) +#undef PA_LOGL_ +#define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__)) +/* These defines are set in order to allow the WIndows DirectX +* headers to compile with a GCC compiler such as MinGW +* NOTE: The headers may generate a few warning in GCC, but +* they should compile */ +#define _INC_MMSYSTEM +#define _INC_MMREG +#define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */ +#define DEFINE_GUID_THUNK(name,guid) DEFINE_GUID(name,guid) +#define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK( n, STATIC_##n ) +#if !defined( DEFINE_WAVEFORMATEX_GUID ) +#define DEFINE_WAVEFORMATEX_GUID(x) (USHORT)(x), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 +#endif +#define WAVE_FORMAT_ADPCM 0x0002 +#define WAVE_FORMAT_IEEE_FLOAT 0x0003 +#define WAVE_FORMAT_ALAW 0x0006 +#define WAVE_FORMAT_MULAW 0x0007 +#define WAVE_FORMAT_MPEG 0x0050 +#define WAVE_FORMAT_DRM 0x0009 +#define DYNAMIC_GUID_THUNK(l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}} +#define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data) #endif -#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ -#pragma comment( lib, "setupapi.lib" ) -#endif - -/* use CreateThread for CYGWIN, _beginthreadex for all others */ -#ifndef __CYGWIN__ -#define CREATE_THREAD (HANDLE)_beginthreadex( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId ) +/* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */ +#if !defined(__CYGWIN__) && !defined(_WIN32_WCE) +#define CREATE_THREAD_FUNCTION (HANDLE)_beginthreadex +#define PA_THREAD_FUNC static unsigned WINAPI #else -#define CREATE_THREAD CreateThread( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId ) -#endif - -/* use ExitThread for CYGWIN, _endthreadex for all others */ -#ifndef __CYGWIN__ -#define EXIT_THREAD _endthreadex(0) -#else -#define EXIT_THREAD ExitThread(0) +#define CREATE_THREAD_FUNCTION CreateThread +#define PA_THREAD_FUNC static DWORD WINAPI #endif #ifdef _MSC_VER - #define NOMMIDS - #define DYNAMIC_GUID(data) {data} - #define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */ - #undef DEFINE_GUID - #define DEFINE_GUID(n,data) EXTERN_C const GUID n = {data} - #define DEFINE_GUID_THUNK(n,data) DEFINE_GUID(n,data) - #define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n) +#define NOMMIDS +#define DYNAMIC_GUID(data) {data} +#define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */ +#undef DEFINE_GUID +#define DEFINE_GUID(n,data) EXTERN_C const GUID n = {data} +#define DEFINE_GUID_THUNK(n,data) DEFINE_GUID(n,data) +#define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n) #endif +#include + +#ifndef EXTERN_C +#define EXTERN_C extern +#endif + +#if defined(__GNUC__) + +/* For MinGW we reference mingw-include files supplied with WASAPI */ +#define WINBOOL BOOL + +#include "../wasapi/mingw-include/ks.h" +#include "../wasapi/mingw-include/ksmedia.h" + +#else + #include #include + +/* Note that Windows SDK V6.0A or later is needed for WaveRT specific structs to be present in + ksmedia.h. Also make sure that the SDK include path is before other include paths (that may contain + an "old" ksmedia.h), so the proper ksmedia.h is used */ #include -#include + +#endif + #include #include /* These next definitions allow the use of the KSUSER DLL */ -typedef KSDDKAPI DWORD WINAPI KSCREATEPIN(HANDLE, PKSPIN_CONNECT, ACCESS_MASK, PHANDLE); +typedef /*KSDDKAPI*/ DWORD WINAPI KSCREATEPIN(HANDLE, PKSPIN_CONNECT, ACCESS_MASK, PHANDLE); extern HMODULE DllKsUser; extern KSCREATEPIN* FunctionKsCreatePin; +/* These definitions allows the use of AVRT.DLL on Vista and later OSs */ +typedef enum _PA_AVRT_PRIORITY +{ + PA_AVRT_PRIORITY_LOW = -1, + PA_AVRT_PRIORITY_NORMAL, + PA_AVRT_PRIORITY_HIGH, + PA_AVRT_PRIORITY_CRITICAL +} PA_AVRT_PRIORITY, *PPA_AVRT_PRIORITY; + +typedef struct +{ + HINSTANCE hInstance; + + HANDLE (WINAPI *AvSetMmThreadCharacteristics) (LPCSTR, LPDWORD); + BOOL (WINAPI *AvRevertMmThreadCharacteristics) (HANDLE); + BOOL (WINAPI *AvSetMmThreadPriority) (HANDLE, PA_AVRT_PRIORITY); +} PaWinWDMKSAvRtEntryPoints; + +static PaWinWDMKSAvRtEntryPoints paWinWDMKSAvRtEntryPoints = {0}; + +/* An unspecified channel count (-1) is not treated correctly, so we replace it with +* an arbitrarily large number */ +#define MAXIMUM_NUMBER_OF_CHANNELS 256 + /* Forward definition to break circular type reference between pin and filter */ struct __PaWinWdmFilter; typedef struct __PaWinWdmFilter PaWinWdmFilter; +struct __PaWinWdmPin; +typedef struct __PaWinWdmPin PaWinWdmPin; + +struct __PaWinWdmStream; +typedef struct __PaWinWdmStream PaWinWdmStream; + +/* Function prototype for getting audio position */ +typedef PaError (*FunctionGetPinAudioPosition)(PaWinWdmPin*, unsigned long*); + +/* Function prototype for memory barrier */ +typedef void (*FunctionMemoryBarrier)(void); + +struct __PaProcessThreadInfo; +typedef struct __PaProcessThreadInfo PaProcessThreadInfo; + +typedef PaError (*FunctionPinHandler)(PaProcessThreadInfo* pInfo, unsigned eventIndex); + +typedef enum __PaStreamStartEnum +{ + StreamStart_kOk, + StreamStart_kFailed, + StreamStart_kCnt +} PaStreamStartEnum; + +/* Multiplexed input structure. +* Very often several physical inputs are multiplexed through a MUX node (represented in the topology filter) */ +typedef struct __PaWinWdmMuxedInput +{ + wchar_t friendlyName[MAX_PATH]; + ULONG muxPinId; + ULONG muxNodeId; + ULONG endpointPinId; +} PaWinWdmMuxedInput; + /* The Pin structure - * A pin is an input or output node, e.g. for audio flow */ -typedef struct __PaWinWdmPin +* A pin is an input or output node, e.g. for audio flow */ +struct __PaWinWdmPin { HANDLE handle; + PaWinWdmMuxedInput** inputs; + unsigned inputCount; + wchar_t friendlyName[MAX_PATH]; + PaWinWdmFilter* parentFilter; + PaWDMKSSubType pinKsSubType; unsigned long pinId; + unsigned long endpointPinId; /* For output pins */ KSPIN_CONNECT* pinConnect; unsigned long pinConnectSize; KSDATAFORMAT_WAVEFORMATEX* ksDataFormatWfx; @@ -168,26 +288,46 @@ typedef struct __PaWinWdmPin unsigned long frameSize; int maxChannels; unsigned long formats; - int bestSampleRate; -} -PaWinWdmPin; + int defaultSampleRate; + ULONG *positionRegister; /* WaveRT */ + ULONG hwLatency; /* WaveRT */ + FunctionMemoryBarrier fnMemBarrier; /* WaveRT */ + FunctionGetPinAudioPosition fnAudioPosition; /* WaveRT */ + FunctionPinHandler fnEventHandler; + FunctionPinHandler fnSubmitHandler; +}; /* The Filter structure - * A filter has a number of pins and a "friendly name" */ +* A filter has a number of pins and a "friendly name" */ struct __PaWinWdmFilter { HANDLE handle; + PaWinWDMKSDeviceInfo devInfo; /* This will hold information that is exposed in PaDeviceInfo */ + + DWORD deviceNode; int pinCount; PaWinWdmPin** pins; - TCHAR filterName[MAX_PATH]; - TCHAR friendlyName[MAX_PATH]; - int maxInputChannels; - int maxOutputChannels; - unsigned long formats; + PaWinWdmFilter* topologyFilter; + wchar_t friendlyName[MAX_PATH]; + int validPinCount; int usageCount; - int bestSampleRate; + KSMULTIPLE_ITEM* connections; + KSMULTIPLE_ITEM* nodes; + int filterRefCount; }; + +typedef struct __PaWinWdmDeviceInfo +{ + PaDeviceInfo inheritedDeviceInfo; + char compositeName[MAX_PATH]; /* Composite name consists of pin name + device name in utf8 */ + PaWinWdmFilter* filter; + unsigned long pin; + int muxPosition; /* Used only for input devices */ + int endpointPinId; +} +PaWinWdmDeviceInfo; + /* PaWinWdmHostApiRepresentation - host api datastructure specific to this implementation */ typedef struct __PaWinWdmHostApiRepresentation { @@ -196,59 +336,105 @@ typedef struct __PaWinWdmHostApiRepresentation PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup* allocations; - PaWinWdmFilter** filters; - int filterCount; + int deviceCount; } PaWinWdmHostApiRepresentation; -typedef struct __PaWinWdmDeviceInfo -{ - PaDeviceInfo inheritedDeviceInfo; - PaWinWdmFilter* filter; -} -PaWinWdmDeviceInfo; - typedef struct __DATAPACKET { KSSTREAM_HEADER Header; OVERLAPPED Signal; } DATAPACKET; +typedef struct __PaIOPacket +{ + DATAPACKET* packet; + unsigned startByte; + unsigned lengthBytes; +} PaIOPacket; + +typedef struct __PaWinWdmIOInfo +{ + PaWinWdmPin* pPin; + char* hostBuffer; + unsigned hostBufferSize; + unsigned framesPerBuffer; + unsigned bytesPerFrame; + unsigned bytesPerSample; + unsigned noOfPackets; /* Only used in WaveCyclic */ + HANDLE *events; /* noOfPackets handles (WaveCyclic) 1 (WaveRT) */ + DATAPACKET *packets; /* noOfPackets packets (WaveCyclic) 2 (WaveRT) */ + /* WaveRT polled mode */ + unsigned lastPosition; + unsigned pollCntr; +} PaWinWdmIOInfo; + /* PaWinWdmStream - a stream data structure specifically for this implementation */ -typedef struct __PaWinWdmStream +struct __PaWinWdmStream { PaUtilStreamRepresentation streamRepresentation; + PaWDMKSSpecificStreamInfo hostApiStreamInfo; /* This holds info that is exposed through PaStreamInfo */ PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; - PaWinWdmPin* recordingPin; - PaWinWdmPin* playbackPin; - char* hostBuffer; - unsigned long framesPerHostIBuffer; - unsigned long framesPerHostOBuffer; - int bytesPerInputFrame; - int bytesPerOutputFrame; +#if PA_TRACE_REALTIME_EVENTS + LogHandle hLog; +#endif + + PaUtilAllocationGroup* allocGroup; + PaWinWdmIOInfo capture; + PaWinWdmIOInfo render; int streamStarted; int streamActive; int streamStop; int streamAbort; int oldProcessPriority; HANDLE streamThread; - HANDLE events[5]; /* 2 play + 2 record packets + abort events */ - DATAPACKET packets[4]; /* 2 play + 2 record */ + HANDLE eventAbort; + HANDLE eventStreamStart[StreamStart_kCnt]; /* 0 = OK, 1 = Failed */ + PaError threadResult; PaStreamFlags streamFlags; + + /* Capture ring buffer */ + PaUtilRingBuffer ringBuffer; + char* ringBufferData; + /* These values handle the case where the user wants to use fewer - * channels than the device has */ + * channels than the device has */ int userInputChannels; int deviceInputChannels; int userOutputChannels; int deviceOutputChannels; - int inputSampleSize; - int outputSampleSize; -} -PaWinWdmStream; +}; -#include +/* Gather all processing variables in a struct */ +struct __PaProcessThreadInfo +{ + PaWinWdmStream *stream; + PaStreamCallbackTimeInfo ti; + PaStreamCallbackFlags underover; + int cbResult; + volatile int pending; + volatile int priming; + volatile int pinsStarted; + unsigned long timeout; + unsigned captureHead; + unsigned captureTail; + unsigned renderHead; + unsigned renderTail; + PaIOPacket capturePackets[4]; + PaIOPacket renderPackets[4]; +}; + +/* Used for transferring device infos during scanning / rescanning */ +typedef struct __PaWinWDMScanDeviceInfosResults +{ + PaDeviceInfo **deviceInfos; + PaDeviceIndex defaultInputDevice; + PaDeviceIndex defaultOutputDevice; +} PaWinWDMScanDeviceInfosResults; + +static const unsigned cPacketsArrayMask = 3; HMODULE DllKsUser = NULL; KSCREATEPIN* FunctionKsCreatePin = NULL; @@ -260,7 +446,7 @@ extern "C" { #endif /* __cplusplus */ -PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); + PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); #ifdef __cplusplus } @@ -268,37 +454,50 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd /* Low level I/O functions */ static PaError WdmSyncIoctl(HANDLE handle, - unsigned long ioctlNumber, - void* inBuffer, - unsigned long inBufferCount, - void* outBuffer, - unsigned long outBufferCount, - unsigned long* bytesReturned); + unsigned long ioctlNumber, + void* inBuffer, + unsigned long inBufferCount, + void* outBuffer, + unsigned long outBufferCount, + unsigned long* bytesReturned); + static PaError WdmGetPropertySimple(HANDLE handle, - const GUID* const guidPropertySet, - unsigned long property, - void* value, - unsigned long valueCount, - void* instance, - unsigned long instanceCount); + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount); + static PaError WdmSetPropertySimple(HANDLE handle, - const GUID* const guidPropertySet, - unsigned long property, - void* value, - unsigned long valueCount, - void* instance, - unsigned long instanceCount); + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount, + void* instance, + unsigned long instanceCount); + static PaError WdmGetPinPropertySimple(HANDLE handle, - unsigned long pinId, - const GUID* const guidPropertySet, - unsigned long property, - void* value, - unsigned long valueCount); + unsigned long pinId, + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount, + unsigned long* byteCount); + static PaError WdmGetPinPropertyMulti(HANDLE handle, - unsigned long pinId, - const GUID* const guidPropertySet, - unsigned long property, - KSMULTIPLE_ITEM** ksMultipleItem); + unsigned long pinId, + const GUID* const guidPropertySet, + unsigned long property, + KSMULTIPLE_ITEM** ksMultipleItem); + +static PaError WdmGetPropertyMulti(HANDLE handle, + const GUID* const guidPropertySet, + unsigned long property, + KSMULTIPLE_ITEM** ksMultipleItem); + +static PaError WdmSetMuxNodeProperty(HANDLE handle, + ULONG nodeId, + ULONG pinId); + /** Pin management functions */ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, PaError* error); @@ -309,49 +508,48 @@ static PaError PinInstantiate(PaWinWdmPin* pin); static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state); static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format); static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format); +/* WaveRT support */ +static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult); +static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier); +static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin); +static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle); +static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle); +static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay); +static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition); +static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition); +static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition); /* Filter management functions */ -static PaWinWdmFilter* FilterNew( - TCHAR* filterName, - TCHAR* friendlyName, - PaError* error); +static PaWinWdmFilter* FilterNew(PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error); +static PaError FilterInitializePins(PaWinWdmFilter* filter); static void FilterFree(PaWinWdmFilter* filter); -static PaWinWdmPin* FilterCreateRenderPin( - PaWinWdmFilter* filter, - const WAVEFORMATEX* wfex, - PaError* error); -static PaWinWdmPin* FilterFindViableRenderPin( - PaWinWdmFilter* filter, - const WAVEFORMATEX* wfex, - PaError* error); -static PaError FilterCanCreateRenderPin( - PaWinWdmFilter* filter, - const WAVEFORMATEX* wfex); -static PaWinWdmPin* FilterCreateCapturePin( - PaWinWdmFilter* filter, - const WAVEFORMATEX* wfex, - PaError* error); -static PaWinWdmPin* FilterFindViableCapturePin( - PaWinWdmFilter* filter, - const WAVEFORMATEX* wfex, - PaError* error); -static PaError FilterCanCreateCapturePin( - PaWinWdmFilter* filter, - const WAVEFORMATEX* pwfx); -static PaError FilterUse( - PaWinWdmFilter* filter); -static void FilterRelease( - PaWinWdmFilter* filter); +static void FilterAddRef(PaWinWdmFilter* filter); +static PaWinWdmPin* FilterCreatePin( + PaWinWdmFilter* filter, + int pinId, + const WAVEFORMATEX* wfex, + PaError* error); +static PaError FilterUse(PaWinWdmFilter* filter); +static void FilterRelease(PaWinWdmFilter* filter); + +/* Hot plug functions */ +static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1, + const PaWinWdmDeviceInfo* pDev2); /* Interface functions */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); static PaError IsFormatSupported( - struct PaUtilHostApiRepresentation *hostApi, +struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); + +static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void **newDeviceInfos, int *newDeviceCount ); +static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *deviceInfos, int deviceCount ); +static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos, int deviceCount ); + static PaError OpenStream( - struct PaUtilHostApiRepresentation *hostApi, +struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, @@ -369,27 +567,120 @@ static PaError IsStreamActive( PaStream *stream ); static PaTime GetStreamTime( PaStream *stream ); static double GetStreamCpuLoad( PaStream* stream ); static PaError ReadStream( - PaStream* stream, - void *buffer, - unsigned long frames ); + PaStream* stream, + void *buffer, + unsigned long frames ); static PaError WriteStream( - PaStream* stream, - const void *buffer, - unsigned long frames ); + PaStream* stream, + const void *buffer, + unsigned long frames ); static signed long GetStreamReadAvailable( PaStream* stream ); static signed long GetStreamWriteAvailable( PaStream* stream ); /* Utility functions */ static unsigned long GetWfexSize(const WAVEFORMATEX* wfex); -static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi); +static PaWinWdmFilter** BuildFilterList(int* filterCount, int* noOfPaDevices, PaError* result); static BOOL PinWrite(HANDLE h, DATAPACKET* p); static BOOL PinRead(HANDLE h, DATAPACKET* p); static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples); static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples); -static DWORD WINAPI ProcessingThread(LPVOID pParam); +PA_THREAD_FUNC ProcessingThread(void*); + +/* Pin handler functions */ +static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex); + +static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex); + +static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex); + +static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex); +static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex); /* Function bodies */ +#if defined(_DEBUG) && defined(PA_ENABLE_DEBUG_OUTPUT) +#define PA_WDMKS_SET_TREF +static PaTime tRef = 0; + +static void PaWinWdmDebugPrintf(const char* fmt, ...) +{ + va_list list; + char buffer[1024]; + PaTime t = PaUtil_GetTime() - tRef; + va_start(list, fmt); + _vsnprintf(buffer, 1023, fmt, list); + va_end(list); + PaUtil_DebugPrint("%6.3lf: %s", t, buffer); +} + +#ifdef PA_DEBUG +#undef PA_DEBUG +#define PA_DEBUG(x) PaWinWdmDebugPrintf x ; +#endif +#endif + +static BOOL IsDeviceTheSame(const PaWinWdmDeviceInfo* pDev1, + const PaWinWdmDeviceInfo* pDev2) +{ + if (pDev1 == NULL || pDev2 == NULL) + return FALSE; + + if (pDev1 == pDev2) + return TRUE; + + if (strcmp(pDev1->compositeName, pDev2->compositeName) == 0) + return TRUE; + + return FALSE; +} + +static BOOL IsEarlierThanVista() +{ +/* +NOTE: GetVersionEx() is deprecated as of Windows 8.1 and can not be used to reliably detect +versions of Windows higher than Windows 8 (due to manifest requirements for reporting higher versions). +Microsoft recommends switching to VerifyVersionInfo (available on Win 2k and later), however GetVersionEx +is is faster, for now we just disable the deprecation warning. +See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx +See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe +*/ +#pragma warning (disable : 4996) /* use of GetVersionEx */ + + OSVERSIONINFO osvi; + osvi.dwOSVersionInfoSize = sizeof(osvi); + if (GetVersionEx(&osvi) && osvi.dwMajorVersion<6) + { + return TRUE; + } + return FALSE; + +#pragma warning (default : 4996) +} + + + +static void MemoryBarrierDummy(void) +{ + /* Do nothing */ +} + +static void MemoryBarrierRead(void) +{ + PaUtil_ReadMemoryBarrier(); +} + +static void MemoryBarrierWrite(void) +{ + PaUtil_WriteMemoryBarrier(); +} + static unsigned long GetWfexSize(const WAVEFORMATEX* wfex) { if( wfex->wFormatTag == WAVE_FORMAT_PCM ) @@ -402,133 +693,103 @@ static unsigned long GetWfexSize(const WAVEFORMATEX* wfex) } } +static void PaWinWDM_SetLastErrorInfo(long errCode, const char* fmt, ...) +{ + va_list list; + char buffer[1024]; + va_start(list, fmt); + _vsnprintf(buffer, 1023, fmt, list); + va_end(list); + PaUtil_SetLastHostErrorInfo(paWDMKS, errCode, buffer); +} + /* Low level pin/filter access functions */ static PaError WdmSyncIoctl( - HANDLE handle, - unsigned long ioctlNumber, - void* inBuffer, - unsigned long inBufferCount, - void* outBuffer, - unsigned long outBufferCount, - unsigned long* bytesReturned) + HANDLE handle, + unsigned long ioctlNumber, + void* inBuffer, + unsigned long inBufferCount, + void* outBuffer, + unsigned long outBufferCount, + unsigned long* bytesReturned) { PaError result = paNoError; - OVERLAPPED overlapped; - int boolResult; - unsigned long dummyBytesReturned; - unsigned long error; + unsigned long dummyBytesReturned = 0; + BOOL bRes; if( !bytesReturned ) { - /* User a dummy as the caller hasn't supplied one */ + /* Use a dummy as the caller hasn't supplied one */ bytesReturned = &dummyBytesReturned; } - FillMemory((void *)&overlapped,sizeof(overlapped),0); - overlapped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL); - if( !overlapped.hEvent ) + bRes = DeviceIoControl(handle, ioctlNumber, inBuffer, inBufferCount, outBuffer, outBufferCount, bytesReturned, NULL); + if (!bRes) { - result = paInsufficientMemory; - goto error; - } - overlapped.hEvent = (HANDLE)((DWORD_PTR)overlapped.hEvent | 0x1); + unsigned long error = GetLastError(); + if ( !(((error == ERROR_INSUFFICIENT_BUFFER ) || ( error == ERROR_MORE_DATA )) && + ( ioctlNumber == IOCTL_KS_PROPERTY ) && + ( outBufferCount == 0 ) ) ) + { + KSPROPERTY* ksProperty = (KSPROPERTY*)inBuffer; - boolResult = DeviceIoControl(handle, ioctlNumber, inBuffer, inBufferCount, - outBuffer, outBufferCount, bytesReturned, &overlapped); - if( !boolResult ) - { - error = GetLastError(); - if( error == ERROR_IO_PENDING ) - { - error = WaitForSingleObject(overlapped.hEvent,INFINITE); - if( error != WAIT_OBJECT_0 ) - { - result = paUnanticipatedHostError; - goto error; - } - } - else if((( error == ERROR_INSUFFICIENT_BUFFER ) || - ( error == ERROR_MORE_DATA )) && - ( ioctlNumber == IOCTL_KS_PROPERTY ) && - ( outBufferCount == 0 )) - { - boolResult = TRUE; - } - else - { + PaWinWDM_SetLastErrorInfo(result, "WdmSyncIoctl: DeviceIoControl GLE = 0x%08X (prop_set = {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}, prop_id = %u)", + error, + ksProperty->Set.Data1, ksProperty->Set.Data2, ksProperty->Set.Data3, + ksProperty->Set.Data4[0], ksProperty->Set.Data4[1], + ksProperty->Set.Data4[2], ksProperty->Set.Data4[3], + ksProperty->Set.Data4[4], ksProperty->Set.Data4[5], + ksProperty->Set.Data4[6], ksProperty->Set.Data4[7], + ksProperty->Id + ); result = paUnanticipatedHostError; } } - if( !boolResult ) - *bytesReturned = 0; - -error: - if( overlapped.hEvent ) - { - CloseHandle( overlapped.hEvent ); - } return result; } static PaError WdmGetPropertySimple(HANDLE handle, - const GUID* const guidPropertySet, - unsigned long property, - void* value, - unsigned long valueCount, - void* instance, - unsigned long instanceCount) + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount) { PaError result; - KSPROPERTY* ksProperty; - unsigned long propertyCount; + KSPROPERTY ksProperty; - propertyCount = sizeof(KSPROPERTY) + instanceCount; - ksProperty = (KSPROPERTY*)PaUtil_AllocateMemory( propertyCount ); - if( !ksProperty ) - { - return paInsufficientMemory; - } - - FillMemory((void*)ksProperty,sizeof(ksProperty),0); - ksProperty->Set = *guidPropertySet; - ksProperty->Id = property; - ksProperty->Flags = KSPROPERTY_TYPE_GET; - - if( instance ) - { - memcpy( (void*)(((char*)ksProperty)+sizeof(KSPROPERTY)), instance, instanceCount ); - } + ksProperty.Set = *guidPropertySet; + ksProperty.Id = property; + ksProperty.Flags = KSPROPERTY_TYPE_GET; result = WdmSyncIoctl( - handle, - IOCTL_KS_PROPERTY, - ksProperty, - propertyCount, - value, - valueCount, - NULL); + handle, + IOCTL_KS_PROPERTY, + &ksProperty, + sizeof(KSPROPERTY), + value, + valueCount, + NULL); - PaUtil_FreeMemory( ksProperty ); return result; } static PaError WdmSetPropertySimple( - HANDLE handle, - const GUID* const guidPropertySet, - unsigned long property, - void* value, - unsigned long valueCount, - void* instance, - unsigned long instanceCount) + HANDLE handle, + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount, + void* instance, + unsigned long instanceCount) { PaError result; KSPROPERTY* ksProperty; unsigned long propertyCount = 0; propertyCount = sizeof(KSPROPERTY) + instanceCount; - ksProperty = (KSPROPERTY*)PaUtil_AllocateMemory( propertyCount ); + ksProperty = (KSPROPERTY*)_alloca( propertyCount ); if( !ksProperty ) { return paInsufficientMemory; @@ -544,25 +805,25 @@ static PaError WdmSetPropertySimple( } result = WdmSyncIoctl( - handle, - IOCTL_KS_PROPERTY, - ksProperty, - propertyCount, - value, - valueCount, - NULL); + handle, + IOCTL_KS_PROPERTY, + ksProperty, + propertyCount, + value, + valueCount, + NULL); - PaUtil_FreeMemory( ksProperty ); return result; } static PaError WdmGetPinPropertySimple( - HANDLE handle, - unsigned long pinId, - const GUID* const guidPropertySet, - unsigned long property, - void* value, - unsigned long valueCount) + HANDLE handle, + unsigned long pinId, + const GUID* const guidPropertySet, + unsigned long property, + void* value, + unsigned long valueCount, + unsigned long *byteCount) { PaError result; @@ -574,23 +835,23 @@ static PaError WdmGetPinPropertySimple( ksPProp.Reserved = 0; result = WdmSyncIoctl( - handle, - IOCTL_KS_PROPERTY, - &ksPProp, - sizeof(KSP_PIN), - value, - valueCount, - NULL); + handle, + IOCTL_KS_PROPERTY, + &ksPProp, + sizeof(KSP_PIN), + value, + valueCount, + byteCount); return result; } static PaError WdmGetPinPropertyMulti( - HANDLE handle, - unsigned long pinId, - const GUID* const guidPropertySet, - unsigned long property, - KSMULTIPLE_ITEM** ksMultipleItem) + HANDLE handle, + unsigned long pinId, + const GUID* const guidPropertySet, + unsigned long property, + KSMULTIPLE_ITEM** ksMultipleItem) { PaError result; unsigned long multipleItemSize = 0; @@ -603,13 +864,13 @@ static PaError WdmGetPinPropertyMulti( ksPProp.Reserved = 0; result = WdmSyncIoctl( - handle, - IOCTL_KS_PROPERTY, - &ksPProp.Property, - sizeof(KSP_PIN), - NULL, - 0, - &multipleItemSize); + handle, + IOCTL_KS_PROPERTY, + &ksPProp.Property, + sizeof(KSP_PIN), + NULL, + 0, + &multipleItemSize); if( result != paNoError ) { return result; @@ -622,13 +883,13 @@ static PaError WdmGetPinPropertyMulti( } result = WdmSyncIoctl( - handle, - IOCTL_KS_PROPERTY, - &ksPProp, - sizeof(KSP_PIN), - (void*)*ksMultipleItem, - multipleItemSize, - NULL); + handle, + IOCTL_KS_PROPERTY, + &ksPProp, + sizeof(KSP_PIN), + (void*)*ksMultipleItem, + multipleItemSize, + NULL); if( result != paNoError ) { @@ -638,6 +899,416 @@ static PaError WdmGetPinPropertyMulti( return result; } +static PaError WdmGetPropertyMulti(HANDLE handle, + const GUID* const guidPropertySet, + unsigned long property, + KSMULTIPLE_ITEM** ksMultipleItem) +{ + PaError result; + unsigned long multipleItemSize = 0; + KSPROPERTY ksProp; + + ksProp.Set = *guidPropertySet; + ksProp.Id = property; + ksProp.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl( + handle, + IOCTL_KS_PROPERTY, + &ksProp, + sizeof(KSPROPERTY), + NULL, + 0, + &multipleItemSize); + if( result != paNoError ) + { + return result; + } + + *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize ); + if( !*ksMultipleItem ) + { + return paInsufficientMemory; + } + + result = WdmSyncIoctl( + handle, + IOCTL_KS_PROPERTY, + &ksProp, + sizeof(KSPROPERTY), + (void*)*ksMultipleItem, + multipleItemSize, + NULL); + + if( result != paNoError ) + { + PaUtil_FreeMemory( ksMultipleItem ); + } + + return result; +} + +static PaError WdmSetMuxNodeProperty(HANDLE handle, + ULONG nodeId, + ULONG pinId) +{ + PaError result = paNoError; + KSNODEPROPERTY prop; + prop.Property.Set = KSPROPSETID_Audio; + prop.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE; + prop.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; + prop.NodeId = nodeId; + prop.Reserved = 0; + + result = WdmSyncIoctl(handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSNODEPROPERTY), &pinId, sizeof(ULONG), NULL); + + return result; +} + +/* Used when traversing topology for outputs */ +static const KSTOPOLOGY_CONNECTION* GetConnectionTo(const KSTOPOLOGY_CONNECTION* pFrom, PaWinWdmFilter* filter, int muxIdx) +{ + unsigned i; + const KSTOPOLOGY_CONNECTION* retval = NULL; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + (void)muxIdx; + PA_DEBUG(("GetConnectionTo: Checking %u connections... (pFrom = %p)", filter->connections->Count, pFrom)); + for (i = 0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + if (pConn == pFrom) + continue; + + if (pConn->FromNode == pFrom->ToNode) + { + retval = pConn; + break; + } + } + PA_DEBUG(("GetConnectionTo: Returning %p\n", retval)); + return retval; +} + +/* Used when traversing topology for inputs */ +static const KSTOPOLOGY_CONNECTION* GetConnectionFrom(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter, int muxIdx) +{ + unsigned i; + const KSTOPOLOGY_CONNECTION* retval = NULL; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + int muxCntr = 0; + PA_DEBUG(("GetConnectionFrom: Checking %u connections... (pTo = %p)\n", filter->connections->Count, pTo)); + for (i = 0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + if (pConn == pTo) + continue; + + if (pConn->ToNode == pTo->FromNode) + { + if (muxIdx >= 0) + { + if (muxCntr < muxIdx) + { + ++muxCntr; + continue; + } + } + retval = pConn; + break; + } + } + PA_DEBUG(("GetConnectionFrom: Returning %p\n", retval)); + return retval; +} + +static ULONG GetNumberOfConnectionsTo(const KSTOPOLOGY_CONNECTION* pTo, PaWinWdmFilter* filter) +{ + ULONG retval = 0; + unsigned i; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + PA_DEBUG(("GetNumberOfConnectionsTo: Checking %u connections...\n", filter->connections->Count)); + for (i = 0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + if (pConn->ToNode == pTo->FromNode && + (pTo->FromNode != KSFILTER_NODE || pConn->ToNodePin == pTo->FromNodePin)) + { + ++retval; + } + } + PA_DEBUG(("GetNumberOfConnectionsTo: Returning %d\n", retval)); + return retval; +} + +typedef const KSTOPOLOGY_CONNECTION *(*TFnGetConnection)(const KSTOPOLOGY_CONNECTION*, PaWinWdmFilter*, int); + +static const KSTOPOLOGY_CONNECTION* FindStartConnectionFrom(ULONG startPin, PaWinWdmFilter* filter) +{ + unsigned i; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + PA_DEBUG(("FindStartConnectionFrom: Startpin %u, Checking %u connections...\n", startPin, filter->connections->Count)); + for (i = 0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + if (pConn->ToNode == KSFILTER_NODE && pConn->ToNodePin == startPin) + { + PA_DEBUG(("FindStartConnectionFrom: returning %p\n", pConn)); + return pConn; + } + } + + PA_DEBUG(("FindStartConnectionFrom: returning NULL\n")); + assert(FALSE); + return 0; +} + +static const KSTOPOLOGY_CONNECTION* FindStartConnectionTo(ULONG startPin, PaWinWdmFilter* filter) +{ + unsigned i; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + PA_DEBUG(("FindStartConnectionTo: Startpin %u, Checking %u connections...\n", startPin, filter->connections->Count)); + for (i = 0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + if (pConn->FromNode == KSFILTER_NODE && pConn->FromNodePin == startPin) + { + PA_DEBUG(("FindStartConnectionTo: returning %p\n", pConn)); + return pConn; + } + } + + PA_DEBUG(("FindStartConnectionTo: returning NULL\n")); + assert(FALSE); + return 0; +} + +static ULONG GetConnectedPin(ULONG startPin, BOOL forward, PaWinWdmFilter* filter, int muxPosition, ULONG *muxInputPinId, ULONG *muxNodeId) +{ + int limit=1000; + const KSTOPOLOGY_CONNECTION *conn = NULL; + TFnGetConnection fnGetConnection = forward ? GetConnectionTo : GetConnectionFrom ; + PA_LOGE_; + while (1) + { + limit--; + if (limit == 0) { + PA_DEBUG(("GetConnectedPin: LOOP LIMIT REACHED\n")); + break; + } + + if (conn == NULL) + { + conn = forward ? FindStartConnectionTo(startPin, filter) : FindStartConnectionFrom(startPin, filter); + } + else + { + conn = fnGetConnection(conn, filter, -1); + } + + /* Handling case of erroneous connection list */ + if (conn == NULL) + { + break; + } + + if (forward ? conn->ToNode == KSFILTER_NODE : conn->FromNode == KSFILTER_NODE) + { + return forward ? conn->ToNodePin : conn->FromNodePin; + } + else + { + PA_DEBUG(("GetConnectedPin: count=%d, forward=%d, muxPosition=%d\n", filter->nodes->Count, forward, muxPosition)); + if (filter->nodes->Count > 0 && !forward && muxPosition >= 0) + { + const GUID* nodes = (const GUID*)(filter->nodes + 1); + if (IsEqualGUID(&nodes[conn->FromNode], &KSNODETYPE_MUX)) + { + ULONG nConn = GetNumberOfConnectionsTo(conn, filter); + conn = fnGetConnection(conn, filter, muxPosition); + if (conn == NULL) + { + break; + } + if (muxInputPinId != 0) + { + *muxInputPinId = conn->ToNodePin; + } + if (muxNodeId != 0) + { + *muxNodeId = conn->ToNode; + } + } + } + } + } + PA_LOGL_; + return KSFILTER_NODE; +} + +static void DumpConnectionsAndNodes(PaWinWdmFilter* filter) +{ + unsigned i; + const KSTOPOLOGY_CONNECTION* connections = (const KSTOPOLOGY_CONNECTION*)(filter->connections + 1); + const GUID* nodes = (const GUID*)(filter->nodes + 1); + + PA_LOGE_; + PA_DEBUG(("DumpConnectionsAndNodes: connections=%d, nodes=%d\n", filter->connections->Count, filter->nodes->Count)); + + for (i=0; i < filter->connections->Count; ++i) + { + const KSTOPOLOGY_CONNECTION* pConn = connections + i; + PA_DEBUG((" Connection: %u - FromNode=%u,FromPin=%u -> ToNode=%u,ToPin=%u\n", + i, + pConn->FromNode, pConn->FromNodePin, + pConn->ToNode, pConn->ToNodePin + )); + } + + for (i=0; i < filter->nodes->Count; ++i) + { + const GUID* pConn = nodes + i; + PA_DEBUG((" Node: %d - {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n", + i, + pConn->Data1, pConn->Data2, pConn->Data3, + pConn->Data4[0], pConn->Data4[1], + pConn->Data4[2], pConn->Data4[3], + pConn->Data4[4], pConn->Data4[5], + pConn->Data4[6], pConn->Data4[7] + )); + } + PA_LOGL_; + +} + +typedef struct __PaUsbTerminalGUIDToName +{ + USHORT usbGUID; + wchar_t name[64]; +} PaUsbTerminalGUIDToName; + +static const PaUsbTerminalGUIDToName kNames[] = +{ + /* Types copied from: http://msdn.microsoft.com/en-us/library/ff537742(v=vs.85).aspx */ + /* Input terminal types */ + { 0x0201, L"Microphone" }, + { 0x0202, L"Desktop Microphone" }, + { 0x0203, L"Personal Microphone" }, + { 0x0204, L"Omni Directional Microphone" }, + { 0x0205, L"Microphone Array" }, + { 0x0206, L"Processing Microphone Array" }, + /* Output terminal types */ + { 0x0301, L"Speakers" }, + { 0x0302, L"Headphones" }, + { 0x0303, L"Head Mounted Display Audio" }, + { 0x0304, L"Desktop Speaker" }, + { 0x0305, L"Room Speaker" }, + { 0x0306, L"Communication Speaker" }, + { 0x0307, L"LFE Speakers" }, + /* External terminal types */ + { 0x0601, L"Analog" }, + { 0x0602, L"Digital" }, + { 0x0603, L"Line" }, + { 0x0604, L"Audio" }, + { 0x0605, L"SPDIF" }, +}; + +static const unsigned kNamesCnt = sizeof(kNames)/sizeof(PaUsbTerminalGUIDToName); + +static int PaUsbTerminalGUIDToNameCmp(const void* lhs, const void* rhs) +{ + const PaUsbTerminalGUIDToName* pL = (const PaUsbTerminalGUIDToName*)lhs; + const PaUsbTerminalGUIDToName* pR = (const PaUsbTerminalGUIDToName*)rhs; + return ((int)(pL->usbGUID) - (int)(pR->usbGUID)); +} + +static PaError GetNameFromCategory(const GUID* pGUID, BOOL input, wchar_t* name, unsigned length) +{ + PaError result = paUnanticipatedHostError; + USHORT usbTerminalGUID = (USHORT)(pGUID->Data1 - 0xDFF219E0); + + PA_LOGE_; + if (input && usbTerminalGUID >= 0x301 && usbTerminalGUID < 0x400) + { + /* Output terminal name for an input !? Set it to Line! */ + usbTerminalGUID = 0x603; + } + if (!input && usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x300) + { + /* Input terminal name for an output !? Set it to Line! */ + usbTerminalGUID = 0x603; + } + if (usbTerminalGUID >= 0x201 && usbTerminalGUID < 0x713) + { + PaUsbTerminalGUIDToName s = { usbTerminalGUID }; + const PaUsbTerminalGUIDToName* ptr = bsearch( + &s, + kNames, + kNamesCnt, + sizeof(PaUsbTerminalGUIDToName), + PaUsbTerminalGUIDToNameCmp + ); + if (ptr != 0) + { + PA_DEBUG(("GetNameFromCategory: USB GUID %04X -> '%S'\n", usbTerminalGUID, ptr->name)); + + if (name != NULL && length > 0) + { + int n = _snwprintf(name, length, L"%s", ptr->name); + if (usbTerminalGUID >= 0x601 && usbTerminalGUID < 0x700) + { + _snwprintf(name + n, length - n, L" %s", (input ? L"In":L"Out")); + } + } + result = paNoError; + } + } + else + { + PaWinWDM_SetLastErrorInfo(result, "GetNameFromCategory: usbTerminalGUID = %04X ", usbTerminalGUID); + } + PA_LOGL_; + return result; +} + +static BOOL IsFrequencyWithinRange(const KSDATARANGE_AUDIO* range, int frequency) +{ + if (frequency < (int)range->MinimumSampleFrequency) + return FALSE; + if (frequency > (int)range->MaximumSampleFrequency) + return FALSE; + return TRUE; +} + +static BOOL IsBitsWithinRange(const KSDATARANGE_AUDIO* range, int noOfBits) +{ + if (noOfBits < (int)range->MinimumBitsPerSample) + return FALSE; + if (noOfBits > (int)range->MaximumBitsPerSample) + return FALSE; + return TRUE; +} + +/* Note: Somewhat different order compared to WMME implementation, as we want to focus on fidelity first */ +static const int defaultSampleRateSearchOrder[] = +{ 44100, 48000, 88200, 96000, 192000, 32000, 24000, 22050, 16000, 12000, 11025, 9600, 8000 }; +static const int defaultSampleRateSearchOrderCount = sizeof(defaultSampleRateSearchOrder)/sizeof(defaultSampleRateSearchOrder[0]); + +static int DefaultSampleFrequencyIndex(const KSDATARANGE_AUDIO* range) +{ + int i; + + for(i=0; i < defaultSampleRateSearchOrderCount; ++i) + { + int currentFrequency = defaultSampleRateSearchOrder[i]; + + if (IsFrequencyWithinRange(range, currentFrequency)) + { + return i; + } + } + + return -1; +} /* Create a new pin object belonging to a filter @@ -652,9 +1323,11 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa KSMULTIPLE_ITEM* item = NULL; KSIDENTIFIER* identifier; KSDATARANGE* dataRange; + const ULONG streamingId = (parentFilter->devInfo.streamingType == Type_kWaveRT) ? KSINTERFACE_STANDARD_LOOPED_STREAMING : KSINTERFACE_STANDARD_STREAMING; + int defaultSampleRateIndex = defaultSampleRateSearchOrderCount; PA_LOGE_; - PA_DEBUG(("Creating pin %d:\n",pinId)); + PA_DEBUG(("PinNew: Creating pin %d:\n",pinId)); /* Allocate the new PIN object */ pin = (PaWinWdmPin*)PaUtil_AllocateMemory( sizeof(PaWinWdmPin) ); @@ -681,7 +1354,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa /* Configure the connect structure with default values */ pin->pinConnect->Interface.Set = KSINTERFACESETID_Standard; - pin->pinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING; + pin->pinConnect->Interface.Id = streamingId; pin->pinConnect->Interface.Flags = 0; pin->pinConnect->Medium.Set = KSMEDIUMSETID_Standard; pin->pinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE; @@ -707,15 +1380,16 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa &KSPROPSETID_Pin, KSPROPERTY_PIN_COMMUNICATION, &pin->communication, - sizeof(KSPIN_COMMUNICATION)); + sizeof(KSPIN_COMMUNICATION), + NULL); if( result != paNoError ) goto error; if( /*(pin->communication != KSPIN_COMMUNICATION_SOURCE) &&*/ - (pin->communication != KSPIN_COMMUNICATION_SINK) && - (pin->communication != KSPIN_COMMUNICATION_BOTH) ) + (pin->communication != KSPIN_COMMUNICATION_SINK) && + (pin->communication != KSPIN_COMMUNICATION_BOTH) ) { - PA_DEBUG(("Not source/sink\n")); + PA_DEBUG(("PinNew: Not source/sink\n")); result = paInvalidDevice; goto error; } @@ -727,7 +1401,8 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa &KSPROPSETID_Pin, KSPROPERTY_PIN_DATAFLOW, &pin->dataFlow, - sizeof(KSPIN_DATAFLOW)); + sizeof(KSPIN_DATAFLOW), + NULL); if( result != paNoError ) goto error; @@ -749,8 +1424,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa result = paUnanticipatedHostError; for( i = 0; i < item->Count; i++ ) { - if( !memcmp( (void*)&identifier[i].Set, (void*)&KSINTERFACESETID_Standard, sizeof( GUID ) ) && - ( identifier[i].Id == KSINTERFACE_STANDARD_STREAMING ) ) + if( IsEqualGUID(&identifier[i].Set, &KSINTERFACESETID_Standard) && ( identifier[i].Id == streamingId ) ) { result = paNoError; break; @@ -759,7 +1433,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa if( result != paNoError ) { - PA_DEBUG(("No standard streaming\n")); + PA_DEBUG(("PinNew: No %s streaming\n", streamingId==KSINTERFACE_STANDARD_LOOPED_STREAMING?"looped":"standard")); goto error; } @@ -784,8 +1458,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa result = paUnanticipatedHostError; for( i = 0; i < item->Count; i++ ) { - if( !memcmp( (void*)&identifier[i].Set, (void*)&KSMEDIUMSETID_Standard, sizeof( GUID ) ) && - ( identifier[i].Id == KSMEDIUM_STANDARD_DEVIO ) ) + if( IsEqualGUID(&identifier[i].Set, &KSMEDIUMSETID_Standard) && ( identifier[i].Id == KSMEDIUM_STANDARD_DEVIO ) ) { result = paNoError; break; @@ -818,53 +1491,66 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa result = paUnanticipatedHostError; dataRange = pin->dataRanges; pin->maxChannels = 0; - pin->bestSampleRate = 0; + pin->defaultSampleRate = 0; pin->formats = 0; - for( i = 0; i dataRangesItem->Count; i++) + PA_DEBUG(("PinNew: Checking %u no of dataranges...\n", pin->dataRangesItem->Count)); + for( i = 0; i < pin->dataRangesItem->Count; i++) { - PA_DEBUG(("DR major format %x\n",*(unsigned long*)(&(dataRange->MajorFormat)))); + PA_DEBUG(("PinNew: DR major format %x\n",*(unsigned long*)(&(dataRange->MajorFormat)))); /* Check that subformat is WAVEFORMATEX, PCM or WILDCARD */ if( IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) || - !memcmp((void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_PCM, sizeof ( GUID ) ) || - ( !memcmp((void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_WILDCARD, sizeof ( GUID ) ) && - ( !memcmp((void*)&dataRange->MajorFormat, (void*)&KSDATAFORMAT_TYPE_AUDIO, sizeof ( GUID ) ) ) ) ) + IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) || + IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) || + IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_WILDCARD) || + IsEqualGUID(&dataRange->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) ) { + int defaultIndex; result = paNoError; /* Record the maximum possible channels with this pin */ - PA_DEBUG(("MaxChannel: %d\n",pin->maxChannels)); - if( (int)((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels > pin->maxChannels ) + if( ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels == (ULONG) -1 ) { - pin->maxChannels = ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels; - /*PA_DEBUG(("MaxChannel: %d\n",pin->maxChannels));*/ + pin->maxChannels = MAXIMUM_NUMBER_OF_CHANNELS; } + else if( (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels > pin->maxChannels ) + { + pin->maxChannels = (int) ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels; + } + PA_DEBUG(("PinNew: MaxChannel: %d\n",pin->maxChannels)); + /* Record the formats (bit depths) that are supported */ - if( ((KSDATARANGE_AUDIO*)dataRange)->MinimumBitsPerSample <= 16 ) + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 8) ) + { + pin->formats |= paInt8; + PA_DEBUG(("PinNew: Format PCM 8 bit supported\n")); + } + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 16) ) { pin->formats |= paInt16; - PA_DEBUG(("Format 16 bit supported\n")); + PA_DEBUG(("PinNew: Format PCM 16 bit supported\n")); } - if( ((KSDATARANGE_AUDIO*)dataRange)->MaximumBitsPerSample >= 24 ) + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 24) ) { pin->formats |= paInt24; - PA_DEBUG(("Format 24 bit supported\n")); + PA_DEBUG(("PinNew: Format PCM 24 bit supported\n")); } - if( ( pin->bestSampleRate != 48000) && - (((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency >= 48000) && - (((KSDATARANGE_AUDIO*)dataRange)->MinimumSampleFrequency <= 48000) ) + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 32) ) { - pin->bestSampleRate = 48000; - PA_DEBUG(("48kHz supported\n")); + if (IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + { + pin->formats |= paFloat32; + PA_DEBUG(("PinNew: Format IEEE float 32 bit supported\n")); + } + else + { + pin->formats |= paInt32; + PA_DEBUG(("PinNew: Format PCM 32 bit supported\n")); + } } - else if(( pin->bestSampleRate != 48000) && ( pin->bestSampleRate != 44100 ) && - (((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency >= 44100) && - (((KSDATARANGE_AUDIO*)dataRange)->MinimumSampleFrequency <= 44100) ) + + defaultIndex = DefaultSampleFrequencyIndex((KSDATARANGE_AUDIO*)dataRange); + if (defaultIndex >= 0 && defaultIndex < defaultSampleRateIndex) { - pin->bestSampleRate = 44100; - PA_DEBUG(("44.1kHz supported\n")); - } - else - { - pin->bestSampleRate = ((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency; + defaultSampleRateIndex = defaultIndex; } } dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize); @@ -873,6 +1559,19 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa if( result != paNoError ) goto error; + /* If none of the frequencies searched for are present, there's something seriously wrong */ + if (defaultSampleRateIndex == defaultSampleRateSearchOrderCount) + { + PA_DEBUG(("PinNew: No default sample rate found, skipping pin!\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "PinNew: No default sample rate found"); + result = paUnanticipatedHostError; + goto error; + } + + /* Set the default sample rate */ + pin->defaultSampleRate = defaultSampleRateSearchOrder[defaultSampleRateIndex]; + PA_DEBUG(("PinNew: Default sample rate = %d Hz\n", pin->defaultSampleRate)); + /* Get instance information */ result = WdmGetPinPropertySimple( parentFilter->handle, @@ -880,11 +1579,421 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa &KSPROPSETID_Pin, KSPROPERTY_PIN_CINSTANCES, &pin->instances, - sizeof(KSPIN_CINSTANCES)); + sizeof(KSPIN_CINSTANCES), + NULL); if( result != paNoError ) goto error; + /* If WaveRT, check if pin supports notification mode */ + if (parentFilter->devInfo.streamingType == Type_kWaveRT) + { + BOOL bSupportsNotification = FALSE; + if (PinQueryNotificationSupport(pin, &bSupportsNotification) == paNoError) + { + pin->pinKsSubType = bSupportsNotification ? SubType_kNotification : SubType_kPolled; + } + } + + /* Query pin name (which means we need to traverse to non IRP pin, via physical connection to topology filter pin, through + its nodes to the endpoint pin, and get that ones name... phew...) */ + PA_DEBUG(("PinNew: Finding topology pin...\n")); + + { + ULONG topoPinId = GetConnectedPin(pinId, (pin->dataFlow == KSPIN_DATAFLOW_IN), parentFilter, -1, NULL, NULL); + const wchar_t kInputName[] = L"Input"; + const wchar_t kOutputName[] = L"Output"; + + if (topoPinId != KSFILTER_NODE) + { + /* Get physical connection for topo pin */ + unsigned long cbBytes = 0; + PA_DEBUG(("PinNew: Getting physical connection...\n")); + result = WdmGetPinPropertySimple(parentFilter->handle, + topoPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_PHYSICALCONNECTION, + 0, + 0, + &cbBytes + ); + + if (result != paNoError) + { + /* No physical connection -> there is no topology filter! So we get the name of the pin! */ + PA_DEBUG(("PinNew: No physical connection! Getting the pin name\n")); + result = WdmGetPinPropertySimple(parentFilter->handle, + topoPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_NAME, + pin->friendlyName, + MAX_PATH, + NULL); + if (result != paNoError) + { + GUID category = {0}; + + /* Get pin category information */ + result = WdmGetPinPropertySimple(parentFilter->handle, + topoPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_CATEGORY, + &category, + sizeof(GUID), + NULL); + + if (result == paNoError) + { + result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH); + } + } + + /* Make sure pin gets a name here... */ + if (wcslen(pin->friendlyName) == 0) + { + wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName); +#ifdef UNICODE + PA_DEBUG(("PinNew: Setting pin friendly name to '%s'\n", pin->friendlyName)); +#else + PA_DEBUG(("PinNew: Setting pin friendly name to '%S'\n", pin->friendlyName)); +#endif + } + + /* This is then == the endpoint pin */ + pin->endpointPinId = (pin->dataFlow == KSPIN_DATAFLOW_IN) ? pinId : topoPinId; + } + else + { + KSPIN_PHYSICALCONNECTION* pc = (KSPIN_PHYSICALCONNECTION*)PaUtil_AllocateMemory(cbBytes + 2); + ULONG pcPin; + wchar_t symbLinkName[MAX_PATH]; + PA_DEBUG(("PinNew: Physical connection found!\n")); + if (pc == NULL) + { + result = paInsufficientMemory; + goto error; + } + result = WdmGetPinPropertySimple(parentFilter->handle, + topoPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_PHYSICALCONNECTION, + pc, + cbBytes, + NULL + ); + + pcPin = pc->Pin; + wcsncpy(symbLinkName, pc->SymbolicLinkName, MAX_PATH); + PaUtil_FreeMemory( pc ); + + if (result != paNoError) + { + /* Shouldn't happen, but fail if it does */ + PA_DEBUG(("PinNew: failed to retrieve physical connection!\n")); + goto error; + } + + if (symbLinkName[1] == TEXT('?')) + { + symbLinkName[1] = TEXT('\\'); + } + + if (pin->parentFilter->topologyFilter == NULL) + { + PA_DEBUG(("PinNew: Creating topology filter '%S'\n", symbLinkName)); + + pin->parentFilter->topologyFilter = FilterNew(Type_kNotUsed, 0, symbLinkName, L"", &result); + if (pin->parentFilter->topologyFilter == NULL) + { + PA_DEBUG(("PinNew: Failed creating topology filter\n")); + result = paUnanticipatedHostError; + PaWinWDM_SetLastErrorInfo(result, "Failed to create topology filter '%S'", symbLinkName); + goto error; + } + + /* Copy info so we have it in device info */ + wcsncpy(pin->parentFilter->devInfo.topologyPath, symbLinkName, MAX_PATH); + } + else + { + /* Must be the same */ + assert(wcscmp(symbLinkName, pin->parentFilter->topologyFilter->devInfo.filterPath) == 0); + } + + PA_DEBUG(("PinNew: Opening topology filter...")); + + result = FilterUse(pin->parentFilter->topologyFilter); + if (result == paNoError) + { + unsigned long endpointPinId; + + if (pin->dataFlow == KSPIN_DATAFLOW_IN) + { + /* The "endpointPinId" is what WASAPI looks at for pin names */ + GUID category = {0}; + + PA_DEBUG(("PinNew: Checking for output endpoint pin id...\n")); + + endpointPinId = GetConnectedPin(pcPin, TRUE, pin->parentFilter->topologyFilter, -1, NULL, NULL); + + if (endpointPinId == KSFILTER_NODE) + { + result = paUnanticipatedHostError; + PaWinWDM_SetLastErrorInfo(result, "Failed to get endpoint pin ID on topology filter!"); + goto error; + } + + PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId)); + + /* Get pin category information */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_CATEGORY, + &category, + sizeof(GUID), + NULL); + + if (result == paNoError) + { +#if !PA_WDMKS_USE_CATEGORY_FOR_PIN_NAMES + wchar_t pinName[MAX_PATH]; + + PA_DEBUG(("PinNew: Getting pin name property...")); + + /* Ok, try pin name also, and favor that if available */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_NAME, + pinName, + MAX_PATH, + NULL); + + if (result == paNoError && wcslen(pinName)>0) + { + wcsncpy(pin->friendlyName, pinName, MAX_PATH); + } + else +#endif + { + result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH); + } + } + + /* Make sure we get a name for the pin */ + if (wcslen(pin->friendlyName) == 0) + { + wcscpy(pin->friendlyName, kOutputName); + } +#ifdef UNICODE + PA_DEBUG(("PinNew: Pin name '%s'\n", pin->friendlyName)); +#else + PA_DEBUG(("PinNew: Pin name '%S'\n", pin->friendlyName)); +#endif + + /* Set endpoint pin ID (this is the topology INPUT pin, since portmixer will always traverse the + filter in audio streaming direction, see http://msdn.microsoft.com/en-us/library/windows/hardware/ff536331(v=vs.85).aspx + for more information) + */ + pin->endpointPinId = pcPin; + } + else + { + unsigned muxCount = 0; + int muxPos = 0; + /* Max 64 multiplexer inputs... sanity check :) */ + for (i = 0; i < 64; ++i) + { + ULONG muxNodeIdTest = (unsigned)-1; + PA_DEBUG(("PinNew: Checking for input endpoint pin id (%d)...\n", i)); + + endpointPinId = GetConnectedPin(pcPin, + FALSE, + pin->parentFilter->topologyFilter, + (int)i, + NULL, + &muxNodeIdTest); + + if (endpointPinId == KSFILTER_NODE) + { + /* We're done */ + PA_DEBUG(("PinNew: Done with inputs.\n", endpointPinId)); + break; + } + else + { + /* The "endpointPinId" is what WASAPI looks at for pin names */ + GUID category = {0}; + + PA_DEBUG(("PinNew: Found endpoint pin id %u\n", endpointPinId)); + + /* Get pin category information */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_CATEGORY, + &category, + sizeof(GUID), + NULL); + + if (result == paNoError) + { + if (muxNodeIdTest == (unsigned)-1) + { + /* Ok, try pin name, and favor that if available */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_NAME, + pin->friendlyName, + MAX_PATH, + NULL); + + if (result != paNoError) + { + result = GetNameFromCategory(&category, TRUE, pin->friendlyName, MAX_PATH); + } + break; + } + else + { + result = GetNameFromCategory(&category, TRUE, NULL, 0); + + if (result == paNoError) + { + ++muxCount; + } + } + } + else + { + PA_DEBUG(("PinNew: Failed to get pin category")); + } + } + } + + if (muxCount == 0) + { + pin->endpointPinId = endpointPinId; + /* Make sure we get a name for the pin */ + if (wcslen(pin->friendlyName) == 0) + { + wcscpy(pin->friendlyName, kInputName); + } +#ifdef UNICODE + PA_DEBUG(("PinNew: Input friendly name '%s'\n", pin->friendlyName)); +#else + PA_DEBUG(("PinNew: Input friendly name '%S'\n", pin->friendlyName)); +#endif + } + else // muxCount > 0 + { + PA_DEBUG(("PinNew: Setting up %u inputs\n", muxCount)); + + /* Now we redo the operation once known how many multiplexer positions there are */ + pin->inputs = (PaWinWdmMuxedInput**)PaUtil_AllocateMemory(muxCount * sizeof(PaWinWdmMuxedInput*)); + if (pin->inputs == NULL) + { + FilterRelease(pin->parentFilter->topologyFilter); + result = paInsufficientMemory; + goto error; + } + pin->inputCount = muxCount; + + for (i = 0; i < muxCount; ++muxPos) + { + PA_DEBUG(("PinNew: Setting up input %u...\n", i)); + + if (pin->inputs[i] == NULL) + { + pin->inputs[i] = (PaWinWdmMuxedInput*)PaUtil_AllocateMemory(sizeof(PaWinWdmMuxedInput)); + if (pin->inputs[i] == NULL) + { + FilterRelease(pin->parentFilter->topologyFilter); + result = paInsufficientMemory; + goto error; + } + } + + endpointPinId = GetConnectedPin(pcPin, + FALSE, + pin->parentFilter->topologyFilter, + muxPos, + &pin->inputs[i]->muxPinId, + &pin->inputs[i]->muxNodeId); + + if (endpointPinId != KSFILTER_NODE) + { + /* The "endpointPinId" is what WASAPI looks at for pin names */ + GUID category = {0}; + + /* Set input endpoint ID */ + pin->inputs[i]->endpointPinId = endpointPinId; + + /* Get pin category information */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_CATEGORY, + &category, + sizeof(GUID), + NULL); + + if (result == paNoError) + { + /* Try pin name first, and if that is not defined, use category instead */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_NAME, + pin->inputs[i]->friendlyName, + MAX_PATH, + NULL); + + if (result != paNoError) + { + result = GetNameFromCategory(&category, TRUE, pin->inputs[i]->friendlyName, MAX_PATH); + if (result != paNoError) + { + /* Only specify name, let name hash in ScanDeviceInfos fix postfix enumerators */ + wcscpy(pin->inputs[i]->friendlyName, kInputName); + } + } +#ifdef UNICODE + PA_DEBUG(("PinNew: Input (%u) friendly name '%s'\n", i, pin->inputs[i]->friendlyName)); +#else + PA_DEBUG(("PinNew: Input (%u) friendly name '%S'\n", i, pin->inputs[i]->friendlyName)); +#endif + ++i; + } + } + else + { + /* Should never come here! */ + assert(FALSE); + } + } + } + } + } + } + } + else + { + PA_DEBUG(("PinNew: No topology pin id found. Bad...\n")); + /* No TOPO pin id ??? This is bad. Ok, so we just say it is an input or output... */ + wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? kOutputName : kInputName); + } + } + + /* Release topology filter if it has been used */ + if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL) + { + PA_DEBUG(("PinNew: Releasing topology filter...\n")); + FilterRelease(pin->parentFilter->topologyFilter); + } + /* Success */ *error = paNoError; PA_DEBUG(("Pin created successfully\n")); @@ -892,16 +2001,19 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa return pin; error: + PA_DEBUG(("PinNew: Error %d\n", result)); /* Error cleanup */ - PaUtil_FreeMemory( item ); - if( pin ) + + if (pin->parentFilter->topologyFilter && pin->parentFilter->topologyFilter->handle != NULL) { - PaUtil_FreeMemory( pin->pinConnect ); - PaUtil_FreeMemory( pin->dataRangesItem ); - PaUtil_FreeMemory( pin ); + FilterRelease(pin->parentFilter->topologyFilter); } + + PaUtil_FreeMemory( item ); + PinFree(pin); + *error = result; PA_LOGL_; return NULL; @@ -912,6 +2024,7 @@ Safely free all resources associated with the pin */ static void PinFree(PaWinWdmPin* pin) { + unsigned i; PA_LOGE_; if( pin ) { @@ -924,6 +2037,14 @@ static void PinFree(PaWinWdmPin* pin) { PaUtil_FreeMemory( pin->dataRangesItem ); } + if( pin->inputs ) + { + for (i = 0; i < pin->inputCount; ++i) + { + PaUtil_FreeMemory( pin->inputs[i] ); + } + PaUtil_FreeMemory( pin->inputs ); + } PaUtil_FreeMemory( pin ); } PA_LOGL_; @@ -957,22 +2078,21 @@ Set the state of this (instantiated) pin */ static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state) { - PaError result; + PaError result = paNoError; + KSPROPERTY prop; PA_LOGE_; + prop.Set = KSPROPSETID_Connection; + prop.Id = KSPROPERTY_CONNECTION_STATE; + prop.Flags = KSPROPERTY_TYPE_SET; + if( pin == NULL ) return paInternalError; if( pin->handle == NULL ) return paInternalError; - result = WdmSetPropertySimple( - pin->handle, - &KSPROPSETID_Connection, - KSPROPERTY_CONNECTION_STATE, - &state, - sizeof(state), - NULL, - 0); + result = WdmSyncIoctl(pin->handle, IOCTL_KS_PROPERTY, &prop, sizeof(KSPROPERTY), &state, sizeof(KSSTATE), NULL); + PA_LOGL_; return result; } @@ -1000,41 +2120,52 @@ static PaError PinInstantiate(PaWinWdmPin* pin) &pin->handle ); - PA_DEBUG(("Pin create result = %x\n",createResult)); + PA_DEBUG(("Pin create result = 0x%08x\n",createResult)); if( createResult != ERROR_SUCCESS ) { FilterRelease(pin->parentFilter); pin->handle = NULL; - return paInvalidDevice; + switch (createResult) + { + case ERROR_INVALID_PARAMETER: + /* First case when pin actually don't support the format */ + return paSampleFormatNotSupported; + case ERROR_BAD_COMMAND: + /* Case when pin is occupied (by another application) */ + return paDeviceUnavailable; + default: + /* All other cases */ + return paInvalidDevice; + } } - result = WdmGetPropertySimple( - pin->handle, - &KSPROPSETID_Connection, - KSPROPERTY_CONNECTION_ALLOCATORFRAMING, - &ksaf, - sizeof(ksaf), - NULL, - 0); - - if( result != paNoError ) + if (pin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) { + /* Framing size query only valid for WaveCyclic devices */ result = WdmGetPropertySimple( pin->handle, &KSPROPSETID_Connection, - KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX, - &ksafex, - sizeof(ksafex), - NULL, - 0); - if( result == paNoError ) + KSPROPERTY_CONNECTION_ALLOCATORFRAMING, + &ksaf, + sizeof(ksaf)); + + if( result != paNoError ) { - pin->frameSize = ksafex.FramingItem[0].FramingRange.Range.MinFrameSize; + result = WdmGetPropertySimple( + pin->handle, + &KSPROPSETID_Connection, + KSPROPERTY_CONNECTION_ALLOCATORFRAMING_EX, + &ksafex, + sizeof(ksafex)); + if( result == paNoError ) + { + pin->frameSize = ksafex.FramingItem[0].FramingRange.Range.MinFrameSize; + } + } + else + { + pin->frameSize = ksaf.FrameSize; } - } - else - { - pin->frameSize = ksaf.FrameSize; } PA_LOGL_; @@ -1042,30 +2173,6 @@ static PaError PinInstantiate(PaWinWdmPin* pin) return paNoError; } -/* NOT USED -static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state) -{ - PaError result; - - if( state == NULL ) - return paInternalError; - if( pin == NULL ) - return paInternalError; - if( pin->handle == NULL ) - return paInternalError; - - result = WdmGetPropertySimple( - pin->handle, - KSPROPSETID_Connection, - KSPROPERTY_CONNECTION_STATE, - state, - sizeof(KSSTATE), - NULL, - 0); - - return result; -} -*/ static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format) { unsigned long size; @@ -1107,65 +2214,252 @@ static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format unsigned long count; GUID guid = DYNAMIC_GUID( DEFINE_WAVEFORMATEX_GUID(format->wFormatTag) ); PaError result = paInvalidDevice; + const WAVEFORMATEXTENSIBLE* pFormatExt = (format->wFormatTag == WAVE_FORMAT_EXTENSIBLE) ? (const WAVEFORMATEXTENSIBLE*)format : 0; PA_LOGE_; - if( format->wFormatTag == WAVE_FORMAT_EXTENSIBLE ) + if( pFormatExt != 0 ) { - guid = ((WAVEFORMATEXTENSIBLE*)format)->SubFormat; + guid = pFormatExt->SubFormat; } dataRange = (KSDATARANGE_AUDIO*)pin->dataRanges; - for(count = 0; countdataRangesItem->Count; count++) + for(count = 0; + countdataRangesItem->Count; + count++, + dataRange = (KSDATARANGE_AUDIO*)( ((char*)dataRange) + dataRange->DataRange.FormatSize)) /* Need to update dataRange here, due to 'continue' !! */ { - if(( !memcmp(&(dataRange->DataRange.MajorFormat),&KSDATAFORMAT_TYPE_AUDIO,sizeof(GUID)) ) || - ( !memcmp(&(dataRange->DataRange.MajorFormat),&KSDATAFORMAT_TYPE_WILDCARD,sizeof(GUID)) )) + /* Check major format*/ + if (!(IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_AUDIO) || + IsEqualGUID(&(dataRange->DataRange.MajorFormat), &KSDATAFORMAT_TYPE_WILDCARD))) { - /* This is an audio or wildcard datarange... */ - if(( !memcmp(&(dataRange->DataRange.SubFormat),&KSDATAFORMAT_SUBTYPE_WILDCARD,sizeof(GUID)) ) || - ( !memcmp(&(dataRange->DataRange.SubFormat),&guid,sizeof(GUID)) )) + continue; + } + + /* This is an audio or wildcard datarange... */ + if (! (IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_WILDCARD) || + IsEqualGUID(&(dataRange->DataRange.SubFormat), &KSDATAFORMAT_SUBTYPE_PCM) || + IsEqualGUID(&(dataRange->DataRange.SubFormat), &guid) )) + { + continue; + } + + /* Check specifier... */ + if (! (IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WILDCARD) || + IsEqualGUID(&(dataRange->DataRange.Specifier), &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) ) + { + continue; + } + + PA_DEBUG(("Pin:%x, DataRange:%d\n",(void*)pin,count)); + PA_DEBUG(("\tFormatSize:%d, SampleSize:%d\n",dataRange->DataRange.FormatSize,dataRange->DataRange.SampleSize)); + PA_DEBUG(("\tMaxChannels:%d\n",dataRange->MaximumChannels)); + PA_DEBUG(("\tBits:%d-%d\n",dataRange->MinimumBitsPerSample,dataRange->MaximumBitsPerSample)); + PA_DEBUG(("\tSampleRate:%d-%d\n",dataRange->MinimumSampleFrequency,dataRange->MaximumSampleFrequency)); + + if( dataRange->MaximumChannels != (ULONG)-1 && + dataRange->MaximumChannels < format->nChannels ) + { + result = paInvalidChannelCount; + continue; + } + + if (pFormatExt != 0) + { + if (!IsBitsWithinRange(dataRange, pFormatExt->Samples.wValidBitsPerSample)) { - if(( !memcmp(&(dataRange->DataRange.Specifier),&KSDATAFORMAT_SPECIFIER_WILDCARD,sizeof(GUID)) ) || - ( !memcmp(&(dataRange->DataRange.Specifier),&KSDATAFORMAT_SPECIFIER_WAVEFORMATEX,sizeof(GUID) ))) - { - - PA_DEBUG(("Pin:%x, DataRange:%d\n",(void*)pin,count)); - PA_DEBUG(("\tFormatSize:%d, SampleSize:%d\n",dataRange->DataRange.FormatSize,dataRange->DataRange.SampleSize)); - PA_DEBUG(("\tMaxChannels:%d\n",dataRange->MaximumChannels)); - PA_DEBUG(("\tBits:%d-%d\n",dataRange->MinimumBitsPerSample,dataRange->MaximumBitsPerSample)); - PA_DEBUG(("\tSampleRate:%d-%d\n",dataRange->MinimumSampleFrequency,dataRange->MaximumSampleFrequency)); - - if( dataRange->MaximumChannels < format->nChannels ) - { - result = paInvalidChannelCount; - continue; - } - if( dataRange->MinimumBitsPerSample > format->wBitsPerSample ) - { - result = paSampleFormatNotSupported; - continue; - } - if( dataRange->MaximumBitsPerSample < format->wBitsPerSample ) - { - result = paSampleFormatNotSupported; - continue; - } - if( dataRange->MinimumSampleFrequency > format->nSamplesPerSec ) - { - result = paInvalidSampleRate; - continue; - } - if( dataRange->MaximumSampleFrequency < format->nSamplesPerSec ) - { - result = paInvalidSampleRate; - continue; - } - /* Success! */ - PA_LOGL_; - return paNoError; - } + result = paSampleFormatNotSupported; + continue; } } - dataRange = (KSDATARANGE_AUDIO*)( ((char*)dataRange) + dataRange->DataRange.FormatSize); + else + { + if (!IsBitsWithinRange(dataRange, format->wBitsPerSample)) + { + result = paSampleFormatNotSupported; + continue; + } + } + + if (!IsFrequencyWithinRange(dataRange, format->nSamplesPerSec)) + { + result = paInvalidSampleRate; + continue; + } + + /* Success! */ + result = paNoError; + break; + } + + PA_LOGL_; + return result; +} + +static PaError PinQueryNotificationSupport(PaWinWdmPin* pPin, BOOL* pbResult) +{ + PaError result = paNoError; + KSPROPERTY propIn; + + PA_LOGE_; + + propIn.Set = KSPROPSETID_RtAudio; + propIn.Id = 8; /* = KSPROPERTY_RTAUDIO_QUERY_NOTIFICATION_SUPPORT */ + propIn.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY, + &propIn, + sizeof(KSPROPERTY), + pbResult, + sizeof(BOOL), + NULL); + + if (result != paNoError) + { + PA_DEBUG(("Failed PinQueryNotificationSupport\n")); + } + + PA_LOGL_; + return result; +} + +static PaError PinGetBufferWithNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier) +{ + PaError result = paNoError; + KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION propIn; + KSRTAUDIO_BUFFER propOut; + + PA_LOGE_; + + propIn.BaseAddress = 0; + propIn.NotificationCount = 2; + propIn.RequestedBufferSize = *pRequestedBufSize; + propIn.Property.Set = KSPROPSETID_RtAudio; + propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER_WITH_NOTIFICATION; + propIn.Property.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY, + &propIn, + sizeof(KSRTAUDIO_BUFFER_PROPERTY_WITH_NOTIFICATION), + &propOut, + sizeof(KSRTAUDIO_BUFFER), + NULL); + + if (result == paNoError) + { + *pBuffer = propOut.BufferAddress; + *pRequestedBufSize = propOut.ActualBufferSize; + *pbCallMemBarrier = propOut.CallMemoryBarrier; + } + else + { + PA_DEBUG(("Failed to get buffer with notification\n")); + } + + PA_LOGL_; + return result; +} + +static PaError PinGetBufferWithoutNotification(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier) +{ + PaError result = paNoError; + KSRTAUDIO_BUFFER_PROPERTY propIn; + KSRTAUDIO_BUFFER propOut; + + PA_LOGE_; + + propIn.BaseAddress = NULL; + propIn.RequestedBufferSize = *pRequestedBufSize; + propIn.Property.Set = KSPROPSETID_RtAudio; + propIn.Property.Id = KSPROPERTY_RTAUDIO_BUFFER; + propIn.Property.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY, + &propIn, + sizeof(KSRTAUDIO_BUFFER_PROPERTY), + &propOut, + sizeof(KSRTAUDIO_BUFFER), + NULL); + + if (result == paNoError) + { + *pBuffer = propOut.BufferAddress; + *pRequestedBufSize = propOut.ActualBufferSize; + *pbCallMemBarrier = propOut.CallMemoryBarrier; + } + else + { + PA_DEBUG(("Failed to get buffer without notification\n")); + } + + PA_LOGL_; + return result; +} + +/* greatest common divisor - PGCD in French */ +static unsigned long PaWinWDMGCD( unsigned long a, unsigned long b ) +{ + return (b==0) ? a : PaWinWDMGCD( b, a%b); +} + + +/* This function will handle getting the cyclic buffer from a WaveRT driver. Certain WaveRT drivers needs to have +requested buffer size on multiples of 128 bytes: + +*/ +static PaError PinGetBuffer(PaWinWdmPin* pPin, void** pBuffer, DWORD* pRequestedBufSize, BOOL* pbCallMemBarrier) +{ + PaError result = paNoError; + int limit = 1000; + PA_LOGE_; + + while (1) + { + limit--; + if (limit == 0) { + PA_DEBUG(("PinGetBuffer: LOOP LIMIT REACHED\n")); + break; + } + + if (pPin->pinKsSubType != SubType_kPolled) + { + /* In case of unknown (or notification), we try both modes */ + result = PinGetBufferWithNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier); + if (result == paNoError) + { + PA_DEBUG(("PinGetBuffer: SubType_kNotification\n")); + pPin->pinKsSubType = SubType_kNotification; + break; + } + } + + result = PinGetBufferWithoutNotification(pPin, pBuffer, pRequestedBufSize, pbCallMemBarrier); + if (result == paNoError) + { + PA_DEBUG(("PinGetBuffer: SubType_kPolled\n")); + pPin->pinKsSubType = SubType_kPolled; + break; + } + + /* Check if requested size is on a 128 byte boundary */ + if (((*pRequestedBufSize) % 128UL) == 0) + { + PA_DEBUG(("Buffer size on 128 byte boundary, still fails :(\n")); + /* Ok, can't do much more */ + break; + } + else + { + /* Compute LCM so we know which sizes are on a 128 byte boundary */ + const unsigned gcd = PaWinWDMGCD(128UL, pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign); + const unsigned lcm = (128UL * pPin->ksDataFormatWfx->WaveFormatEx.nBlockAlign) / gcd; + DWORD dwOldSize = *pRequestedBufSize; + + /* Align size to (next larger) LCM byte boundary, and then we try again. Note that LCM is not necessarily a + power of 2. */ + *pRequestedBufSize = ((*pRequestedBufSize + lcm - 1) / lcm) * lcm; + + PA_DEBUG(("Adjusting buffer size from %u to %u bytes (128 byte boundary, LCM=%u)\n", dwOldSize, *pRequestedBufSize, lcm)); + } } PA_LOGL_; @@ -1173,16 +2467,219 @@ static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format return result; } -/** - * Create a new filter object - */ -static PaWinWdmFilter* FilterNew(TCHAR* filterName, TCHAR* friendlyName, PaError* error) +static PaError PinRegisterPositionRegister(PaWinWdmPin* pPin) { - PaWinWdmFilter* filter; - PaError result; - int pinId; - int valid; + PaError result = paNoError; + KSRTAUDIO_HWREGISTER_PROPERTY propIn; + KSRTAUDIO_HWREGISTER propOut; + PA_LOGE_; + + propIn.BaseAddress = NULL; + propIn.Property.Set = KSPROPSETID_RtAudio; + propIn.Property.Id = KSPROPERTY_RTAUDIO_POSITIONREGISTER; + propIn.Property.Flags = KSPROPERTY_TYPE_SET; + + result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY, + &propIn, + sizeof(KSRTAUDIO_HWREGISTER_PROPERTY), + &propOut, + sizeof(KSRTAUDIO_HWREGISTER), + NULL); + + if (result == paNoError) + { + pPin->positionRegister = (ULONG*)propOut.Register; + } + else + { + PA_DEBUG(("Failed to register position register\n")); + } + + PA_LOGL_; + + return result; +} + +static PaError PinRegisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle) +{ + PaError result = paNoError; + KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop; + + PA_LOGE_; + + prop.NotificationEvent = handle; + prop.Property.Set = KSPROPSETID_RtAudio; + prop.Property.Id = KSPROPERTY_RTAUDIO_REGISTER_NOTIFICATION_EVENT; + prop.Property.Flags = KSPROPERTY_TYPE_SET; + + result = WdmSyncIoctl(pPin->handle, + IOCTL_KS_PROPERTY, + &prop, + sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY), + &prop, + sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY), + NULL); + + if (result != paNoError) { + PA_DEBUG(("Failed to register notification handle 0x%08X\n", handle)); + } + + PA_LOGL_; + + return result; +} + +static PaError PinUnregisterNotificationHandle(PaWinWdmPin* pPin, HANDLE handle) +{ + PaError result = paNoError; + KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY prop; + + PA_LOGE_; + + if (handle != NULL) + { + prop.NotificationEvent = handle; + prop.Property.Set = KSPROPSETID_RtAudio; + prop.Property.Id = KSPROPERTY_RTAUDIO_UNREGISTER_NOTIFICATION_EVENT; + prop.Property.Flags = KSPROPERTY_TYPE_SET; + + result = WdmSyncIoctl(pPin->handle, + IOCTL_KS_PROPERTY, + &prop, + sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY), + &prop, + sizeof(KSRTAUDIO_NOTIFICATION_EVENT_PROPERTY), + NULL); + + if (result != paNoError) { + PA_DEBUG(("Failed to unregister notification handle 0x%08X\n", handle)); + } + } + PA_LOGL_; + + return result; +} + +static PaError PinGetHwLatency(PaWinWdmPin* pPin, ULONG* pFifoSize, ULONG* pChipsetDelay, ULONG* pCodecDelay) +{ + PaError result = paNoError; + KSPROPERTY propIn; + KSRTAUDIO_HWLATENCY propOut; + + PA_LOGE_; + + propIn.Set = KSPROPSETID_RtAudio; + propIn.Id = KSPROPERTY_RTAUDIO_HWLATENCY; + propIn.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, IOCTL_KS_PROPERTY, + &propIn, + sizeof(KSPROPERTY), + &propOut, + sizeof(KSRTAUDIO_HWLATENCY), + NULL); + + if (result == paNoError) + { + *pFifoSize = propOut.FifoSize; + *pChipsetDelay = propOut.ChipsetDelay; + *pCodecDelay = propOut.CodecDelay; + } + else + { + PA_DEBUG(("Failed to retrieve hardware FIFO size!\n")); + } + + PA_LOGL_; + + return result; +} + +/* This one is used for WaveRT */ +static PaError PinGetAudioPositionMemoryMapped(PaWinWdmPin* pPin, ULONG* pPosition) +{ + *pPosition = (*pPin->positionRegister); + return paNoError; +} + +/* This one also, but in case the driver hasn't implemented memory mapped access to the position register */ +static PaError PinGetAudioPositionViaIOCTLRead(PaWinWdmPin* pPin, ULONG* pPosition) +{ + PaError result = paNoError; + KSPROPERTY propIn; + KSAUDIO_POSITION propOut; + + PA_LOGE_; + + propIn.Set = KSPROPSETID_Audio; + propIn.Id = KSPROPERTY_AUDIO_POSITION; + propIn.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, + IOCTL_KS_PROPERTY, + &propIn, sizeof(KSPROPERTY), + &propOut, sizeof(KSAUDIO_POSITION), + NULL); + + if (result == paNoError) + { + *pPosition = (ULONG)(propOut.PlayOffset); + } + else + { + PA_DEBUG(("Failed to get audio play position!\n")); + } + + PA_LOGL_; + + return result; + +} + +/* This one also, but in case the driver hasn't implemented memory mapped access to the position register */ +static PaError PinGetAudioPositionViaIOCTLWrite(PaWinWdmPin* pPin, ULONG* pPosition) +{ + PaError result = paNoError; + KSPROPERTY propIn; + KSAUDIO_POSITION propOut; + + PA_LOGE_; + + propIn.Set = KSPROPSETID_Audio; + propIn.Id = KSPROPERTY_AUDIO_POSITION; + propIn.Flags = KSPROPERTY_TYPE_GET; + + result = WdmSyncIoctl(pPin->handle, + IOCTL_KS_PROPERTY, + &propIn, sizeof(KSPROPERTY), + &propOut, sizeof(KSAUDIO_POSITION), + NULL); + + if (result == paNoError) + { + *pPosition = (ULONG)(propOut.WriteOffset); + } + else + { + PA_DEBUG(("Failed to get audio write position!\n")); + } + + PA_LOGL_; + + return result; + +} + +/***********************************************************************************************/ + +/** +* Create a new filter object. +*/ +static PaWinWdmFilter* FilterNew( PaWDMKSType type, DWORD devNode, const wchar_t* filterName, const wchar_t* friendlyName, PaError* error ) +{ + PaWinWdmFilter* filter = 0; + PaError result; /* Allocate the new filter object */ filter = (PaWinWdmFilter*)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter) ); @@ -1192,14 +2689,24 @@ static PaWinWdmFilter* FilterNew(TCHAR* filterName, TCHAR* friendlyName, PaError goto error; } + PA_DEBUG(("FilterNew: Creating filter '%S'\n", friendlyName)); + + /* Set type flag */ + filter->devInfo.streamingType = type; + + /* Store device node */ + filter->deviceNode = devNode; + /* Zero the filter object - done by AllocateMemory */ /* memset( (void*)filter, 0, sizeof(PaWinWdmFilter) ); */ /* Copy the filter name */ - _tcsncpy(filter->filterName, filterName, MAX_PATH); + wcsncpy(filter->devInfo.filterPath, filterName, MAX_PATH); /* Copy the friendly name */ - _tcsncpy(filter->friendlyName, friendlyName, MAX_PATH); + wcsncpy(filter->friendlyName, friendlyName, MAX_PATH); + + PA_DEBUG(("FilterNew: Opening filter...\n", friendlyName)); /* Open the filter handle */ result = FilterUse(filter); @@ -1216,14 +2723,106 @@ static PaWinWdmFilter* FilterNew(TCHAR* filterName, TCHAR* friendlyName, PaError &KSPROPSETID_Pin, KSPROPERTY_PIN_CTYPES, &filter->pinCount, - sizeof(filter->pinCount) - ); + sizeof(filter->pinCount), + NULL); if( result != paNoError) { goto error; } + /* Get connections & nodes for filter */ + result = WdmGetPropertyMulti( + filter->handle, + &KSPROPSETID_Topology, + KSPROPERTY_TOPOLOGY_CONNECTIONS, + &filter->connections); + + if( result != paNoError) + { + goto error; + } + + result = WdmGetPropertyMulti( + filter->handle, + &KSPROPSETID_Topology, + KSPROPERTY_TOPOLOGY_NODES, + &filter->nodes); + + if( result != paNoError) + { + goto error; + } + + /* For debugging purposes */ + DumpConnectionsAndNodes(filter); + + /* Get product GUID (it might not be supported) */ + { + KSCOMPONENTID compId; + if (WdmGetPropertySimple(filter->handle, &KSPROPSETID_General, KSPROPERTY_GENERAL_COMPONENTID, &compId, sizeof(KSCOMPONENTID)) == paNoError) + { + filter->devInfo.deviceProductGuid = compId.Product; + } + } + + /* This section is not executed for topology filters */ + if (type != Type_kNotUsed) + { + /* Initialize the pins */ + result = FilterInitializePins(filter); + + if( result != paNoError) + { + goto error; + } + } + + /* Close the filter handle for now + * It will be opened later when needed */ + FilterRelease(filter); + + *error = paNoError; + return filter; + +error: + PA_DEBUG(("FilterNew: Error %d\n", result)); + /* + Error cleanup + */ + FilterFree(filter); + + *error = result; + return NULL; +} + +/** +* Add reference to filter +*/ +static void FilterAddRef( PaWinWdmFilter* filter ) +{ + if (filter != 0) + { + filter->filterRefCount++; + } +} + + +/** +* Initialize the pins of the filter. This is separated from FilterNew because this might fail if there is another +* process using the pin(s). +*/ +PaError FilterInitializePins( PaWinWdmFilter* filter ) +{ + PaError result = paNoError; + int pinId; + + if (filter->devInfo.streamingType == Type_kNotUsed) + return paNoError; + + if (filter->pins != NULL) + return paNoError; + /* Allocate pointer array to hold the pins */ filter->pins = (PaWinWdmPin**)PaUtil_AllocateMemory( sizeof(PaWinWdmPin*) * filter->pinCount ); if( !filter->pins ) @@ -1233,11 +2832,6 @@ static PaWinWdmFilter* FilterNew(TCHAR* filterName, TCHAR* friendlyName, PaError } /* Create all the pins we can */ - filter->maxInputChannels = 0; - filter->maxOutputChannels = 0; - filter->bestSampleRate = 0; - - valid = 0; for(pinId = 0; pinId < filter->pinCount; pinId++) { /* Create the pin with this Id */ @@ -1248,83 +2842,75 @@ static PaWinWdmFilter* FilterNew(TCHAR* filterName, TCHAR* friendlyName, PaError if( newPin != NULL ) { filter->pins[pinId] = newPin; - valid = 1; - - /* Get the max output channel count */ - if(( newPin->dataFlow == KSPIN_DATAFLOW_IN ) && - (( newPin->communication == KSPIN_COMMUNICATION_SINK) || - ( newPin->communication == KSPIN_COMMUNICATION_BOTH))) - { - if(newPin->maxChannels > filter->maxOutputChannels) - filter->maxOutputChannels = newPin->maxChannels; - filter->formats |= newPin->formats; - } - /* Get the max input channel count */ - if(( newPin->dataFlow == KSPIN_DATAFLOW_OUT ) && - (( newPin->communication == KSPIN_COMMUNICATION_SINK) || - ( newPin->communication == KSPIN_COMMUNICATION_BOTH))) - { - if(newPin->maxChannels > filter->maxInputChannels) - filter->maxInputChannels = newPin->maxChannels; - filter->formats |= newPin->formats; - } - - if(newPin->bestSampleRate > filter->bestSampleRate) - { - filter->bestSampleRate = newPin->bestSampleRate; - } + ++filter->validPinCount; } } - if(( filter->maxInputChannels == 0) && ( filter->maxOutputChannels == 0)) + if (filter->validPinCount == 0) { - /* No input or output... not valid */ - valid = 0; - } - - if( !valid ) - { - /* No valid pin was found on this filter so we destroy it */ result = paDeviceUnavailable; goto error; } - /* Close the filter handle for now - * It will be opened later when needed */ - FilterRelease(filter); - - *error = paNoError; - return filter; + return paNoError; error: - /* - Error cleanup - */ - if( filter ) + + if (filter->pins) { - for( pinId = 0; pinId < filter->pinCount; pinId++ ) - PinFree(filter->pins[pinId]); + for (pinId = 0; pinId < filter->pinCount; ++pinId) + { + if (filter->pins[pinId]) + { + PinFree(filter->pins[pinId]); + filter->pins[pinId] = 0; + } + } PaUtil_FreeMemory( filter->pins ); - if( filter->handle ) - CloseHandle( filter->handle ); - PaUtil_FreeMemory( filter ); + filter->pins = 0; } - *error = result; - return NULL; + + return result; } + /** - * Free a previously created filter - */ +* Free a previously created filter +*/ static void FilterFree(PaWinWdmFilter* filter) { - int pinId; PA_LOGL_; if( filter ) { - for( pinId = 0; pinId < filter->pinCount; pinId++ ) - PinFree(filter->pins[pinId]); - PaUtil_FreeMemory( filter->pins ); + if (--filter->filterRefCount > 0) + { + /* Ok, a stream has a ref count to this filter */ + return; + } + + if ( filter->topologyFilter ) + { + FilterFree(filter->topologyFilter); + filter->topologyFilter = 0; + } + if ( filter->pins ) + { + int pinId; + for( pinId = 0; pinId < filter->pinCount; pinId++ ) + PinFree(filter->pins[pinId]); + PaUtil_FreeMemory( filter->pins ); + filter->pins = 0; + } + if( filter->connections ) + { + PaUtil_FreeMemory(filter->connections); + filter->connections = 0; + } + if( filter->nodes ) + { + PaUtil_FreeMemory(filter->nodes); + filter->nodes = 0; + } if( filter->handle ) CloseHandle( filter->handle ); PaUtil_FreeMemory( filter ); @@ -1333,8 +2919,8 @@ static void FilterFree(PaWinWdmFilter* filter) } /** - * Reopen the filter handle if necessary so it can be used - **/ +* Reopen the filter handle if necessary so it can be used +**/ static PaError FilterUse(PaWinWdmFilter* filter) { assert( filter ); @@ -1343,8 +2929,8 @@ static PaError FilterUse(PaWinWdmFilter* filter) if( filter->handle == NULL ) { /* Open the filter */ - filter->handle = CreateFile( - filter->filterName, + filter->handle = CreateFileW( + filter->devInfo.filterPath, GENERIC_READ | GENERIC_WRITE, 0, NULL, @@ -1363,14 +2949,20 @@ static PaError FilterUse(PaWinWdmFilter* filter) } /** - * Release the filter handle if nobody is using it - **/ +* Release the filter handle if nobody is using it +**/ static void FilterRelease(PaWinWdmFilter* filter) { assert( filter ); assert( filter->usageCount > 0 ); PA_LOGE_; + /* Check first topology filter, if used */ + if (filter->topologyFilter != NULL && filter->topologyFilter->handle != NULL) + { + FilterRelease(filter->topologyFilter); + } + filter->usageCount--; if( filter->usageCount == 0 ) { @@ -1384,200 +2976,85 @@ static void FilterRelease(PaWinWdmFilter* filter) } /** - * Create a render (playback) Pin using the supplied format - **/ -static PaWinWdmPin* FilterCreateRenderPin(PaWinWdmFilter* filter, - const WAVEFORMATEX* wfex, - PaError* error) -{ - PaError result; - PaWinWdmPin* pin; - - assert( filter ); - - pin = FilterFindViableRenderPin(filter,wfex,&result); - if(!pin) - { - goto error; - } - result = PinSetFormat(pin,wfex); - if( result != paNoError ) - { - goto error; - } - result = PinInstantiate(pin); - if( result != paNoError ) - { - goto error; - } - - *error = paNoError; - return pin; - -error: - *error = result; - return NULL; -} - -/** - * Find a pin that supports the given format - **/ -static PaWinWdmPin* FilterFindViableRenderPin(PaWinWdmFilter* filter, - const WAVEFORMATEX* wfex, - PaError* error) -{ - int pinId; - PaWinWdmPin* pin; - PaError result = paDeviceUnavailable; - *error = paNoError; - - assert( filter ); - - for( pinId = 0; pinIdpinCount; pinId++ ) - { - pin = filter->pins[pinId]; - if( pin != NULL ) - { - if(( pin->dataFlow == KSPIN_DATAFLOW_IN ) && - (( pin->communication == KSPIN_COMMUNICATION_SINK) || - ( pin->communication == KSPIN_COMMUNICATION_BOTH))) - { - result = PinIsFormatSupported( pin, wfex ); - if( result == paNoError ) - { - return pin; - } - } - } - } - - *error = result; - return NULL; -} - -/** - * Check if there is a pin that should playback - * with the supplied format - **/ -static PaError FilterCanCreateRenderPin(PaWinWdmFilter* filter, - const WAVEFORMATEX* wfex) -{ - PaWinWdmPin* pin; - PaError result; - - assert ( filter ); - - pin = FilterFindViableRenderPin(filter,wfex,&result); - /* result will be paNoError if pin found - * or else an error code indicating what is wrong with the format - **/ - return result; -} - -/** - * Create a capture (record) Pin using the supplied format - **/ -static PaWinWdmPin* FilterCreateCapturePin(PaWinWdmFilter* filter, - const WAVEFORMATEX* wfex, - PaError* error) -{ - PaError result; - PaWinWdmPin* pin; - - assert( filter ); - - pin = FilterFindViableCapturePin(filter,wfex,&result); - if(!pin) - { - goto error; - } - - result = PinSetFormat(pin,wfex); - if( result != paNoError ) - { - goto error; - } - - result = PinInstantiate(pin); - if( result != paNoError ) - { - goto error; - } - - *error = paNoError; - return pin; - -error: - *error = result; - return NULL; -} - -/** - * Find a capture pin that supports the given format - **/ -static PaWinWdmPin* FilterFindViableCapturePin(PaWinWdmFilter* filter, - const WAVEFORMATEX* wfex, - PaError* error) -{ - int pinId; - PaWinWdmPin* pin; - PaError result = paDeviceUnavailable; - *error = paNoError; - - assert( filter ); - - for( pinId = 0; pinIdpinCount; pinId++ ) - { - pin = filter->pins[pinId]; - if( pin != NULL ) - { - if(( pin->dataFlow == KSPIN_DATAFLOW_OUT ) && - (( pin->communication == KSPIN_COMMUNICATION_SINK) || - ( pin->communication == KSPIN_COMMUNICATION_BOTH))) - { - result = PinIsFormatSupported( pin, wfex ); - if( result == paNoError ) - { - return pin; - } - } - } - } - - *error = result; - return NULL; -} - -/** - * Check if there is a pin that should playback - * with the supplied format - **/ -static PaError FilterCanCreateCapturePin(PaWinWdmFilter* filter, - const WAVEFORMATEX* wfex) -{ - PaWinWdmPin* pin; - PaError result; - - assert ( filter ); - - pin = FilterFindViableCapturePin(filter,wfex,&result); - /* result will be paNoError if pin found - * or else an error code indicating what is wrong with the format - **/ - return result; -} - -/** - * Build the list of available filters - * Use the SetupDi API to enumerate all devices in the KSCATEGORY_AUDIO which - * have a KSCATEGORY_RENDER or KSCATEGORY_CAPTURE alias. For each of these - * devices initialise a PaWinWdmFilter structure by calling our NewFilter() - * function. We enumerate devices twice, once to count how many there are, - * and once to initialize the PaWinWdmFilter structures. - */ -static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi) +* Create a render or playback pin using the supplied format +**/ +static PaWinWdmPin* FilterCreatePin(PaWinWdmFilter* filter, + int pinId, + const WAVEFORMATEX* wfex, + PaError* error) { PaError result = paNoError; + PaWinWdmPin* pin = NULL; + assert( filter ); + assert( pinId < filter->pinCount ); + pin = filter->pins[pinId]; + assert( pin ); + result = PinSetFormat(pin,wfex); + if( result == paNoError ) + { + result = PinInstantiate(pin); + } + *error = result; + return result == paNoError ? pin : 0; +} + +static const wchar_t kUsbPrefix[] = L"\\\\?\\USB"; + +static BOOL IsUSBDevice(const wchar_t* devicePath) +{ + /* Alex Lessard pointed out that different devices might present the device path with + lower case letters. */ + return (_wcsnicmp(devicePath, kUsbPrefix, sizeof(kUsbPrefix)/sizeof(kUsbPrefix[0]) ) == 0); +} + +/* This should make it more language tolerant, I hope... */ +static const wchar_t kUsbNamePrefix[] = L"USB Audio"; + +static BOOL IsNameUSBAudioDevice(const wchar_t* friendlyName) +{ + return (_wcsnicmp(friendlyName, kUsbNamePrefix, sizeof(kUsbNamePrefix)/sizeof(kUsbNamePrefix[0])) == 0); +} + +typedef enum _tag_EAlias +{ + Alias_kRender = (1<<0), + Alias_kCapture = (1<<1), + Alias_kRealtime = (1<<2), +} EAlias; + +/* Trim whitespace from string */ +static void TrimString(wchar_t* str, size_t length) +{ + wchar_t* s = str; + wchar_t* e = 0; + + /* Find start of string */ + while (iswspace(*s)) ++s; + e=s+min(length,wcslen(s))-1; + + /* Find end of string */ + while(e>s && iswspace(*e)) --e; + ++e; + + length = e - s; + memmove(str, s, length * sizeof(wchar_t)); + str[length] = 0; +} + +/** +* Build the list of available filters +* Use the SetupDi API to enumerate all devices in the KSCATEGORY_AUDIO which +* have a KSCATEGORY_RENDER or KSCATEGORY_CAPTURE alias. For each of these +* devices initialise a PaWinWdmFilter structure by calling our NewFilter() +* function. We enumerate devices twice, once to count how many there are, +* and once to initialize the PaWinWdmFilter structures. +* +* Vista and later: Also check KSCATEGORY_REALTIME for WaveRT devices. +*/ +//PaError BuildFilterList( PaWinWdmHostApiRepresentation* wdmHostApi, int* noOfPaDevices ) +PaWinWdmFilter** BuildFilterList( int* pFilterCount, int* pNoOfPaDevices, PaError* pResult ) +{ + PaWinWdmFilter** ppFilters = NULL; HDEVINFO handle = NULL; int device; int invalidDevices; @@ -1588,26 +3065,32 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi) int noError; const int sizeInterface = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR)); unsigned char interfaceDetailsArray[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (MAX_PATH * sizeof(WCHAR))]; - SP_DEVICE_INTERFACE_DETAIL_DATA* devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA*)interfaceDetailsArray; - TCHAR friendlyName[MAX_PATH]; - HKEY hkey; - DWORD sizeFriendlyName; - DWORD type; - PaWinWdmFilter* newFilter; - GUID* category = (GUID*)&KSCATEGORY_AUDIO; - GUID* alias_render = (GUID*)&KSCATEGORY_RENDER; - GUID* alias_capture = (GUID*)&KSCATEGORY_CAPTURE; - DWORD hasAlias; + SP_DEVICE_INTERFACE_DETAIL_DATA_W* devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)interfaceDetailsArray; + const GUID* category = (const GUID*)&KSCATEGORY_AUDIO; + const GUID* alias_render = (const GUID*)&KSCATEGORY_RENDER; + const GUID* alias_capture = (const GUID*)&KSCATEGORY_CAPTURE; + const GUID* category_realtime = (const GUID*)&KSCATEGORY_REALTIME; + DWORD aliasFlags; + PaWDMKSType streamingType; + int filterCount = 0; + int noOfPaDevices = 0; PA_LOGE_; - devInterfaceDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + assert(pFilterCount != NULL); + assert(pNoOfPaDevices != NULL); + assert(pResult != NULL); + + devInterfaceDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); + *pFilterCount = 0; + *pNoOfPaDevices = 0; /* Open a handle to search for devices (filters) */ handle = SetupDiGetClassDevs(category,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); - if( handle == NULL ) + if( handle == INVALID_HANDLE_VALUE ) { - return paUnanticipatedHostError; + *pResult = paUnanticipatedHostError; + return NULL; } PA_DEBUG(("Setup called\n")); @@ -1625,7 +3108,7 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi) break; /* No more devices */ /* Check this one has the render or capture alias */ - hasAlias = 0; + aliasFlags = 0; noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData); PA_DEBUG(("noError = %d\n",noError)); if(noError) @@ -1633,7 +3116,7 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi) if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) { PA_DEBUG(("Device %d has render alias\n",device)); - hasAlias |= 1; /* Has render alias */ + aliasFlags |= Alias_kRender; /* Has render alias */ } else { @@ -1646,29 +3129,29 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi) if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) { PA_DEBUG(("Device %d has capture alias\n",device)); - hasAlias |= 2; /* Has capture alias */ + aliasFlags |= Alias_kCapture; /* Has capture alias */ } else { PA_DEBUG(("Device %d has no capture alias\n",device)); } } - if(!hasAlias) + if(!aliasFlags) invalidDevices++; /* This was not a valid capture or render audio device */ - } /* Remember how many there are */ - wdmHostApi->filterCount = device-invalidDevices; + filterCount = device-invalidDevices; PA_DEBUG(("Interfaces found: %d\n",device-invalidDevices)); /* Now allocate the list of pointers to devices */ - wdmHostApi->filters = (PaWinWdmFilter**)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter*) * device ); - if( !wdmHostApi->filters ) + ppFilters = (PaWinWdmFilter**)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter*) * filterCount); + if( ppFilters == 0 ) { if(handle != NULL) SetupDiDestroyDeviceInfoList(handle); - return paInsufficientMemory; + *pResult = paInsufficientMemory; + return NULL; } /* Now create filter objects for each interface found */ @@ -1681,20 +3164,21 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi) aliasData.Reserved = 0; devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); devInfoData.Reserved = 0; + streamingType = Type_kWaveCyclic; noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData); if( !noError ) break; /* No more devices */ /* Check this one has the render or capture alias */ - hasAlias = 0; + aliasFlags = 0; noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData); if(noError) { if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) { PA_DEBUG(("Device %d has render alias\n",device)); - hasAlias |= 1; /* Has render alias */ + aliasFlags |= Alias_kRender; /* Has render alias */ } } noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData); @@ -1703,48 +3187,114 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi) if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED))) { PA_DEBUG(("Device %d has capture alias\n",device)); - hasAlias |= 2; /* Has capture alias */ + aliasFlags |= Alias_kCapture; /* Has capture alias */ } } - if(!hasAlias) + if(!aliasFlags) + { continue; /* This was not a valid capture or render audio device */ + } + else + { + /* Check if filter is WaveRT, if not it is a WaveCyclic */ + noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,category_realtime,&aliasData); + if (noError) + { + PA_DEBUG(("Device %d has realtime alias\n",device)); + aliasFlags |= Alias_kRealtime; + streamingType = Type_kWaveRT; + } + } - noError = SetupDiGetDeviceInterfaceDetail(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData); + noError = SetupDiGetDeviceInterfaceDetailW(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData); if( noError ) { + DWORD type; + WCHAR friendlyName[MAX_PATH] = {0}; + DWORD sizeFriendlyName; + PaWinWdmFilter* newFilter = 0; + + PaError result = paNoError; /* Try to get the "friendly name" for this interface */ sizeFriendlyName = sizeof(friendlyName); - /* Fix contributed by Ben Allison - * Removed KEY_SET_VALUE from flags on following call - * as its causes failure when running without admin rights - * and it was not required */ - hkey=SetupDiOpenDeviceInterfaceRegKey(handle,&interfaceData,0,KEY_QUERY_VALUE); - if(hkey!=INVALID_HANDLE_VALUE) + + if (IsEarlierThanVista() && IsUSBDevice(devInterfaceDetails->DevicePath)) { - noError = RegQueryValueEx(hkey,TEXT("FriendlyName"),0,&type,(BYTE*)friendlyName,&sizeFriendlyName); - if( noError == ERROR_SUCCESS ) - { - PA_DEBUG(("Interface %d, Name: %s\n",device,friendlyName)); - RegCloseKey(hkey); - } - else + /* XP and USB audio device needs to look elsewhere, otherwise it'll only be a "USB Audio Device". Not + very literate. */ + if (!SetupDiGetDeviceRegistryPropertyW(handle, + &devInfoData, + SPDRP_LOCATION_INFORMATION, + &type, + (BYTE*)friendlyName, + sizeof(friendlyName), + NULL)) { friendlyName[0] = 0; } } - newFilter = FilterNew(devInterfaceDetails->DevicePath,friendlyName,&result); + + if (friendlyName[0] == 0 || IsNameUSBAudioDevice(friendlyName)) + { + /* Fix contributed by Ben Allison + * Removed KEY_SET_VALUE from flags on following call + * as its causes failure when running without admin rights + * and it was not required */ + HKEY hkey=SetupDiOpenDeviceInterfaceRegKey(handle,&interfaceData,0,KEY_QUERY_VALUE); + if(hkey!=INVALID_HANDLE_VALUE) + { + noError = RegQueryValueExW(hkey,L"FriendlyName",0,&type,(BYTE*)friendlyName,&sizeFriendlyName); + if( noError == ERROR_SUCCESS ) + { + PA_DEBUG(("Interface %d, Name: %s\n",device,friendlyName)); + RegCloseKey(hkey); + } + else + { + friendlyName[0] = 0; + } + } + } + + TrimString(friendlyName, sizeFriendlyName); + + newFilter = FilterNew(streamingType, + devInfoData.DevInst, + devInterfaceDetails->DevicePath, + friendlyName, + &result); + if( result == paNoError ) { - PA_DEBUG(("Filter created\n")); - wdmHostApi->filters[slot] = newFilter; + int pin; + unsigned filterIOs = 0; + + /* Increment number of "devices" */ + for (pin = 0; pin < newFilter->pinCount; ++pin) + { + PaWinWdmPin* pPin = newFilter->pins[pin]; + if (pPin == NULL) + continue; + + filterIOs += max(1, pPin->inputCount); + } + + noOfPaDevices += filterIOs; + + PA_DEBUG(("Filter (%s) created with %d valid pins (total I/Os: %u)\n", ((newFilter->devInfo.streamingType==Type_kWaveRT)?"WaveRT":"WaveCyclic"), newFilter->validPinCount, filterIOs)); + + assert(slot < filterCount); + + ppFilters[slot] = newFilter; + slot++; } else { PA_DEBUG(("Filter NOT created\n")); /* As there are now less filters than we initially thought - * we must reduce the count by one */ - wdmHostApi->filterCount--; + * we must reduce the count by one */ + filterCount--; } } } @@ -1753,21 +3303,493 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi) if(handle != NULL) SetupDiDestroyDeviceInfoList(handle); + *pFilterCount = filterCount; + *pNoOfPaDevices = noOfPaDevices; + + return ppFilters; +} + +typedef struct PaNameHashIndex +{ + unsigned index; + unsigned count; + ULONG hash; + struct PaNameHashIndex *next; +} PaNameHashIndex; + +typedef struct PaNameHashObject +{ + PaNameHashIndex* list; + PaUtilAllocationGroup* allocGroup; +} PaNameHashObject; + +static ULONG GetNameHash(const wchar_t* str, const BOOL input) +{ + /* This is to make sure that a name that exists as both input & output won't get the same hash value */ + const ULONG fnv_prime = (input ? 0x811C9DD7 : 0x811FEB0B); + ULONG hash = 0; + for(; *str != 0; str++) + { + hash *= fnv_prime; + hash ^= (*str); + } + assert(hash != 0); + return hash; +} + +static PaError CreateHashEntry(PaNameHashObject* obj, const wchar_t* name, const BOOL input) +{ + ULONG hash = GetNameHash(name, input); + PaNameHashIndex * pLast = NULL; + PaNameHashIndex * p = obj->list; + while (p != 0) + { + if (p->hash == hash) + { + break; + } + pLast = p; + p = p->next; + } + if (p == NULL) + { + p = (PaNameHashIndex*)PaUtil_GroupAllocateMemory(obj->allocGroup, sizeof(PaNameHashIndex)); + if (p == NULL) + { + return paInsufficientMemory; + } + p->hash = hash; + p->count = 1; + if (pLast != 0) + { + assert(pLast->next == 0); + pLast->next = p; + } + if (obj->list == 0) + { + obj->list = p; + } + } + else + { + ++p->count; + } return paNoError; } +static PaError InitNameHashObject(PaNameHashObject* obj, PaWinWdmFilter* pFilter) +{ + int i; + + obj->allocGroup = PaUtil_CreateAllocationGroup(); + if (obj->allocGroup == NULL) + { + return paInsufficientMemory; + } + + for (i = 0; i < pFilter->pinCount; ++i) + { + unsigned m; + PaWinWdmPin* pin = pFilter->pins[i]; + + if (pin == NULL) + continue; + + for (m = 0; m < max(1, pin->inputCount); ++m) + { + const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT); + const wchar_t* name = (pin->inputs == NULL) ? pin->friendlyName : pin->inputs[m]->friendlyName; + + PaError result = CreateHashEntry(obj, name, isInput); + + if (result != paNoError) + { + return result; + } + } + } + return paNoError; +} + +static void DeinitNameHashObject(PaNameHashObject* obj) +{ + assert(obj != 0); + PaUtil_FreeAllAllocations(obj->allocGroup); + PaUtil_DestroyAllocationGroup(obj->allocGroup); + memset(obj, 0, sizeof(PaNameHashObject)); +} + +static unsigned GetNameIndex(PaNameHashObject* obj, const wchar_t* name, const BOOL input) +{ + ULONG hash = GetNameHash(name, input); + PaNameHashIndex* p = obj->list; + while (p != NULL) + { + if (p->hash == hash) + { + if (p->count > 1) + { + return (++p->index); + } + else + { + return 0; + } + } + + p = p->next; + } + // Should never get here!! + assert(FALSE); + return 0; +} + +static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, void **scanResults, int *newDeviceCount ) +{ + PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; + PaError result = paNoError; + PaWinWdmFilter** ppFilters = 0; + PaWinWDMScanDeviceInfosResults *outArgument = 0; + int filterCount = 0; + int totalDeviceCount = 0; + int idxDevice = 0; + DWORD defaultInDevPathSize = 0; + DWORD defaultOutDevPathSize = 0; + wchar_t* defaultInDevPath = 0; + wchar_t* defaultOutDevPath = 0; + + ppFilters = BuildFilterList( &filterCount, &totalDeviceCount, &result ); + if( result != paNoError ) + { + goto error; + } + + // Get hold of default device paths for capture & playback + if( waveInMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultInDevPathSize, 0 ) == MMSYSERR_NOERROR ) + { + defaultInDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultInDevPathSize + 1) * sizeof(wchar_t)); + waveInMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultInDevPath, defaultInDevPathSize); + } + if( waveOutMessage(0, DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&defaultOutDevPathSize, 0 ) == MMSYSERR_NOERROR ) + { + defaultOutDevPath = (wchar_t *)PaUtil_AllocateMemory((defaultOutDevPathSize + 1) * sizeof(wchar_t)); + waveOutMessage(0, DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)defaultOutDevPath, defaultOutDevPathSize); + } + + if( totalDeviceCount > 0 ) + { + PaWinWdmDeviceInfo *deviceInfoArray = 0; + int idxFilter; + int i; + unsigned devIsDefaultIn = 0, devIsDefaultOut = 0; + + /* Allocate the out param for all the info we need */ + outArgument = (PaWinWDMScanDeviceInfosResults *) PaUtil_GroupAllocateMemory( + wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults) ); + if( !outArgument ) + { + result = paInsufficientMemory; + goto error; + } + + outArgument->defaultInputDevice = paNoDevice; + outArgument->defaultOutputDevice = paNoDevice; + + outArgument->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + wdmHostApi->allocations, sizeof(PaDeviceInfo*) * totalDeviceCount ); + if( !outArgument->deviceInfos ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate all device info structs in a contiguous block */ + deviceInfoArray = (PaWinWdmDeviceInfo*)PaUtil_GroupAllocateMemory( + wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo) * totalDeviceCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + goto error; + } + + /* Make sure all items in array */ + for( i = 0 ; i < totalDeviceCount; ++i ) + { + PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo; + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + deviceInfo->name = 0; + outArgument->deviceInfos[ i ] = deviceInfo; + } + + idxDevice = 0; + for (idxFilter = 0; idxFilter < filterCount; ++idxFilter) + { + PaNameHashObject nameHash = {0}; + PaWinWdmFilter* pFilter = ppFilters[idxFilter]; + if( pFilter == NULL ) + continue; + + if (InitNameHashObject(&nameHash, pFilter) != paNoError) + { + DeinitNameHashObject(&nameHash); + continue; + } + + devIsDefaultIn = (defaultInDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultInDevPath) == 0)); + devIsDefaultOut = (defaultOutDevPath && (_wcsicmp(pFilter->devInfo.filterPath, defaultOutDevPath) == 0)); + + for (i = 0; i < pFilter->pinCount; ++i) + { + unsigned m; + ULONG nameIndex = 0; + ULONG nameIndexHash = 0; + PaWinWdmPin* pin = pFilter->pins[i]; + + if (pin == NULL) + continue; + + for (m = 0; m < max(1, pin->inputCount); ++m) + { + PaWinWdmDeviceInfo *wdmDeviceInfo = (PaWinWdmDeviceInfo *)outArgument->deviceInfos[idxDevice]; + PaDeviceInfo *deviceInfo = &wdmDeviceInfo->inheritedDeviceInfo; + wchar_t localCompositeName[MAX_PATH]; + unsigned nameIndex = 0; + const BOOL isInput = (pin->dataFlow == KSPIN_DATAFLOW_OUT); + + wdmDeviceInfo->filter = pFilter; + + deviceInfo->structVersion = 2; + deviceInfo->hostApi = hostApiIndex; + deviceInfo->name = wdmDeviceInfo->compositeName; + /* deviceInfo->hostApiSpecificDeviceInfo = &pFilter->devInfo; */ + + wdmDeviceInfo->pin = pin->pinId; + + /* Get the name of the "device" */ + if (pin->inputs == NULL) + { + wcsncpy(localCompositeName, pin->friendlyName, MAX_PATH); + wdmDeviceInfo->muxPosition = -1; + wdmDeviceInfo->endpointPinId = pin->endpointPinId; + } + else + { + PaWinWdmMuxedInput* input = pin->inputs[m]; + wcsncpy(localCompositeName, input->friendlyName, MAX_PATH); + wdmDeviceInfo->muxPosition = (int)m; + wdmDeviceInfo->endpointPinId = input->endpointPinId; + } + + { + /* Get base length */ + size_t n = wcslen(localCompositeName); + + /* Check if there are more entries with same name (which might very well be the case), if there + are, the name will be postfixed with an index. */ + nameIndex = GetNameIndex(&nameHash, localCompositeName, isInput); + if (nameIndex > 0) + { + /* This name has multiple instances, so we post fix with a number */ + n += _snwprintf(localCompositeName + n, MAX_PATH - n, L" %u", nameIndex); + } + /* Postfix with filter name */ + _snwprintf(localCompositeName + n, MAX_PATH - n, L" (%s)", pFilter->friendlyName); + } + + /* Convert wide char string to utf-8 */ + WideCharToMultiByte(CP_UTF8, 0, localCompositeName, -1, wdmDeviceInfo->compositeName, MAX_PATH, NULL, NULL); + + /* NB! WDM/KS has no concept of a full-duplex device, each pin is either an input or an output */ + if (isInput) + { + /* INPUT ! */ + deviceInfo->maxInputChannels = pin->maxChannels; + deviceInfo->maxOutputChannels = 0; + + /* RoBi NB: Due to the fact that input audio endpoints in Vista (& later OSs) can be the same device, but with + different input mux settings, there might be a discrepancy between the default input device chosen, and + that which will be used by Portaudio. Not much to do about that unfortunately. + */ + if ((defaultInDevPath == 0 || devIsDefaultIn) && + outArgument->defaultInputDevice == paNoDevice) + { + outArgument->defaultInputDevice = idxDevice; + } + } + else + { + /* OUTPUT ! */ + deviceInfo->maxInputChannels = 0; + deviceInfo->maxOutputChannels = pin->maxChannels; + + if ((defaultOutDevPath == 0 || devIsDefaultOut) && + outArgument->defaultOutputDevice == paNoDevice) + { + outArgument->defaultOutputDevice = idxDevice; + } + } + + /* These low values are not very useful because + * a) The lowest latency we end up with can depend on many factors such + * as the device buffer sizes/granularities, sample rate, channels and format + * b) We cannot know the device buffer sizes until we try to open/use it at + * a particular setting + * So: we give 512x48000Hz frames as the default low input latency + **/ + switch (pFilter->devInfo.streamingType) + { + case Type_kWaveCyclic: + if (IsEarlierThanVista()) + { + /* XP doesn't tolerate low latency, unless the Process Priority Class is set to REALTIME_PRIORITY_CLASS + through SetPriorityClass, then 10 ms is quite feasible. However, one should then bear in mind that ALL of + the process is running in REALTIME_PRIORITY_CLASS, which might not be appropriate for an application with + a GUI . In this case it is advisable to separate the audio engine in another process and use IPC to communicate + with it. */ + deviceInfo->defaultLowInputLatency = 0.02; + deviceInfo->defaultLowOutputLatency = 0.02; + } + else + { + /* This is a conservative estimate. Most WaveCyclic drivers will limit the available latency, but f.i. my Edirol + PCR-A30 can reach 3 ms latency easily... */ + deviceInfo->defaultLowInputLatency = 0.01; + deviceInfo->defaultLowOutputLatency = 0.01; + } + deviceInfo->defaultHighInputLatency = (4096.0/48000.0); + deviceInfo->defaultHighOutputLatency = (4096.0/48000.0); + deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate); + break; + case Type_kWaveRT: + /* This is also a conservative estimate, based on WaveRT polled mode. In polled mode, the latency will be dictated + by the buffer size given by the driver. */ + deviceInfo->defaultLowInputLatency = 0.01; + deviceInfo->defaultLowOutputLatency = 0.01; + deviceInfo->defaultHighInputLatency = 0.04; + deviceInfo->defaultHighOutputLatency = 0.04; + deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate); + break; + default: + assert(0); + break; + } + + /* Add reference to filter */ + FilterAddRef(wdmDeviceInfo->filter); + + assert(idxDevice < totalDeviceCount); + ++idxDevice; + } + } + + /* If no one has add ref'd the filter, drop it */ + if (pFilter->filterRefCount == 0) + { + FilterFree(pFilter); + } + + /* Deinitialize name hash object */ + DeinitNameHashObject(&nameHash); + } + } + + *scanResults = outArgument; + *newDeviceCount = idxDevice; + return result; + +error: + result = DisposeDeviceInfos(hostApi, outArgument, totalDeviceCount); + + return result; +} + +static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *scanResults, int deviceCount ) +{ + PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; + + hostApi->info.deviceCount = 0; + hostApi->info.defaultInputDevice = paNoDevice; + hostApi->info.defaultOutputDevice = paNoDevice; + + /* Free any old memory which might be in the device info */ + if( hostApi->deviceInfos ) + { + PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory( + wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults)); + localScanResults->deviceInfos = hostApi->deviceInfos; + + DisposeDeviceInfos(hostApi, &localScanResults, hostApi->info.deviceCount); + + hostApi->deviceInfos = NULL; + } + + if( scanResults != NULL ) + { + PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults; + + if( deviceCount > 0 ) + { + /* use the array allocated in ScanDeviceInfos() as our deviceInfos */ + hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos; + + hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice; + hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice; + + hostApi->info.deviceCount = deviceCount; + } + + PaUtil_GroupFreeMemory( wdmHostApi->allocations, scanDeviceInfosResults ); + } + + return paNoError; + +} + +static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount ) +{ + PaWinWdmHostApiRepresentation *winDsHostApi = (PaWinWdmHostApiRepresentation*)hostApi; + + if( scanResults != NULL ) + { + PaWinWDMScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinWDMScanDeviceInfosResults * ) scanResults; + + if( scanDeviceInfosResults->deviceInfos ) + { + int i; + for (i = 0; i < deviceCount; ++i) + { + PaWinWdmDeviceInfo* pDevice = (PaWinWdmDeviceInfo*)scanDeviceInfosResults->deviceInfos[i]; + if (pDevice->filter != 0) + { + FilterFree(pDevice->filter); + } + } + + PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] ); /* all device info structs are allocated in a block so we can destroy them here */ + PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos ); + } + + PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults ); + } + + return paNoError; + +} + PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; - int i, deviceCount; - PaWinWdmHostApiRepresentation *wdmHostApi; - PaWinWdmDeviceInfo *deviceInfoArray; - PaWinWdmFilter* pFilter; - PaWinWdmDeviceInfo *wdmDeviceInfo; - PaDeviceInfo *deviceInfo; + int deviceCount = 0; + void *scanResults = 0; + PaWinWdmHostApiRepresentation *wdmHostApi = NULL; PA_LOGE_; +#ifdef PA_WDMKS_SET_TREF + tRef = PaUtil_GetTime(); +#endif + /* Attempt to load the KSUSER.DLL without which we cannot create pins We will unload this on termination @@ -1778,11 +3800,25 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd if(DllKsUser == NULL) goto error; } - FunctionKsCreatePin = (KSCREATEPIN*)GetProcAddress(DllKsUser, "KsCreatePin"); if(FunctionKsCreatePin == NULL) goto error; + /* Attempt to load AVRT.DLL, if we can't, then we'll just use time critical prio instead... */ + if(paWinWDMKSAvRtEntryPoints.hInstance == NULL) + { + paWinWDMKSAvRtEntryPoints.hInstance = LoadLibrary(TEXT("avrt.dll")); + if (paWinWDMKSAvRtEntryPoints.hInstance != NULL) + { + paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics = + (HANDLE(WINAPI*)(LPCSTR,LPDWORD))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance,"AvSetMmThreadCharacteristicsA"); + paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics = + (BOOL(WINAPI*)(HANDLE))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvRevertMmThreadCharacteristics"); + paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority = + (BOOL(WINAPI*)(HANDLE,PA_AVRT_PRIORITY))GetProcAddress(paWinWDMKSAvRtEntryPoints.hInstance, "AvSetMmThreadPriority"); + } + } + wdmHostApi = (PaWinWdmHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWdmHostApiRepresentation) ); if( !wdmHostApi ) { @@ -1797,129 +3833,50 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd goto error; } - result = BuildFilterList( wdmHostApi ); - if( result != paNoError ) - { - goto error; - } - deviceCount = wdmHostApi->filterCount; - *hostApi = &wdmHostApi->inheritedHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paWDMKS; (*hostApi)->info.name = "Windows WDM-KS"; + + /* these are all updated by CommitDeviceInfos() */ + (*hostApi)->info.deviceCount = 0; (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; + (*hostApi)->deviceInfos = 0; - if( deviceCount > 0 ) + result = ScanDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, &scanResults, &deviceCount); + if (result != paNoError) { - (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( - wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo*) * deviceCount ); - if( !(*hostApi)->deviceInfos ) - { - result = paInsufficientMemory; - goto error; - } - - /* allocate all device info structs in a contiguous block */ - deviceInfoArray = (PaWinWdmDeviceInfo*)PaUtil_GroupAllocateMemory( - wdmHostApi->allocations, sizeof(PaWinWdmDeviceInfo) * deviceCount ); - if( !deviceInfoArray ) - { - result = paInsufficientMemory; - goto error; - } - - for( i=0; i < deviceCount; ++i ) - { - wdmDeviceInfo = &deviceInfoArray[i]; - deviceInfo = &wdmDeviceInfo->inheritedDeviceInfo; - pFilter = wdmHostApi->filters[i]; - if( pFilter == NULL ) - continue; - wdmDeviceInfo->filter = pFilter; - deviceInfo->structVersion = 2; - deviceInfo->hostApi = hostApiIndex; - deviceInfo->name = (char*)pFilter->friendlyName; - PA_DEBUG(("Device found name: %s\n",(char*)pFilter->friendlyName)); - deviceInfo->maxInputChannels = pFilter->maxInputChannels; - if(deviceInfo->maxInputChannels > 0) - { - /* Set the default input device to the first device we find with - * more than zero input channels - **/ - if((*hostApi)->info.defaultInputDevice == paNoDevice) - { - (*hostApi)->info.defaultInputDevice = i; - } - } - - deviceInfo->maxOutputChannels = pFilter->maxOutputChannels; - if(deviceInfo->maxOutputChannels > 0) - { - /* Set the default output device to the first device we find with - * more than zero output channels - **/ - if((*hostApi)->info.defaultOutputDevice == paNoDevice) - { - (*hostApi)->info.defaultOutputDevice = i; - } - } - - /* These low values are not very useful because - * a) The lowest latency we end up with can depend on many factors such - * as the device buffer sizes/granularities, sample rate, channels and format - * b) We cannot know the device buffer sizes until we try to open/use it at - * a particular setting - * So: we give 512x48000Hz frames as the default low input latency - **/ - deviceInfo->defaultLowInputLatency = (512.0/48000.0); - deviceInfo->defaultLowOutputLatency = (512.0/48000.0); - deviceInfo->defaultHighInputLatency = (4096.0/48000.0); - deviceInfo->defaultHighOutputLatency = (4096.0/48000.0); - deviceInfo->defaultSampleRate = (double)(pFilter->bestSampleRate); - - (*hostApi)->deviceInfos[i] = deviceInfo; - } + goto error; } - (*hostApi)->info.deviceCount = deviceCount; + CommitDeviceInfos(&wdmHostApi->inheritedHostApiRep, hostApiIndex, scanResults, deviceCount); (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; - + /* In preparation for hotplug + (*hostApi)->ScanDeviceInfos = ScanDeviceInfos; + (*hostApi)->CommitDeviceInfos = CommitDeviceInfos; + (*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos; + */ PaUtil_InitializeStreamInterface( &wdmHostApi->callbackStreamInterface, CloseStream, StartStream, - StopStream, AbortStream, IsStreamStopped, IsStreamActive, - GetStreamTime, GetStreamCpuLoad, - PaUtil_DummyRead, PaUtil_DummyWrite, - PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, GetStreamCpuLoad, + PaUtil_DummyRead, PaUtil_DummyWrite, + PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &wdmHostApi->blockingStreamInterface, CloseStream, StartStream, - StopStream, AbortStream, IsStreamStopped, IsStreamActive, - GetStreamTime, PaUtil_DummyGetCpuLoad, - ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); + StopStream, AbortStream, IsStreamStopped, IsStreamActive, + GetStreamTime, PaUtil_DummyGetCpuLoad, + ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); PA_LOGL_; return result; error: - if( DllKsUser != NULL ) - { - FreeLibrary( DllKsUser ); - DllKsUser = NULL; - } + Terminate( (PaUtilHostApiRepresentation*)wdmHostApi ); - if( wdmHostApi ) - { - PaUtil_FreeMemory( wdmHostApi->filters ); - if( wdmHostApi->allocations ) - { - PaUtil_FreeAllAllocations( wdmHostApi->allocations ); - PaUtil_DestroyAllocationGroup( wdmHostApi->allocations ); - } - PaUtil_FreeMemory( wdmHostApi ); - } PA_LOGL_; return result; } @@ -1928,85 +3885,42 @@ error: static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) { PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; - int i; PA_LOGE_; - if( wdmHostApi->filters ) + /* Do not unload the libraries */ + if( DllKsUser != NULL ) { - for( i=0; ifilterCount; i++) + FreeLibrary( DllKsUser ); + DllKsUser = NULL; + } + + if( paWinWDMKSAvRtEntryPoints.hInstance != NULL ) + { + FreeLibrary( paWinWDMKSAvRtEntryPoints.hInstance ); + paWinWDMKSAvRtEntryPoints.hInstance = NULL; + } + + if( wdmHostApi) + { + PaWinWDMScanDeviceInfosResults* localScanResults = (PaWinWDMScanDeviceInfosResults*)PaUtil_GroupAllocateMemory( + wdmHostApi->allocations, sizeof(PaWinWDMScanDeviceInfosResults)); + localScanResults->deviceInfos = hostApi->deviceInfos; + DisposeDeviceInfos(hostApi, localScanResults, hostApi->info.deviceCount); + + if( wdmHostApi->allocations ) { - if( wdmHostApi->filters[i] != NULL ) - { - FilterFree( wdmHostApi->filters[i] ); - wdmHostApi->filters[i] = NULL; - } + PaUtil_FreeAllAllocations( wdmHostApi->allocations ); + PaUtil_DestroyAllocationGroup( wdmHostApi->allocations ); } + PaUtil_FreeMemory( wdmHostApi ); } - PaUtil_FreeMemory( wdmHostApi->filters ); - if( wdmHostApi->allocations ) - { - PaUtil_FreeAllAllocations( wdmHostApi->allocations ); - PaUtil_DestroyAllocationGroup( wdmHostApi->allocations ); - } - PaUtil_FreeMemory( wdmHostApi ); - PA_LOGL_; -} - -static void FillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat, double sampleRate, int channelCount) -{ - PA_LOGE_; - PA_DEBUG(( "sampleFormat = %lx\n" , sampleFormat )); - PA_DEBUG(( "sampleRate = %f\n" , sampleRate )); - PA_DEBUG(( "chanelCount = %d\n", channelCount )); - - pwfext->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - pwfext->Format.nChannels = channelCount; - pwfext->Format.nSamplesPerSec = (int)sampleRate; - if(channelCount == 1) - pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT; - else - pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO; - if(sampleFormat == paFloat32) - { - pwfext->Format.nBlockAlign = channelCount * 4; - pwfext->Format.wBitsPerSample = 32; - pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); - pwfext->Samples.wValidBitsPerSample = 32; - pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - } - else if(sampleFormat == paInt32) - { - pwfext->Format.nBlockAlign = channelCount * 4; - pwfext->Format.wBitsPerSample = 32; - pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); - pwfext->Samples.wValidBitsPerSample = 32; - pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - else if(sampleFormat == paInt24) - { - pwfext->Format.nBlockAlign = channelCount * 3; - pwfext->Format.wBitsPerSample = 24; - pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); - pwfext->Samples.wValidBitsPerSample = 24; - pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - else if(sampleFormat == paInt16) - { - pwfext->Format.nBlockAlign = channelCount * 2; - pwfext->Format.wBitsPerSample = 16; - pwfext->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX); - pwfext->Samples.wValidBitsPerSample = 16; - pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - pwfext->Format.nAvgBytesPerSec = pwfext->Format.nSamplesPerSec * pwfext->Format.nBlockAlign; - PA_LOGL_; } static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate ) + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ) { int inputChannelCount, outputChannelCount; PaSampleFormat inputSampleFormat, outputSampleFormat; @@ -2014,49 +3928,114 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, PaWinWdmFilter* pFilter; int result = paFormatIsSupported; WAVEFORMATEXTENSIBLE wfx; + PaWinWaveFormatChannelMask channelMask; PA_LOGE_; if( inputParameters ) { + PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device]; + PaWinWdmPin* pin; + unsigned fmt; + unsigned long testFormat = 0; + unsigned validBits = 0; + inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, - this implementation doesn't support any custom sample formats */ + this implementation doesn't support any custom sample formats */ if( inputSampleFormat & paCustomFormat ) + { + PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom input format not supported"); return paSampleFormatNotSupported; + } /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ + paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported"); return paInvalidDevice; + } /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + { + PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "IsFormatSupported: Invalid input channel count"); return paInvalidChannelCount; + } /* validate inputStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) + { + PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported"); return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + + pFilter = pDeviceInfo->filter; + pin = pFilter->pins[pDeviceInfo->pin]; + + /* Find out the testing format */ + for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1) + { + if ((fmt & pin->formats) != 0) + { + /* Found a matching format! */ + testFormat = fmt; + break; + } + } + if (testFormat == 0) + { + PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: no testformat found!"); + return paUnanticipatedHostError; + } + + /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and + valid bits = 24 (instead of 24 bit samples) */ + if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24) + { + PA_DEBUG(("IsFormatSupported (capture): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)")); + testFormat = paInt32; + validBits = 24; + } /* Check that the input format is supported */ - FillWFEXT(&wfx,paInt16,sampleRate,inputChannelCount); + channelMask = PaWin_DefaultChannelMask(inputChannelCount); + PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx, + inputChannelCount, + testFormat, + PaWin_SampleFormatToLinearWaveFormatTag(testFormat), + sampleRate, + channelMask ); + if (validBits != 0) + { + wfx.Samples.wValidBitsPerSample = validBits; + } - pFilter = wdmHostApi->filters[inputParameters->device]; - result = FilterCanCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx); + result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx); if( result != paNoError ) { /* Try a WAVE_FORMAT_PCM instead */ - wfx.Format.wFormatTag = WAVE_FORMAT_PCM; - wfx.Format.cbSize = 0; - wfx.Samples.wValidBitsPerSample = 0; - wfx.dwChannelMask = 0; - wfx.SubFormat = GUID_NULL; - result = FilterCanCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx); + PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx, + inputChannelCount, + testFormat, + PaWin_SampleFormatToLinearWaveFormatTag(testFormat), + sampleRate); + + if (validBits != 0) + { + wfx.Samples.wValidBitsPerSample = validBits; + } + + result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx); if( result != paNoError ) - return result; + { + PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(capture) failed: sr=%u,ch=%u,bits=%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample); + return result; + } } } else @@ -2066,44 +4045,109 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, if( outputParameters ) { + PaWinWdmDeviceInfo* pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device]; + PaWinWdmPin* pin; + unsigned fmt; + unsigned long testFormat = 0; + unsigned validBits = 0; + outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* all standard sample formats are supported by the buffer adapter, - this implementation doesn't support any custom sample formats */ + this implementation doesn't support any custom sample formats */ if( outputSampleFormat & paCustomFormat ) + { + PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "IsFormatSupported: Custom output format not supported"); return paSampleFormatNotSupported; + } /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ + paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + PaWinWDM_SetLastErrorInfo(paInvalidDevice, "IsFormatSupported: paUseHostApiSpecificDeviceSpecification not supported"); return paInvalidDevice; + } /* check that output device can support outputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + { + PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count"); return paInvalidChannelCount; + } /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) + { + PaWinWDM_SetLastErrorInfo(paIncompatibleHostApiSpecificStreamInfo, "Host API stream info not supported"); return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ + } + + pFilter = pDeviceInfo->filter; + pin = pFilter->pins[pDeviceInfo->pin]; + + /* Find out the testing format */ + for (fmt = paFloat32; fmt <= paUInt8; fmt <<= 1) + { + if ((fmt & pin->formats) != 0) + { + /* Found a matching format! */ + testFormat = fmt; + break; + } + } + if (testFormat == 0) + { + PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: no testformat found!"); + return paUnanticipatedHostError; + } + + /* Due to special considerations, WaveRT devices with paInt24 should be tested with paInt32 and + valid bits = 24 (instead of 24 bit samples) */ + if (pFilter->devInfo.streamingType == Type_kWaveRT && testFormat == paInt24) + { + PA_DEBUG(("IsFormatSupported (render): WaveRT overriding testFormat paInt24 with paInt32 (24 valid bits)")); + testFormat = paInt32; + validBits = 24; + } /* Check that the output format is supported */ - FillWFEXT(&wfx,paInt16,sampleRate,outputChannelCount); + channelMask = PaWin_DefaultChannelMask(outputChannelCount); + PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx, + outputChannelCount, + testFormat, + PaWin_SampleFormatToLinearWaveFormatTag(testFormat), + sampleRate, + channelMask ); - pFilter = wdmHostApi->filters[outputParameters->device]; - result = FilterCanCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx); + if (validBits != 0) + { + wfx.Samples.wValidBitsPerSample = validBits; + } + + result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx); if( result != paNoError ) { /* Try a WAVE_FORMAT_PCM instead */ - wfx.Format.wFormatTag = WAVE_FORMAT_PCM; - wfx.Format.cbSize = 0; - wfx.Samples.wValidBitsPerSample = 0; - wfx.dwChannelMask = 0; - wfx.SubFormat = GUID_NULL; - result = FilterCanCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx); + PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx, + outputChannelCount, + testFormat, + PaWin_SampleFormatToLinearWaveFormatTag(testFormat), + sampleRate); + + if (validBits != 0) + { + wfx.Samples.wValidBitsPerSample = validBits; + } + + result = PinIsFormatSupported(pin, (const WAVEFORMATEX*)&wfx); if( result != paNoError ) - return result; + { + PaWinWDM_SetLastErrorInfo(result, "IsFormatSupported(render) failed: %u,%u,%u", wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample); + return result; + } } } @@ -2113,43 +4157,172 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, } /* - IMPLEMENT ME: + IMPLEMENT ME: - - if a full duplex stream is requested, check that the combination - of input and output parameters is supported if necessary + - if a full duplex stream is requested, check that the combination + of input and output parameters is supported if necessary - - check that the device supports sampleRate + - check that the device supports sampleRate - Because the buffer adapter handles conversion between all standard - sample formats, the following checks are only required if paCustomFormat - is implemented, or under some other unusual conditions. + Because the buffer adapter handles conversion between all standard + sample formats, the following checks are only required if paCustomFormat + is implemented, or under some other unusual conditions. - - check that input device can support inputSampleFormat, or that - we have the capability to convert from inputSampleFormat to - a native format + - check that input device can support inputSampleFormat, or that + we have the capability to convert from inputSampleFormat to + a native format - - check that output device can support outputSampleFormat, or that - we have the capability to convert from outputSampleFormat to - a native format + - check that output device can support outputSampleFormat, or that + we have the capability to convert from outputSampleFormat to + a native format */ if((inputChannelCount == 0)&&(outputChannelCount == 0)) - result = paSampleFormatNotSupported; /* Not right error */ + { + PaWinWDM_SetLastErrorInfo(paSampleFormatNotSupported, "No input or output channels defined"); + result = paSampleFormatNotSupported; /* Not right error */ + } PA_LOGL_; return result; } +static void ResetStreamEvents(PaWinWdmStream* stream) +{ + unsigned i; + ResetEvent(stream->eventAbort); + ResetEvent(stream->eventStreamStart[StreamStart_kOk]); + ResetEvent(stream->eventStreamStart[StreamStart_kFailed]); + + for (i=0; icapture.noOfPackets; ++i) + { + if (stream->capture.events && stream->capture.events[i]) + { + ResetEvent(stream->capture.events[i]); + } + } + + for (i=0; irender.noOfPackets; ++i) + { + if (stream->render.events && stream->render.events[i]) + { + ResetEvent(stream->render.events[i]); + } + } +} + +static void CloseStreamEvents(PaWinWdmStream* stream) +{ + unsigned i; + PaWinWdmIOInfo* ios[2] = { &stream->capture, &stream->render }; + + if (stream->eventAbort) + { + CloseHandle(stream->eventAbort); + stream->eventAbort = 0; + } + if (stream->eventStreamStart[StreamStart_kOk]) + { + CloseHandle(stream->eventStreamStart[StreamStart_kOk]); + } + if (stream->eventStreamStart[StreamStart_kFailed]) + { + CloseHandle(stream->eventStreamStart[StreamStart_kFailed]); + } + + for (i = 0; i < 2; ++i) + { + unsigned j; + /* Unregister notification handles for WaveRT */ + if (ios[i]->pPin && ios[i]->pPin->parentFilter->devInfo.streamingType == Type_kWaveRT && + ios[i]->pPin->pinKsSubType == SubType_kNotification && + ios[i]->events != 0) + { + PinUnregisterNotificationHandle(ios[i]->pPin, ios[i]->events[0]); + } + + for (j=0; j < ios[i]->noOfPackets; ++j) + { + if (ios[i]->events && ios[i]->events[j]) + { + CloseHandle(ios[i]->events[j]); + ios[i]->events[j] = 0; + } + } + } +} + +static unsigned NextPowerOf2(unsigned val) +{ + val--; + val = (val >> 1) | val; + val = (val >> 2) | val; + val = (val >> 4) | val; + val = (val >> 8) | val; + val = (val >> 16) | val; + return ++val; +} + +static PaError ValidateSpecificStreamParameters( + const PaStreamParameters *streamParameters, + const PaWinWDMKSInfo *streamInfo, + unsigned isInput) +{ + if( streamInfo ) + { + if( streamInfo->size != sizeof( PaWinWDMKSInfo ) + || streamInfo->version != 1 ) + { + PA_DEBUG(("Stream parameters: size or version not correct")); + return paIncompatibleHostApiSpecificStreamInfo; + } + + if (!!(streamInfo->flags & ~(paWinWDMKSOverrideFramesize | paWinWDMKSUseGivenChannelMask))) + { + PA_DEBUG(("Stream parameters: non supported flags set")); + return paIncompatibleHostApiSpecificStreamInfo; + } + + if (streamInfo->noOfPackets != 0 && + (streamInfo->noOfPackets < 2 || streamInfo->noOfPackets > 8)) + { + PA_DEBUG(("Stream parameters: noOfPackets %u out of range [2,8]", streamInfo->noOfPackets)); + return paIncompatibleHostApiSpecificStreamInfo; + } + + if (streamInfo->flags & paWinWDMKSUseGivenChannelMask) + { + if (isInput) + { + PA_DEBUG(("Stream parameters: Channels mask setting not supported for input stream")); + return paIncompatibleHostApiSpecificStreamInfo; + } + + if (streamInfo->channelMask & PAWIN_SPEAKER_RESERVED) + { + PA_DEBUG(("Stream parameters: Given channels mask 0x%08X not supported", streamInfo->channelMask)); + return paIncompatibleHostApiSpecificStreamInfo; + } + } + + } + + return paNoError; +} + + + + /* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, - PaStream** s, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - unsigned long framesPerBuffer, - PaStreamFlags streamFlags, - PaStreamCallback *streamCallback, - void *userData ) + PaStream** s, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerUserBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ) { PaError result = paNoError; PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi; @@ -2158,13 +4331,11 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaSampleFormat inputSampleFormat, outputSampleFormat; PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat; int userInputChannels,userOutputChannels; - int size; - PaWinWdmFilter* pFilter; WAVEFORMATEXTENSIBLE wfx; PA_LOGE_; PA_DEBUG(("OpenStream:sampleRate = %f\n",sampleRate)); - PA_DEBUG(("OpenStream:framesPerBuffer = %lu\n",framesPerBuffer)); + PA_DEBUG(("OpenStream:framesPerBuffer = %lu\n",framesPerUserBuffer)); if( inputParameters ) { @@ -2172,24 +4343,33 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, inputSampleFormat = inputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ + paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(in) not supported"); return paInvalidDevice; + } /* check that input device can support stream->userInputChannels */ if( userInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) + { + PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid input channel count"); return paInvalidChannelCount; + } /* validate inputStreamInfo */ - if( inputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - + result = ValidateSpecificStreamParameters(inputParameters, inputParameters->hostApiSpecificStreamInfo, 1 ); + if(result != paNoError) + { + PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (in)"); + return result; /* this implementation doesn't use custom stream info */ + } } else { userInputChannels = 0; - inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */ + inputSampleFormat = hostInputSampleFormat = paInt16; /* Supress 'uninitialised var' warnings. */ } if( outputParameters ) @@ -2198,29 +4378,41 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, outputSampleFormat = outputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ + paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) + { + PaWinWDM_SetLastErrorInfo(paInvalidDevice, "paUseHostApiSpecificDeviceSpecification(out) not supported"); return paInvalidDevice; + } /* check that output device can support stream->userInputChannels */ if( userOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) + { + PaWinWDM_SetLastErrorInfo(paInvalidChannelCount, "Invalid output channel count"); return paInvalidChannelCount; + } /* validate outputStreamInfo */ - if( outputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - + result = ValidateSpecificStreamParameters( outputParameters, outputParameters->hostApiSpecificStreamInfo, 0 ); + if (result != paNoError) + { + PaWinWDM_SetLastErrorInfo(result, "Host API stream info not supported (out)"); + return result; /* this implementation doesn't use custom stream info */ + } } else { userOutputChannels = 0; - outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */ + outputSampleFormat = hostOutputSampleFormat = paInt16; /* Supress 'uninitialized var' warnings. */ } /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) + { + PaWinWDM_SetLastErrorInfo(paInvalidFlag, "Invalid flag supplied"); return paInvalidFlag; /* unexpected platform specific flag */ + } stream = (PaWinWdmStream*)PaUtil_AllocateMemory( sizeof(PaWinWdmStream) ); if( !stream ) @@ -2228,18 +4420,33 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, result = paInsufficientMemory; goto error; } + + /* Create allocation group */ + stream->allocGroup = PaUtil_CreateAllocationGroup(); + if( !stream->allocGroup ) + { + result = paInsufficientMemory; + goto error; + } + /* Zero the stream object */ /* memset((void*)stream,0,sizeof(PaWinWdmStream)); */ if( streamCallback ) { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, - &wdmHostApi->callbackStreamInterface, streamCallback, userData ); + &wdmHostApi->callbackStreamInterface, streamCallback, userData ); } else { - PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, - &wdmHostApi->blockingStreamInterface, streamCallback, userData ); + /* PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, + &wdmHostApi->blockingStreamInterface, streamCallback, userData ); */ + + /* We don't support the blocking API yet */ + PA_DEBUG(("Blocking API not supported yet!\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Blocking API not supported yet"); + result = paUnanticipatedHostError; + goto error; } PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); @@ -2247,315 +4454,795 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* Instantiate the input pin if necessary */ if(userInputChannels > 0) { + PaWinWdmFilter* pFilter; + PaWinWdmDeviceInfo* pDeviceInfo; + PaWinWdmPin* pPin; + unsigned validBitsPerSample = 0; + PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userInputChannels ); + result = paSampleFormatNotSupported; - pFilter = wdmHostApi->filters[inputParameters->device]; + pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device]; + pFilter = pDeviceInfo->filter; + pPin = pFilter->pins[pDeviceInfo->pin]; + stream->userInputChannels = userInputChannels; - if(((inputSampleFormat & ~paNonInterleaved) & pFilter->formats) != 0) - { /* inputSampleFormat is supported, so try to use it */ - hostInputSampleFormat = inputSampleFormat; - FillWFEXT(&wfx, hostInputSampleFormat, sampleRate, stream->userInputChannels); - stream->bytesPerInputFrame = wfx.Format.nBlockAlign; - stream->recordingPin = FilterCreateCapturePin(pFilter, (const WAVEFORMATEX*)&wfx, &result); - stream->deviceInputChannels = stream->userInputChannels; - } - - if(result != paNoError) - { /* Search through all PaSampleFormats to find one that works */ - hostInputSampleFormat = paFloat32; - - do { - FillWFEXT(&wfx, hostInputSampleFormat, sampleRate, stream->userInputChannels); - stream->bytesPerInputFrame = wfx.Format.nBlockAlign; - stream->recordingPin = FilterCreateCapturePin(pFilter, (const WAVEFORMATEX*)&wfx, &result); - stream->deviceInputChannels = stream->userInputChannels; - - if(stream->recordingPin == NULL) result = paSampleFormatNotSupported; - if(result != paNoError) hostInputSampleFormat <<= 1; - } - while(result != paNoError && hostInputSampleFormat <= paUInt8); - } - - if(result != paNoError) - { /* None of the PaSampleFormats worked. Set the hostInputSampleFormat to the best fit - * and try a PCM format. - **/ - hostInputSampleFormat = - PaUtil_SelectClosestAvailableFormat( pFilter->formats, inputSampleFormat ); - - /* Try a WAVE_FORMAT_PCM instead */ - wfx.Format.wFormatTag = WAVE_FORMAT_PCM; - wfx.Format.cbSize = 0; - wfx.Samples.wValidBitsPerSample = 0; - wfx.dwChannelMask = 0; - wfx.SubFormat = GUID_NULL; - stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result); - if(stream->recordingPin == NULL) result = paSampleFormatNotSupported; - } - - if( result != paNoError ) + hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, inputSampleFormat ); + if (hostInputSampleFormat == paSampleFormatNotSupported) { - /* Some or all KS devices can only handle the exact number of channels - * they specify. But PortAudio clients expect to be able to - * at least specify mono I/O on a multi-channel device - * If this is the case, then we will do the channel mapping internally - **/ - if( stream->userInputChannels < pFilter->maxInputChannels ) - { - FillWFEXT(&wfx,hostInputSampleFormat,sampleRate,pFilter->maxInputChannels); - stream->bytesPerInputFrame = wfx.Format.nBlockAlign; - stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result); - stream->deviceInputChannels = pFilter->maxInputChannels; + result = paUnanticipatedHostError; + PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (input)", pPin->formats, inputSampleFormat); + goto error; + } + else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostInputSampleFormat == paInt24) + { + /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a + 128 byte boundary (see PinGetBuffer) */ + hostInputSampleFormat = paInt32; + /* But we'll tell the driver that it's 24 bit in 32 bit container */ + validBitsPerSample = 24; + } - if( result != paNoError ) + while (hostInputSampleFormat <= paUInt8) + { + unsigned channelsToProbe = stream->userInputChannels; + /* Some or all KS devices can only handle the exact number of channels + * they specify. But PortAudio clients expect to be able to + * at least specify mono I/O on a multi-channel device + * If this is the case, then we will do the channel mapping internally + * The following loop tests this case + **/ + while (1) + { + PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx, + channelsToProbe, + hostInputSampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat), + sampleRate, + channelMask ); + stream->capture.bytesPerFrame = wfx.Format.nBlockAlign; + if (validBitsPerSample != 0) + { + wfx.Samples.wValidBitsPerSample = validBitsPerSample; + } + stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result); + stream->deviceInputChannels = channelsToProbe; + + if( result != paNoError && result != paDeviceUnavailable ) { /* Try a WAVE_FORMAT_PCM instead */ - wfx.Format.wFormatTag = WAVE_FORMAT_PCM; - wfx.Format.cbSize = 0; - wfx.Samples.wValidBitsPerSample = 0; - wfx.dwChannelMask = 0; - wfx.SubFormat = GUID_NULL; - stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result); + PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx, + channelsToProbe, + hostInputSampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag(hostInputSampleFormat), + sampleRate); + if (validBitsPerSample != 0) + { + wfx.Samples.wValidBitsPerSample = validBitsPerSample; + } + stream->capture.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result); } + + if (result == paDeviceUnavailable) goto occupied; + + if (result == paNoError) + { + /* We're done */ + break; + } + + if (channelsToProbe < (unsigned)pPin->maxChannels) + { + /* Go to next multiple of 2 */ + channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels); + continue; + } + + break; } + + if (result == paNoError) + { + /* We're done */ + break; + } + + /* Go to next format in line with lower resolution */ + hostInputSampleFormat <<= 1; } - if(stream->recordingPin == NULL) + if(stream->capture.pPin == NULL) { + PaWinWDM_SetLastErrorInfo(result, "Failed to create capture pin: sr=%u,ch=%u,bits=%u,align=%u", + wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign); goto error; } - switch(hostInputSampleFormat) + /* Select correct mux input on MUX node of topology filter */ + if (pDeviceInfo->muxPosition >= 0) { - case paInt16: stream->inputSampleSize = 2; break; - case paInt24: stream->inputSampleSize = 3; break; - case paInt32: - case paFloat32: stream->inputSampleSize = 4; break; + assert(pPin->parentFilter->topologyFilter != NULL); + + result = FilterUse(pPin->parentFilter->topologyFilter); + if (result != paNoError) + { + PaWinWDM_SetLastErrorInfo(result, "Failed to open topology filter"); + goto error; + } + + result = WdmSetMuxNodeProperty(pPin->parentFilter->topologyFilter->handle, + pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId, + pPin->inputs[pDeviceInfo->muxPosition]->muxPinId); + + FilterRelease(pPin->parentFilter->topologyFilter); + + if(result != paNoError) + { + PaWinWDM_SetLastErrorInfo(result, "Failed to set topology mux node"); + goto error; + } } - stream->recordingPin->frameSize /= stream->bytesPerInputFrame; - PA_DEBUG(("Pin output frames: %d\n",stream->recordingPin->frameSize)); + stream->capture.bytesPerSample = stream->capture.bytesPerFrame / stream->deviceInputChannels; + stream->capture.pPin->frameSize /= stream->capture.bytesPerFrame; + PA_DEBUG(("Capture pin frames: %d\n",stream->capture.pPin->frameSize)); } else { - stream->recordingPin = NULL; - stream->bytesPerInputFrame = 0; + stream->capture.pPin = NULL; + stream->capture.bytesPerFrame = 0; } /* Instantiate the output pin if necessary */ if(userOutputChannels > 0) { + PaWinWdmFilter* pFilter; + PaWinWdmDeviceInfo* pDeviceInfo; + PaWinWdmPin* pPin; + PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)(outputParameters->hostApiSpecificStreamInfo); + unsigned validBitsPerSample = 0; + PaWinWaveFormatChannelMask channelMask = PaWin_DefaultChannelMask( userOutputChannels ); + if (pInfo && (pInfo->flags & paWinWDMKSUseGivenChannelMask)) + { + PA_DEBUG(("Using channelMask 0x%08X instead of default 0x%08X\n", + pInfo->channelMask, + channelMask)); + channelMask = pInfo->channelMask; + } + result = paSampleFormatNotSupported; - pFilter = wdmHostApi->filters[outputParameters->device]; + pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device]; + pFilter = pDeviceInfo->filter; + pPin = pFilter->pins[pDeviceInfo->pin]; + stream->userOutputChannels = userOutputChannels; - if(((outputSampleFormat & ~paNonInterleaved) & pFilter->formats) != 0) + hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( pPin->formats, outputSampleFormat ); + if (hostOutputSampleFormat == paSampleFormatNotSupported) { - hostOutputSampleFormat = outputSampleFormat; - FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,stream->userOutputChannels); - stream->bytesPerOutputFrame = wfx.Format.nBlockAlign; - stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result); - stream->deviceOutputChannels = stream->userOutputChannels; + result = paUnanticipatedHostError; + PaWinWDM_SetLastErrorInfo(result, "PU_SCAF(%X,%X) failed (output)", pPin->formats, hostOutputSampleFormat); + goto error; + } + else if (pFilter->devInfo.streamingType == Type_kWaveRT && hostOutputSampleFormat == paInt24) + { + /* For WaveRT, we choose 32 bit format instead of paInt24, since we MIGHT need to align buffer on a + 128 byte boundary (see PinGetBuffer) */ + hostOutputSampleFormat = paInt32; + /* But we'll tell the driver that it's 24 bit in 32 bit container */ + validBitsPerSample = 24; } - if(result != paNoError) - { - hostOutputSampleFormat = paFloat32; - - do { - FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,stream->userOutputChannels); - stream->bytesPerOutputFrame = wfx.Format.nBlockAlign; - stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result); - stream->deviceOutputChannels = stream->userOutputChannels; - - if(stream->playbackPin == NULL) result = paSampleFormatNotSupported; - if(result != paNoError) hostOutputSampleFormat <<= 1; - } - while(result != paNoError && hostOutputSampleFormat <= paUInt8); - } - - if(result != paNoError) - { - hostOutputSampleFormat = - PaUtil_SelectClosestAvailableFormat( pFilter->formats, outputSampleFormat ); - - /* Try a WAVE_FORMAT_PCM instead */ - wfx.Format.wFormatTag = WAVE_FORMAT_PCM; - wfx.Format.cbSize = 0; - wfx.Samples.wValidBitsPerSample = 0; - wfx.dwChannelMask = 0; - wfx.SubFormat = GUID_NULL; - stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result); - if(stream->playbackPin == NULL) result = paSampleFormatNotSupported; - } - - if( result != paNoError ) + while (hostOutputSampleFormat <= paUInt8) { + unsigned channelsToProbe = stream->userOutputChannels; /* Some or all KS devices can only handle the exact number of channels - * they specify. But PortAudio clients expect to be able to - * at least specify mono I/O on a multi-channel device - * If this is the case, then we will do the channel mapping internally - **/ - if( stream->userOutputChannels < pFilter->maxOutputChannels ) + * they specify. But PortAudio clients expect to be able to + * at least specify mono I/O on a multi-channel device + * If this is the case, then we will do the channel mapping internally + * The following loop tests this case + **/ + while (1) { - FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,pFilter->maxOutputChannels); - stream->bytesPerOutputFrame = wfx.Format.nBlockAlign; - stream->playbackPin = FilterCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx,&result); - stream->deviceOutputChannels = pFilter->maxOutputChannels; - if( result != paNoError ) + PaWin_InitializeWaveFormatExtensible((PaWinWaveFormat*)&wfx, + channelsToProbe, + hostOutputSampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat), + sampleRate, + channelMask ); + stream->render.bytesPerFrame = wfx.Format.nBlockAlign; + if (validBitsPerSample != 0) { - /* Try a WAVE_FORMAT_PCM instead */ - wfx.Format.wFormatTag = WAVE_FORMAT_PCM; - wfx.Format.cbSize = 0; - wfx.Samples.wValidBitsPerSample = 0; - wfx.dwChannelMask = 0; - wfx.SubFormat = GUID_NULL; - stream->playbackPin = FilterCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx,&result); + wfx.Samples.wValidBitsPerSample = validBitsPerSample; } + stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (WAVEFORMATEX*)&wfx, &result); + stream->deviceOutputChannels = channelsToProbe; + + if( result != paNoError && result != paDeviceUnavailable ) + { + PaWin_InitializeWaveFormatEx((PaWinWaveFormat*)&wfx, + channelsToProbe, + hostOutputSampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag(hostOutputSampleFormat), + sampleRate); + if (validBitsPerSample != 0) + { + wfx.Samples.wValidBitsPerSample = validBitsPerSample; + } + stream->render.pPin = FilterCreatePin(pFilter, pPin->pinId, (const WAVEFORMATEX*)&wfx, &result); + } + + if (result == paDeviceUnavailable) goto occupied; + + if (result == paNoError) + { + /* We're done */ + break; + } + + if (channelsToProbe < (unsigned)pPin->maxChannels) + { + /* Go to next multiple of 2 */ + channelsToProbe = min((((channelsToProbe>>1)+1)<<1), (unsigned)pPin->maxChannels); + continue; + } + + break; + }; + + if (result == paNoError) + { + /* We're done */ + break; } + + /* Go to next format in line with lower resolution */ + hostOutputSampleFormat <<= 1; } - if(stream->playbackPin == NULL) + if(stream->render.pPin == NULL) { + PaWinWDM_SetLastErrorInfo(result, "Failed to create render pin: sr=%u,ch=%u,bits=%u,align=%u", + wfx.Format.nSamplesPerSec, wfx.Format.nChannels, wfx.Format.wBitsPerSample, wfx.Format.nBlockAlign); goto error; } - switch(hostOutputSampleFormat) - { - case paInt16: stream->outputSampleSize = 2; break; - case paInt24: stream->outputSampleSize = 3; break; - case paInt32: - case paFloat32: stream->outputSampleSize = 4; break; - } - - stream->playbackPin->frameSize /= stream->bytesPerOutputFrame; - PA_DEBUG(("Pin output frames: %d\n",stream->playbackPin->frameSize)); + stream->render.bytesPerSample = stream->render.bytesPerFrame / stream->deviceOutputChannels; + stream->render.pPin->frameSize /= stream->render.bytesPerFrame; + PA_DEBUG(("Render pin frames: %d\n",stream->render.pPin->frameSize)); } else { - stream->playbackPin = NULL; - stream->bytesPerOutputFrame = 0; + stream->render.pPin = NULL; + stream->render.bytesPerFrame = 0; } /* Calculate the framesPerHostXxxxBuffer size based upon the suggested latency values */ - /* Record the buffer length */ if(inputParameters) { /* Calculate the frames from the user's value - add a bit to round up */ - stream->framesPerHostIBuffer = (unsigned long)((inputParameters->suggestedLatency*sampleRate)+0.0001); - if(stream->framesPerHostIBuffer > (unsigned long)sampleRate) + stream->capture.framesPerBuffer = (unsigned long)((inputParameters->suggestedLatency*sampleRate)+0.0001); + if(stream->capture.framesPerBuffer > (unsigned long)sampleRate) { /* Upper limit is 1 second */ - stream->framesPerHostIBuffer = (unsigned long)sampleRate; + stream->capture.framesPerBuffer = (unsigned long)sampleRate; } - else if(stream->framesPerHostIBuffer < stream->recordingPin->frameSize) + else if(stream->capture.framesPerBuffer < stream->capture.pPin->frameSize) { - stream->framesPerHostIBuffer = stream->recordingPin->frameSize; + stream->capture.framesPerBuffer = stream->capture.pPin->frameSize; + } + PA_DEBUG(("Input frames chosen:%ld\n",stream->capture.framesPerBuffer)); + + /* Setup number of packets to use */ + stream->capture.noOfPackets = 2; + + if (inputParameters->hostApiSpecificStreamInfo) + { + PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)inputParameters->hostApiSpecificStreamInfo; + + if (stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic && + pInfo->noOfPackets != 0) + { + stream->capture.noOfPackets = pInfo->noOfPackets; + } } - PA_DEBUG(("Input frames chosen:%ld\n",stream->framesPerHostIBuffer)); } if(outputParameters) { /* Calculate the frames from the user's value - add a bit to round up */ - stream->framesPerHostOBuffer = (unsigned long)((outputParameters->suggestedLatency*sampleRate)+0.0001); - if(stream->framesPerHostOBuffer > (unsigned long)sampleRate) + stream->render.framesPerBuffer = (unsigned long)((outputParameters->suggestedLatency*sampleRate)+0.0001); + if(stream->render.framesPerBuffer > (unsigned long)sampleRate) { /* Upper limit is 1 second */ - stream->framesPerHostOBuffer = (unsigned long)sampleRate; + stream->render.framesPerBuffer = (unsigned long)sampleRate; } - else if(stream->framesPerHostOBuffer < stream->playbackPin->frameSize) + else if(stream->render.framesPerBuffer < stream->render.pPin->frameSize) { - stream->framesPerHostOBuffer = stream->playbackPin->frameSize; + stream->render.framesPerBuffer = stream->render.pPin->frameSize; + } + PA_DEBUG(("Output frames chosen:%ld\n",stream->render.framesPerBuffer)); + + /* Setup number of packets to use */ + stream->render.noOfPackets = 2; + + if (outputParameters->hostApiSpecificStreamInfo) + { + PaWinWDMKSInfo* pInfo = (PaWinWDMKSInfo*)outputParameters->hostApiSpecificStreamInfo; + + if (stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic && + pInfo->noOfPackets != 0) + { + stream->render.noOfPackets = pInfo->noOfPackets; + } } - PA_DEBUG(("Output frames chosen:%ld\n",stream->framesPerHostOBuffer)); } - /* Host buffer size is bounded to the largest of the input and output - frame sizes */ - + /* Host buffer size is bound to the largest of the input and output frame sizes */ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, - stream->userInputChannels, inputSampleFormat, hostInputSampleFormat, - stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat, - sampleRate, streamFlags, framesPerBuffer, - max(stream->framesPerHostOBuffer,stream->framesPerHostIBuffer), - paUtilBoundedHostBufferSize, - streamCallback, userData ); + stream->userInputChannels, inputSampleFormat, hostInputSampleFormat, + stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, framesPerUserBuffer, + max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer), + paUtilBoundedHostBufferSize, + streamCallback, userData ); if( result != paNoError ) + { + PaWinWDM_SetLastErrorInfo(result, "PaUtil_InitializeBufferProcessor failed: ich=%u, isf=%u, hisf=%u, och=%u, osf=%u, hosf=%u, sr=%lf, flags=0x%X, fpub=%u, fphb=%u", + stream->userInputChannels, inputSampleFormat, hostInputSampleFormat, + stream->userOutputChannels, outputSampleFormat, hostOutputSampleFormat, + sampleRate, streamFlags, framesPerUserBuffer, + max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer)); goto error; + } + + /* Allocate/get all the buffers for host I/O */ + if (stream->userInputChannels > 0) + { + stream->streamRepresentation.streamInfo.inputLatency = stream->capture.framesPerBuffer / sampleRate; + + switch (stream->capture.pPin->parentFilter->devInfo.streamingType) + { + case Type_kWaveCyclic: + { + unsigned size = stream->capture.noOfPackets * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame; + /* Allocate input host buffer */ + stream->capture.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size); + PA_DEBUG(("Input buffer allocated (size = %u)\n", size)); + if( !stream->capture.hostBuffer ) + { + PA_DEBUG(("Cannot allocate host input buffer!\n")); + PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate input buffer"); + result = paInsufficientMemory; + goto error; + } + stream->capture.hostBufferSize = size; + PA_DEBUG(("Input buffer start = %p (size=%u)\n",stream->capture.hostBuffer, stream->capture.hostBufferSize)); + stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveCyclic; + stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveCyclic; + } + break; + case Type_kWaveRT: + { + const DWORD dwTotalSize = 2 * stream->capture.framesPerBuffer * stream->capture.bytesPerFrame; + DWORD dwRequestedSize = dwTotalSize; + BOOL bCallMemoryBarrier = FALSE; + ULONG hwFifoLatency = 0; + ULONG dummy; + result = PinGetBuffer(stream->capture.pPin, (void**)&stream->capture.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier); + if (!result) + { + PA_DEBUG(("Input buffer start = %p, size = %u\n", stream->capture.hostBuffer, dwRequestedSize)); + if (dwRequestedSize != dwTotalSize) + { + PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize)); + /* Recalculate to what the driver has given us */ + stream->capture.framesPerBuffer = dwRequestedSize / (2 * stream->capture.bytesPerFrame); + } + stream->capture.hostBufferSize = dwRequestedSize; + + if (stream->capture.pPin->pinKsSubType == SubType_kPolled) + { + stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTPolled; + stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTPolled; + } + else + { + stream->capture.pPin->fnEventHandler = PaPinCaptureEventHandler_WaveRTEvent; + stream->capture.pPin->fnSubmitHandler = PaPinCaptureSubmitHandler_WaveRTEvent; + } + + stream->capture.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierRead : MemoryBarrierDummy; + } + else + { + PA_DEBUG(("Failed to get input buffer (WaveRT)\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get input buffer (WaveRT)"); + result = paUnanticipatedHostError; + goto error; + } + + /* Get latency */ + result = PinGetHwLatency(stream->capture.pPin, &hwFifoLatency, &dummy, &dummy); + if (result == paNoError) + { + stream->capture.pPin->hwLatency = hwFifoLatency; + + /* Add HW latency into total input latency */ + stream->streamRepresentation.streamInfo.inputLatency += ((hwFifoLatency / stream->capture.bytesPerFrame) / sampleRate); + } + else + { + PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n")); + stream->capture.pPin->hwLatency = 0; + } + } + break; + default: + /* Undefined wave type!! */ + assert(0); + result = paInternalError; + PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType); + goto error; + } + } + else + { + stream->capture.hostBuffer = 0; + } + + if (stream->userOutputChannels > 0) + { + stream->streamRepresentation.streamInfo.outputLatency = stream->render.framesPerBuffer / sampleRate; + + switch (stream->render.pPin->parentFilter->devInfo.streamingType) + { + case Type_kWaveCyclic: + { + unsigned size = stream->render.noOfPackets * stream->render.framesPerBuffer * stream->render.bytesPerFrame; + /* Allocate output device buffer */ + stream->render.hostBuffer = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, size); + PA_DEBUG(("Output buffer allocated (size = %u)\n", size)); + if( !stream->render.hostBuffer ) + { + PA_DEBUG(("Cannot allocate host output buffer!\n")); + PaWinWDM_SetLastErrorInfo(paInsufficientMemory, "Failed to allocate output buffer"); + result = paInsufficientMemory; + goto error; + } + stream->render.hostBufferSize = size; + PA_DEBUG(("Output buffer start = %p (size=%u)\n",stream->render.hostBuffer, stream->render.hostBufferSize)); + + stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveCyclic; + stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveCyclic; + } + break; + case Type_kWaveRT: + { + const DWORD dwTotalSize = 2 * stream->render.framesPerBuffer * stream->render.bytesPerFrame; + DWORD dwRequestedSize = dwTotalSize; + BOOL bCallMemoryBarrier = FALSE; + ULONG hwFifoLatency = 0; + ULONG dummy; + result = PinGetBuffer(stream->render.pPin, (void**)&stream->render.hostBuffer, &dwRequestedSize, &bCallMemoryBarrier); + if (!result) + { + PA_DEBUG(("Output buffer start = %p, size = %u, membarrier = %u\n", stream->render.hostBuffer, dwRequestedSize, bCallMemoryBarrier)); + if (dwRequestedSize != dwTotalSize) + { + PA_DEBUG(("Buffer length changed by driver from %u to %u !\n", dwTotalSize, dwRequestedSize)); + /* Recalculate to what the driver has given us */ + stream->render.framesPerBuffer = dwRequestedSize / (2 * stream->render.bytesPerFrame); + } + stream->render.hostBufferSize = dwRequestedSize; + + if (stream->render.pPin->pinKsSubType == SubType_kPolled) + { + stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTPolled; + stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTPolled; + } + else + { + stream->render.pPin->fnEventHandler = PaPinRenderEventHandler_WaveRTEvent; + stream->render.pPin->fnSubmitHandler = PaPinRenderSubmitHandler_WaveRTEvent; + } + + stream->render.pPin->fnMemBarrier = bCallMemoryBarrier ? MemoryBarrierWrite : MemoryBarrierDummy; + } + else + { + PA_DEBUG(("Failed to get output buffer (with notification)\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to get output buffer (with notification)"); + result = paUnanticipatedHostError; + goto error; + } + + /* Get latency */ + result = PinGetHwLatency(stream->render.pPin, &hwFifoLatency, &dummy, &dummy); + if (result == paNoError) + { + stream->render.pPin->hwLatency = hwFifoLatency; + + /* Add HW latency into total output latency */ + stream->streamRepresentation.streamInfo.outputLatency += ((hwFifoLatency / stream->render.bytesPerFrame) / sampleRate); + } + else + { + PA_DEBUG(("Failed to get size of FIFO hardware buffer (is set to zero)\n")); + stream->render.pPin->hwLatency = 0; + } + } + break; + default: + /* Undefined wave type!! */ + assert(0); + result = paInternalError; + PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType); + goto error; + } + } + else + { + stream->render.hostBuffer = 0; + } - stream->streamRepresentation.streamInfo.inputLatency = - ((double)stream->framesPerHostIBuffer) / sampleRate; - stream->streamRepresentation.streamInfo.outputLatency = - ((double)stream->framesPerHostOBuffer) / sampleRate; stream->streamRepresentation.streamInfo.sampleRate = sampleRate; - PA_DEBUG(("BytesPerInputFrame = %d\n",stream->bytesPerInputFrame)); - PA_DEBUG(("BytesPerOutputFrame = %d\n",stream->bytesPerOutputFrame)); + PA_DEBUG(("BytesPerInputFrame = %d\n",stream->capture.bytesPerFrame)); + PA_DEBUG(("BytesPerOutputFrame = %d\n",stream->render.bytesPerFrame)); - /* Allocate all the buffers for host I/O */ - size = 2 * (stream->framesPerHostIBuffer*stream->bytesPerInputFrame + stream->framesPerHostOBuffer*stream->bytesPerOutputFrame); - PA_DEBUG(("Buffer size = %d\n",size)); - stream->hostBuffer = (char*)PaUtil_AllocateMemory(size); - PA_DEBUG(("Buffer allocated\n")); - if( !stream->hostBuffer ) + /* memset(stream->hostBuffer,0,size); */ + + /* Abort */ + stream->eventAbort = CreateEvent(NULL, TRUE, FALSE, NULL); + if (stream->eventAbort == 0) + { + result = paInsufficientMemory; + goto error; + } + stream->eventStreamStart[0] = CreateEvent(NULL, TRUE, FALSE, NULL); + if (stream->eventStreamStart[0] == 0) + { + result = paInsufficientMemory; + goto error; + } + stream->eventStreamStart[1] = CreateEvent(NULL, TRUE, FALSE, NULL); + if (stream->eventStreamStart[1] == 0) { - PA_DEBUG(("Cannot allocate host buffer!\n")); result = paInsufficientMemory; goto error; } - PA_DEBUG(("Buffer start = %p\n",stream->hostBuffer)); - /* memset(stream->hostBuffer,0,size); */ - /* Set up the packets */ - stream->events[0] = CreateEvent(NULL, FALSE, FALSE, NULL); - ResetEvent(stream->events[0]); /* Record buffer 1 */ - stream->events[1] = CreateEvent(NULL, FALSE, FALSE, NULL); - ResetEvent(stream->events[1]); /* Record buffer 2 */ - stream->events[2] = CreateEvent(NULL, FALSE, FALSE, NULL); - ResetEvent(stream->events[2]); /* Play buffer 1 */ - stream->events[3] = CreateEvent(NULL, FALSE, FALSE, NULL); - ResetEvent(stream->events[3]); /* Play buffer 2 */ - stream->events[4] = CreateEvent(NULL, FALSE, FALSE, NULL); - ResetEvent(stream->events[4]); /* Abort event */ if(stream->userInputChannels > 0) { - DATAPACKET *p = &(stream->packets[0]); - p->Signal.hEvent = stream->events[0]; - p->Header.Data = stream->hostBuffer; - p->Header.FrameExtent = stream->framesPerHostIBuffer*stream->bytesPerInputFrame; - p->Header.DataUsed = 0; - p->Header.Size = sizeof(p->Header); - p->Header.PresentationTime.Numerator = 1; - p->Header.PresentationTime.Denominator = 1; + const unsigned bufferSizeInBytes = stream->capture.framesPerBuffer * stream->capture.bytesPerFrame; + const unsigned ringBufferFrameSize = NextPowerOf2( 1024 + 2 * max(stream->capture.framesPerBuffer, stream->render.framesPerBuffer) ); - p = &(stream->packets[1]); - p->Signal.hEvent = stream->events[1]; - p->Header.Data = stream->hostBuffer + stream->framesPerHostIBuffer*stream->bytesPerInputFrame; - p->Header.FrameExtent = stream->framesPerHostIBuffer*stream->bytesPerInputFrame; - p->Header.DataUsed = 0; - p->Header.Size = sizeof(p->Header); - p->Header.PresentationTime.Numerator = 1; - p->Header.PresentationTime.Denominator = 1; + stream->capture.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(HANDLE)); + if (stream->capture.events == NULL) + { + result = paInsufficientMemory; + goto error; + } + + stream->capture.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->capture.noOfPackets * sizeof(DATAPACKET)); + if (stream->capture.packets == NULL) + { + result = paInsufficientMemory; + goto error; + } + + switch(stream->capture.pPin->parentFilter->devInfo.streamingType) + { + case Type_kWaveCyclic: + { + /* WaveCyclic case */ + unsigned i; + for (i = 0; i < stream->capture.noOfPackets; ++i) + { + /* Set up the packets */ + DATAPACKET *p = stream->capture.packets + i; + + /* Record event */ + stream->capture.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL); + + p->Signal.hEvent = stream->capture.events[i]; + p->Header.Data = stream->capture.hostBuffer + (i*bufferSizeInBytes); + p->Header.FrameExtent = bufferSizeInBytes; + p->Header.DataUsed = 0; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + } + } + break; + case Type_kWaveRT: + { + /* Set up the "packets" */ + DATAPACKET *p = stream->capture.packets + 0; + + /* Record event: WaveRT has a single event for 2 notification per buffer */ + stream->capture.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL); + + p->Header.Data = stream->capture.hostBuffer; + p->Header.FrameExtent = bufferSizeInBytes; + p->Header.DataUsed = 0; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + + ++p; + p->Header.Data = stream->capture.hostBuffer + bufferSizeInBytes; + p->Header.FrameExtent = bufferSizeInBytes; + p->Header.DataUsed = 0; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + + if (stream->capture.pPin->pinKsSubType == SubType_kNotification) + { + result = PinRegisterNotificationHandle(stream->capture.pPin, stream->capture.events[0]); + + if (result != paNoError) + { + PA_DEBUG(("Failed to register capture notification handle\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register capture notification handle"); + result = paUnanticipatedHostError; + goto error; + } + } + + result = PinRegisterPositionRegister(stream->capture.pPin); + + if (result != paNoError) + { + unsigned long pos = 0xdeadc0de; + PA_DEBUG(("Failed to register capture position register, using PinGetAudioPositionViaIOCTLWrite\n")); + stream->capture.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLWrite; + /* Test position function */ + result = (stream->capture.pPin->fnAudioPosition)(stream->capture.pPin, &pos); + if (result != paNoError || pos != 0x0) + { + PA_DEBUG(("Failed to read capture position register (IOCTL)\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read capture position register (IOCTL)"); + result = paUnanticipatedHostError; + goto error; + } + } + else + { + stream->capture.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped; + } + } + break; + default: + /* Undefined wave type!! */ + assert(0); + result = paInternalError; + PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType); + goto error; + } + + /* Setup the input ring buffer here */ + stream->ringBufferData = (char*)PaUtil_GroupAllocateMemory(stream->allocGroup, ringBufferFrameSize * stream->capture.bytesPerFrame); + if (stream->ringBufferData == NULL) + { + result = paInsufficientMemory; + goto error; + } + PaUtil_InitializeRingBuffer(&stream->ringBuffer, stream->capture.bytesPerFrame, ringBufferFrameSize, stream->ringBufferData); } if(stream->userOutputChannels > 0) { - DATAPACKET *p = &(stream->packets[2]); - p->Signal.hEvent = stream->events[2]; - p->Header.Data = stream->hostBuffer + 2*stream->framesPerHostIBuffer*stream->bytesPerInputFrame; - p->Header.FrameExtent = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame; - p->Header.DataUsed = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame; - p->Header.Size = sizeof(p->Header); - p->Header.PresentationTime.Numerator = 1; - p->Header.PresentationTime.Denominator = 1; - - p = &(stream->packets[3]); - p->Signal.hEvent = stream->events[3]; - p->Header.Data = stream->hostBuffer + 2*stream->framesPerHostIBuffer*stream->bytesPerInputFrame + stream->framesPerHostOBuffer*stream->bytesPerOutputFrame; - p->Header.FrameExtent = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame; - p->Header.DataUsed = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame; - p->Header.Size = sizeof(p->Header); - p->Header.PresentationTime.Numerator = 1; - p->Header.PresentationTime.Denominator = 1; + const unsigned bufferSizeInBytes = stream->render.framesPerBuffer * stream->render.bytesPerFrame; + + stream->render.events = (HANDLE*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(HANDLE)); + if (stream->render.events == NULL) + { + result = paInsufficientMemory; + goto error; + } + + stream->render.packets = (DATAPACKET*)PaUtil_GroupAllocateMemory(stream->allocGroup, stream->render.noOfPackets * sizeof(DATAPACKET)); + if (stream->render.packets == NULL) + { + result = paInsufficientMemory; + goto error; + } + + switch(stream->render.pPin->parentFilter->devInfo.streamingType) + { + case Type_kWaveCyclic: + { + /* WaveCyclic case */ + unsigned i; + for (i = 0; i < stream->render.noOfPackets; ++i) + { + /* Set up the packets */ + DATAPACKET *p = stream->render.packets + i; + + /* Playback event */ + stream->render.events[i] = CreateEvent(NULL, TRUE, FALSE, NULL); + + /* In this case, we just use the packets as ptr to the device buffer */ + p->Signal.hEvent = stream->render.events[i]; + p->Header.Data = stream->render.hostBuffer + (i*bufferSizeInBytes); + p->Header.FrameExtent = bufferSizeInBytes; + p->Header.DataUsed = bufferSizeInBytes; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + } + } + break; + case Type_kWaveRT: + { + /* WaveRT case */ + + /* Set up the "packets" */ + DATAPACKET *p = stream->render.packets; + + /* The only playback event */ + stream->render.events[0] = CreateEvent(NULL, FALSE, FALSE, NULL); + + /* In this case, we just use the packets as ptr to the device buffer */ + p->Header.Data = stream->render.hostBuffer; + p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame; + p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + + ++p; + p->Header.Data = stream->render.hostBuffer + stream->render.framesPerBuffer*stream->render.bytesPerFrame; + p->Header.FrameExtent = stream->render.framesPerBuffer*stream->render.bytesPerFrame; + p->Header.DataUsed = stream->render.framesPerBuffer*stream->render.bytesPerFrame; + p->Header.Size = sizeof(p->Header); + p->Header.PresentationTime.Numerator = 1; + p->Header.PresentationTime.Denominator = 1; + + if (stream->render.pPin->pinKsSubType == SubType_kNotification) + { + result = PinRegisterNotificationHandle(stream->render.pPin, stream->render.events[0]); + + if (result != paNoError) + { + PA_DEBUG(("Failed to register rendering notification handle\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to register rendering notification handle"); + result = paUnanticipatedHostError; + goto error; + } + } + + result = PinRegisterPositionRegister(stream->render.pPin); + + if (result != paNoError) + { + unsigned long pos = 0xdeadc0de; + PA_DEBUG(("Failed to register rendering position register, using PinGetAudioPositionViaIOCTLRead\n")); + stream->render.pPin->fnAudioPosition = PinGetAudioPositionViaIOCTLRead; + /* Test position function */ + result = (stream->render.pPin->fnAudioPosition)(stream->render.pPin, &pos); + if (result != paNoError || pos != 0x0) + { + PA_DEBUG(("Failed to read render position register (IOCTL)\n")); + PaWinWDM_SetLastErrorInfo(paUnanticipatedHostError, "Failed to read render position register (IOCTL)"); + result = paUnanticipatedHostError; + goto error; + } + } + else + { + stream->render.pPin->fnAudioPosition = PinGetAudioPositionMemoryMapped; + } + } + break; + default: + /* Undefined wave type!! */ + assert(0); + result = paInternalError; + PaWinWDM_SetLastErrorInfo(result, "Wave type %u ??", stream->capture.pPin->parentFilter->devInfo.streamingType); + goto error; + } } stream->streamStarted = 0; @@ -2565,45 +5252,93 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, stream->streamFlags = streamFlags; stream->oldProcessPriority = REALTIME_PRIORITY_CLASS; + /* Increase ref count on filters in use, so that a CommitDeviceInfos won't delete them */ + if (stream->capture.pPin != 0) + { + FilterAddRef(stream->capture.pPin->parentFilter); + } + if (stream->render.pPin != 0) + { + FilterAddRef(stream->render.pPin->parentFilter); + } + + /* Ok, now update our host API specific stream info */ + if (stream->userInputChannels) + { + PaWinWdmDeviceInfo *pDeviceInfo = (PaWinWdmDeviceInfo*)wdmHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device]; + + stream->hostApiStreamInfo.input.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), inputParameters->device); + stream->hostApiStreamInfo.input.channels = stream->deviceInputChannels; + stream->hostApiStreamInfo.input.muxNodeId = -1; + if (stream->capture.pPin->inputs) + { + stream->hostApiStreamInfo.input.muxNodeId = stream->capture.pPin->inputs[pDeviceInfo->muxPosition]->muxNodeId; + } + stream->hostApiStreamInfo.input.endpointPinId = pDeviceInfo->endpointPinId; + stream->hostApiStreamInfo.input.framesPerHostBuffer = stream->capture.framesPerBuffer; + stream->hostApiStreamInfo.input.streamingSubType = stream->capture.pPin->pinKsSubType; + } + else + { + stream->hostApiStreamInfo.input.device = paNoDevice; + } + if (stream->userOutputChannels) + { + stream->hostApiStreamInfo.output.device = Pa_HostApiDeviceIndexToDeviceIndex(Pa_HostApiTypeIdToHostApiIndex(paWDMKS), outputParameters->device); + stream->hostApiStreamInfo.output.channels = stream->deviceOutputChannels; + stream->hostApiStreamInfo.output.framesPerHostBuffer = stream->render.framesPerBuffer; + stream->hostApiStreamInfo.output.endpointPinId = stream->render.pPin->endpointPinId; + stream->hostApiStreamInfo.output.streamingSubType = stream->render.pPin->pinKsSubType; + } + else + { + stream->hostApiStreamInfo.output.device = paNoDevice; + } + /*stream->streamRepresentation.streamInfo.hostApiTypeId = paWDMKS; + stream->streamRepresentation.streamInfo.hostApiSpecificStreamInfo = &stream->hostApiStreamInfo;*/ + stream->streamRepresentation.streamInfo.structVersion = 2; + *s = (PaStream*)stream; PA_LOGL_; return result; +occupied: + /* Ok, someone else is hogging the pin, bail out */ + assert (result == paDeviceUnavailable); + PaWinWDM_SetLastErrorInfo(result, "Device is occupied"); + error: - size = 5; - while(size--) + PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); + + CloseStreamEvents(stream); + + if (stream->allocGroup) { - if(stream->events[size] != NULL) - { - CloseHandle(stream->events[size]); - stream->events[size] = NULL; - } + PaUtil_FreeAllAllocations(stream->allocGroup); + PaUtil_DestroyAllocationGroup(stream->allocGroup); + stream->allocGroup = 0; } - if(stream->hostBuffer) - PaUtil_FreeMemory( stream->hostBuffer ); - if(stream->playbackPin) - PinClose(stream->playbackPin); - if(stream->recordingPin) - PinClose(stream->recordingPin); + if(stream->render.pPin) + PinClose(stream->render.pPin); + if(stream->capture.pPin) + PinClose(stream->capture.pPin); - if( stream ) - PaUtil_FreeMemory( stream ); + PaUtil_FreeMemory( stream ); PA_LOGL_; return result; } /* - When CloseStream() is called, the multi-api layer ensures that - the stream has already been stopped or aborted. +When CloseStream() is called, the multi-api layer ensures that +the stream has already been stopped or aborted. */ static PaError CloseStream( PaStream* s ) { PaError result = paNoError; PaWinWdmStream *stream = (PaWinWdmStream*)s; - int size; PA_LOGE_; @@ -2612,22 +5347,33 @@ static PaError CloseStream( PaStream* s ) PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); - size = 5; - while(size--) - { - if(stream->events[size] != NULL) - { - CloseHandle(stream->events[size]); - stream->events[size] = NULL; - } - } - if(stream->hostBuffer) - PaUtil_FreeMemory( stream->hostBuffer ); - if(stream->playbackPin) - PinClose(stream->playbackPin); - if(stream->recordingPin) - PinClose(stream->recordingPin); + CloseStreamEvents(stream); + + if (stream->allocGroup) + { + PaUtil_FreeAllAllocations(stream->allocGroup); + PaUtil_DestroyAllocationGroup(stream->allocGroup); + stream->allocGroup = 0; + } + + if(stream->render.pPin) + { + PinClose(stream->render.pPin); + } + if(stream->capture.pPin) + { + PinClose(stream->capture.pPin); + } + + if (stream->render.pPin) + { + FilterFree(stream->render.pPin->parentFilter); + } + if (stream->capture.pPin) + { + FilterFree(stream->capture.pPin->parentFilter); + } PaUtil_FreeMemory( stream ); @@ -2638,25 +5384,57 @@ static PaError CloseStream( PaStream* s ) /* Write the supplied packet to the pin Asynchronous -Should return false on success +Should return paNoError on success */ -static BOOL PinWrite(HANDLE h, DATAPACKET* p) +static PaError PinWrite(HANDLE h, DATAPACKET* p) { + PaError result = paNoError; unsigned long cbReturned = 0; - return DeviceIoControl(h,IOCTL_KS_WRITE_STREAM,NULL,0, - &p->Header,p->Header.Size,&cbReturned,&p->Signal); + BOOL fRes = DeviceIoControl(h, + IOCTL_KS_WRITE_STREAM, + NULL, + 0, + &p->Header, + p->Header.Size, + &cbReturned, + &p->Signal); + if (!fRes) + { + unsigned long error = GetLastError(); + if (error != ERROR_IO_PENDING) + { + result = paInternalError; + } + } + return result; } /* Read to the supplied packet from the pin Asynchronous -Should return false on success +Should return paNoError on success */ -static BOOL PinRead(HANDLE h, DATAPACKET* p) +static PaError PinRead(HANDLE h, DATAPACKET* p) { + PaError result = paNoError; unsigned long cbReturned = 0; - return DeviceIoControl(h,IOCTL_KS_READ_STREAM,NULL,0, - &p->Header,p->Header.Size,&cbReturned,&p->Signal); + BOOL fRes = DeviceIoControl(h, + IOCTL_KS_READ_STREAM, + NULL, + 0, + &p->Header, + p->Header.Size, + &cbReturned, + &p->Signal); + if (!fRes) + { + unsigned long error = GetLastError(); + if (error != ERROR_IO_PENDING) + { + result = paInternalError; + } + } + return result; } /* @@ -2722,365 +5500,767 @@ static void DuplicateFirstChannelInt32(void* buffer, int channels, int samples) } } -static DWORD WINAPI ProcessingThread(LPVOID pParam) +/* +Increase the priority of the calling thread to RT +*/ +static HANDLE BumpThreadPriority() +{ + HANDLE hThread = GetCurrentThread(); + DWORD dwTask = 0; + HANDLE hAVRT = NULL; + + /* If we have access to AVRT.DLL (Vista and later), use it */ + if (paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics != NULL) + { + hAVRT = paWinWDMKSAvRtEntryPoints.AvSetMmThreadCharacteristics("Pro Audio", &dwTask); + if (hAVRT != NULL && hAVRT != INVALID_HANDLE_VALUE) + { + BOOL bret = paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_CRITICAL); + if (!bret) + { + PA_DEBUG(("Set mm thread prio to critical failed!\n")); + } + else + { + return hAVRT; + } + } + else + { + PA_DEBUG(("Set mm thread characteristic to 'Pro Audio' failed, reverting to SetThreadPriority\n")); + } + } + + /* For XP and earlier, or if AvSetMmThreadCharacteristics fails (MMCSS disabled ?) */ + if (timeBeginPeriod(1) != TIMERR_NOERROR) { + PA_DEBUG(("timeBeginPeriod(1) failed!\n")); + } + + if (!SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL)) { + PA_DEBUG(("SetThreadPriority failed!\n")); + } + + return hAVRT; +} + +/* +Decrease the priority of the calling thread to normal +*/ +static void DropThreadPriority(HANDLE hAVRT) +{ + HANDLE hThread = GetCurrentThread(); + + if (hAVRT != NULL) + { + paWinWDMKSAvRtEntryPoints.AvSetMmThreadPriority(hAVRT, PA_AVRT_PRIORITY_NORMAL); + paWinWDMKSAvRtEntryPoints.AvRevertMmThreadCharacteristics(hAVRT); + return; + } + + SetThreadPriority(hThread, THREAD_PRIORITY_NORMAL); + timeEndPeriod(1); +} + +static PaError PreparePinForStart(PaWinWdmPin* pin) { - PaWinWdmStream *stream = (PaWinWdmStream*)pParam; - PaStreamCallbackTimeInfo ti; - int cbResult = paContinue; - int inbuf = 0; - int outbuf = 0; - int pending = 0; PaError result; - unsigned long wait; - unsigned long eventSignaled; - int fillPlaybuf = 0; - int emptyRecordbuf = 0; - int framesProcessed; - unsigned long timeout; - int i; - int doChannelCopy; - int priming = 0; - PaStreamCallbackFlags underover = 0; + result = PinSetState(pin, KSSTATE_ACQUIRE); + if (result != paNoError) + { + goto error; + } + result = PinSetState(pin, KSSTATE_PAUSE); + if (result != paNoError) + { + goto error; + } + return result; + +error: + PinSetState(pin, KSSTATE_STOP); + return result; +} + +static PaError PreparePinsForStart(PaProcessThreadInfo* pInfo) +{ + PaError result = paNoError; + /* Submit buffers */ + if (pInfo->stream->capture.pPin) + { + if ((result = PreparePinForStart(pInfo->stream->capture.pPin)) != paNoError) + { + goto error; + } + + if (pInfo->stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) + { + unsigned i; + for(i=0; i < pInfo->stream->capture.noOfPackets; ++i) + { + if ((result = PinRead(pInfo->stream->capture.pPin->handle, pInfo->stream->capture.packets + i)) != paNoError) + { + goto error; + } + ++pInfo->pending; + } + } + else + { + pInfo->pending = 2; + } + } + + if(pInfo->stream->render.pPin) + { + if ((result = PreparePinForStart(pInfo->stream->render.pPin)) != paNoError) + { + goto error; + } + + pInfo->priming += pInfo->stream->render.noOfPackets; + ++pInfo->pending; + SetEvent(pInfo->stream->render.events[0]); + if (pInfo->stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) + { + unsigned i; + for(i=1; i < pInfo->stream->render.noOfPackets; ++i) + { + SetEvent(pInfo->stream->render.events[i]); + ++pInfo->pending; + } + } + } + +error: + PA_DEBUG(("PreparePinsForStart = %d\n", result)); + return result; +} + +static PaError StartPin(PaWinWdmPin* pin) +{ + return PinSetState(pin, KSSTATE_RUN); +} + +static PaError StartPins(PaProcessThreadInfo* pInfo) +{ + PaError result = paNoError; + /* Start the pins as synced as possible */ + if (pInfo->stream->capture.pPin) + { + result = StartPin(pInfo->stream->capture.pPin); + } + if(pInfo->stream->render.pPin) + { + result = StartPin(pInfo->stream->render.pPin); + } + PA_DEBUG(("StartPins = %d\n", result)); + return result; +} + + +static PaError StopPin(PaWinWdmPin* pin) +{ + PinSetState(pin, KSSTATE_PAUSE); + PinSetState(pin, KSSTATE_STOP); + return paNoError; +} + + +static PaError StopPins(PaProcessThreadInfo* pInfo) +{ + PaError result = paNoError; + if(pInfo->stream->render.pPin) + { + StopPin(pInfo->stream->render.pPin); + } + if(pInfo->stream->capture.pPin) + { + StopPin(pInfo->stream->capture.pPin); + } + return result; +} + +typedef void (*TSetInputFrameCount)(PaUtilBufferProcessor*, unsigned long); +typedef void (*TSetInputChannel)(PaUtilBufferProcessor*, unsigned int, void *, unsigned int); +static const TSetInputFrameCount fnSetInputFrameCount[2] = { PaUtil_SetInputFrameCount, PaUtil_Set2ndInputFrameCount }; +static const TSetInputChannel fnSetInputChannel[2] = { PaUtil_SetInputChannel, PaUtil_Set2ndInputChannel }; + +static PaError PaDoProcessing(PaProcessThreadInfo* pInfo) +{ + PaError result = paNoError; + int i, framesProcessed = 0, doChannelCopy = 0; + ring_buffer_size_t inputFramesAvailable = PaUtil_GetRingBufferReadAvailable(&pInfo->stream->ringBuffer); + + /* Do necessary buffer processing (which will invoke user callback if necessary) */ + if (pInfo->cbResult == paContinue && + (pInfo->renderHead != pInfo->renderTail || inputFramesAvailable)) + { + unsigned processFullDuplex = pInfo->stream->capture.pPin && pInfo->stream->render.pPin && (!pInfo->priming); + + PA_HP_TRACE((pInfo->stream->hLog, "DoProcessing: InputFrames=%u", inputFramesAvailable)); + + PaUtil_BeginCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer ); + + pInfo->ti.currentTime = PaUtil_GetTime(); + + PaUtil_BeginBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->ti, pInfo->underover); + pInfo->underover = 0; /* Reset the (under|over)flow status */ + + if (pInfo->renderTail != pInfo->renderHead) + { + DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet; + + assert(packet != 0); + assert(packet->Header.Data != 0); + + PaUtil_SetOutputFrameCount(&pInfo->stream->bufferProcessor, pInfo->stream->render.framesPerBuffer); + + for(i=0;istream->userOutputChannels;i++) + { + /* Only write the user output channels. Leave the rest blank */ + PaUtil_SetOutputChannel(&pInfo->stream->bufferProcessor, + i, + ((unsigned char*)(packet->Header.Data))+(i*pInfo->stream->render.bytesPerSample), + pInfo->stream->deviceOutputChannels); + } + + /* We will do a copy to the other channels after the data has been written */ + doChannelCopy = ( pInfo->stream->userOutputChannels == 1 ); + } + + if (inputFramesAvailable && (!pInfo->stream->userOutputChannels || inputFramesAvailable >= (int)pInfo->stream->render.framesPerBuffer)) + { + unsigned wrapCntr = 0; + void* data[2] = {0}; + ring_buffer_size_t size[2] = {0}; + + /* If full-duplex, we just extract output buffer number of frames */ + if (pInfo->stream->userOutputChannels) + { + inputFramesAvailable = min(inputFramesAvailable, (int)pInfo->stream->render.framesPerBuffer); + } + + inputFramesAvailable = PaUtil_GetRingBufferReadRegions(&pInfo->stream->ringBuffer, + inputFramesAvailable, + &data[0], + &size[0], + &data[1], + &size[1]); + + for (wrapCntr = 0; wrapCntr < 2; ++wrapCntr) + { + if (size[wrapCntr] == 0) + break; + + fnSetInputFrameCount[wrapCntr](&pInfo->stream->bufferProcessor, size[wrapCntr]); + for(i=0;istream->userInputChannels;i++) + { + /* Only read as many channels as the user wants */ + fnSetInputChannel[wrapCntr](&pInfo->stream->bufferProcessor, + i, + ((unsigned char*)(data[wrapCntr]))+(i*pInfo->stream->capture.bytesPerSample), + pInfo->stream->deviceInputChannels); + } + } + } + else + { + /* We haven't consumed anything from the ring buffer... */ + inputFramesAvailable = 0; + /* If we have full-duplex, this is at startup, so mark no-input! */ + if (pInfo->stream->userOutputChannels>0 && pInfo->stream->userInputChannels>0) + { + PA_HP_TRACE((pInfo->stream->hLog, "Input startup, marking no input.")); + PaUtil_SetNoInput(&pInfo->stream->bufferProcessor); + } + } + + if (processFullDuplex) /* full duplex */ + { + /* Only call the EndBufferProcessing function when the total input frames == total output frames */ + const unsigned long totalInputFrameCount = pInfo->stream->bufferProcessor.hostInputFrameCount[0] + pInfo->stream->bufferProcessor.hostInputFrameCount[1]; + const unsigned long totalOutputFrameCount = pInfo->stream->bufferProcessor.hostOutputFrameCount[0] + pInfo->stream->bufferProcessor.hostOutputFrameCount[1]; + + if(totalInputFrameCount == totalOutputFrameCount && totalOutputFrameCount != 0) + { + framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult); + } + else + { + framesProcessed = 0; + } + } + else + { + framesProcessed = PaUtil_EndBufferProcessing(&pInfo->stream->bufferProcessor, &pInfo->cbResult); + } + + PA_HP_TRACE((pInfo->stream->hLog, "Frames processed: %u %s", framesProcessed, (pInfo->priming ? "(priming)":""))); + + if( doChannelCopy ) + { + DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet; + /* Copy the first output channel to the other channels */ + switch (pInfo->stream->render.bytesPerSample) + { + case 2: + DuplicateFirstChannelInt16(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer); + break; + case 3: + DuplicateFirstChannelInt24(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer); + break; + case 4: + DuplicateFirstChannelInt32(packet->Header.Data, pInfo->stream->deviceOutputChannels, pInfo->stream->render.framesPerBuffer); + break; + default: + assert(0); /* Unsupported format! */ + break; + } + } + PaUtil_EndCpuLoadMeasurement( &pInfo->stream->cpuLoadMeasurer, framesProcessed ); + + if (inputFramesAvailable) + { + PaUtil_AdvanceRingBufferReadIndex(&pInfo->stream->ringBuffer, inputFramesAvailable); + } + + if (pInfo->renderTail != pInfo->renderHead) + { + if (!pInfo->stream->streamStop) + { + result = pInfo->stream->render.pPin->fnSubmitHandler(pInfo, pInfo->renderTail); + if (result != paNoError) + { + PA_HP_TRACE((pInfo->stream->hLog, "Capture submit handler failed with result %d", result)); + return result; + } + } + pInfo->renderTail++; + if (!pInfo->pinsStarted && pInfo->priming == 0) + { + /* We start the pins here to allow "prime time" */ + if ((result = StartPins(pInfo)) == paNoError) + { + PA_HP_TRACE((pInfo->stream->hLog, "Starting pins!")); + pInfo->pinsStarted = 1; + } + } + } + } + + return result; +} + +static VOID CALLBACK TimerAPCWaveRTPolledMode( + LPVOID lpArgToCompletionRoutine, + DWORD dwTimerLowValue, + DWORD dwTimerHighValue) +{ + HANDLE* pHandles = (HANDLE*)lpArgToCompletionRoutine; + if (pHandles[0]) SetEvent(pHandles[0]); + if (pHandles[1]) SetEvent(pHandles[1]); +} + +static DWORD GetCurrentTimeInMillisecs() +{ + return timeGetTime(); +} + +PA_THREAD_FUNC ProcessingThread(void* pParam) +{ + PaError result = paNoError; + HANDLE hAVRT = NULL; + HANDLE hTimer = NULL; + HANDLE *handleArray = NULL; + HANDLE timerEventHandles[2] = {0}; + unsigned noOfHandles = 0; + unsigned captureEvents = 0; + unsigned renderEvents = 0; + unsigned timerPeriod = 0; + DWORD timeStamp[2] = {0}; + + PaProcessThreadInfo info; + memset(&info, 0, sizeof(PaProcessThreadInfo)); + info.stream = (PaWinWdmStream*)pParam; + + info.stream->threadResult = paNoError; PA_LOGE_; - ti.inputBufferAdcTime = 0.0; - ti.currentTime = 0.0; - ti.outputBufferDacTime = 0.0; + info.ti.inputBufferAdcTime = 0.0; + info.ti.currentTime = 0.0; + info.ti.outputBufferDacTime = 0.0; - /* Get double buffering going */ + PA_DEBUG(("In buffer len: %.3f ms\n",(2000*info.stream->capture.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate)); + PA_DEBUG(("Out buffer len: %.3f ms\n",(2000*info.stream->render.framesPerBuffer) / info.stream->streamRepresentation.streamInfo.sampleRate)); + info.timeout = (DWORD)max( + (2000*info.stream->render.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5), + (2000*info.stream->capture.framesPerBuffer/info.stream->streamRepresentation.streamInfo.sampleRate + 0.5)); + info.timeout = max(info.timeout*8, 100); + timerPeriod = info.timeout; + PA_DEBUG(("Timeout = %ld ms\n",info.timeout)); - /* Submit buffers */ - if(stream->playbackPin) + /* Allocate handle array */ + handleArray = (HANDLE*)PaUtil_AllocateMemory((info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1) * sizeof(HANDLE)); + + /* Setup handle array for WFMO */ + if (info.stream->capture.pPin != 0) { - result = PinSetState(stream->playbackPin, KSSTATE_RUN); - - PA_DEBUG(("play state run = %d;",(int)result)); - SetEvent(stream->events[outbuf+2]); - outbuf = (outbuf+1)&1; - SetEvent(stream->events[outbuf+2]); - outbuf = (outbuf+1)&1; - pending += 2; - priming += 4; - } - if(stream->recordingPin) - { - result = PinSetState(stream->recordingPin, KSSTATE_RUN); - - PA_DEBUG(("recording state run = %d;",(int)result)); - PinRead(stream->recordingPin->handle,&stream->packets[inbuf]); - inbuf = (inbuf+1)&1; /* Increment and wrap */ - PinRead(stream->recordingPin->handle,&stream->packets[inbuf]); - inbuf = (inbuf+1)&1; /* Increment and wrap */ - /* FIXME - do error checking */ - pending += 2; - } - PA_DEBUG(("Out buffer len:%f\n",(2000*stream->framesPerHostOBuffer) / stream->streamRepresentation.streamInfo.sampleRate)); - PA_DEBUG(("In buffer len:%f\n",(2000*stream->framesPerHostIBuffer) / stream->streamRepresentation.streamInfo.sampleRate)); - timeout = max( - ((2000*(DWORD)stream->framesPerHostOBuffer) / (DWORD)stream->streamRepresentation.streamInfo.sampleRate), - ((2000*(DWORD)stream->framesPerHostIBuffer) / (DWORD)stream->streamRepresentation.streamInfo.sampleRate)); - timeout = max(timeout,1); - PA_DEBUG(("Timeout = %ld\n",timeout)); - - while(!stream->streamAbort) - { - fillPlaybuf = 0; - emptyRecordbuf = 0; - - /* Wait for next input or output buffer to be finished with*/ - assert(pending>0); - - if(stream->streamStop) + handleArray[noOfHandles++] = info.stream->capture.events[0]; + if (info.stream->capture.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) { - PA_DEBUG(("ss1:pending=%d ",pending)); + unsigned i; + for(i=1; i < info.stream->capture.noOfPackets; ++i) + { + handleArray[noOfHandles++] = info.stream->capture.events[i]; + } } - wait = WaitForMultipleObjects(5, stream->events, FALSE, 0); - if( wait == WAIT_TIMEOUT ) + captureEvents = noOfHandles; + renderEvents = noOfHandles; + } + + if (info.stream->render.pPin != 0) + { + handleArray[noOfHandles++] = info.stream->render.events[0]; + if (info.stream->render.pPin->parentFilter->devInfo.streamingType == Type_kWaveCyclic) { - /* No (under|over)flow has ocurred */ - wait = WaitForMultipleObjects(5, stream->events, FALSE, timeout); - eventSignaled = wait - WAIT_OBJECT_0; + unsigned i; + for(i=1; i < info.stream->render.noOfPackets; ++i) + { + handleArray[noOfHandles++] = info.stream->render.events[i]; + } + } + renderEvents = noOfHandles; + } + handleArray[noOfHandles++] = info.stream->eventAbort; + assert(noOfHandles <= (info.stream->capture.noOfPackets + info.stream->render.noOfPackets + 1)); + + /* Prepare render and capture pins */ + if ((result = PreparePinsForStart(&info)) != paNoError) + { + PA_DEBUG(("Failed to prepare device(s)!\n")); + goto error; + } + + /* Init high speed logger */ + if (PaUtil_InitializeHighSpeedLog(&info.stream->hLog, 1000000) != paNoError) + { + PA_DEBUG(("Failed to init high speed logger!\n")); + goto error; + } + + /* Heighten priority here */ + hAVRT = BumpThreadPriority(); + + /* If input only, we start the pins immediately */ + if (info.stream->render.pPin == 0) + { + if ((result = StartPins(&info)) != paNoError) + { + PA_DEBUG(("Failed to start device(s)!\n")); + goto error; + } + info.pinsStarted = 1; + } + + /* Handle WaveRT polled mode */ + { + const unsigned fs = (unsigned)info.stream->streamRepresentation.streamInfo.sampleRate; + if (info.stream->capture.pPin != 0 && info.stream->capture.pPin->pinKsSubType == SubType_kPolled) + { + timerEventHandles[0] = info.stream->capture.events[0]; + timerPeriod = min(timerPeriod, (1000*info.stream->capture.framesPerBuffer)/fs); + } + + if (info.stream->render.pPin != 0 && info.stream->render.pPin->pinKsSubType == SubType_kPolled) + { + timerEventHandles[1] = info.stream->render.events[0]; + timerPeriod = min(timerPeriod, (1000*info.stream->render.framesPerBuffer)/fs); + } + + if (timerEventHandles[0] || timerEventHandles[1]) + { + LARGE_INTEGER dueTime = {0}; + + timerPeriod=max(timerPeriod/5,1); + PA_DEBUG(("Timer event handles=0x%04X,0x%04X period=%u ms", timerEventHandles[0], timerEventHandles[1], timerPeriod)); + hTimer = CreateWaitableTimer(0, FALSE, NULL); + if (hTimer == NULL) + { + result = paUnanticipatedHostError; + goto error; + } + /* invoke first timeout immediately */ + if (!SetWaitableTimer(hTimer, &dueTime, timerPeriod, TimerAPCWaveRTPolledMode, timerEventHandles, FALSE)) + { + result = paUnanticipatedHostError; + goto error; + } + PA_DEBUG(("Waitable timer started, period = %u ms\n", timerPeriod)); + } + } + + /* Mark stream as active */ + info.stream->streamActive = 1; + info.stream->threadResult = paNoError; + + /* Up and running... */ + SetEvent(info.stream->eventStreamStart[StreamStart_kOk]); + + /* Take timestamp here */ + timeStamp[0] = timeStamp[1] = GetCurrentTimeInMillisecs(); + + while(!info.stream->streamAbort) + { + unsigned doProcessing = 1; + unsigned wait = WaitForMultipleObjects(noOfHandles, handleArray, FALSE, 0); + unsigned eventSignalled = wait - WAIT_OBJECT_0; + DWORD dwCurrentTime = 0; + + if (wait == WAIT_FAILED) + { + PA_DEBUG(("Wait failed = %ld! \n",wait)); + break; + } + if (wait == WAIT_TIMEOUT) + { + wait = WaitForMultipleObjectsEx(noOfHandles, handleArray, FALSE, 50, TRUE); + eventSignalled = wait - WAIT_OBJECT_0; } else { - eventSignaled = wait - WAIT_OBJECT_0; - if( eventSignaled < 2 ) + if (eventSignalled < captureEvents) { - underover |= paInputOverflow; - PA_DEBUG(("Input overflow\n")); + if (PaUtil_GetRingBufferWriteAvailable(&info.stream->ringBuffer) == 0) + { + PA_HP_TRACE((info.stream->hLog, "!!!!! Input overflow !!!!!")); + info.underover |= paInputOverflow; + } } - else if(( eventSignaled < 4 )&&(!priming)) + else if (eventSignalled < renderEvents) { - underover |= paOutputUnderflow; - PA_DEBUG(("Output underflow\n")); + if (!info.priming && info.renderHead - info.renderTail > 1) + { + PA_HP_TRACE((info.stream->hLog, "!!!!! Output underflow !!!!!")); + info.underover |= paOutputUnderflow; + } } } - if(stream->streamStop) + /* Get event time */ + dwCurrentTime = GetCurrentTimeInMillisecs(); + + /* Since we can mix capture/render devices between WaveCyclic, WaveRT polled and WaveRT notification (3x3 combinations), + we can't rely on the timeout of WFMO to check for device timeouts, we need to keep tally. */ + if (info.stream->capture.pPin && (dwCurrentTime - timeStamp[0]) >= info.timeout) { - PA_DEBUG(("ss2:wait=%ld",wait)); - } - if(wait == WAIT_FAILED) - { - PA_DEBUG(("Wait fail = %ld! ",wait)); + PA_DEBUG(("Timeout for capture device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[0]))); + result = paTimedOut; break; } - if(wait == WAIT_TIMEOUT) + if (info.stream->render.pPin && (dwCurrentTime - timeStamp[1]) >= info.timeout) { + PA_DEBUG(("Timeout for render device (%u ms)!", info.timeout, (dwCurrentTime - timeStamp[1]))); + result = paTimedOut; + break; + } + + if (wait == WAIT_IO_COMPLETION) + { + /* Waitable timer has fired! */ + PA_HP_TRACE((info.stream->hLog, "WAIT_IO_COMPLETION")); continue; } - if(eventSignaled < 2) - { /* Recording input buffer has been filled */ - if(stream->playbackPin) - { - /* First check if also the next playback buffer has been signaled */ - wait = WaitForSingleObject(stream->events[outbuf+2],0); - if(wait == WAIT_OBJECT_0) - { - /* Yes, so do both buffers at same time */ - fillPlaybuf = 1; - pending--; - /* Was this an underflow situation? */ - if( underover ) - underover |= paOutputUnderflow; /* Yes! */ - } - } - emptyRecordbuf = 1; - pending--; - } - else if(eventSignaled < 4) - { /* Playback output buffer has been emptied */ - if(stream->recordingPin) - { - /* First check if also the next recording buffer has been signaled */ - wait = WaitForSingleObject(stream->events[inbuf],0); - if(wait == WAIT_OBJECT_0) - { /* Yes, so do both buffers at same time */ - emptyRecordbuf = 1; - pending--; - /* Was this an overflow situation? */ - if( underover ) - underover |= paInputOverflow; /* Yes! */ - } - } - fillPlaybuf = 1; - pending--; + if (wait == WAIT_TIMEOUT) + { + continue; } else { - /* Abort event! */ - assert(stream->streamAbort); /* Should have been set */ - PA_DEBUG(("ABORTING ")); - break; - } - ResetEvent(stream->events[eventSignaled]); - - if(stream->streamStop) - { - PA_DEBUG(("Stream stop! pending=%d",pending)); - cbResult = paComplete; /* Stop, but play remaining buffers */ - } - - /* Do necessary buffer processing (which will invoke user callback if necessary */ - doChannelCopy = 0; - if(cbResult==paContinue) - { - PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); - if((stream->bufferProcessor.hostInputFrameCount[0] + stream->bufferProcessor.hostInputFrameCount[1]) == - (stream->bufferProcessor.hostOutputFrameCount[0] + stream->bufferProcessor.hostOutputFrameCount[1]) ) - PaUtil_BeginBufferProcessing(&stream->bufferProcessor,&ti,underover); - underover = 0; /* Reset the (under|over)flow status */ - if(fillPlaybuf) + if (eventSignalled < captureEvents) { - PaUtil_SetOutputFrameCount(&stream->bufferProcessor,0); - if( stream->userOutputChannels == 1 ) + if (info.stream->capture.pPin->fnEventHandler(&info, eventSignalled) == paNoError) { - /* Write the single user channel to the first interleaved block */ - PaUtil_SetOutputChannel(&stream->bufferProcessor,0,stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels); - /* We will do a copy to the other channels after the data has been written */ - doChannelCopy = 1; - } - else - { - for(i=0;iuserOutputChannels;i++) + timeStamp[0] = dwCurrentTime; + + /* Since we use the ring buffer, we can submit the buffers directly */ + if (!info.stream->streamStop) { - /* Only write the user output channels. Leave the rest blank */ - PaUtil_SetOutputChannel(&stream->bufferProcessor,i,((unsigned char*)(stream->packets[outbuf+2].Header.Data))+(i*stream->outputSampleSize),stream->deviceOutputChannels); + result = info.stream->capture.pPin->fnSubmitHandler(&info, info.captureTail); + if (result != paNoError) + { + PA_HP_TRACE((info.stream->hLog, "Capture submit handler failed with result %d", result)); + break; + } + } + ++info.captureTail; + /* If full-duplex, let _only_ render event trigger processing. We still need the stream stop + handling working, so let that be processed anyways... */ + if (info.stream->userOutputChannels > 0) + { + doProcessing = 0; } } } - if(emptyRecordbuf) + else if (eventSignalled < renderEvents) { - PaUtil_SetInputFrameCount(&stream->bufferProcessor,stream->packets[inbuf].Header.DataUsed/stream->bytesPerInputFrame); - for(i=0;iuserInputChannels;i++) - { - /* Only read as many channels as the user wants */ - PaUtil_SetInputChannel(&stream->bufferProcessor,i,((unsigned char*)(stream->packets[inbuf].Header.Data))+(i*stream->inputSampleSize),stream->deviceInputChannels); - } + timeStamp[1] = dwCurrentTime; + eventSignalled -= captureEvents; + info.stream->render.pPin->fnEventHandler(&info, eventSignalled); } - - if (stream->recordingPin && stream->playbackPin) /* full duplex */ + else { - /* Only call the EndBufferProcessing function when the total input frames == total output frames */ + assert(info.stream->streamAbort); + PA_HP_TRACE((info.stream->hLog, "Stream abort!")); + continue; + } + } - if((stream->bufferProcessor.hostInputFrameCount[0] + stream->bufferProcessor.hostInputFrameCount[1]) == - (stream->bufferProcessor.hostOutputFrameCount[0] + stream->bufferProcessor.hostOutputFrameCount[1]) ) - { - framesProcessed = PaUtil_EndBufferProcessing(&stream->bufferProcessor,&cbResult); - } - else - { - framesProcessed = 0; - } - } - else + /* Handle processing */ + if (doProcessing) + { + result = PaDoProcessing(&info); + if (result != paNoError) { - framesProcessed = PaUtil_EndBufferProcessing(&stream->bufferProcessor,&cbResult); + PA_HP_TRACE((info.stream->hLog, "PaDoProcessing failed!")); + break; } + } - if( doChannelCopy ) - { - /* Copy the first output channel to the other channels */ - switch(stream->outputSampleSize) - { - case 2: - DuplicateFirstChannelInt16(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer); - break; - case 3: - DuplicateFirstChannelInt24(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer); - break; - case 4: - DuplicateFirstChannelInt32(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer); - break; - default: - assert(0); /* Unsupported format! */ - break; - } - } - PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); - } - else + if(info.stream->streamStop && info.cbResult != paComplete) { - fillPlaybuf = 0; - emptyRecordbuf = 0; + PA_HP_TRACE((info.stream->hLog, "Stream stop! pending=%d",info.pending)); + info.cbResult = paComplete; /* Stop, but play remaining buffers */ } - - /* - if(cbResult != paContinue) + + if(info.pending<=0) { - PA_DEBUG(("cbResult=%d, pending=%d:",cbResult,pending)); - } - */ - /* Submit buffers */ - if((fillPlaybuf)&&(cbResult!=paAbort)) - { - if(!PinWrite(stream->playbackPin->handle,&stream->packets[outbuf+2])) - outbuf = (outbuf+1)&1; /* Increment and wrap */ - pending++; - if( priming ) - priming--; /* Have to prime twice */ - } - if((emptyRecordbuf)&&(cbResult==paContinue)) - { - stream->packets[inbuf].Header.DataUsed = 0; /* Reset for reuse */ - PinRead(stream->recordingPin->handle,&stream->packets[inbuf]); - inbuf = (inbuf+1)&1; /* Increment and wrap */ - pending++; - } - if(pending==0) - { - PA_DEBUG(("pending==0 finished...;")); + PA_HP_TRACE((info.stream->hLog, "pending==0 finished...")); break; } - if((!stream->playbackPin)&&(cbResult!=paContinue)) + if((!info.stream->render.pPin)&&(info.cbResult!=paContinue)) { - PA_DEBUG(("record only cbResult=%d...;",cbResult)); + PA_HP_TRACE((info.stream->hLog, "record only cbResult=%d...",info.cbResult)); break; } } - PA_DEBUG(("Finished thread")); + PA_DEBUG(("Finished processing loop\n")); - /* Finished, either normally or aborted */ - if(stream->playbackPin) + info.stream->threadResult = result; + goto bailout; + +error: + PA_DEBUG(("Error starting processing thread\n")); + /* Set the "error" event together with result */ + info.stream->threadResult = result; + SetEvent(info.stream->eventStreamStart[StreamStart_kFailed]); + +bailout: + if (hTimer) { - result = PinSetState(stream->playbackPin, KSSTATE_PAUSE); - result = PinSetState(stream->playbackPin, KSSTATE_STOP); - } - if(stream->recordingPin) - { - result = PinSetState(stream->recordingPin, KSSTATE_PAUSE); - result = PinSetState(stream->recordingPin, KSSTATE_STOP); + PA_DEBUG(("Waitable timer stopped\n", timerPeriod)); + CancelWaitableTimer(hTimer); + CloseHandle(hTimer); + hTimer = 0; } - stream->streamActive = 0; - - if((!stream->streamStop)&&(!stream->streamAbort)) + if (info.pinsStarted) { - /* Invoke the user stream finished callback */ - /* Only do it from here if not being stopped/aborted by user */ - if( stream->streamRepresentation.streamFinishedCallback != 0 ) - stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + StopPins(&info); } - stream->streamStop = 0; - stream->streamAbort = 0; - /* Reset process priority if necessary */ - if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS) + /* Lower prio here */ + DropThreadPriority(hAVRT); + + if (handleArray != NULL) { - SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority); - stream->oldProcessPriority = REALTIME_PRIORITY_CLASS; + PaUtil_FreeMemory(handleArray); } +#if PA_TRACE_REALTIME_EVENTS + if (info.stream->hLog) + { + PA_DEBUG(("Dumping highspeed trace...\n")); + PaUtil_DumpHighSpeedLog(info.stream->hLog, "hp_trace.log"); + PaUtil_DiscardHighSpeedLog(info.stream->hLog); + info.stream->hLog = 0; + } +#endif + info.stream->streamActive = 0; + + if((!info.stream->streamStop)&&(!info.stream->streamAbort)) + { + /* Invoke the user stream finished callback */ + /* Only do it from here if not being stopped/aborted by user */ + if( info.stream->streamRepresentation.streamFinishedCallback != 0 ) + info.stream->streamRepresentation.streamFinishedCallback( info.stream->streamRepresentation.userData ); + } + info.stream->streamStop = 0; + info.stream->streamAbort = 0; + PA_LOGL_; - EXIT_THREAD; return 0; } + static PaError StartStream( PaStream *s ) { PaError result = paNoError; PaWinWdmStream *stream = (PaWinWdmStream*)s; - DWORD dwID; - BOOL ret; - int size; PA_LOGE_; + if (stream->streamThread != NULL) + { + return paStreamIsNotStopped; + } + stream->streamStop = 0; stream->streamAbort = 0; - size = 5; - while(size--) - { - if(stream->events[size] != NULL) - { - ResetEvent(stream->events[size]); - } - } + + ResetStreamEvents(stream); PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); stream->oldProcessPriority = GetPriorityClass(GetCurrentProcess()); /* Uncomment the following line to enable dynamic boosting of the process - * priority to real time for best low latency support - * Disabled by default because RT processes can easily block the OS */ + * priority to real time for best low latency support + * Disabled by default because RT processes can easily block the OS */ /*ret = SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS); - PA_DEBUG(("Class ret = %d;",ret));*/ + PA_DEBUG(("Class ret = %d;",ret));*/ - stream->streamStarted = 1; - stream->streamThread = (HANDLE)_beginthreadex(NULL, 0, ProcessingThread, stream, 0, &dwID); + stream->streamThread = CREATE_THREAD_FUNCTION (NULL, 0, ProcessingThread, stream, CREATE_SUSPENDED, NULL); if(stream->streamThread == NULL) { - stream->streamStarted = 0; result = paInsufficientMemory; goto end; } - ret = SetThreadPriority(stream->streamThread,THREAD_PRIORITY_TIME_CRITICAL); - PA_DEBUG(("Priority ret = %d;",ret)); - /* Make the stream active */ - stream->streamActive = 1; + ResumeThread(stream->streamThread); + + switch (WaitForMultipleObjects(2, stream->eventStreamStart, FALSE, 5000)) + { + case WAIT_OBJECT_0 + StreamStart_kOk: + PA_DEBUG(("Processing thread started!\n")); + result = paNoError; + /* streamActive is set in processing thread */ + stream->streamStarted = 1; + break; + case WAIT_OBJECT_0 + StreamStart_kFailed: + PA_DEBUG(("Processing thread start failed! (result=%d)\n", stream->threadResult)); + result = stream->threadResult; + /* Wait for the stream to really exit */ + WaitForSingleObject(stream->streamThread, 200); + CloseHandle(stream->streamThread); + stream->streamThread = 0; + break; + case WAIT_TIMEOUT: + default: + result = paTimedOut; + PaWinWDM_SetLastErrorInfo(result, "Failed to start processing thread (timeout)!"); + break; + } end: PA_LOGL_; @@ -3092,35 +6272,48 @@ static PaError StopStream( PaStream *s ) { PaError result = paNoError; PaWinWdmStream *stream = (PaWinWdmStream*)s; - int doCb = 0; + BOOL doCb = FALSE; PA_LOGE_; if(stream->streamActive) { - doCb = 1; + DWORD dwExitCode; + doCb = TRUE; stream->streamStop = 1; - while(stream->streamActive) + if (GetExitCodeThread(stream->streamThread, &dwExitCode) && dwExitCode == STILL_ACTIVE) { - PA_DEBUG(("W.")); - Sleep(10); /* Let thread sleep for 10 msec */ + if (WaitForSingleObject(stream->streamThread, INFINITE) != WAIT_OBJECT_0) + { + PA_DEBUG(("StopStream: stream thread terminated\n")); + TerminateThread(stream->streamThread, -1); + result = paTimedOut; + } + } + else + { + PA_DEBUG(("StopStream: GECT says not active, but streamActive is not false ??")); + result = paUnanticipatedHostError; + PaWinWDM_SetLastErrorInfo(result, "StopStream: GECT says not active, but streamActive = %d", stream->streamActive); + } + } + else + { + if (stream->threadResult != paNoError) + { + PA_DEBUG(("StopStream: Stream not active (%d)\n", stream->threadResult)); + result = stream->threadResult; + stream->threadResult = paNoError; } } - PA_DEBUG(("Terminating thread")); - if(stream->streamStarted && stream->streamThread) + if (stream->streamThread != NULL) { - TerminateThread(stream->streamThread,0); - stream->streamThread = NULL; + CloseHandle(stream->streamThread); + stream->streamThread = 0; } - stream->streamStarted = 0; - - if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS) - { - SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority); - stream->oldProcessPriority = REALTIME_PRIORITY_CLASS; - } + stream->streamActive = 0; if(doCb) { @@ -3128,7 +6321,7 @@ static PaError StopStream( PaStream *s ) /* This means it should be safe for the called function */ /* to invoke e.g. StartStream */ if( stream->streamRepresentation.streamFinishedCallback != 0 ) - stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); + stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); } PA_LOGL_; @@ -3147,27 +6340,20 @@ static PaError AbortStream( PaStream *s ) { doCb = 1; stream->streamAbort = 1; - SetEvent(stream->events[4]); /* Signal immediately */ - while(stream->streamActive) + SetEvent(stream->eventAbort); /* Signal immediately */ + if (WaitForSingleObject(stream->streamThread, 10000) != WAIT_OBJECT_0) { - Sleep(10); + TerminateThread(stream->streamThread, -1); + result = paTimedOut; + + PA_DEBUG(("AbortStream: stream thread terminated\n")); } + assert(!stream->streamActive); } - - if(stream->streamStarted && stream->streamThread) - { - TerminateThread(stream->streamThread,0); - stream->streamThread = NULL; - } - + CloseHandle(stream->streamThread); + stream->streamThread = NULL; stream->streamStarted = 0; - if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS) - { - SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority); - stream->oldProcessPriority = REALTIME_PRIORITY_CLASS; - } - if(doCb) { /* Do user callback now after all state has been reset */ @@ -3236,13 +6422,32 @@ static double GetStreamCpuLoad( PaStream* s ) /* - As separate stream interfaces are used for blocking and callback - streams, the following functions can be guaranteed to only be called - for blocking streams. +As separate stream interfaces are used for blocking and callback +streams, the following functions can be guaranteed to only be called +for blocking streams. */ static PaError ReadStream( PaStream* s, - void *buffer, + void *buffer, + unsigned long frames ) +{ + PaWinWdmStream *stream = (PaWinWdmStream*)s; + + PA_LOGE_; + + /* suppress unused variable warnings */ + (void) buffer; + (void) frames; + (void) stream; + + /* IMPLEMENT ME, see portaudio.h for required behavior*/ + PA_LOGL_; + return paInternalError; +} + + +static PaError WriteStream( PaStream* s, + const void *buffer, unsigned long frames ) { PaWinWdmStream *stream = (PaWinWdmStream*)s; @@ -3256,26 +6461,7 @@ static PaError ReadStream( PaStream* s, /* IMPLEMENT ME, see portaudio.h for required behavior*/ PA_LOGL_; - return paNoError; -} - - -static PaError WriteStream( PaStream* s, - const void *buffer, - unsigned long frames ) -{ - PaWinWdmStream *stream = (PaWinWdmStream*)s; - - PA_LOGE_; - - /* suppress unused variable warnings */ - (void) buffer; - (void) frames; - (void) stream; - - /* IMPLEMENT ME, see portaudio.h for required behavior*/ - PA_LOGL_; - return paNoError; + return paInternalError; } @@ -3305,4 +6491,301 @@ static signed long GetStreamWriteAvailable( PaStream* s ) /* IMPLEMENT ME, see portaudio.h for required behavior*/ PA_LOGL_; return 0; -} \ No newline at end of file +} + +/***************************************************************************************/ +/* Event and submit handlers for WaveCyclic */ +/***************************************************************************************/ + +static PaError PaPinCaptureEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + PaError result = paNoError; + ring_buffer_size_t frameCount; + DATAPACKET* packet = pInfo->stream->capture.packets + eventIndex; + + assert( eventIndex < pInfo->stream->capture.noOfPackets ); + + if (packet->Header.DataUsed == 0) + { + PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture bogus event (no data): idx=%u", eventIndex)); + + /* Bogus event, reset! This is to handle the behavior of this USB mic: http://shop.xtz.se/measurement-system/microphone-to-dirac-live-room-correction-suite + on startup of streaming, where it erroneously sets the event without the corresponding buffer being filled (DataUsed == 0) */ + ResetEvent(packet->Signal.hEvent); + + result = -1; /* Only need this to be NOT paNoError */ + } + else + { + pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet; + + frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pInfo->stream->capture.framesPerBuffer); + + PA_HP_TRACE((pInfo->stream->hLog, ">>> Capture event: idx=%u (frames=%u)", eventIndex, frameCount)); + ++pInfo->captureHead; + } + + --pInfo->pending; /* This needs to be done in either case */ + return result; +} + +static PaError PaPinCaptureSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + PaError result = paNoError; + DATAPACKET* packet = pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet; + pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0; + assert(packet != 0); + PA_HP_TRACE((pInfo->stream->hLog, "Capture submit: %u", eventIndex)); + packet->Header.DataUsed = 0; /* Reset for reuse */ + ResetEvent(packet->Signal.hEvent); + result = PinRead(pInfo->stream->capture.pPin->handle, packet); + ++pInfo->pending; + return result; +} + +static PaError PaPinRenderEventHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + assert( eventIndex < pInfo->stream->render.noOfPackets ); + + pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask].packet = pInfo->stream->render.packets + eventIndex; + PA_HP_TRACE((pInfo->stream->hLog, "<<< Render event : idx=%u head=%u", eventIndex, pInfo->renderHead)); + ++pInfo->renderHead; + --pInfo->pending; + return paNoError; +} + +static PaError PaPinRenderSubmitHandler_WaveCyclic(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + PaError result = paNoError; + DATAPACKET* packet = pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet; + pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0; + assert(packet != 0); + + PA_HP_TRACE((pInfo->stream->hLog, "Render submit : %u idx=%u", pInfo->renderTail, (unsigned)(packet - pInfo->stream->render.packets))); + ResetEvent(packet->Signal.hEvent); + result = PinWrite(pInfo->stream->render.pPin->handle, packet); + /* Reset event, just in case we have an analogous situation to capture (see PaPinCaptureSubmitHandler_WaveCyclic) */ + ++pInfo->pending; + if (pInfo->priming) + { + --pInfo->priming; + } + return result; +} + +/***************************************************************************************/ +/* Event and submit handlers for WaveRT */ +/***************************************************************************************/ + +static PaError PaPinCaptureEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + unsigned long pos; + unsigned realInBuf; + unsigned frameCount; + PaWinWdmIOInfo* pCapture = &pInfo->stream->capture; + const unsigned halfInputBuffer = pCapture->hostBufferSize >> 1; + PaWinWdmPin* pin = pCapture->pPin; + DATAPACKET* packet = 0; + + /* Get hold of current ADC position */ + pin->fnAudioPosition(pin, &pos); + /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from + where it should be, i.e. at beginning or half buffer position. Why? No idea.) */ + + pos %= pCapture->hostBufferSize; + /* Then realInBuf will point to "other" half of double buffer */ + realInBuf = pos < halfInputBuffer ? 1U : 0U; + + packet = pInfo->stream->capture.packets + realInBuf; + + /* Call barrier (or dummy) */ + pin->fnMemBarrier(); + + /* Put it in queue */ + frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, packet->Header.Data, pCapture->framesPerBuffer); + + pInfo->capturePackets[pInfo->captureHead & cPacketsArrayMask].packet = packet; + + PA_HP_TRACE((pInfo->stream->hLog, "Capture event (WaveRT): idx=%u head=%u (pos = %4.1lf%%, frames=%u)", realInBuf, pInfo->captureHead, (pos * 100.0 / pCapture->hostBufferSize), frameCount)); + + ++pInfo->captureHead; + --pInfo->pending; + + return paNoError; +} + +static PaError PaPinCaptureEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + unsigned long pos; + unsigned bytesToRead; + PaWinWdmIOInfo* pCapture = &pInfo->stream->capture; + const unsigned halfInputBuffer = pCapture->hostBufferSize>>1; + PaWinWdmPin* pin = pInfo->stream->capture.pPin; + + /* Get hold of current ADC position */ + pin->fnAudioPosition(pin, &pos); + /* Wrap it (robi: why not use hw latency compensation here ?? because pos then gets _way_ off from + where it should be, i.e. at beginning or half buffer position. Why? No idea.) */ + /* Compensate for HW FIFO to get to last read buffer position */ + pos += pin->hwLatency; + pos %= pCapture->hostBufferSize; + /* Need to align position on frame boundary */ + pos &= ~(pCapture->bytesPerFrame - 1); + + /* Call barrier (or dummy) */ + pin->fnMemBarrier(); + + /* Put it in "queue" */ + bytesToRead = (pCapture->hostBufferSize + pos - pCapture->lastPosition) % pCapture->hostBufferSize; + if (bytesToRead > 0) + { + unsigned frameCount = PaUtil_WriteRingBuffer(&pInfo->stream->ringBuffer, + pCapture->hostBuffer + pCapture->lastPosition, + bytesToRead / pCapture->bytesPerFrame); + + pCapture->lastPosition = (pCapture->lastPosition + frameCount * pCapture->bytesPerFrame) % pCapture->hostBufferSize; + + PA_HP_TRACE((pInfo->stream->hLog, "Capture event (WaveRTPolled): pos = %4.1lf%%, framesRead=%u", (pos * 100.0 / pCapture->hostBufferSize), frameCount)); + ++pInfo->captureHead; + --pInfo->pending; + } + return paNoError; +} + +static PaError PaPinCaptureSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0; + ++pInfo->pending; + return paNoError; +} + +static PaError PaPinCaptureSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + pInfo->capturePackets[pInfo->captureTail & cPacketsArrayMask].packet = 0; + ++pInfo->pending; + return paNoError; +} + +static PaError PaPinRenderEventHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + unsigned long pos; + unsigned realOutBuf; + PaWinWdmIOInfo* pRender = &pInfo->stream->render; + const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1; + PaWinWdmPin* pin = pInfo->stream->render.pPin; + PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask]; + + /* Get hold of current DAC position */ + pin->fnAudioPosition(pin, &pos); + /* Compensate for HW FIFO to get to last read buffer position */ + pos += pin->hwLatency; + /* Wrap it */ + pos %= pRender->hostBufferSize; + /* And align it, not sure its really needed though */ + pos &= ~(pRender->bytesPerFrame - 1); + /* Then realOutBuf will point to "other" half of double buffer */ + realOutBuf = pos < halfOutputBuffer ? 1U : 0U; + + if (pInfo->priming) + { + realOutBuf = pInfo->renderHead & 0x1; + } + ioPacket->packet = pInfo->stream->render.packets + realOutBuf; + ioPacket->startByte = realOutBuf * halfOutputBuffer; + ioPacket->lengthBytes = halfOutputBuffer; + + PA_HP_TRACE((pInfo->stream->hLog, "Render event (WaveRT) : idx=%u head=%u (pos = %4.1lf%%)", realOutBuf, pInfo->renderHead, (pos * 100.0 / pRender->hostBufferSize) )); + + ++pInfo->renderHead; + --pInfo->pending; + return paNoError; +} + +static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + unsigned long pos; + unsigned realOutBuf; + unsigned bytesToWrite; + + PaWinWdmIOInfo* pRender = &pInfo->stream->render; + const unsigned halfOutputBuffer = pRender->hostBufferSize >> 1; + PaWinWdmPin* pin = pInfo->stream->render.pPin; + PaIOPacket* ioPacket = &pInfo->renderPackets[pInfo->renderHead & cPacketsArrayMask]; + + /* Get hold of current DAC position */ + pin->fnAudioPosition(pin, &pos); + /* Compensate for HW FIFO to get to last read buffer position */ + pos += pin->hwLatency; + /* Wrap it */ + pos %= pRender->hostBufferSize; + /* And align it, not sure its really needed though */ + pos &= ~(pRender->bytesPerFrame - 1); + + if (pInfo->priming) + { + realOutBuf = pInfo->renderHead & 0x1; + ioPacket->packet = pInfo->stream->render.packets + realOutBuf; + ioPacket->startByte = realOutBuf * halfOutputBuffer; + ioPacket->lengthBytes = halfOutputBuffer; + ++pInfo->renderHead; + --pInfo->pending; + } + else + { + bytesToWrite = (pRender->hostBufferSize + pos - pRender->lastPosition) % pRender->hostBufferSize; + ++pRender->pollCntr; + if (bytesToWrite >= halfOutputBuffer) + { + realOutBuf = (pos < halfOutputBuffer) ? 1U : 0U; + ioPacket->packet = pInfo->stream->render.packets + realOutBuf; + pRender->lastPosition = realOutBuf ? 0U : halfOutputBuffer; + ioPacket->startByte = realOutBuf * halfOutputBuffer; + ioPacket->lengthBytes = halfOutputBuffer; + ++pInfo->renderHead; + --pInfo->pending; + PA_HP_TRACE((pInfo->stream->hLog, "Render event (WaveRTPolled) : idx=%u head=%u (pos = %4.1lf%%, cnt=%u)", realOutBuf, pInfo->renderHead, (pos * 100.0 / pRender->hostBufferSize), pRender->pollCntr)); + pRender->pollCntr = 0; + } + } + return paNoError; +} + +static PaError PaPinRenderSubmitHandler_WaveRTEvent(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + PaWinWdmPin* pin = pInfo->stream->render.pPin; + pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0; + /* Call barrier (if needed) */ + pin->fnMemBarrier(); + PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRT) : submit=%u", pInfo->renderTail)); + ++pInfo->pending; + if (pInfo->priming) + { + --pInfo->priming; + if (pInfo->priming) + { + PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)")); + SetEvent(pInfo->stream->render.events[0]); + } + } + return paNoError; +} + +static PaError PaPinRenderSubmitHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, unsigned eventIndex) +{ + PaWinWdmPin* pin = pInfo->stream->render.pPin; + pInfo->renderPackets[pInfo->renderTail & cPacketsArrayMask].packet = 0; + /* Call barrier (if needed) */ + pin->fnMemBarrier(); + PA_HP_TRACE((pInfo->stream->hLog, "Render submit (WaveRTPolled) : submit=%u", pInfo->renderTail)); + ++pInfo->pending; + if (pInfo->priming) + { + --pInfo->priming; + if (pInfo->priming) + { + PA_HP_TRACE((pInfo->stream->hLog, "Setting WaveRT event for priming (2)")); + SetEvent(pInfo->stream->render.events[0]); + } + } + return paNoError; +} diff --git a/Externals/portaudio/src/hostapi/wdmks/readme.txt b/Externals/portaudio/src/hostapi/wdmks/readme.txt index 1a381fe79f..c4c349c2a4 100644 --- a/Externals/portaudio/src/hostapi/wdmks/readme.txt +++ b/Externals/portaudio/src/hostapi/wdmks/readme.txt @@ -3,12 +3,15 @@ Notes about WDM-KS host API Status history -------------- +16th January 2011: +Added support for WaveRT device API (Vista and later) for even lesser +latency support. + 10th November 2005: Made following changes: * OpenStream: Try all PaSampleFormats internally if the the chosen format is not supported natively. This fixed several problems - with soundcards that soundcards that did not take kindly to - using 24-bit 3-byte formats. + with soundcards that did not take kindly to using 24-bit 3-byte formats. * OpenStream: Make the minimum framesPerHostIBuffer (and framesPerHostOBuffer) the default frameSize for the playback/recording pin. * ProcessingThread: Added a switch to only call PaUtil_EndBufferProcessing @@ -71,7 +74,7 @@ In PortAudio terms, this means having a stream Open on a WDMKS device. Usage ----- To add the WDMKS backend to your program which is already using -PortAudio, you must undefine PA_NO_WDMKS from your build file, +PortAudio, you must define PA_USE_WDMKS=1 in your build file, and include the pa_win_wdmks\pa_win_wdmks.c into your build. The file should compile in both C and C++. You will need a DirectX SDK installed on your system for the @@ -79,4 +82,4 @@ ks.h and ksmedia.h header files. You will need to link to the system "setupapi" library. Note that if you use MinGW, you will get more warnings from the DX header files when using GCC(C), and still a few warnings -with G++(CPP). \ No newline at end of file +with G++(CPP). diff --git a/Externals/portaudio/src/hostapi/wmme/pa_win_wmme.c b/Externals/portaudio/src/hostapi/wmme/pa_win_wmme.c index ec891a94ed..422c86714a 100644 --- a/Externals/portaudio/src/hostapi/wmme/pa_win_wmme.c +++ b/Externals/portaudio/src/hostapi/wmme/pa_win_wmme.c @@ -1,5 +1,5 @@ /* - * $Id: pa_win_wmme.c 1739 2011-08-25 07:15:31Z rossb $ + * $Id$ * pa_win_wmme.c * Implementation of PortAudio for Windows MultiMedia Extensions (WMME) * @@ -62,7 +62,7 @@ */ /** @file - @ingroup hostapi_src + @ingroup hostapi_src @brief Win32 host API implementation for the Windows MultiMedia Extensions (WMME) audio API. */ @@ -86,6 +86,7 @@ #include #include +#include #include #include #include @@ -201,31 +202,52 @@ static const char constInputMapperSuffix_[] = " - Input"; static const char constOutputMapperSuffix_[] = " - Output"; -/* -copies TCHAR string to explicit char string -*/ -char *StrTCpyToC(char *to, const TCHAR *from) +/********************************************************************/ + +/* Copy null-terminated TCHAR string to explicit char string using UTF8 encoding */ +static char *CopyTCharStringToUtf8CString(char *destination, size_t destLengthBytes, const TCHAR *source) { #if !defined(_UNICODE) && !defined(UNICODE) - return strcpy(to, from); + return strcpy(destination, source); #else - int count = wcslen(from); - if (count != 0) - if (WideCharToMultiByte(CP_ACP, 0, from, count, to, count, NULL, NULL) == 0) - return NULL; - return to; + /* The cbMultiByte parameter ["destLengthBytes" below] is: + """ + Size, in bytes, of the buffer indicated by lpMultiByteStr ["destination" below]. + If this parameter is set to 0, the function returns the required buffer + size for lpMultiByteStr and makes no use of the output parameter itself. + """ + Source: WideCharToMultiByte at MSDN: + http://msdn.microsoft.com/en-us/library/windows/desktop/dd374130(v=vs.85).aspx + */ + int intDestLengthBytes; /* cbMultiByte */ + /* intDestLengthBytes is an int, destLengthBytes is a size_t. Ensure that we don't overflow + intDestLengthBytes by only using at most INT_MAX bytes of destination buffer. + */ + if (destLengthBytes < INT_MAX) + { +#pragma warning (disable : 4267) /* "conversion from 'size_t' to 'int', possible loss of data" */ + intDestLengthBytes = (int)destLengthBytes; /* destLengthBytes is guaranteed < INT_MAX here */ +#pragma warning (default : 4267) + } + else + { + intDestLengthBytes = INT_MAX; + } + + if (WideCharToMultiByte(CP_UTF8, 0, source, -1, destination, /*cbMultiByte=*/intDestLengthBytes, NULL, NULL) == 0) + return NULL; + return destination; #endif } -/* -returns length of TCHAR string -*/ -size_t StrTLen(const TCHAR *str) +/* returns required length (in bytes) of destination buffer when + converting TCHAR string to UTF8 bytes, not including the terminating null. */ +static size_t TCharStringLen(const TCHAR *str) { #if !defined(_UNICODE) && !defined(UNICODE) - return strlen(str); + return strlen(str); #else - return wcslen(str); + return WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); #endif } @@ -450,7 +472,7 @@ static PaDeviceIndex GetEnvDefaultDeviceID( char *envName ) #ifndef WIN32_PLATFORM_PSPC /* no GetEnvironmentVariable on PocketPC */ /* Let user determine default device by setting environment variable. */ - hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE_ ); + hresult = GetEnvironmentVariableA( envName, envbuf, PA_ENV_BUF_SIZE_ ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE_) ) { recommendedIndex = atoi( envbuf ); @@ -491,7 +513,7 @@ static UINT LocalDeviceIndexToWinMmeDeviceId( PaWinMmeHostApiRepresentation *hos { assert( device >= 0 && device < hostApi->inputDeviceCount + hostApi->outputDeviceCount ); - return hostApi->winMmeDeviceIds[ device ]; + return hostApi->winMmeDeviceIds[ device ]; } @@ -686,6 +708,7 @@ static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeH MMRESULT mmresult; WAVEINCAPS wic; PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo; + size_t len; *success = 0; @@ -705,29 +728,35 @@ static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeH return paNoError; } + /* NOTE: the WAVEOUTCAPS.szPname is a null-terminated array of 32 characters, + so we are limited to displaying only the first 31 characters of the device name. */ if( winMmeInputDeviceId == WAVE_MAPPER ) { + len = TCharStringLen( wic.szPname ) + 1 + sizeof(constInputMapperSuffix_); /* Append I/O suffix to WAVE_MAPPER device. */ - deviceName = (char *)PaUtil_GroupAllocateMemory( - winMmeHostApi->allocations, StrTLen( wic.szPname ) + 1 + sizeof(constInputMapperSuffix_) ); + deviceName = (char*)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, + (long)len ); if( !deviceName ) { result = paInsufficientMemory; goto error; } - StrTCpyToC( deviceName, wic.szPname ); + CopyTCharStringToUtf8CString( deviceName, len, wic.szPname ); strcat( deviceName, constInputMapperSuffix_ ); } else { + len = TCharStringLen( wic.szPname ) + 1; deviceName = (char*)PaUtil_GroupAllocateMemory( - winMmeHostApi->allocations, StrTLen( wic.szPname ) + 1 ); + winMmeHostApi->allocations, + (long)len ); if( !deviceName ) { result = paInsufficientMemory; goto error; } - StrTCpyToC( deviceName, wic.szPname ); + CopyTCharStringToUtf8CString( deviceName, len, wic.szPname ); } deviceInfo->name = deviceName; @@ -809,6 +838,7 @@ static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMme MMRESULT mmresult; WAVEOUTCAPS woc; PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo; + size_t len; #ifdef PAWIN_USE_WDMKS_DEVICE_INFO int wdmksDeviceOutputChannelCountIsKnown; #endif @@ -831,29 +861,35 @@ static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMme return paNoError; } + /* NOTE: the WAVEOUTCAPS.szPname is a null-terminated array of 32 characters, + so we are limited to displaying only the first 31 characters of the device name. */ if( winMmeOutputDeviceId == WAVE_MAPPER ) { /* Append I/O suffix to WAVE_MAPPER device. */ - deviceName = (char *)PaUtil_GroupAllocateMemory( - winMmeHostApi->allocations, StrTLen( woc.szPname ) + 1 + sizeof(constOutputMapperSuffix_) ); + len = TCharStringLen( woc.szPname ) + 1 + sizeof(constOutputMapperSuffix_); + deviceName = (char*)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, + (long)len ); if( !deviceName ) { result = paInsufficientMemory; goto error; } - StrTCpyToC( deviceName, woc.szPname ); + CopyTCharStringToUtf8CString( deviceName, len, woc.szPname ); strcat( deviceName, constOutputMapperSuffix_ ); } else { + len = TCharStringLen( woc.szPname ) + 1; deviceName = (char*)PaUtil_GroupAllocateMemory( - winMmeHostApi->allocations, StrTLen( woc.szPname ) + 1 ); + winMmeHostApi->allocations, + (long)len ); if( !deviceName ) { result = paInsufficientMemory; goto error; } - StrTCpyToC( deviceName, woc.szPname ); + CopyTCharStringToUtf8CString( deviceName, len, woc.szPname ); } deviceInfo->name = deviceName; @@ -878,7 +914,7 @@ static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMme #ifdef PAWIN_USE_WDMKS_DEVICE_INFO wdmksDeviceOutputChannelCountIsKnown = QueryWaveOutKSFilterMaxChannels( - winMmeOutputDeviceId, &deviceInfo->maxOutputChannels ); + winMmeOutputDeviceId, &deviceInfo->maxOutputChannels ); if( wdmksDeviceOutputChannelCountIsKnown && !winMmeDeviceInfo->deviceOutputChannelCountIsKnown ) winMmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ @@ -897,9 +933,19 @@ error: static void GetDefaultLatencies( PaTime *defaultLowLatency, PaTime *defaultHighLatency ) { +/* +NOTE: GetVersionEx() is deprecated as of Windows 8.1 and can not be used to reliably detect +versions of Windows higher than Windows 8 (due to manifest requirements for reporting higher versions). +Microsoft recommends switching to VerifyVersionInfo (available on Win 2k and later), however GetVersionEx +is is faster, for now we just disable the deprecation warning. +See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx +See: http://www.codeproject.com/Articles/678606/Part-Overcoming-Windows-s-deprecation-of-GetVe +*/ +#pragma warning (disable : 4996) /* use of GetVersionEx */ + OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof( osvi ); - GetVersionEx( &osvi ); + GetVersionEx( &osvi ); /* Check for NT */ if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) @@ -916,6 +962,8 @@ static void GetDefaultLatencies( PaTime *defaultLowLatency, PaTime *defaultHighL } *defaultHighLatency = *defaultLowLatency * 2; + +#pragma warning (default : 4996) } @@ -979,11 +1027,11 @@ PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd inputDeviceCount = waveInGetNumDevs(); if( inputDeviceCount > 0 ) - maximumPossibleDeviceCount += inputDeviceCount + 1; /* assume there is a WAVE_MAPPER */ + maximumPossibleDeviceCount += inputDeviceCount + 1; /* assume there is a WAVE_MAPPER */ outputDeviceCount = waveOutGetNumDevs(); if( outputDeviceCount > 0 ) - maximumPossibleDeviceCount += outputDeviceCount + 1; /* assume there is a WAVE_MAPPER */ + maximumPossibleDeviceCount += outputDeviceCount + 1; /* assume there is a WAVE_MAPPER */ if( maximumPossibleDeviceCount > 0 ){ @@ -2153,29 +2201,29 @@ static PaError ValidateWinMmeSpecificStreamInfo( char *throttleProcessingThreadOnOverload, unsigned long *deviceCount ) { - if( streamInfo ) - { - if( streamInfo->size != sizeof( PaWinMmeStreamInfo ) - || streamInfo->version != 1 ) - { - return paIncompatibleHostApiSpecificStreamInfo; - } + if( streamInfo ) + { + if( streamInfo->size != sizeof( PaWinMmeStreamInfo ) + || streamInfo->version != 1 ) + { + return paIncompatibleHostApiSpecificStreamInfo; + } *winMmeSpecificFlags = streamInfo->flags; - if( streamInfo->flags & paWinMmeDontThrottleOverloadedProcessingThread ) - *throttleProcessingThreadOnOverload = 0; + if( streamInfo->flags & paWinMmeDontThrottleOverloadedProcessingThread ) + *throttleProcessingThreadOnOverload = 0; - if( streamInfo->flags & paWinMmeUseMultipleDevices ) - { - if( streamParameters->device != paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - - *deviceCount = streamInfo->deviceCount; - } - } + if( streamInfo->flags & paWinMmeUseMultipleDevices ) + { + if( streamParameters->device != paUseHostApiSpecificDeviceSpecification ) + return paInvalidDevice; + + *deviceCount = streamInfo->deviceCount; + } + } - return paNoError; + return paNoError; } static PaError RetrieveDevicesFromStreamParameters( @@ -2190,34 +2238,34 @@ static PaError RetrieveDevicesFromStreamParameters( int totalChannelCount; PaDeviceIndex hostApiDevice; - if( streamInfo && streamInfo->flags & paWinMmeUseMultipleDevices ) - { - totalChannelCount = 0; - for( i=0; i < deviceCount; ++i ) - { - /* validate that the device number is within range */ - result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, - streamInfo->devices[i].device, hostApi ); - if( result != paNoError ) - return result; - - devices[i].device = hostApiDevice; - devices[i].channelCount = streamInfo->devices[i].channelCount; - - totalChannelCount += devices[i].channelCount; - } - - if( totalChannelCount != streamParameters->channelCount ) - { - /* channelCount must match total channels specified by multiple devices */ - return paInvalidChannelCount; /* REVIEW use of this error code */ - } - } - else - { - devices[0].device = streamParameters->device; - devices[0].channelCount = streamParameters->channelCount; - } + if( streamInfo && streamInfo->flags & paWinMmeUseMultipleDevices ) + { + totalChannelCount = 0; + for( i=0; i < deviceCount; ++i ) + { + /* validate that the device number is within range */ + result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, + streamInfo->devices[i].device, hostApi ); + if( result != paNoError ) + return result; + + devices[i].device = hostApiDevice; + devices[i].channelCount = streamInfo->devices[i].channelCount; + + totalChannelCount += devices[i].channelCount; + } + + if( totalChannelCount != streamParameters->channelCount ) + { + /* channelCount must match total channels specified by multiple devices */ + return paInvalidChannelCount; /* REVIEW use of this error code */ + } + } + else + { + devices[0].device = streamParameters->device; + devices[0].channelCount = streamParameters->channelCount; + } return result; } @@ -2231,10 +2279,10 @@ static PaError ValidateInputChannelCounts( PaWinMmeDeviceInfo *inputDeviceInfo; PaError paerror; - for( i=0; i < deviceCount; ++i ) - { + for( i=0; i < deviceCount; ++i ) + { if( devices[i].channelCount < 1 ) - return paInvalidChannelCount; + return paInvalidChannelCount; inputDeviceInfo = (PaWinMmeDeviceInfo*)hostApi->deviceInfos[ devices[i].device ]; @@ -2242,7 +2290,7 @@ static PaError ValidateInputChannelCounts( paerror = IsInputChannelCountSupported( inputDeviceInfo, devices[i].channelCount ); if( paerror != paNoError ) return paerror; - } + } return paNoError; } @@ -2256,10 +2304,10 @@ static PaError ValidateOutputChannelCounts( PaWinMmeDeviceInfo *outputDeviceInfo; PaError paerror; - for( i=0; i < deviceCount; ++i ) - { + for( i=0; i < deviceCount; ++i ) + { if( devices[i].channelCount < 1 ) - return paInvalidChannelCount; + return paInvalidChannelCount; outputDeviceInfo = (PaWinMmeDeviceInfo*)hostApi->deviceInfos[ devices[i].device ]; @@ -2267,7 +2315,7 @@ static PaError ValidateOutputChannelCounts( paerror = IsOutputChannelCountSupported( outputDeviceInfo, devices[i].channelCount ); if( paerror != paNoError ) return paerror; - } + } return paNoError; } @@ -2316,28 +2364,28 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, if( inputParameters ) { - inputChannelCount = inputParameters->channelCount; + inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; suggestedInputLatency = inputParameters->suggestedLatency; - inputDeviceCount = 1; + inputDeviceCount = 1; - /* validate input hostApiSpecificStreamInfo */ + /* validate input hostApiSpecificStreamInfo */ inputStreamInfo = (PaWinMmeStreamInfo*)inputParameters->hostApiSpecificStreamInfo; - result = ValidateWinMmeSpecificStreamInfo( inputParameters, inputStreamInfo, + result = ValidateWinMmeSpecificStreamInfo( inputParameters, inputStreamInfo, &winMmeSpecificInputFlags, - &throttleProcessingThreadOnOverload, - &inputDeviceCount ); - if( result != paNoError ) return result; + &throttleProcessingThreadOnOverload, + &inputDeviceCount ); + if( result != paNoError ) return result; - inputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * inputDeviceCount ); + inputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * inputDeviceCount ); if( !inputDevices ) return paInsufficientMemory; - result = RetrieveDevicesFromStreamParameters( hostApi, inputParameters, inputStreamInfo, inputDevices, inputDeviceCount ); - if( result != paNoError ) return result; + result = RetrieveDevicesFromStreamParameters( hostApi, inputParameters, inputStreamInfo, inputDevices, inputDeviceCount ); + if( result != paNoError ) return result; - result = ValidateInputChannelCounts( hostApi, inputDevices, inputDeviceCount ); - if( result != paNoError ) return result; + result = ValidateInputChannelCounts( hostApi, inputDevices, inputDeviceCount ); + if( result != paNoError ) return result; hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat ); @@ -2353,7 +2401,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, else inputChannelMask = PaWin_DefaultChannelMask( inputDevices[0].channelCount ); } - } + } else { inputChannelCount = 0; @@ -2372,22 +2420,22 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, outputDeviceCount = 1; - /* validate output hostApiSpecificStreamInfo */ + /* validate output hostApiSpecificStreamInfo */ outputStreamInfo = (PaWinMmeStreamInfo*)outputParameters->hostApiSpecificStreamInfo; - result = ValidateWinMmeSpecificStreamInfo( outputParameters, outputStreamInfo, + result = ValidateWinMmeSpecificStreamInfo( outputParameters, outputStreamInfo, &winMmeSpecificOutputFlags, - &throttleProcessingThreadOnOverload, - &outputDeviceCount ); - if( result != paNoError ) return result; + &throttleProcessingThreadOnOverload, + &outputDeviceCount ); + if( result != paNoError ) return result; - outputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * outputDeviceCount ); + outputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * outputDeviceCount ); if( !outputDevices ) return paInsufficientMemory; - result = RetrieveDevicesFromStreamParameters( hostApi, outputParameters, outputStreamInfo, outputDevices, outputDeviceCount ); - if( result != paNoError ) return result; + result = RetrieveDevicesFromStreamParameters( hostApi, outputParameters, outputStreamInfo, outputDevices, outputDeviceCount ); + if( result != paNoError ) return result; - result = ValidateOutputChannelCounts( hostApi, outputDevices, outputDeviceCount ); - if( result != paNoError ) return result; + result = ValidateOutputChannelCounts( hostApi, outputDevices, outputDeviceCount ); + if( result != paNoError ) return result; hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat ); @@ -3215,9 +3263,9 @@ static PaError StartStream( PaStream *s ) MMRESULT mmresult; unsigned int i, j; int callbackResult; - unsigned int channel; - unsigned long framesProcessed; - PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement this for stream priming */ + unsigned int channel; + unsigned long framesProcessed; + PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement this for stream priming */ PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); diff --git a/Externals/portaudio/src/os/unix/pa_unix_hostapis.c b/Externals/portaudio/src/os/unix/pa_unix_hostapis.c index 4399b875b1..a9b4a05d7f 100644 --- a/Externals/portaudio/src/os/unix/pa_unix_hostapis.c +++ b/Externals/portaudio/src/os/unix/pa_unix_hostapis.c @@ -1,5 +1,5 @@ /* - * $Id: pa_unix_hostapis.c 1740 2011-08-25 07:17:48Z philburk $ + * $Id$ * Portable Audio I/O Library UNIX initialization table * * Based on the Open Source API proposed by Ross Bencina diff --git a/Externals/portaudio/src/os/unix/pa_unix_util.c b/Externals/portaudio/src/os/unix/pa_unix_util.c index 18f806c507..17664eabf0 100644 --- a/Externals/portaudio/src/os/unix/pa_unix_util.c +++ b/Externals/portaudio/src/os/unix/pa_unix_util.c @@ -1,5 +1,5 @@ /* - * $Id: pa_unix_util.c 1510 2010-06-10 08:05:29Z dmitrykos $ + * $Id$ * Portable Audio I/O Library * UNIX platform-specific support functions * diff --git a/Externals/portaudio/src/os/unix/pa_unix_util.h b/Externals/portaudio/src/os/unix/pa_unix_util.h index e900f87726..d73c99c8fa 100644 --- a/Externals/portaudio/src/os/unix/pa_unix_util.h +++ b/Externals/portaudio/src/os/unix/pa_unix_util.h @@ -1,5 +1,5 @@ /* - * $Id: pa_unix_util.h 1241 2007-07-23 20:08:31Z aknudsen $ + * $Id$ * Portable Audio I/O Library * UNIX platform-specific support functions * diff --git a/Externals/portaudio/src/os/win/pa_win_coinitialize.c b/Externals/portaudio/src/os/win/pa_win_coinitialize.c index 5c31716c0f..c4c6dde074 100644 --- a/Externals/portaudio/src/os/win/pa_win_coinitialize.c +++ b/Externals/portaudio/src/os/win/pa_win_coinitialize.c @@ -52,7 +52,7 @@ #include "pa_win_coinitialize.h" -#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */ +#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) && !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)) /* MSC version 6 and above */ #pragma comment( lib, "ole32.lib" ) #endif @@ -76,7 +76,11 @@ PaError PaWinUtil_CoInitialize( PaHostApiTypeId hostApiType, PaWinUtilComInitial RPC_E_CHANGED_MODE was returned. */ +#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY != WINAPI_FAMILY_APP) hr = CoInitialize(0); /* use legacy-safe equivalent to CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) */ +#else + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); +#endif if( FAILED(hr) && hr != RPC_E_CHANGED_MODE ) { PA_DEBUG(("CoInitialize(0) failed. hr=%d\n", hr)); diff --git a/Externals/portaudio/src/os/win/pa_win_hostapis.c b/Externals/portaudio/src/os/win/pa_win_hostapis.c index 5d22438799..9c9927ab77 100644 --- a/Externals/portaudio/src/os/win/pa_win_hostapis.c +++ b/Externals/portaudio/src/os/win/pa_win_hostapis.c @@ -1,5 +1,5 @@ /* - * $Id: pa_win_hostapis.c 1728 2011-08-18 03:31:51Z rossb $ + * $Id$ * Portable Audio I/O Library Windows initialization table * * Based on the Open Source API proposed by Ross Bencina diff --git a/Externals/portaudio/src/os/win/pa_win_util.c b/Externals/portaudio/src/os/win/pa_win_util.c index a9c55d0f8a..1cd35258bd 100644 --- a/Externals/portaudio/src/os/win/pa_win_util.c +++ b/Externals/portaudio/src/os/win/pa_win_util.c @@ -1,5 +1,5 @@ /* - * $Id: pa_win_util.c 1584 2011-02-02 18:58:17Z rossb $ + * $Id$ * Portable Audio I/O Library * Win32 platform-specific support functions * @@ -44,14 +44,17 @@ */ #include -#include /* for timeGetTime() */ -#include "pa_util.h" - -#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */ -#pragma comment( lib, "winmm.lib" ) +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + #include /* for _ftime_s() */ +#else + #include /* for timeGetTime() */ + #if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */ + #pragma comment( lib, "winmm.lib" ) + #endif #endif +#include "pa_util.h" /* Track memory allocations to avoid leaks. @@ -144,8 +147,12 @@ double PaUtil_GetTime( void ) } else { -#ifndef UNDER_CE +#ifndef UNDER_CE + #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + return GetTickCount64() * .001; + #else return timeGetTime() * .001; + #endif #else return GetTickCount() * .001; #endif diff --git a/Externals/portaudio/src/os/win/pa_win_waveformat.c b/Externals/portaudio/src/os/win/pa_win_waveformat.c index beae5825e4..bd5addd407 100644 --- a/Externals/portaudio/src/os/win/pa_win_waveformat.c +++ b/Externals/portaudio/src/os/win/pa_win_waveformat.c @@ -38,6 +38,9 @@ #include #include +#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) + #include /* for WAVEFORMATEX */ +#endif #include "portaudio.h" #include "pa_win_waveformat.h" @@ -47,6 +50,7 @@ #define WAVE_FORMAT_EXTENSIBLE 0xFFFE #endif + static GUID pawin_ksDataFormatSubtypeGuidBase = { (USHORT)(WAVE_FORMAT_PCM), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; @@ -104,7 +108,6 @@ void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat, *((GUID*)&waveFormat->fields[PAWIN_INDEXOF_SUBFORMAT]) = guid; } - PaWinWaveFormatChannelMask PaWin_DefaultChannelMask( int numChannels ) { switch( numChannels ){ @@ -129,11 +132,16 @@ PaWinWaveFormatChannelMask PaWin_DefaultChannelMask( int numChannels ) return PAWIN_SPEAKER_5POINT1; /* case 7: */ case 8: - return PAWIN_SPEAKER_7POINT1; + /* RoBi: PAWIN_SPEAKER_7POINT1_SURROUND fits normal surround sound setups better than PAWIN_SPEAKER_7POINT1, f.i. NVidia HDMI Audio + output is silent on channels 5&6 with NVidia drivers, and channel 7&8 with Micrsoft HD Audio driver using PAWIN_SPEAKER_7POINT1. + With PAWIN_SPEAKER_7POINT1_SURROUND both setups work OK. */ + return PAWIN_SPEAKER_7POINT1_SURROUND; } /* Apparently some Audigy drivers will output silence if the direct-out constant (0) is used. So this is not ideal. + + RoBi 2012-12-19: Also, NVidia driver seem to output garbage instead. Again not very ideal. */ return PAWIN_SPEAKER_DIRECTOUT; diff --git a/Externals/portaudio/src/os/win/pa_win_wdmks_utils.c b/Externals/portaudio/src/os/win/pa_win_wdmks_utils.c index 0dc0b4bdea..4bd067acf9 100644 --- a/Externals/portaudio/src/os/win/pa_win_wdmks_utils.c +++ b/Externals/portaudio/src/os/win/pa_win_wdmks_utils.c @@ -47,41 +47,53 @@ #define _INC_MMREG // for STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT #endif #include // MinGW32 does not define this automatically + +#if defined(__GNUC__) + +#include "../../hostapi/wasapi/mingw-include/ks.h" +#include "../../hostapi/wasapi/mingw-include/ksmedia.h" + +#else + #include #include + +#endif + #include // just for some development printfs #include "portaudio.h" #include "pa_util.h" #include "pa_win_wdmks_utils.h" -#if !defined(PA_WDMKS_NO_KSGUID_LIB) && !defined(PAWIN_WDMKS_NO_KSGUID_LIB) - #if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ - #pragma comment( lib, "ksguid.lib" ) - #endif - #define pa_KSDATAFORMAT_TYPE_AUDIO KSDATAFORMAT_TYPE_AUDIO - #define pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT KSDATAFORMAT_SUBTYPE_IEEE_FLOAT - #define pa_KSDATAFORMAT_SUBTYPE_PCM KSDATAFORMAT_SUBTYPE_PCM - #define pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX KSDATAFORMAT_SUBTYPE_WAVEFORMATEX - #define pa_KSMEDIUMSETID_Standard KSMEDIUMSETID_Standard - #define pa_KSINTERFACESETID_Standard KSINTERFACESETID_Standard - #define pa_KSPROPSETID_Pin KSPROPSETID_Pin -#else - static const GUID pa_KSDATAFORMAT_TYPE_AUDIO = { STATIC_KSDATAFORMAT_TYPE_AUDIO }; - static const GUID pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT }; - static const GUID pa_KSDATAFORMAT_SUBTYPE_PCM = { STATIC_KSDATAFORMAT_SUBTYPE_PCM }; - static const GUID pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX = { STATIC_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX }; - static const GUID pa_KSMEDIUMSETID_Standard = { STATIC_KSMEDIUMSETID_Standard }; - static const GUID pa_KSINTERFACESETID_Standard = { STATIC_KSINTERFACESETID_Standard }; - static const GUID pa_KSPROPSETID_Pin = { STATIC_KSPROPSETID_Pin }; -#endif +/* PortAudio-local instances of GUIDs previously sourced from ksguid.lib */ + +/* GUID KSDATAFORMAT_TYPE_AUDIO */ +static const GUID pa_KSDATAFORMAT_TYPE_AUDIO = { STATIC_KSDATAFORMAT_TYPE_AUDIO }; + +/* GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT */ +static const GUID pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT }; + +/* GUID KSDATAFORMAT_SUBTYPE_PCM */ +static const GUID pa_KSDATAFORMAT_SUBTYPE_PCM = { STATIC_KSDATAFORMAT_SUBTYPE_PCM }; + +/* GUID KSDATAFORMAT_SUBTYPE_WAVEFORMATEX */ +static const GUID pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX = { STATIC_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX }; + +/* GUID KSMEDIUMSETID_Standard */ +static const GUID pa_KSMEDIUMSETID_Standard = { STATIC_KSMEDIUMSETID_Standard }; + +/* GUID KSINTERFACESETID_Standard */ +static const GUID pa_KSINTERFACESETID_Standard = { STATIC_KSINTERFACESETID_Standard }; + +/* GUID KSPROPSETID_Pin */ +static const GUID pa_KSPROPSETID_Pin = { STATIC_KSPROPSETID_Pin }; #define pa_IS_VALID_WAVEFORMATEX_GUID(Guid)\ (!memcmp(((PUSHORT)&pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX) + 1, ((PUSHORT)(Guid)) + 1, sizeof(GUID) - sizeof(USHORT))) - static PaError WdmGetPinPropertySimple( HANDLE handle, unsigned long pinId, diff --git a/Externals/portaudio/src/os/win/pa_x86_plain_converters.c b/Externals/portaudio/src/os/win/pa_x86_plain_converters.c index 4fcde40cb0..ae43d28cb6 100644 --- a/Externals/portaudio/src/os/win/pa_x86_plain_converters.c +++ b/Externals/portaudio/src/os/win/pa_x86_plain_converters.c @@ -112,6 +112,18 @@ TODO: 0011 1111 1000 0000 0000 0000 0000 0000 => 0x3F800000 */ +#if defined(_WIN64) || defined(_WIN32_WCE) + +/* + -EMT64/AMD64 uses different asm + -VC2005 doesnt allow _WIN64 with inline assembly either! + */ +void PaUtil_InitializeX86PlainConverters( void ) +{ +} + +#else + /* -------------------------------------------------------------------------- */ static const short fpuControlWord_ = 0x033F; /*round to nearest, 64 bit precision, all exceptions masked*/ @@ -130,19 +142,6 @@ static const float const_float_dither_scale_ = PA_FLOAT_DITHER_SCALE_; /* -------------------------------------------------------------------------- */ -#if defined(_WIN64) || defined(_WIN32_WCE) - -/* - -EMT64/AMD64 uses different asm - -VC2005 doesnt allow _WIN64 with inline assembly either! - */ -void PaUtil_InitializeX86PlainConverters( void ) -{ -} - -#else - - static void Float32_To_Int32( void *destinationBuffer, signed int destinationStride, void *sourceBuffer, signed int sourceStride,