From 1de1b421f97302064ce2e30c7604e185a28da1ee Mon Sep 17 00:00:00 2001 From: rossb Date: Wed, 21 Jan 2009 12:07:32 +0000 Subject: [PATCH] initial support for ac3+wma spdif passthrough for pa_win_wmme. see flags in pa_win_wmme.h. flags currently work for OpenStream but are ignored for IsFormatSupported --- include/pa_win_waveformat.h | 22 ++++++++++++++++++-- include/pa_win_wmme.h | 4 ++++ src/hostapi/dsound/pa_win_ds.c | 12 +++++++---- src/hostapi/wmme/pa_win_wmme.c | 34 ++++++++++++++++++++++++++----- src/os/win/pa_win_waveformat.c | 37 +++++++++++++++------------------- 5 files changed, 77 insertions(+), 32 deletions(-) diff --git a/include/pa_win_waveformat.h b/include/pa_win_waveformat.h index 63bf1c9..dce18c0 100644 --- a/include/pa_win_waveformat.h +++ b/include/pa_win_waveformat.h @@ -157,16 +157,34 @@ typedef struct{ #define PAWIN_INDEXOF_DWCHANNELMASK (PAWIN_SIZEOF_WAVEFORMATEX+2) #define PAWIN_INDEXOF_SUBFORMAT (PAWIN_SIZEOF_WAVEFORMATEX+6) + +/* + Valid values to pass for the waveFormatTag PaWin_InitializeWaveFormatEx and + PaWin_InitializeWaveFormatExtensible functions below. These must match + the standard Windows WAVE_FORMAT_* values. +*/ +#define PAWIN_WAVE_FORMAT_PCM (1) +#define PAWIN_WAVE_FORMAT_IEEE_FLOAT (3) +#define PAWIN_WAVE_FORMAT_DOLBY_AC3_SPDIF (0x0092) +#define PAWIN_WAVE_FORMAT_WMA_SPDIF (0x0164) + + +/* + returns PAWIN_WAVE_FORMAT_PCM or PAWIN_WAVE_FORMAT_IEEE_FLOAT + depending on the sampleFormat parameter. +*/ +int PaWin_SampleFormatToLinearWaveFormatTag( PaSampleFormat sampleFormat ); + /* Use the following two functions to initialize the waveformat structure. */ void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat, - int numChannels, PaSampleFormat sampleFormat, double sampleRate ); + int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate ); void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat, - int numChannels, PaSampleFormat sampleFormat, double sampleRate, + int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate, PaWinWaveFormatChannelMask channelMask ); diff --git a/include/pa_win_wmme.h b/include/pa_win_wmme.h index f7176ab..fa06944 100644 --- a/include/pa_win_wmme.h +++ b/include/pa_win_wmme.h @@ -64,6 +64,10 @@ extern "C" */ #define paWinMmeDontThrottleOverloadedProcessingThread (0x08) +/* flags for non-PCM spdif passthrough */ +#define paWinMmeWaveFormatDolbyAc3Spdif (0x10) +#define paWinMmeWaveFormatWmaSpdif (0x20) + typedef struct PaWinMmeDeviceAndChannelCount{ PaDeviceIndex device; diff --git a/src/hostapi/dsound/pa_win_ds.c b/src/hostapi/dsound/pa_win_ds.c index e872ede..56c45ca 100644 --- a/src/hostapi/dsound/pa_win_ds.c +++ b/src/hostapi/dsound/pa_win_ds.c @@ -1401,12 +1401,14 @@ static HRESULT InitInputBuffer( PaWinDsStream *stream, PaSampleFormat sampleForm // first try WAVEFORMATEXTENSIBLE. if this fails, fall back to WAVEFORMATEX PaWin_InitializeWaveFormatExtensible( &waveFormat, nChannels, - sampleFormat, nFrameRate, channelMask ); + sampleFormat, PaWin_SampleFormatToLinearWaveFormatTag( sampleFormat ), + nFrameRate, channelMask ); if( IDirectSoundCapture_CreateCaptureBuffer( stream->pDirectSoundCapture, &captureDesc, &stream->pDirectSoundInputBuffer, NULL) != DS_OK ) { - PaWin_InitializeWaveFormatEx( &waveFormat, nChannels, sampleFormat, nFrameRate ); + PaWin_InitializeWaveFormatEx( &waveFormat, nChannels, sampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag( sampleFormat ), nFrameRate ); if ((result = IDirectSoundCapture_CreateCaptureBuffer( stream->pDirectSoundCapture, &captureDesc, &stream->pDirectSoundInputBuffer, NULL)) != DS_OK) return result; @@ -1477,11 +1479,13 @@ static HRESULT InitOutputBuffer( PaWinDsStream *stream, PaSampleFormat sampleFor // first try WAVEFORMATEXTENSIBLE. if this fails, fall back to WAVEFORMATEX PaWin_InitializeWaveFormatExtensible( &waveFormat, nChannels, - sampleFormat, nFrameRate, channelMask ); + sampleFormat, PaWin_SampleFormatToLinearWaveFormatTag( sampleFormat ), + nFrameRate, channelMask ); if( IDirectSoundBuffer_SetFormat( pPrimaryBuffer, (WAVEFORMATEX*)&waveFormat) != DS_OK ) { - PaWin_InitializeWaveFormatEx( &waveFormat, nChannels, sampleFormat, nFrameRate ); + PaWin_InitializeWaveFormatEx( &waveFormat, nChannels, sampleFormat, + PaWin_SampleFormatToLinearWaveFormatTag( sampleFormat ), nFrameRate ); if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, (WAVEFORMATEX*)&waveFormat)) != DS_OK) return result; } diff --git a/src/hostapi/wmme/pa_win_wmme.c b/src/hostapi/wmme/pa_win_wmme.c index d5ccdaf..b516c99 100644 --- a/src/hostapi/wmme/pa_win_wmme.c +++ b/src/hostapi/wmme/pa_win_wmme.c @@ -556,12 +556,14 @@ static PaError QueryFormatSupported( PaDeviceInfo *deviceInfo, /* @todo at the moment we only query with 16 bit sample format and directout speaker config*/ PaWin_InitializeWaveFormatExtensible( &waveFormat, channels, - paInt16, sampleRate, PAWIN_SPEAKER_DIRECTOUT ); + paInt16, PaWin_SampleFormatToLinearWaveFormatTag( paInt16 ), + sampleRate, PAWIN_SPEAKER_DIRECTOUT ); if( waveFormatExQueryFunction( winMmeDeviceId, (WAVEFORMATEX*)&waveFormat ) == paNoError ) return paNoError; - PaWin_InitializeWaveFormatEx( &waveFormat, channels, paInt16, sampleRate ); + PaWin_InitializeWaveFormatEx( &waveFormat, channels, paInt16, + PaWin_SampleFormatToLinearWaveFormatTag( paInt16 ), sampleRate ); return waveFormatExQueryFunction( winMmeDeviceId, (WAVEFORMATEX*)&waveFormat ); } @@ -1683,6 +1685,7 @@ typedef struct static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers ); static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi, PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, + unsigned long winMmeSpecificFlags, unsigned long bytesPerHostSample, double sampleRate, PaWinMmeDeviceAndChannelCount *devices, unsigned int deviceCount, PaWinWaveFormatChannelMask channelMask, int isInput ); @@ -1707,6 +1710,7 @@ static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionH static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi, PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, + unsigned long winMmeSpecificFlags, unsigned long bytesPerHostSample, double sampleRate, PaWinMmeDeviceAndChannelCount *devices, unsigned int deviceCount, PaWinWaveFormatChannelMask channelMask, int isInput ) @@ -1714,6 +1718,8 @@ static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostA PaError result; MMRESULT mmresult; signed int i, j; + PaSampleFormat sampleFormat; + int waveFormatTag; /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers() has already been called to zero some fields */ @@ -1741,6 +1747,15 @@ static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostA ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] = 0; } + /* @todo at the moment we only use 16 bit sample format */ + sampleFormat = paInt16; + waveFormatTag = PaWin_SampleFormatToLinearWaveFormatTag( sampleFormat ); + + if( winMmeSpecificFlags & paWinMmeWaveFormatDolbyAc3Spdif ) + waveFormatTag = PAWIN_WAVE_FORMAT_DOLBY_AC3_SPDIF; + else if( winMmeSpecificFlags & paWinMmeWaveFormatWmaSpdif ) + waveFormatTag = PAWIN_WAVE_FORMAT_WMA_SPDIF; + for( i = 0; i < (signed int)deviceCount; ++i ) { PaWinWaveFormat waveFormat; @@ -1756,16 +1771,16 @@ static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostA /* first, attempt to open the device using WAVEFORMATEXTENSIBLE, if this fails we fall back to WAVEFORMATEX */ - /* @todo at the moment we only use 16 bit sample format */ PaWin_InitializeWaveFormatExtensible( &waveFormat, devices[i].channelCount, - paInt16, sampleRate, channelMask ); + sampleFormat, waveFormatTag, sampleRate, channelMask ); } else { /* retry with WAVEFORMATEX */ - PaWin_InitializeWaveFormatEx( &waveFormat, devices[i].channelCount, paInt16, sampleRate ); + PaWin_InitializeWaveFormatEx( &waveFormat, devices[i].channelCount, + sampleFormat, waveFormatTag, sampleRate ); } /* REVIEW: consider not firing an event for input when a full duplex @@ -2070,6 +2085,7 @@ struct PaWinMmeStream static PaError ValidateWinMmeSpecificStreamInfo( const PaStreamParameters *streamParameters, const PaWinMmeStreamInfo *streamInfo, + unsigned long *winMmeSpecificFlags, char *throttleProcessingThreadOnOverload, unsigned long *deviceCount ) { @@ -2081,6 +2097,8 @@ static PaError ValidateWinMmeSpecificStreamInfo( return paIncompatibleHostApiSpecificStreamInfo; } + *winMmeSpecificFlags = streamInfo->flags; + if( streamInfo->flags & paWinMmeDontThrottleOverloadedProcessingThread ) *throttleProcessingThreadOnOverload = 0; @@ -2224,8 +2242,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, unsigned long hostOutputBufferCount; unsigned long framesPerBufferProcessorCall; PaWinMmeDeviceAndChannelCount *inputDevices = 0; /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */ + unsigned long winMmeSpecificInputFlags = 0; unsigned long inputDeviceCount = 0; PaWinMmeDeviceAndChannelCount *outputDevices = 0; + unsigned long winMmeSpecificOutputFlags = 0; unsigned long outputDeviceCount = 0; /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */ char throttleProcessingThreadOnOverload = 1; @@ -2241,6 +2261,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* validate input hostApiSpecificStreamInfo */ inputStreamInfo = (PaWinMmeStreamInfo*)inputParameters->hostApiSpecificStreamInfo; result = ValidateWinMmeSpecificStreamInfo( inputParameters, inputStreamInfo, + &winMmeSpecificInputFlags, &throttleProcessingThreadOnOverload, &inputDeviceCount ); if( result != paNoError ) return result; @@ -2290,6 +2311,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, /* validate output hostApiSpecificStreamInfo */ outputStreamInfo = (PaWinMmeStreamInfo*)outputParameters->hostApiSpecificStreamInfo; result = ValidateWinMmeSpecificStreamInfo( outputParameters, outputStreamInfo, + &winMmeSpecificOutputFlags, &throttleProcessingThreadOnOverload, &outputDeviceCount ); if( result != paNoError ) return result; @@ -2437,6 +2459,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, if( inputParameters ) { result = InitializeWaveHandles( winMmeHostApi, &stream->input, + winMmeSpecificInputFlags, stream->bufferProcessor.bytesPerHostInputSample, sampleRate, inputDevices, inputDeviceCount, inputChannelMask, 1 /* isInput */ ); if( result != paNoError ) goto error; @@ -2445,6 +2468,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, if( outputParameters ) { result = InitializeWaveHandles( winMmeHostApi, &stream->output, + winMmeSpecificOutputFlags, stream->bufferProcessor.bytesPerHostOutputSample, sampleRate, outputDevices, outputDeviceCount, outputChannelMask, 0 /* isInput */ ); if( result != paNoError ) goto error; diff --git a/src/os/win/pa_win_waveformat.c b/src/os/win/pa_win_waveformat.c index 6b91ebd..bbf616c 100644 --- a/src/os/win/pa_win_waveformat.c +++ b/src/os/win/pa_win_waveformat.c @@ -47,30 +47,27 @@ #define WAVE_FORMAT_EXTENSIBLE 0xFFFE #endif -#if !defined(WAVE_FORMAT_IEEE_FLOAT) -#define WAVE_FORMAT_IEEE_FLOAT 0x0003 -#endif - -static GUID pawin_ksDataFormatSubtypePcm = +static GUID pawin_ksDataFormatSubtypeGuidBase = { (USHORT)(WAVE_FORMAT_PCM), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; -static GUID pawin_ksDataFormatSubtypeIeeeFloat = - { (USHORT)(WAVE_FORMAT_IEEE_FLOAT), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; +int PaWin_SampleFormatToLinearWaveFormatTag( PaSampleFormat sampleFormat ) +{ + if( sampleFormat == paFloat32 ) + return PAWIN_WAVE_FORMAT_IEEE_FLOAT; + + return PAWIN_WAVE_FORMAT_PCM; +} void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat, - int numChannels, PaSampleFormat sampleFormat, double sampleRate ) + int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate ) { WAVEFORMATEX *waveFormatEx = (WAVEFORMATEX*)waveFormat; int bytesPerSample = Pa_GetSampleSize(sampleFormat); unsigned long bytesPerFrame = numChannels * bytesPerSample; - - if( sampleFormat == paFloat32 ) - waveFormatEx->wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - else - waveFormatEx->wFormatTag = WAVE_FORMAT_PCM; + waveFormatEx->wFormatTag = waveFormatTag; waveFormatEx->nChannels = (WORD)numChannels; waveFormatEx->nSamplesPerSec = (DWORD)sampleRate; waveFormatEx->nAvgBytesPerSec = waveFormatEx->nSamplesPerSec * bytesPerFrame; @@ -81,12 +78,13 @@ void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat, void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat, - int numChannels, PaSampleFormat sampleFormat, double sampleRate, + int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate, PaWinWaveFormatChannelMask channelMask ) { WAVEFORMATEX *waveFormatEx = (WAVEFORMATEX*)waveFormat; int bytesPerSample = Pa_GetSampleSize(sampleFormat); unsigned long bytesPerFrame = numChannels * bytesPerSample; + GUID guid; waveFormatEx->wFormatTag = WAVE_FORMAT_EXTENSIBLE; waveFormatEx->nChannels = (WORD)numChannels; @@ -100,13 +98,10 @@ void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat, waveFormatEx->wBitsPerSample; *((DWORD*)&waveFormat->fields[PAWIN_INDEXOF_DWCHANNELMASK]) = channelMask; - - if( sampleFormat == paFloat32 ) - *((GUID*)&waveFormat->fields[PAWIN_INDEXOF_SUBFORMAT]) = - pawin_ksDataFormatSubtypeIeeeFloat; - else - *((GUID*)&waveFormat->fields[PAWIN_INDEXOF_SUBFORMAT]) = - pawin_ksDataFormatSubtypePcm; + + guid = pawin_ksDataFormatSubtypeGuidBase; + guid.Data1 = (USHORT)waveFormatTag; + *((GUID*)&waveFormat->fields[PAWIN_INDEXOF_SUBFORMAT]) = guid; } -- 2.43.0