PortAudio 2.0
pa_win_wmme.c File Reference

Win32 host API implementation for the Windows MultiMedia Extensions (WMME) audio API. More...

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <windows.h>
#include <mmsystem.h>
#include <process.h>
#include <assert.h>
#include <malloc.h>
#include <memory.h>
#include "portaudio.h"
#include "pa_trace.h"
#include "pa_util.h"
#include "pa_allocation.h"
#include "pa_hostapi.h"
#include "pa_stream.h"
#include "pa_cpuload.h"
#include "pa_process.h"
#include "pa_debugprint.h"
#include "pa_win_wmme.h"
#include "pa_win_waveformat.h"
#include "pa_win_util.h"
#include "pa_win_version.h"

Data Structures

struct  PaWinMmeHostApiRepresentation
 
struct  PaWinMmeDeviceInfo
 
struct  PaWinMmeSingleDirectionHandlesAndBuffers
 
struct  PaWinMmeStream
 

Macros

#define CREATE_THREAD   (HANDLE)_beginthreadex( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId )
 
#define PA_THREAD_FUNC   static unsigned WINAPI
 
#define PA_THREAD_ID   unsigned
 
#define DWORD_PTR   unsigned long
 
#define PA_MME_USE_HIGH_DEFAULT_LATENCY_   (0) /* For debugging glitches. */
 
#define PA_MME_WIN_9X_DEFAULT_LATENCY_   (0.2)
 
#define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_   (2)
 
#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_   (3) /* always use at least 3 input buffers for full duplex */
 
#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_   (2)
 
#define PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_   (16)
 
#define PA_MME_MAX_HOST_BUFFER_SECS_   (0.1) /* Do not exceed unless user buffer exceeds */
 
#define PA_MME_MAX_HOST_BUFFER_BYTES_   (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */
 
#define PA_MME_WIN_NT_DEFAULT_LATENCY_   (0.4)
 
#define PA_MME_WIN_WDM_DEFAULT_LATENCY_   (0.090)
 
#define PA_MME_TARGET_HOST_BUFFER_COUNT_   8
 
#define PA_MME_MIN_TIMEOUT_MSEC_   (1000)
 
#define PA_MME_SET_LAST_WAVEIN_ERROR(mmresult)
 
#define PA_MME_SET_LAST_WAVEOUT_ERROR(mmresult)
 
#define PA_MME_SET_LAST_SYSTEM_ERROR(errorCode)
 
#define PA_ENV_BUF_SIZE_   (32)
 
#define PA_REC_IN_DEV_ENV_NAME_   ("PA_RECOMMENDED_INPUT_DEVICE")
 
#define PA_REC_OUT_DEV_ENV_NAME_   ("PA_RECOMMENDED_OUTPUT_DEVICE")
 
#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_   (13) /* must match array length below */
 
#define DRVM_MAPPER_PREFERRED_GET   (0x2000+21)
 
#define PA_IS_INPUT_STREAM_(stream)
 
#define PA_IS_OUTPUT_STREAM_(stream)
 
#define PA_IS_FULL_DUPLEX_STREAM_(stream)
 
#define PA_IS_HALF_DUPLEX_STREAM_(stream)
 
#define PA_CIRCULAR_INCREMENT_(current, max)
 
#define PA_CIRCULAR_DECREMENT_(current, max)
 

Typedefs

typedef struct PaWinMmeStream PaWinMmeStream
 

Functions

PaError PaWinMme_Initialize (PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index)
 
PA_THREAD_FUNC ProcessingThreadProc (void *pArg)
 
int PaWinMME_GetStreamInputHandleCount (PaStream *s)
 
HWAVEIN PaWinMME_GetStreamInputHandle (PaStream *s, int handleIndex)
 
int PaWinMME_GetStreamOutputHandleCount (PaStream *s)
 
HWAVEOUT PaWinMME_GetStreamOutputHandle (PaStream *s, int handleIndex)
 

Detailed Description

Win32 host API implementation for the Windows MultiMedia Extensions (WMME) audio API.

Macro Definition Documentation

◆ CREATE_THREAD

#define CREATE_THREAD   (HANDLE)_beginthreadex( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId )

◆ DRVM_MAPPER_PREFERRED_GET

#define DRVM_MAPPER_PREFERRED_GET   (0x2000+21)

Referenced by PaWinMme_Initialize().

◆ DWORD_PTR

#define DWORD_PTR   unsigned long

Referenced by PaWinMme_Initialize().

◆ PA_CIRCULAR_DECREMENT_

#define PA_CIRCULAR_DECREMENT_ ( current,
max )
Value:
( ((current) == 0) ? ((max)-1) : (current-1) )

◆ PA_CIRCULAR_INCREMENT_

#define PA_CIRCULAR_INCREMENT_ ( current,
max )
Value:
( (((current) + 1) >= (max)) ? (0) : (current+1) )

◆ PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_

#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_   (13) /* must match array length below */

◆ PA_ENV_BUF_SIZE_

#define PA_ENV_BUF_SIZE_   (32)

◆ PA_IS_FULL_DUPLEX_STREAM_

#define PA_IS_FULL_DUPLEX_STREAM_ ( stream)
Value:
( stream ->input.waveHandles && stream ->output.waveHandles )

Referenced by ProcessingThreadProc().

◆ PA_IS_HALF_DUPLEX_STREAM_

#define PA_IS_HALF_DUPLEX_STREAM_ ( stream)
Value:
( !(stream ->input.waveHandles && stream ->output.waveHandles) )

Referenced by ProcessingThreadProc().

◆ PA_IS_INPUT_STREAM_

#define PA_IS_INPUT_STREAM_ ( stream)
Value:
( stream ->input.waveHandles )

Referenced by PaWinMME_GetStreamInputHandle(), PaWinMME_GetStreamInputHandleCount(), and ProcessingThreadProc().

◆ PA_IS_OUTPUT_STREAM_

#define PA_IS_OUTPUT_STREAM_ ( stream)
Value:
( stream ->output.waveHandles )

Referenced by PaWinMME_GetStreamOutputHandle(), PaWinMME_GetStreamOutputHandleCount(), and ProcessingThreadProc().

◆ PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_

#define PA_MME_HOST_BUFFER_GRANULARITY_FRAMES_WHEN_UNSPECIFIED_   (16)

◆ PA_MME_MAX_HOST_BUFFER_BYTES_

#define PA_MME_MAX_HOST_BUFFER_BYTES_   (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */

◆ PA_MME_MAX_HOST_BUFFER_SECS_

#define PA_MME_MAX_HOST_BUFFER_SECS_   (0.1) /* Do not exceed unless user buffer exceeds */

◆ PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_

#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_   (3) /* always use at least 3 input buffers for full duplex */

◆ PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_

#define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_   (2)

◆ PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_

#define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_   (2)

◆ PA_MME_MIN_TIMEOUT_MSEC_

#define PA_MME_MIN_TIMEOUT_MSEC_   (1000)

◆ PA_MME_SET_LAST_SYSTEM_ERROR

#define PA_MME_SET_LAST_SYSTEM_ERROR ( errorCode)
Value:
PaMme_SetLastSystemError( errorCode )

◆ PA_MME_SET_LAST_WAVEIN_ERROR

#define PA_MME_SET_LAST_WAVEIN_ERROR ( mmresult)
Value:
{ \
wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \
char mmeErrorText[ MAXERRORLENGTH ]; \
waveInGetErrorTextW( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \
WideCharToMultiByte( CP_UTF8, 0, mmeErrorTextWide, -1, \
mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \
PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
}
@ paMME
Definition portaudio.h:281

◆ PA_MME_SET_LAST_WAVEOUT_ERROR

#define PA_MME_SET_LAST_WAVEOUT_ERROR ( mmresult)
Value:
{ \
wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \
char mmeErrorText[ MAXERRORLENGTH ]; \
waveOutGetErrorTextW( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \
WideCharToMultiByte( CP_UTF8, 0, mmeErrorTextWide, -1, \
mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \
PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
}

◆ PA_MME_TARGET_HOST_BUFFER_COUNT_

#define PA_MME_TARGET_HOST_BUFFER_COUNT_   8

◆ PA_MME_USE_HIGH_DEFAULT_LATENCY_

#define PA_MME_USE_HIGH_DEFAULT_LATENCY_   (0) /* For debugging glitches. */

◆ PA_MME_WIN_9X_DEFAULT_LATENCY_

#define PA_MME_WIN_9X_DEFAULT_LATENCY_   (0.2)

◆ PA_MME_WIN_NT_DEFAULT_LATENCY_

#define PA_MME_WIN_NT_DEFAULT_LATENCY_   (0.4)

◆ PA_MME_WIN_WDM_DEFAULT_LATENCY_

#define PA_MME_WIN_WDM_DEFAULT_LATENCY_   (0.090)

◆ PA_REC_IN_DEV_ENV_NAME_

#define PA_REC_IN_DEV_ENV_NAME_   ("PA_RECOMMENDED_INPUT_DEVICE")

◆ PA_REC_OUT_DEV_ENV_NAME_

#define PA_REC_OUT_DEV_ENV_NAME_   ("PA_RECOMMENDED_OUTPUT_DEVICE")

◆ PA_THREAD_FUNC

#define PA_THREAD_FUNC   static unsigned WINAPI

◆ PA_THREAD_ID

#define PA_THREAD_ID   unsigned

Typedef Documentation

◆ PaWinMmeStream

typedef struct PaWinMmeStream PaWinMmeStream

Function Documentation

◆ PaWinMME_GetStreamInputHandle()

HWAVEIN PaWinMME_GetStreamInputHandle ( PaStream * stream,
int handleIndex )

Retrieve a wave in handle used by a PortAudio WinMME stream.

Parameters
streamThe stream to query.
handleIndexThe zero based index of the wave in handle to retrieve. This should be in the range [0, PaWinMME_GetStreamInputHandleCount(stream)-1].
Returns
A valid wave in handle, or NULL if an error occurred.
See also
PaWinMME_GetStreamInputHandle

References PaWinMmeStream::input, PA_IS_INPUT_STREAM_, paNoError, and PaWinMmeSingleDirectionHandlesAndBuffers::waveHandles.

◆ PaWinMME_GetStreamInputHandleCount()

int PaWinMME_GetStreamInputHandleCount ( PaStream * stream)

Retrieve the number of wave in handles used by a PortAudio WinMME stream. Returns zero if the stream is output only.

Returns
A non-negative value indicating the number of wave in handles or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered.
See also
PaWinMME_GetStreamInputHandle

References PaWinMmeSingleDirectionHandlesAndBuffers::deviceCount, PaWinMmeStream::input, PA_IS_INPUT_STREAM_, and paNoError.

◆ PaWinMME_GetStreamOutputHandle()

HWAVEOUT PaWinMME_GetStreamOutputHandle ( PaStream * stream,
int handleIndex )

Retrieve a wave out handle used by a PortAudio WinMME stream.

Parameters
streamThe stream to query.
handleIndexThe zero based index of the wave out handle to retrieve. This should be in the range [0, PaWinMME_GetStreamOutputHandleCount(stream)-1].
Returns
A valid wave out handle, or NULL if an error occurred.
See also
PaWinMME_GetStreamOutputHandleCount

References PaWinMmeStream::output, PA_IS_OUTPUT_STREAM_, paNoError, and PaWinMmeSingleDirectionHandlesAndBuffers::waveHandles.

◆ PaWinMME_GetStreamOutputHandleCount()

int PaWinMME_GetStreamOutputHandleCount ( PaStream * stream)

Retrieve the number of wave out handles used by a PortAudio WinMME stream. Returns zero if the stream is input only.

Returns
A non-negative value indicating the number of wave out handles or, a PaErrorCode (which are always negative) if PortAudio is not initialized or an error is encountered.
See also
PaWinMME_GetStreamOutputHandle

References PaWinMmeSingleDirectionHandlesAndBuffers::deviceCount, PaWinMmeStream::output, PA_IS_OUTPUT_STREAM_, and paNoError.

◆ PaWinMme_Initialize()

PaError PaWinMme_Initialize ( PaUtilHostApiRepresentation ** hostApi,
PaHostApiIndex index )

References PaWinMmeHostApiRepresentation::allocations, PaWinMmeHostApiRepresentation::blockingStreamInterface, PaWinMmeHostApiRepresentation::callbackStreamInterface, PaDeviceInfo::defaultHighInputLatency, PaDeviceInfo::defaultHighOutputLatency, PaDeviceInfo::defaultLowInputLatency, PaDeviceInfo::defaultLowOutputLatency, PaWinMmeDeviceInfo::deviceInputChannelCountIsKnown, PaWinMmeDeviceInfo::deviceOutputChannelCountIsKnown, DRVM_MAPPER_PREFERRED_GET, DWORD_PTR, GetStreamCpuLoad(), GetStreamReadAvailable(), GetStreamTime(), GetStreamWriteAvailable(), PaDeviceInfo::hostApi, PaUtilHostApiRepresentation::info, PaWinMmeDeviceInfo::inheritedDeviceInfo, PaWinMmeHostApiRepresentation::inheritedHostApiRep, PaWinMmeHostApiRepresentation::inputDeviceCount, IsFormatSupported(), IsStreamActive(), IsStreamStopped(), PaDeviceInfo::maxInputChannels, PaDeviceInfo::maxOutputChannels, OpenStream(), PaWinMmeHostApiRepresentation::outputDeviceCount, paInsufficientMemory, paMME, paNoDevice, paNoError, PaUtil_AllocateZeroInitializedMemory(), PaUtil_CreateAllocationGroup(), PaUtil_DestroyAllocationGroup(), PaUtil_DummyGetCpuLoad(), PaUtil_DummyGetReadAvailable(), PaUtil_DummyGetWriteAvailable(), PaUtil_DummyRead(), PaUtil_DummyWrite(), PaUtil_FreeAllAllocations(), PaUtil_FreeMemory(), PaUtil_GroupAllocateZeroInitializedMemory(), PaUtil_InitializeStreamInterface(), ReadStream(), PaDeviceInfo::structVersion, PaHostApiInfo::structVersion, Terminate(), PaWinMmeHostApiRepresentation::winMmeDeviceIds, and WriteStream().

◆ ProcessingThreadProc()

PA_THREAD_FUNC ProcessingThreadProc ( void * pArg)
Todo
support paInputUnderflow, paOutputOverflow and paNeverDropInput
Todo
FIXME/REVIEW: can't return host error info from an asynchronous thread. see http://www.portaudio.com/trac/ticket/143
Todo
if all of the other buffers are also ready then we discard all but the most recent. This is an input buffer overflow. FIXME: these buffers should be passed to the callback in a paNeverDropInput stream. http://www.portaudio.com/trac/ticket/142

note that it is also possible for an input overflow to happen while the callback is processing a buffer. that is handled further down.

Todo
implement inputBufferAdcTime
Todo
FIXME: should probably reset the output device immediately once the callback returns paAbort see: http://www.portaudio.com/trac/ticket/141
Todo
need to handle PaNeverDropInput here where necessary

References PaWinMmeStream::abortEvent, PaWinMmeStream::abortProcessing, PaWinMmeStream::allBuffersDurationMs, PaWinMmeSingleDirectionHandlesAndBuffers::bufferCount, PaWinMmeSingleDirectionHandlesAndBuffers::bufferEvent, PaWinMmeStream::bufferProcessor, PaUtilBufferProcessor::bytesPerHostInputSample, PaUtilBufferProcessor::bytesPerHostOutputSample, PaWinMmeStream::cpuLoadMeasurer, PaWinMmeSingleDirectionHandlesAndBuffers::currentBufferIndex, PaStreamCallbackTimeInfo::currentTime, PaWinMmeSingleDirectionHandlesAndBuffers::deviceCount, FALSE, PaWinMmeSingleDirectionHandlesAndBuffers::framesPerBuffer, PaUtilBufferProcessor::framesPerHostBuffer, PaWinMmeSingleDirectionHandlesAndBuffers::framesUsedInCurrentBuffer, PaWinMmeStream::highThreadPriority, PaWinMmeStream::input, PaWinMmeStream::isActive, PaWinMmeStream::output, PaStreamCallbackTimeInfo::outputBufferDacTime, PA_IS_FULL_DUPLEX_STREAM_, PA_IS_HALF_DUPLEX_STREAM_, PA_IS_INPUT_STREAM_, PA_IS_OUTPUT_STREAM_, paAbort, paContinue, paInputOverflow, paNoError, paOutputUnderflow, paUnanticipatedHostError, PaUtil_BeginBufferProcessing(), PaUtil_BeginCpuLoadMeasurement(), PaUtil_EndBufferProcessing(), PaUtil_EndCpuLoadMeasurement(), PaUtil_GetCpuLoad(), PaUtil_GetTime(), PaUtil_ResetCpuLoadMeasurer(), PaUtil_SetInputFrameCount(), PaUtil_SetInterleavedInputChannels(), PaUtil_SetInterleavedOutputChannels(), PaUtil_SetOutputFrameCount(), PaUtil_ZeroOutput(), PaWinMmeStream::processingThread, PaWinMmeStream::processingThreadPriority, PaUtilBufferProcessor::samplePeriod, PaWinMmeStream::stopProcessing, PaUtilStreamRepresentation::streamFinishedCallback, PaWinMmeStream::streamRepresentation, PaWinMmeStream::throttledSleepMsecs, PaWinMmeStream::throttledThreadPriority, PaWinMmeStream::throttleProcessingThreadOnOverload, PaUtilStreamRepresentation::userData, PaWinMmeSingleDirectionHandlesAndBuffers::waveHandles, and PaWinMmeSingleDirectionHandlesAndBuffers::waveHeaders.