mirror of https://github.com/PCSX2/pcsx2.git
Sync with portaudio r1541 at rama's request.
Too many changes to list here, check portaudio svn log from r1505 to r1541 if you are curious. Hope it works fine. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3879 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
53ebbc0242
commit
d61d46bd7b
|
@ -46,3 +46,5 @@ PaWasapi_GetDeviceRole @57
|
|||
PaWasapi_ThreadPriorityBoost @58
|
||||
PaWasapi_ThreadPriorityRevert @59
|
||||
PaWasapi_GetFramesPerHostBuffer @60
|
||||
PaWasapi_GetJackDescription @61
|
||||
PaWasapi_GetJackCount @62
|
|
@ -42,3 +42,5 @@ PaWasapi_GetDeviceRole @57
|
|||
PaWasapi_ThreadPriorityBoost @58
|
||||
PaWasapi_ThreadPriorityRevert @59
|
||||
PaWasapi_GetFramesPerHostBuffer @60
|
||||
PaWasapi_GetJackDescription @61
|
||||
PaWasapi_GetJackCount @62
|
|
@ -0,0 +1,109 @@
|
|||
Hello
|
||||
|
||||
This is a small list of steps in order to build portaudio
|
||||
(Currently v19-devel) into a VC6 DLL and lib file.
|
||||
This DLL contains all 3 current win32 PA APIS (MM/DS/ASIO)
|
||||
|
||||
1)Copy the source dirs that comes with the ASIO SDK inside src\hostapi\asio\ASIOSDK
|
||||
so you should now have example:
|
||||
|
||||
portaudio19svn\src\hostapi\asio\ASIOSDK\common
|
||||
portaudio19svn\src\hostapi\asio\ASIOSDK\host
|
||||
portaudio19svn\src\hostapi\asio\ASIOSDK\host\sample
|
||||
portaudio19svn\src\hostapi\asio\ASIOSDK\host\pc
|
||||
portaudio19svn\src\hostapi\asio\ASIOSDK\host\mac (not needed)
|
||||
|
||||
You dont need "driver"
|
||||
|
||||
To build without ASIO (or another Host API) see the "Building without ASIO support" section below.
|
||||
|
||||
2)
|
||||
*If you have Visual Studio 6.0*, please make sure you have it updated with the latest (and final)
|
||||
microsoft libraries for it, namely:
|
||||
|
||||
Service pack 5:
|
||||
Latest known URL:
|
||||
http://msdn2.microsoft.com/en-us/vstudio/aa718363.aspx
|
||||
Yes there EXISTS a service pack 6 , but the processor pack (below) isnt compatible with it.
|
||||
|
||||
Processor Pack(only works with above SP5)
|
||||
Latest known URL:
|
||||
http://msdn2.microsoft.com/en-us/vstudio/Aa718349.aspx
|
||||
This isnt absolutely required for portaudio, but if you plan on using SSE intrinsics and similar things.
|
||||
Up to you to decide upon Service pack 5 or 6 depending on your need for intrinsics.
|
||||
|
||||
Platform SDK (Feb 2003) :
|
||||
Latest known URL:
|
||||
http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm
|
||||
(This will allow your code base to be x64 friendly, with correct defines
|
||||
for LONG_PTR and such)
|
||||
NOTE A) Yes you have to use IE activex scripts to install that - wont work in Firefox, you
|
||||
may have to temporarily change tyour default browser(aint life unfair)
|
||||
NOTE B) Dont forget to hit "Register PSDK Directories with Visual Studio".
|
||||
you can make sure its right in VC6 if you open tools/options/directories/include files and you see SDK 2003 as the FIRST entry
|
||||
(it must be the same for libs)
|
||||
|
||||
DirectX 9.0 SDK Update - (Summer 2003)
|
||||
Latest known URL:
|
||||
http://www.microsoft.com/downloads/details.aspx?familyid=9216652f-51e0-402e-b7b5-feb68d00f298&displaylang=en
|
||||
Again register the links in VC6, and check inside vc6 if headers are in second place right after SDk 2003
|
||||
|
||||
*If you have 7.0(VC.NET/2001) or 7.1(VC.2003) *
|
||||
then I suggest you open portaudio.dsp (and convert if needed)
|
||||
|
||||
*If you have Visual Studio 2005*, I suggest you open the portaudio.sln file
|
||||
which contains 4 configurations. Win32/x64 in both Release and Debug variants
|
||||
|
||||
hit compile and hope for the best.
|
||||
|
||||
3)Now in any project, in which you require portaudio,
|
||||
you can just link with portaudio_x86.lib, (or _x64) and of course include the
|
||||
relevant headers
|
||||
(portaudio.h, and/or pa_asio.h , pa_x86_plain_converters.h) See (*)
|
||||
|
||||
4) Your new exe should now use portaudio_xXX.dll.
|
||||
|
||||
|
||||
Have fun!
|
||||
|
||||
(*): you may want to add/remove some DLL entry points.
|
||||
Right now those 6 entries are _not_ from portaudio.h
|
||||
|
||||
(from portaudio.def)
|
||||
(...)
|
||||
PaAsio_GetAvailableLatencyValues @50
|
||||
PaAsio_ShowControlPanel @51
|
||||
PaUtil_InitializeX86PlainConverters @52
|
||||
PaAsio_GetInputChannelName @53
|
||||
PaAsio_GetOutputChannelName @54
|
||||
PaUtil_SetLogPrintFunction @55
|
||||
|
||||
|
||||
*** Building without ASIO support ***
|
||||
|
||||
To build PortAudio without ASIO support you need to:
|
||||
A. Make sure your project doesn't try to build any ASIO SDK files.
|
||||
If you're using one of the shipped projects, remove the ASIO related files
|
||||
from the project.
|
||||
|
||||
B. Make sure your project doesn't try to build the PortAudio ASIO
|
||||
implementation files:
|
||||
src/hostapi/pa_asio.cpp src/hostapi/iasiothiscallresolver.cpp
|
||||
If you're using one of the shipped projects remove them from the project.
|
||||
|
||||
C. Define the PA_NO_ASIO preprocessor symbol in the project properties.
|
||||
In VS2005 this can be added under
|
||||
Project Properties > Configuration Properties > C/C++ > Preprocessor > Preprocessor Definitions
|
||||
|
||||
Defining PA_NO_ASIO stops src/os/win/pa_win_hostapis.c
|
||||
from trying to initialize the PA ASIO implementation.
|
||||
|
||||
D. Remove PaAsio_* entry points from portaudio.def
|
||||
|
||||
A similar procedure can be used to omit any of the other host APIs from the
|
||||
build. The relevant preprocessor symbols used by pa_win_hostapis.c are:
|
||||
PA_NO_WMME, PA_NO_DS, PA_NO_ASIO, PA_NO_WASAPI and PA_NO_WDMKS
|
||||
|
||||
|
||||
-----
|
||||
David Viens, davidv@plogue.com
|
|
@ -109,6 +109,70 @@ typedef enum PaWasapiDeviceRole
|
|||
PaWasapiDeviceRole;
|
||||
|
||||
|
||||
/* Jack connection type */
|
||||
typedef enum PaWasapiJackConnectionType
|
||||
{
|
||||
eJackConnTypeUnknown,
|
||||
eJackConnType3Point5mm,
|
||||
eJackConnTypeQuarter,
|
||||
eJackConnTypeAtapiInternal,
|
||||
eJackConnTypeRCA,
|
||||
eJackConnTypeOptical,
|
||||
eJackConnTypeOtherDigital,
|
||||
eJackConnTypeOtherAnalog,
|
||||
eJackConnTypeMultichannelAnalogDIN,
|
||||
eJackConnTypeXlrProfessional,
|
||||
eJackConnTypeRJ11Modem,
|
||||
eJackConnTypeCombination
|
||||
}
|
||||
PaWasapiJackConnectionType;
|
||||
|
||||
|
||||
/* Jack geometric location */
|
||||
typedef enum PaWasapiJackGeoLocation
|
||||
{
|
||||
eJackGeoLocUnk = 0,
|
||||
eJackGeoLocRear = 0x1, /* matches EPcxGeoLocation::eGeoLocRear */
|
||||
eJackGeoLocFront,
|
||||
eJackGeoLocLeft,
|
||||
eJackGeoLocRight,
|
||||
eJackGeoLocTop,
|
||||
eJackGeoLocBottom,
|
||||
eJackGeoLocRearPanel,
|
||||
eJackGeoLocRiser,
|
||||
eJackGeoLocInsideMobileLid,
|
||||
eJackGeoLocDrivebay,
|
||||
eJackGeoLocHDMI,
|
||||
eJackGeoLocOutsideMobileLid,
|
||||
eJackGeoLocATAPI,
|
||||
eJackGeoLocReserved5,
|
||||
eJackGeoLocReserved6,
|
||||
}
|
||||
PaWasapiJackGeoLocation;
|
||||
|
||||
|
||||
/* Jack general location */
|
||||
typedef enum PaWasapiJackGenLocation
|
||||
{
|
||||
eJackGenLocPrimaryBox = 0,
|
||||
eJackGenLocInternal,
|
||||
eJackGenLocSeparate,
|
||||
eJackGenLocOther
|
||||
}
|
||||
PaWasapiJackGenLocation;
|
||||
|
||||
|
||||
/* Jack's type of port */
|
||||
typedef enum PaWasapiJackPortConnection
|
||||
{
|
||||
eJackPortConnJack = 0,
|
||||
eJackPortConnIntegratedDevice,
|
||||
eJackPortConnBothIntegratedAndJack,
|
||||
eJackPortConnUnknown
|
||||
}
|
||||
PaWasapiJackPortConnection;
|
||||
|
||||
|
||||
/* Thread priority */
|
||||
typedef enum PaWasapiThreadPriority
|
||||
{
|
||||
|
@ -124,6 +188,20 @@ typedef enum PaWasapiThreadPriority
|
|||
PaWasapiThreadPriority;
|
||||
|
||||
|
||||
/* Stream descriptor. */
|
||||
typedef struct PaWasapiJackDescription
|
||||
{
|
||||
unsigned long channelMapping;
|
||||
unsigned long color; /* derived from macro: #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16))) */
|
||||
PaWasapiJackConnectionType connectionType;
|
||||
PaWasapiJackGeoLocation geoLocation;
|
||||
PaWasapiJackGenLocation genLocation;
|
||||
PaWasapiJackPortConnection portConnection;
|
||||
unsigned int isConnected;
|
||||
}
|
||||
PaWasapiJackDescription;
|
||||
|
||||
|
||||
/* Stream descriptor. */
|
||||
typedef struct PaWasapiStreamInfo
|
||||
{
|
||||
|
@ -223,6 +301,31 @@ PaError PaWasapi_ThreadPriorityRevert( void *hTask );
|
|||
PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput, unsigned int *nOutput );
|
||||
|
||||
|
||||
/** 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.
|
||||
@param nDevice device index.
|
||||
@param jcount Number of jacks is returned in this variable
|
||||
@return Error code indicating success or failure
|
||||
@see PaWasapi_GetJackDescription
|
||||
*/
|
||||
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.
|
||||
@param nDevice device index.
|
||||
@param jindex Which jack to return information
|
||||
@param KSJACK_DESCRIPTION This structure filled in on success.
|
||||
@return Error code indicating success or failure
|
||||
@see PaWasapi_GetJackCount
|
||||
*/
|
||||
PaError PaWasapi_GetJackDescription(PaDeviceIndex nDevice, int jindex, PaWasapiJackDescription *pJackDescription);
|
||||
|
||||
|
||||
/*
|
||||
IMPORTANT:
|
||||
|
||||
|
@ -243,8 +346,8 @@ PaError PaWasapi_GetFramesPerHostBuffer( PaStream *pStream, unsigned int *nInput
|
|||
1) Event-Driven:
|
||||
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
|
||||
usually - 1.4(Vista only)-3ms(Windows 7+) for HD Audio class audio chips. For the
|
||||
Shared mode latency can not be lower than 20ms.
|
||||
3 ms for HD Audio class audio chips. For the Shared mode latency can not be
|
||||
lower than 20 ms.
|
||||
|
||||
2) Poll-Driven:
|
||||
Polling is another 2-nd method to operate with WASAPI. It is less efficient than Event-Driven
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id: pa_process.c 1408 2009-03-13 16:41:39Z rossb $
|
||||
* $Id: pa_process.c 1523 2010-07-10 17:41:25Z dmitrykos $
|
||||
* Portable Audio I/O Library
|
||||
* streamCallback <-> host buffer processing adapter
|
||||
*
|
||||
|
@ -264,6 +264,9 @@ PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
|
|||
|
||||
bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
|
||||
|
||||
bp->hostInputIsInterleaved = (hostInputSampleFormat & paNonInterleaved)?0:1;
|
||||
|
||||
bp->userInputSampleFormatIsEqualToHost = ((userInputSampleFormat & ~paNonInterleaved) == (hostInputSampleFormat & ~paNonInterleaved));
|
||||
|
||||
tempInputBufferSize =
|
||||
bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;
|
||||
|
@ -331,6 +334,10 @@ PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
|
|||
|
||||
bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;
|
||||
|
||||
bp->hostOutputIsInterleaved = (hostOutputSampleFormat & paNonInterleaved)?0:1;
|
||||
|
||||
bp->userOutputSampleFormatIsEqualToHost = ((userOutputSampleFormat & ~paNonInterleaved) == (hostOutputSampleFormat & ~paNonInterleaved));
|
||||
|
||||
tempOutputBufferSize =
|
||||
bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;
|
||||
|
||||
|
@ -495,6 +502,7 @@ void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,
|
|||
|
||||
assert( firstChannel < bp->inputChannelCount );
|
||||
assert( firstChannel + channelCount <= bp->inputChannelCount );
|
||||
assert( bp->hostInputIsInterleaved );
|
||||
|
||||
for( i=0; i< channelCount; ++i )
|
||||
{
|
||||
|
@ -509,6 +517,7 @@ void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
|
|||
unsigned int channel, void *data )
|
||||
{
|
||||
assert( channel < bp->inputChannelCount );
|
||||
assert( !bp->hostInputIsInterleaved );
|
||||
|
||||
bp->hostInputChannels[0][channel].data = data;
|
||||
bp->hostInputChannels[0][channel].stride = 1;
|
||||
|
@ -544,6 +553,7 @@ void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,
|
|||
|
||||
assert( firstChannel < bp->inputChannelCount );
|
||||
assert( firstChannel + channelCount <= bp->inputChannelCount );
|
||||
assert( bp->hostInputIsInterleaved );
|
||||
|
||||
for( i=0; i< channelCount; ++i )
|
||||
{
|
||||
|
@ -558,6 +568,7 @@ void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
|
|||
unsigned int channel, void *data )
|
||||
{
|
||||
assert( channel < bp->inputChannelCount );
|
||||
assert( !bp->hostInputIsInterleaved );
|
||||
|
||||
bp->hostInputChannels[1][channel].data = data;
|
||||
bp->hostInputChannels[1][channel].stride = 1;
|
||||
|
@ -605,6 +616,7 @@ void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
|
|||
|
||||
assert( firstChannel < bp->outputChannelCount );
|
||||
assert( firstChannel + channelCount <= bp->outputChannelCount );
|
||||
assert( bp->hostOutputIsInterleaved );
|
||||
|
||||
for( i=0; i< channelCount; ++i )
|
||||
{
|
||||
|
@ -618,6 +630,7 @@ void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
|
|||
unsigned int channel, void *data )
|
||||
{
|
||||
assert( channel < bp->outputChannelCount );
|
||||
assert( !bp->hostOutputIsInterleaved );
|
||||
|
||||
PaUtil_SetOutputChannel( bp, channel, data, 1 );
|
||||
}
|
||||
|
@ -653,6 +666,7 @@ void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
|
|||
|
||||
assert( firstChannel < bp->outputChannelCount );
|
||||
assert( firstChannel + channelCount <= bp->outputChannelCount );
|
||||
assert( bp->hostOutputIsInterleaved );
|
||||
|
||||
for( i=0; i< channelCount; ++i )
|
||||
{
|
||||
|
@ -666,6 +680,7 @@ void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
|
|||
unsigned int channel, void *data )
|
||||
{
|
||||
assert( channel < bp->outputChannelCount );
|
||||
assert( !bp->hostOutputIsInterleaved );
|
||||
|
||||
PaUtil_Set2ndOutputChannel( bp, channel, data, 1 );
|
||||
}
|
||||
|
@ -722,6 +737,8 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
unsigned long frameCount;
|
||||
unsigned long framesToGo = framesToProcess;
|
||||
unsigned long framesProcessed = 0;
|
||||
int skipOutputConvert = 0;
|
||||
int skipInputConvert = 0;
|
||||
|
||||
|
||||
if( *streamCallbackResult == paContinue )
|
||||
|
@ -738,10 +755,6 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
}
|
||||
else /* there are input channels */
|
||||
{
|
||||
/*
|
||||
could use more elaborate logic here and sometimes process
|
||||
buffers in-place.
|
||||
*/
|
||||
|
||||
destBytePtr = (unsigned char *)bp->tempInputBuffer;
|
||||
|
||||
|
@ -749,19 +762,41 @@ 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 )
|
||||
{
|
||||
userInput = hostInputChannels[0].data;
|
||||
destBytePtr = (unsigned char *)hostInputChannels[0].data;
|
||||
skipInputConvert = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
userInput = bp->tempInputBuffer;
|
||||
}
|
||||
}
|
||||
else /* user input is not interleaved */
|
||||
{
|
||||
destSampleStrideSamples = 1;
|
||||
destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample;
|
||||
|
||||
/* setup non-interleaved ptrs */
|
||||
if( bp->userInputSampleFormatIsEqualToHost && !bp->hostInputIsInterleaved )
|
||||
{
|
||||
for( i=0; i<bp->inputChannelCount; ++i )
|
||||
{
|
||||
bp->tempInputBufferPtrs[i] = hostInputChannels[i].data;
|
||||
}
|
||||
skipInputConvert = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i=0; i<bp->inputChannelCount; ++i )
|
||||
{
|
||||
bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
|
||||
i * bp->bytesPerUserInputSample * frameCount;
|
||||
}
|
||||
}
|
||||
|
||||
userInput = bp->tempInputBufferPtrs;
|
||||
}
|
||||
|
@ -777,6 +812,17 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( skipInputConvert )
|
||||
{
|
||||
for( i=0; i<bp->inputChannelCount; ++i )
|
||||
{
|
||||
/* advance src ptr for next iteration */
|
||||
hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
|
||||
frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i=0; i<bp->inputChannelCount; ++i )
|
||||
|
@ -794,6 +840,7 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* configure user output buffer */
|
||||
if( bp->outputChannelCount == 0 )
|
||||
|
@ -804,16 +851,36 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
else /* there are output channels */
|
||||
{
|
||||
if( bp->userOutputIsInterleaved )
|
||||
{
|
||||
/* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved */
|
||||
if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved )
|
||||
{
|
||||
userOutput = hostOutputChannels[0].data;
|
||||
skipOutputConvert = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
userOutput = bp->tempOutputBuffer;
|
||||
}
|
||||
}
|
||||
else /* user output is not interleaved */
|
||||
{
|
||||
if( bp->userOutputSampleFormatIsEqualToHost && !bp->hostOutputIsInterleaved )
|
||||
{
|
||||
for( i=0; i<bp->outputChannelCount; ++i )
|
||||
{
|
||||
bp->tempOutputBufferPtrs[i] = hostOutputChannels[i].data;
|
||||
}
|
||||
skipOutputConvert = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i=0; i<bp->outputChannelCount; ++i )
|
||||
{
|
||||
bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
|
||||
i * bp->bytesPerUserOutputSample * frameCount;
|
||||
}
|
||||
}
|
||||
|
||||
userOutput = bp->tempOutputBufferPtrs;
|
||||
}
|
||||
|
@ -836,10 +903,17 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
|
||||
if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
|
||||
{
|
||||
/*
|
||||
could use more elaborate logic here and sometimes process
|
||||
buffers in-place.
|
||||
*/
|
||||
if( skipOutputConvert )
|
||||
{
|
||||
for( i=0; i<bp->outputChannelCount; ++i )
|
||||
{
|
||||
/* advance dest ptr for next iteration */
|
||||
hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
|
||||
frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
srcBytePtr = (unsigned char *)bp->tempOutputBuffer;
|
||||
|
||||
|
@ -868,6 +942,7 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
|
|||
frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
framesProcessed += frameCount;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef PA_PROCESS_H
|
||||
#define PA_PROCESS_H
|
||||
/*
|
||||
* $Id: pa_process.h 1097 2006-08-26 08:27:53Z rossb $
|
||||
* $Id: pa_process.h 1523 2010-07-10 17:41:25Z dmitrykos $
|
||||
* Portable Audio I/O Library callback buffer processing adapters
|
||||
*
|
||||
* Based on the Open Source API proposed by Ross Bencina
|
||||
|
@ -256,6 +256,8 @@ typedef struct {
|
|||
|
||||
PaUtilHostBufferSizeMode hostBufferSizeMode;
|
||||
int useNonAdaptingProcess;
|
||||
int userOutputSampleFormatIsEqualToHost;
|
||||
int userInputSampleFormatIsEqualToHost;
|
||||
unsigned long framesPerTempBuffer;
|
||||
|
||||
unsigned int inputChannelCount;
|
||||
|
@ -287,12 +289,14 @@ typedef struct {
|
|||
|
||||
PaStreamCallbackFlags callbackStatusFlags;
|
||||
|
||||
int hostInputIsInterleaved;
|
||||
unsigned long hostInputFrameCount[2];
|
||||
PaUtilChannelDescriptor *hostInputChannels[2]; /**< pointers to arrays of channel descriptors.
|
||||
pointers are NULL for half-duplex output processing.
|
||||
hostInputChannels[i].data is NULL when the caller
|
||||
calls PaUtil_SetNoInput()
|
||||
*/
|
||||
int hostOutputIsInterleaved;
|
||||
unsigned long hostOutputFrameCount[2];
|
||||
PaUtilChannelDescriptor *hostOutputChannels[2]; /**< pointers to arrays of channel descriptors.
|
||||
pointers are NULL for half-duplex input processing.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id: pa_linux_alsa.c 1415 2009-06-03 18:57:56Z aknudsen $
|
||||
* $Id: pa_linux_alsa.c 1540 2010-09-20 16:23:30Z dmitrykos $
|
||||
* PortAudio Portable Real-Time Audio Library
|
||||
* Latest Version at: http://www.portaudio.com
|
||||
* ALSA implementation by Joshua Haberman and Arve Knudsen
|
||||
|
@ -1257,6 +1257,10 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se
|
|||
/* test if MMAP supported */
|
||||
self->canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ||
|
||||
snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0;
|
||||
|
||||
PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, (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__, (snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO")));
|
||||
|
||||
if (!self->canMmap)
|
||||
{
|
||||
accessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
|
||||
|
@ -1271,12 +1275,17 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se
|
|||
/* test if MMAP supported */
|
||||
self->canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ||
|
||||
snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0;
|
||||
|
||||
PA_DEBUG(("%s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, (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__, (snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO")));
|
||||
|
||||
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")));
|
||||
|
||||
/* If requested access mode fails, try alternate mode */
|
||||
|
@ -1465,6 +1474,40 @@ static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frame
|
|||
return (int)ceil( 1000 * frames / stream->streamRepresentation.streamInfo.sampleRate );
|
||||
}
|
||||
|
||||
/** Align value in backward direction.
|
||||
*
|
||||
* @param v: Value to align.
|
||||
* @param align: Alignment.
|
||||
*/
|
||||
static unsigned long PaAlsa_AlignBackward(unsigned long v, unsigned long align)
|
||||
{
|
||||
return ((v - (align ? v % align : 0)));
|
||||
}
|
||||
|
||||
/** Align value in forward direction.
|
||||
*
|
||||
* @param v: Value to align.
|
||||
* @param align: Alignment.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/** Get size of host buffer maintained from the number of user frames, sample rate and suggested latency. Minimum double buffering
|
||||
* is maintained to allow 100% CPU usage inside user callback.
|
||||
*
|
||||
* @param userFramesPerBuffer: User buffer size in number of frames.
|
||||
* @param suggestedLatency: User provided desired latency.
|
||||
* @param sampleRate: Sample rate.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/** Determine size per host buffer.
|
||||
*
|
||||
* During this method call, the component's framesPerBuffer attribute gets computed, and the corresponding period size
|
||||
|
@ -1475,18 +1518,20 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo
|
|||
unsigned long framesPerUserBuffer, double sampleRate, snd_pcm_hw_params_t* hwParams, int* accurate )
|
||||
{
|
||||
PaError result = paNoError;
|
||||
unsigned long bufferSize = params->suggestedLatency * sampleRate, framesPerHostBuffer;
|
||||
unsigned long bufferSize, framesPerHostBuffer;
|
||||
int dir = 0;
|
||||
|
||||
{
|
||||
snd_pcm_uframes_t tmp;
|
||||
snd_pcm_hw_params_get_buffer_size_min( hwParams, &tmp );
|
||||
bufferSize = PA_MAX( bufferSize, tmp );
|
||||
snd_pcm_hw_params_get_buffer_size_max( hwParams, &tmp );
|
||||
bufferSize = PA_MIN( bufferSize, tmp );
|
||||
}
|
||||
/* Calculate host buffer size */
|
||||
bufferSize = PaAlsa_GetFramesPerHostBuffer(framesPerUserBuffer, params->suggestedLatency, sampleRate);
|
||||
|
||||
assert( bufferSize > 0 );
|
||||
/* Log */
|
||||
PA_DEBUG(( "%s: user-buffer (frames) = %lu\n", __FUNCTION__, framesPerUserBuffer ));
|
||||
PA_DEBUG(( "%s: user-buffer (sec) = %f\n", __FUNCTION__, (double)(framesPerUserBuffer / sampleRate) ));
|
||||
PA_DEBUG(( "%s: suggested latency (sec) = %f\n", __FUNCTION__, params->suggestedLatency ));
|
||||
PA_DEBUG(( "%s: suggested host buffer (frames) = %lu\n", __FUNCTION__, bufferSize ));
|
||||
PA_DEBUG(( "%s: suggested host buffer (sec) = %f\n", __FUNCTION__, (double)(bufferSize / sampleRate) ));
|
||||
|
||||
#ifdef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC
|
||||
|
||||
if( framesPerUserBuffer != paFramesPerBufferUnspecified )
|
||||
{
|
||||
|
@ -1528,15 +1573,62 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo
|
|||
}
|
||||
}
|
||||
|
||||
/* Using the base number of periods, we try to approximate the suggested latency (+1 period),
|
||||
finding a combination of period/buffer size which best fits these constraints */
|
||||
#endif
|
||||
|
||||
{
|
||||
unsigned numPeriods = numPeriods_, maxPeriods = 0;
|
||||
unsigned numPeriods = numPeriods_, maxPeriods = 0, minPeriods = numPeriods_;
|
||||
|
||||
/* It may be that the device only supports 2 periods for instance */
|
||||
dir = 0;
|
||||
ENSURE_( snd_pcm_hw_params_get_periods_min( hwParams, &minPeriods, &dir ), paUnanticipatedHostError )
|
||||
ENSURE_( snd_pcm_hw_params_get_periods_max( hwParams, &maxPeriods, &dir ), paUnanticipatedHostError );
|
||||
assert( maxPeriods > 1 );
|
||||
numPeriods = PA_MIN( maxPeriods, numPeriods );
|
||||
|
||||
/* Clamp to min/max */
|
||||
numPeriods = PA_MIN(maxPeriods, PA_MAX(minPeriods, numPeriods));
|
||||
|
||||
PA_DEBUG(( "%s: periods min = %lu, max = %lu, req = %lu \n", __FUNCTION__, minPeriods, maxPeriods, numPeriods ));
|
||||
|
||||
#ifndef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC
|
||||
|
||||
/* Calculate period size */
|
||||
framesPerHostBuffer = (bufferSize / numPeriods);
|
||||
|
||||
/* Align & test size */
|
||||
if( framesPerUserBuffer != paFramesPerBufferUnspecified )
|
||||
{
|
||||
/* Align to user buffer size */
|
||||
framesPerHostBuffer = PaAlsa_AlignForward(framesPerHostBuffer, framesPerUserBuffer);
|
||||
|
||||
/* Test (borrowed from older implementation) */
|
||||
if( framesPerHostBuffer < framesPerUserBuffer )
|
||||
{
|
||||
assert( framesPerUserBuffer % framesPerHostBuffer == 0 );
|
||||
if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
|
||||
{
|
||||
if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 )
|
||||
framesPerHostBuffer *= 2;
|
||||
else
|
||||
if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 )
|
||||
framesPerHostBuffer /= 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( framesPerHostBuffer % framesPerUserBuffer == 0 );
|
||||
if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
|
||||
{
|
||||
if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 )
|
||||
framesPerHostBuffer += framesPerUserBuffer;
|
||||
else
|
||||
if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 )
|
||||
framesPerHostBuffer -= framesPerUserBuffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC
|
||||
|
||||
if( framesPerUserBuffer != paFramesPerBufferUnspecified )
|
||||
{
|
||||
|
@ -1594,41 +1686,49 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo
|
|||
{
|
||||
framesPerHostBuffer = bufferSize / numPeriods;
|
||||
}
|
||||
}
|
||||
|
||||
/* non-mmap mode needs a reasonably-sized buffer or it'll stutter */
|
||||
if( !self->canMmap && framesPerHostBuffer < 2048 )
|
||||
framesPerHostBuffer = 2048;
|
||||
#endif
|
||||
PA_DEBUG(( "%s: suggested host buffer period = %lu \n", __FUNCTION__, framesPerHostBuffer ));
|
||||
}
|
||||
|
||||
assert( framesPerHostBuffer > 0 );
|
||||
{
|
||||
snd_pcm_uframes_t min = 0, max = 0;
|
||||
/* Get min/max period sizes and adjust our chosen */
|
||||
snd_pcm_uframes_t min = 0, max = 0, minmax_diff;
|
||||
ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParams, &min, NULL ), paUnanticipatedHostError );
|
||||
ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParams, &max, NULL ), paUnanticipatedHostError );
|
||||
minmax_diff = max - min;
|
||||
|
||||
if( framesPerHostBuffer < min )
|
||||
{
|
||||
PA_DEBUG(( "%s: The determined period size (%lu) is less than minimum (%lu)\n", __FUNCTION__,
|
||||
framesPerHostBuffer, min ));
|
||||
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);
|
||||
}
|
||||
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 = 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);
|
||||
}
|
||||
|
||||
assert( framesPerHostBuffer >= min && framesPerHostBuffer <= 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) ));
|
||||
|
||||
/* Try setting period size */
|
||||
dir = 0;
|
||||
ENSURE_( snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ),
|
||||
paUnanticipatedHostError );
|
||||
ENSURE_( snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ), paUnanticipatedHostError );
|
||||
if( dir != 0 )
|
||||
{
|
||||
PA_DEBUG(( "%s: The configured period size is non-integer.\n", __FUNCTION__, dir ));
|
||||
*accurate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set result */
|
||||
self->framesPerBuffer = framesPerHostBuffer;
|
||||
|
||||
error:
|
||||
|
@ -1996,8 +2096,8 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
|
||||
PA_ENSURE( PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerBuffer,
|
||||
&inputLatency, &outputLatency, &hostBufferSizeMode ) );
|
||||
hostInputSampleFormat = stream->capture.hostSampleFormat;
|
||||
hostOutputSampleFormat = stream->playback.hostSampleFormat;
|
||||
hostInputSampleFormat = stream->capture.hostSampleFormat | (!stream->capture.hostInterleaved ? paNonInterleaved : 0);
|
||||
hostOutputSampleFormat = stream->playback.hostSampleFormat | (!stream->playback.hostInterleaved ? paNonInterleaved : 0);
|
||||
|
||||
PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
|
||||
numInputChannels, inputSampleFormat, hostInputSampleFormat,
|
||||
|
@ -2013,6 +2113,8 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
stream->streamRepresentation.streamInfo.outputLatency = outputLatency + (PaTime)(
|
||||
PaUtil_GetBufferProcessorOutputLatency( &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));
|
||||
|
||||
*s = (PaStream*)stream;
|
||||
|
||||
return result;
|
||||
|
@ -2032,9 +2134,6 @@ static PaError CloseStream( PaStream* s )
|
|||
PaError result = paNoError;
|
||||
PaAlsaStream *stream = (PaAlsaStream*)s;
|
||||
|
||||
free(stream->playback.nonMmapBuffer);
|
||||
free(stream->capture.nonMmapBuffer);
|
||||
|
||||
PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
|
||||
PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
|
||||
|
||||
|
@ -2345,6 +2444,7 @@ static double GetStreamCpuLoad( PaStream* s )
|
|||
|
||||
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;
|
||||
|
@ -2362,7 +2462,24 @@ static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwPara
|
|||
dir = 1;
|
||||
}
|
||||
|
||||
return snd_pcm_hw_params_set_rate( pcm, hwParams, approx, dir );
|
||||
if( snd_pcm_hw_params_set_rate( pcm, hwParams, approx, dir ) < 0)
|
||||
result = paInvalidSampleRate;
|
||||
|
||||
end:
|
||||
|
||||
return result;
|
||||
|
||||
error:
|
||||
|
||||
/* Log */
|
||||
{
|
||||
unsigned int _min = 0, _max = 0; int _dir = 0;
|
||||
ENSURE_( snd_pcm_hw_params_get_rate_min( hwParams, &_min, &_dir ), paUnanticipatedHostError );
|
||||
ENSURE_( 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 ));
|
||||
}
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Return exact sample rate in param sampleRate */
|
||||
|
@ -2987,6 +3104,8 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
|
|||
/* not else ! */
|
||||
if (timeouts >= 64) /* audio device not working, shall return error to notify waiters */
|
||||
{
|
||||
*framesAvail = 0; /* no frames available for processing */
|
||||
|
||||
PA_DEBUG(( "%s: poll timed out, returning error\n", __FUNCTION__, timeouts ));
|
||||
PA_ENSURE( paTimedOut );
|
||||
}
|
||||
|
@ -3113,11 +3232,7 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se
|
|||
}
|
||||
else
|
||||
{
|
||||
/* using realloc for optimisation
|
||||
free( self->nonMmapBuffer );
|
||||
self->nonMmapBuffer = calloc( self->numHostChannels, snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ) );
|
||||
*/
|
||||
unsigned int bufferSize = self->numHostChannels * snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
|
||||
unsigned int bufferSize = self->numHostChannels * snd_pcm_format_size( self->nativeFormat, *numFrames );
|
||||
if (bufferSize > self->nonMmapBufferSize)
|
||||
{
|
||||
self->nonMmapBuffer = realloc(self->nonMmapBuffer, (self->nonMmapBufferSize = bufferSize));
|
||||
|
@ -3144,20 +3259,22 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se
|
|||
else
|
||||
{
|
||||
if( self->canMmap )
|
||||
{
|
||||
for( i = 0; i < self->numUserChannels; ++i )
|
||||
{
|
||||
area = areas + i;
|
||||
buffer = ExtractAddress( area, self->offset );
|
||||
setChannel( bp, i, buffer, 1 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
|
||||
unsigned int buf_per_ch_size = self->nonMmapBufferSize / self->numHostChannels;
|
||||
buffer = self->nonMmapBuffer;
|
||||
for( i = 0; i < self->numUserChannels; ++i )
|
||||
{
|
||||
setChannel( bp, i, buffer, 1 );
|
||||
buffer += bufsize;
|
||||
buffer += buf_per_ch_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3171,13 +3288,13 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se
|
|||
else
|
||||
{
|
||||
void *bufs[self->numHostChannels];
|
||||
int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
|
||||
unsigned int buf_per_ch_size = self->nonMmapBufferSize / self->numHostChannels;
|
||||
unsigned char *buffer = self->nonMmapBuffer;
|
||||
int i;
|
||||
for( i = 0; i < self->numHostChannels; ++i )
|
||||
{
|
||||
bufs[i] = buffer;
|
||||
buffer += bufsize;
|
||||
buffer += buf_per_ch_size;
|
||||
}
|
||||
res = snd_pcm_readn( self->pcm, bufs, *numFrames );
|
||||
}
|
||||
|
@ -3185,11 +3302,6 @@ static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* se
|
|||
{
|
||||
*xrun = 1;
|
||||
*numFrames = 0;
|
||||
|
||||
/* using realloc for optimisation
|
||||
free( self->nonMmapBuffer );
|
||||
self->nonMmapBuffer = NULL;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id: pa_asio.cpp 1436 2009-12-10 08:09:21Z rossb $
|
||||
* $Id: pa_asio.cpp 1525 2010-07-14 06:45:25Z rossb $
|
||||
* Portable Audio I/O Library for ASIO Drivers
|
||||
*
|
||||
* Author: Stephane Letz
|
||||
|
@ -169,6 +169,12 @@
|
|||
*/
|
||||
|
||||
|
||||
/* winmm.lib is needed for timeGetTime() (this is in winmm.a if you're using gcc) */
|
||||
#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
|
||||
#pragma comment(lib, "winmm.lib")
|
||||
#endif
|
||||
|
||||
|
||||
/* external reference to ASIO SDK's asioDrivers.
|
||||
|
||||
This is a bit messy because we want to explicitly manage
|
||||
|
@ -2528,8 +2534,8 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
else /* Using callback interface... */
|
||||
{
|
||||
result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
|
||||
inputChannelCount, inputSampleFormat, hostInputSampleFormat,
|
||||
outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
|
||||
inputChannelCount, inputSampleFormat, (hostInputSampleFormat | paNonInterleaved),
|
||||
outputChannelCount, outputSampleFormat, (hostOutputSampleFormat | paNonInterleaved),
|
||||
sampleRate, streamFlags, framesPerBuffer,
|
||||
framesPerHostBuffer, paUtilFixedHostBufferSize,
|
||||
streamCallback, userData );
|
||||
|
|
|
@ -249,7 +249,6 @@ static PaError AbortStream( PaStream *stream );
|
|||
static PaError IsStreamStopped( PaStream *s );
|
||||
static PaError IsStreamActive( PaStream *stream );
|
||||
static PaTime GetStreamTime( PaStream *stream );
|
||||
static void setStreamStartTime( PaStream *stream );
|
||||
static OSStatus AudioIOProc( void *inRefCon,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
|
@ -798,6 +797,75 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
|
|||
return paFormatIsSupported;
|
||||
}
|
||||
|
||||
|
||||
static void UpdateReciprocalOfActualOutputSampleRateFromDeviceProperty( PaMacCoreStream *stream )
|
||||
{
|
||||
/* FIXME: not sure if this should be the sample rate of the output device or the output unit */
|
||||
Float64 actualOutputSampleRate = stream->outDeviceSampleRate;
|
||||
UInt32 propSize = sizeof(Float64);
|
||||
OSStatus osErr = AudioDeviceGetProperty( stream->outputDevice, 0, /* isInput = */ FALSE, kAudioDevicePropertyActualSampleRate, &propSize, &actualOutputSampleRate);
|
||||
if( osErr != noErr || actualOutputSampleRate < .01 ) // avoid divide by zero if there's an error
|
||||
actualOutputSampleRate = stream->outDeviceSampleRate;
|
||||
|
||||
stream->recipricalOfActualOutputSampleRate = 1. / actualOutputSampleRate;
|
||||
}
|
||||
|
||||
static OSStatus AudioDevicePropertyActualSampleRateListenerProc( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void *inClientData )
|
||||
{
|
||||
PaMacCoreStream *stream = (PaMacCoreStream*)inClientData;
|
||||
|
||||
pthread_mutex_lock( &stream->timingInformationMutex );
|
||||
UpdateReciprocalOfActualOutputSampleRateFromDeviceProperty( stream );
|
||||
pthread_mutex_unlock( &stream->timingInformationMutex );
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
static void UpdateOutputLatencySamplesFromDeviceProperty( PaMacCoreStream *stream )
|
||||
{
|
||||
UInt32 deviceOutputLatencySamples = 0;
|
||||
UInt32 propSize = sizeof(UInt32);
|
||||
OSStatus osErr = AudioDeviceGetProperty( stream->outputDevice, 0, /* isInput= */ FALSE, kAudioDevicePropertyLatency, &propSize, &deviceOutputLatencySamples);
|
||||
if( osErr != noErr )
|
||||
deviceOutputLatencySamples = 0;
|
||||
|
||||
stream->deviceOutputLatencySamples = deviceOutputLatencySamples;
|
||||
}
|
||||
|
||||
static OSStatus AudioDevicePropertyOutputLatencySamplesListenerProc( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void *inClientData )
|
||||
{
|
||||
PaMacCoreStream *stream = (PaMacCoreStream*)inClientData;
|
||||
|
||||
pthread_mutex_lock( &stream->timingInformationMutex );
|
||||
UpdateOutputLatencySamplesFromDeviceProperty( stream );
|
||||
pthread_mutex_unlock( &stream->timingInformationMutex );
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
static void UpdateInputLatencySamplesFromDeviceProperty( PaMacCoreStream *stream )
|
||||
{
|
||||
UInt32 deviceInputLatencySamples = 0;
|
||||
UInt32 propSize = sizeof(UInt32);
|
||||
OSStatus osErr = AudioDeviceGetProperty( stream->inputDevice, 0, /* isInput= */ TRUE, kAudioDevicePropertyLatency, &propSize, &deviceInputLatencySamples);
|
||||
if( osErr != noErr )
|
||||
deviceInputLatencySamples = 0;
|
||||
|
||||
stream->deviceInputLatencySamples = deviceInputLatencySamples;
|
||||
}
|
||||
|
||||
static OSStatus AudioDevicePropertyInputLatencySamplesListenerProc( AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void *inClientData )
|
||||
{
|
||||
PaMacCoreStream *stream = (PaMacCoreStream*)inClientData;
|
||||
|
||||
pthread_mutex_lock( &stream->timingInformationMutex );
|
||||
UpdateInputLatencySamplesFromDeviceProperty( stream );
|
||||
pthread_mutex_unlock( &stream->timingInformationMutex );
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
||||
static PaError OpenAndSetupOneAudioUnit(
|
||||
const PaMacCoreStream *stream,
|
||||
const PaStreamParameters *inStreamParams,
|
||||
|
@ -1356,6 +1424,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
stream->inputFramesPerBuffer = 0;
|
||||
stream->outputFramesPerBuffer = 0;
|
||||
stream->bufferProcessorIsInitialized = FALSE;
|
||||
stream->timingInformationMutexIsInitialized = 0;
|
||||
|
||||
/* assert( streamCallback ) ; */ /* only callback mode is implemented */
|
||||
if( streamCallback )
|
||||
|
@ -1656,7 +1725,39 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
stream->userInChan = inputChannelCount;
|
||||
stream->userOutChan = outputChannelCount;
|
||||
|
||||
stream->isTimeSet = FALSE;
|
||||
pthread_mutex_init( &stream->timingInformationMutex, NULL );
|
||||
stream->timingInformationMutexIsInitialized = 1;
|
||||
|
||||
if( stream->outputUnit ) {
|
||||
UpdateReciprocalOfActualOutputSampleRateFromDeviceProperty( stream );
|
||||
stream->recipricalOfActualOutputSampleRate_ioProcCopy = stream->recipricalOfActualOutputSampleRate;
|
||||
|
||||
AudioDeviceAddPropertyListener( stream->outputDevice, 0, /* isInput = */ FALSE, kAudioDevicePropertyActualSampleRate,
|
||||
AudioDevicePropertyActualSampleRateListenerProc, stream );
|
||||
|
||||
UpdateOutputLatencySamplesFromDeviceProperty( stream );
|
||||
stream->deviceOutputLatencySamples_ioProcCopy = stream->deviceOutputLatencySamples;
|
||||
|
||||
AudioDeviceAddPropertyListener( stream->outputDevice, 0, /* isInput = */ FALSE, kAudioDevicePropertyLatency,
|
||||
AudioDevicePropertyOutputLatencySamplesListenerProc, stream );
|
||||
|
||||
}else{
|
||||
stream->recipricalOfActualOutputSampleRate = 1.;
|
||||
stream->recipricalOfActualOutputSampleRate_ioProcCopy = 0.;
|
||||
stream->deviceOutputLatencySamples_ioProcCopy = 0;
|
||||
}
|
||||
|
||||
if( stream->inputUnit ) {
|
||||
UpdateInputLatencySamplesFromDeviceProperty( stream );
|
||||
stream->deviceInputLatencySamples_ioProcCopy = stream->deviceInputLatencySamples;
|
||||
|
||||
AudioDeviceAddPropertyListener( stream->inputDevice, 0, /* isInput = */ TRUE, kAudioDevicePropertyLatency,
|
||||
AudioDevicePropertyInputLatencySamplesListenerProc, stream );
|
||||
}else{
|
||||
stream->deviceInputLatencySamples = 0;
|
||||
stream->deviceInputLatencySamples_ioProcCopy = 0;
|
||||
}
|
||||
|
||||
stream->state = STOPPED;
|
||||
stream->xrunFlags = 0;
|
||||
|
||||
|
@ -1669,56 +1770,12 @@ error:
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
#define HOST_TIME_TO_PA_TIME( x ) ( AudioConvertHostTimeToNanos( (x) ) * 1.0E-09) /* convert to nanoseconds and then to seconds */
|
||||
|
||||
PaTime GetStreamTime( PaStream *s )
|
||||
{
|
||||
/* FIXME: I am not at all sure this timing info stuff is right.
|
||||
patest_sine_time reports negative latencies, which is wierd.*/
|
||||
PaMacCoreStream *stream = (PaMacCoreStream*)s;
|
||||
AudioTimeStamp timeStamp;
|
||||
|
||||
VVDBUG(("GetStreamTime()\n"));
|
||||
|
||||
if ( !stream->isTimeSet )
|
||||
return (PaTime)0;
|
||||
|
||||
if ( stream->outputDevice ) {
|
||||
AudioDeviceGetCurrentTime( stream->outputDevice, &timeStamp);
|
||||
return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->outDeviceSampleRate;
|
||||
} else if ( stream->inputDevice ) {
|
||||
AudioDeviceGetCurrentTime( stream->inputDevice, &timeStamp);
|
||||
return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->inDeviceSampleRate;
|
||||
} else {
|
||||
return (PaTime)0;
|
||||
}
|
||||
}
|
||||
|
||||
static void setStreamStartTime( PaStream *stream )
|
||||
{
|
||||
/* FIXME: I am not at all sure this timing info stuff is right.
|
||||
patest_sine_time reports negative latencies, which is wierd.*/
|
||||
PaMacCoreStream *s = (PaMacCoreStream *) stream;
|
||||
VVDBUG(("setStreamStartTime()\n"));
|
||||
if( s->outputDevice )
|
||||
AudioDeviceGetCurrentTime( s->outputDevice, &s->startTime);
|
||||
else if( s->inputDevice )
|
||||
AudioDeviceGetCurrentTime( s->inputDevice, &s->startTime);
|
||||
else
|
||||
bzero( &s->startTime, sizeof( s->startTime ) );
|
||||
|
||||
//FIXME: we need a memory barier here
|
||||
|
||||
s->isTimeSet = TRUE;
|
||||
}
|
||||
|
||||
|
||||
static PaTime TimeStampToSecs(PaMacCoreStream *stream, const AudioTimeStamp* timeStamp)
|
||||
{
|
||||
VVDBUG(("TimeStampToSecs()\n"));
|
||||
//printf( "ATS: %lu, %g, %g\n", timeStamp->mFlags, timeStamp->mSampleTime, timeStamp->mRateScalar );
|
||||
if (timeStamp->mFlags & kAudioTimeStampSampleTimeValid)
|
||||
return (timeStamp->mSampleTime / stream->sampleRate);
|
||||
else
|
||||
return 0;
|
||||
return HOST_TIME_TO_PA_TIME( AudioGetCurrentHostTime() );
|
||||
}
|
||||
|
||||
#define RING_BUFFER_EMPTY (1000)
|
||||
|
@ -1799,22 +1856,66 @@ static OSStatus AudioIOProc( void *inRefCon,
|
|||
}
|
||||
----------------------------------------------------------------- */
|
||||
|
||||
if( !stream->isTimeSet )
|
||||
setStreamStartTime( stream );
|
||||
/* compute PaStreamCallbackTimeInfo */
|
||||
|
||||
if( isRender ) {
|
||||
AudioTimeStamp currentTime;
|
||||
timeInfo.outputBufferDacTime = TimeStampToSecs(stream, inTimeStamp);
|
||||
AudioDeviceGetCurrentTime(stream->outputDevice, ¤tTime);
|
||||
timeInfo.currentTime = TimeStampToSecs(stream, ¤tTime);
|
||||
if( pthread_mutex_trylock( &stream->timingInformationMutex ) == 0 ){
|
||||
/* snapshot the ioproc copy of timing information */
|
||||
stream->deviceOutputLatencySamples_ioProcCopy = stream->deviceOutputLatencySamples;
|
||||
stream->recipricalOfActualOutputSampleRate_ioProcCopy = stream->recipricalOfActualOutputSampleRate;
|
||||
stream->deviceInputLatencySamples_ioProcCopy = stream->deviceInputLatencySamples;
|
||||
pthread_mutex_unlock( &stream->timingInformationMutex );
|
||||
}
|
||||
if( isRender && stream->inputUnit == stream->outputUnit )
|
||||
timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp);
|
||||
if( !isRender ) {
|
||||
AudioTimeStamp currentTime;
|
||||
timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp);
|
||||
AudioDeviceGetCurrentTime(stream->inputDevice, ¤tTime);
|
||||
timeInfo.currentTime = TimeStampToSecs(stream, ¤tTime);
|
||||
|
||||
/* For timeInfo.currentTime we could calculate current time backwards from the HAL audio
|
||||
output time to give a more accurate impression of the current timeslice but it doesn't
|
||||
seem worth it at the moment since other PA host APIs don't do any better.
|
||||
*/
|
||||
timeInfo.currentTime = HOST_TIME_TO_PA_TIME( AudioGetCurrentHostTime() );
|
||||
|
||||
/*
|
||||
For an input HAL AU, inTimeStamp is the time the samples are received from the hardware,
|
||||
for an output HAL AU inTimeStamp is the time the samples are sent to the hardware.
|
||||
PA expresses timestamps in terms of when the samples enter the ADC or leave the DAC
|
||||
so we add or subtract kAudioDevicePropertyLatency below.
|
||||
*/
|
||||
|
||||
/* FIXME: not sure what to do below if the host timestamps aren't valid (kAudioTimeStampHostTimeValid isn't set)
|
||||
Could ask on CA mailing list if it is possible for it not to be set. If so, could probably grab a now timestamp
|
||||
at the top and compute from there (modulo scheduling jitter) or ask on mailing list for other options. */
|
||||
|
||||
if( isRender )
|
||||
{
|
||||
if( stream->inputUnit ) /* full duplex */
|
||||
{
|
||||
if( stream->inputUnit == stream->outputUnit ) /* full duplex AUHAL IOProc */
|
||||
{
|
||||
/* FIXME: review. i'm not sure this computation of inputBufferAdcTime is correct for a full-duplex AUHAL */
|
||||
timeInfo.inputBufferAdcTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime)
|
||||
- stream->deviceInputLatencySamples_ioProcCopy * stream->recipricalOfActualOutputSampleRate_ioProcCopy; // FIXME should be using input sample rate here?
|
||||
timeInfo.outputBufferDacTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime)
|
||||
+ stream->deviceOutputLatencySamples_ioProcCopy * stream->recipricalOfActualOutputSampleRate_ioProcCopy;
|
||||
}
|
||||
else /* full duplex with ring-buffer from a separate input AUHAL ioproc */
|
||||
{
|
||||
/* FIXME: review. this computation of inputBufferAdcTime is definitely wrong since it doesn't take the ring buffer latency into account */
|
||||
timeInfo.inputBufferAdcTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime)
|
||||
- stream->deviceInputLatencySamples_ioProcCopy * stream->recipricalOfActualOutputSampleRate_ioProcCopy; // FIXME should be using input sample rate here?
|
||||
timeInfo.outputBufferDacTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime)
|
||||
+ stream->deviceOutputLatencySamples_ioProcCopy * stream->recipricalOfActualOutputSampleRate_ioProcCopy;
|
||||
}
|
||||
}
|
||||
else /* output only */
|
||||
{
|
||||
timeInfo.inputBufferAdcTime = 0;
|
||||
timeInfo.outputBufferDacTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime)
|
||||
+ stream->deviceOutputLatencySamples_ioProcCopy * stream->recipricalOfActualOutputSampleRate_ioProcCopy;
|
||||
}
|
||||
}
|
||||
else /* input only */
|
||||
{
|
||||
timeInfo.inputBufferAdcTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime)
|
||||
- stream->deviceInputLatencySamples_ioProcCopy * stream->recipricalOfActualOutputSampleRate_ioProcCopy; // FIXME should be using input sample rate here?
|
||||
timeInfo.outputBufferDacTime = 0;
|
||||
}
|
||||
|
||||
//printf( "---%g, %g, %g\n", timeInfo.inputBufferAdcTime, timeInfo.currentTime, timeInfo.outputBufferDacTime );
|
||||
|
@ -2128,7 +2229,6 @@ static OSStatus AudioIOProc( void *inRefCon,
|
|||
case paContinue: break;
|
||||
case paComplete:
|
||||
case paAbort:
|
||||
stream->isTimeSet = FALSE;
|
||||
stream->state = CALLBACK_STOPPED ;
|
||||
if( stream->outputUnit )
|
||||
AudioOutputUnitStop(stream->outputUnit);
|
||||
|
@ -2157,6 +2257,19 @@ static PaError CloseStream( PaStream* s )
|
|||
VDBUG( ( "Closing stream.\n" ) );
|
||||
|
||||
if( stream ) {
|
||||
|
||||
if( stream->outputUnit ) {
|
||||
AudioDeviceRemovePropertyListener( stream->outputDevice, 0, /* isInput = */ FALSE, kAudioDevicePropertyActualSampleRate,
|
||||
AudioDevicePropertyActualSampleRateListenerProc );
|
||||
AudioDeviceRemovePropertyListener( stream->outputDevice, 0, /* isInput = */ FALSE, kAudioDevicePropertyLatency,
|
||||
AudioDevicePropertyOutputLatencySamplesListenerProc );
|
||||
}
|
||||
|
||||
if( stream->inputUnit ) {
|
||||
AudioDeviceRemovePropertyListener( stream->inputDevice, 0, /* isInput = */ TRUE, kAudioDevicePropertyLatency,
|
||||
AudioDevicePropertyInputLatencySamplesListenerProc );
|
||||
}
|
||||
|
||||
if( stream->outputUnit ) {
|
||||
int count = removeFromXRunListenerList( stream );
|
||||
if( count == 0 )
|
||||
|
@ -2203,6 +2316,10 @@ static PaError CloseStream( PaStream* s )
|
|||
return result;
|
||||
if( stream->bufferProcessorIsInitialized )
|
||||
PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
|
||||
|
||||
if( stream->timingInformationMutexIsInitialized )
|
||||
pthread_mutex_destroy( &stream->timingInformationMutex );
|
||||
|
||||
PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
|
||||
PaUtil_FreeMemory( stream );
|
||||
}
|
||||
|
@ -2233,9 +2350,6 @@ static PaError StartStream( PaStream *s )
|
|||
ERR_WRAP( AudioOutputUnitStart(stream->outputUnit) );
|
||||
}
|
||||
|
||||
//setStreamStartTime( stream );
|
||||
//stream->isTimeSet = TRUE;
|
||||
|
||||
return paNoError;
|
||||
#undef ERR_WRAP
|
||||
}
|
||||
|
@ -2266,7 +2380,6 @@ static PaError StopStream( PaStream *s )
|
|||
waitUntilBlioWriteBufferIsFlushed( &stream->blio );
|
||||
VDBUG( ( "Stopping stream.\n" ) );
|
||||
|
||||
stream->isTimeSet = FALSE;
|
||||
stream->state = STOPPING;
|
||||
|
||||
#define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0)
|
||||
|
@ -2314,10 +2427,6 @@ static PaError StopStream( PaStream *s )
|
|||
if( paErr )
|
||||
return paErr;
|
||||
|
||||
/*
|
||||
//stream->isTimeSet = FALSE;
|
||||
*/
|
||||
|
||||
VDBUG( ( "Stream Stopped.\n" ) );
|
||||
return paNoError;
|
||||
#undef ERR_WRAP
|
||||
|
|
|
@ -142,7 +142,6 @@ typedef struct PaMacCoreStream
|
|||
AudioTimeStamp startTime;
|
||||
/* FIXME: instead of volatile, these should be properly memory barriered */
|
||||
volatile PaStreamCallbackFlags xrunFlags;
|
||||
volatile bool isTimeSet;
|
||||
volatile enum {
|
||||
STOPPED = 0, /* playback is completely stopped,
|
||||
and the user has called StopStream(). */
|
||||
|
@ -159,6 +158,18 @@ typedef struct PaMacCoreStream
|
|||
//these may be different from the stream sample rate due to SR conversion:
|
||||
double outDeviceSampleRate;
|
||||
double inDeviceSampleRate;
|
||||
|
||||
/* data updated by main thread and notifications, protected by timingInformationMutex */
|
||||
int timingInformationMutexIsInitialized;
|
||||
pthread_mutex_t timingInformationMutex;
|
||||
Float64 recipricalOfActualOutputSampleRate;
|
||||
UInt32 deviceOutputLatencySamples;
|
||||
UInt32 deviceInputLatencySamples;
|
||||
|
||||
/* while the io proc is active, the following values are only accessed and manipulated by the ioproc */
|
||||
Float64 recipricalOfActualOutputSampleRate_ioProcCopy;
|
||||
UInt32 deviceOutputLatencySamples_ioProcCopy;
|
||||
UInt32 deviceInputLatencySamples_ioProcCopy;
|
||||
}
|
||||
PaMacCoreStream;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id: pa_win_ds.c 1450 2010-02-03 00:28:29Z rossb $
|
||||
* $Id: pa_win_ds.c 1534 2010-08-03 21:02:52Z dmitrykos $
|
||||
* Portable Audio I/O Library DirectSound implementation
|
||||
*
|
||||
* Authors: Phil Burk, Robert Marsanyi & Ross Bencina
|
||||
|
@ -244,7 +244,7 @@ typedef struct PaWinDsStream
|
|||
/* Try to detect play buffer underflows. */
|
||||
LARGE_INTEGER perfCounterTicksPerBuffer; /* counter ticks it should take to play a full buffer */
|
||||
LARGE_INTEGER previousPlayTime;
|
||||
UINT previousPlayCursor;
|
||||
DWORD previousPlayCursor;
|
||||
UINT outputUnderflowCount;
|
||||
BOOL outputIsRunning;
|
||||
INT finalZeroBytesWritten; /* used to determine when we've flushed the whole buffer */
|
||||
|
@ -1502,10 +1502,10 @@ static HRESULT InitFullDuplexInputOutputBuffers( PaWinDsStream *stream,
|
|||
|
||||
/* retrieve the pre ds 8 buffer interfaces which are used by the rest of the code */
|
||||
|
||||
hr = IUnknown_QueryInterface( pCaptureBuffer8, &IID_IDirectSoundCaptureBuffer, &stream->pDirectSoundInputBuffer );
|
||||
hr = IUnknown_QueryInterface( pCaptureBuffer8, &IID_IDirectSoundCaptureBuffer, (LPVOID *)&stream->pDirectSoundInputBuffer );
|
||||
|
||||
if( hr == DS_OK )
|
||||
hr = IUnknown_QueryInterface( pRenderBuffer8, &IID_IDirectSoundBuffer, &stream->pDirectSoundOutputBuffer );
|
||||
hr = IUnknown_QueryInterface( pRenderBuffer8, &IID_IDirectSoundBuffer, (LPVOID *)&stream->pDirectSoundOutputBuffer );
|
||||
|
||||
/* release the ds 8 interfaces, we don't need them */
|
||||
IUnknown_Release( pCaptureBuffer8 );
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id: pa_jack.c 1346 2008-02-20 10:09:20Z rossb $
|
||||
* $Id: pa_jack.c 1541 2010-09-22 06:33:47Z dmitrykos $
|
||||
* PortAudio Portable Real-Time Audio Library
|
||||
* Latest Version at: http://www.portaudio.com
|
||||
* JACK Implementation by Joshua Haberman
|
||||
|
@ -71,8 +71,6 @@
|
|||
#include "pa_ringbuffer.h"
|
||||
#include "pa_debugprint.h"
|
||||
|
||||
static int aErr_;
|
||||
static PaError paErr_; /* For use with ENSURE_PA */
|
||||
static pthread_t mainThread_;
|
||||
static char *jackErr_ = NULL;
|
||||
static const char* clientName_ = "PortAudio";
|
||||
|
@ -83,15 +81,17 @@ static const char* clientName_ = "PortAudio";
|
|||
/* Check PaError */
|
||||
#define ENSURE_PA(expr) \
|
||||
do { \
|
||||
if( (paErr_ = (expr)) < paNoError ) \
|
||||
PaError paErr; \
|
||||
if( (paErr = (expr)) < paNoError ) \
|
||||
{ \
|
||||
if( (paErr_) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
|
||||
if( (paErr) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
|
||||
{ \
|
||||
if (! jackErr_ ) jackErr_ = "unknown error";\
|
||||
PaUtil_SetLastHostErrorInfo( paJACK, -1, jackErr_ ); \
|
||||
const char *err = jackErr_; \
|
||||
if (! err ) err = "unknown error"; \
|
||||
PaUtil_SetLastHostErrorInfo( paJACK, -1, err ); \
|
||||
} \
|
||||
PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
|
||||
result = paErr_; \
|
||||
result = paErr; \
|
||||
goto error; \
|
||||
} \
|
||||
} while( 0 )
|
||||
|
@ -102,8 +102,9 @@ static const char* clientName_ = "PortAudio";
|
|||
{ \
|
||||
if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
|
||||
{ \
|
||||
if (!jackErr_) jackErr_ = "unknown error";\
|
||||
PaUtil_SetLastHostErrorInfo( paJACK, -1, jackErr_ ); \
|
||||
const char *err = jackErr_; \
|
||||
if (!err) err = "unknown error"; \
|
||||
PaUtil_SetLastHostErrorInfo( paJACK, -1, err ); \
|
||||
} \
|
||||
PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
|
||||
result = (code); \
|
||||
|
@ -112,8 +113,10 @@ static const char* clientName_ = "PortAudio";
|
|||
} while( 0 )
|
||||
|
||||
#define ASSERT_CALL(expr, success) \
|
||||
aErr_ = (expr); \
|
||||
assert( aErr_ == success );
|
||||
do { \
|
||||
int err = (expr); \
|
||||
assert( err == success ); \
|
||||
} while( 0 )
|
||||
|
||||
/*
|
||||
* Functions that directly map to the PortAudio stream interface
|
||||
|
@ -826,6 +829,7 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
|
|||
PaUtil_FreeMemory( jackHostApi );
|
||||
|
||||
free( jackErr_ );
|
||||
jackErr_ = NULL;
|
||||
}
|
||||
|
||||
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
|
||||
|
@ -1000,7 +1004,7 @@ static PaError WaitCondition( PaJackHostApiRepresentation *hostApi )
|
|||
PaTime pt = PaUtil_GetTime();
|
||||
struct timespec ts;
|
||||
|
||||
ts.tv_sec = (time_t) floor( pt + 1 );
|
||||
ts.tv_sec = (time_t) floor( pt + 10 * 60 /* 10 minutes */ );
|
||||
ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000);
|
||||
/* XXX: Best enclose in loop, in case of spurious wakeups? */
|
||||
err = pthread_cond_timedwait( &hostApi->cond, &hostApi->mtx, &ts );
|
||||
|
@ -1276,10 +1280,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||
&stream->bufferProcessor,
|
||||
inputChannelCount,
|
||||
inputSampleFormat,
|
||||
paFloat32, /* hostInputSampleFormat */
|
||||
paFloat32 | paNonInterleaved, /* hostInputSampleFormat */
|
||||
outputChannelCount,
|
||||
outputSampleFormat,
|
||||
paFloat32, /* hostOutputSampleFormat */
|
||||
paFloat32 | paNonInterleaved, /* hostOutputSampleFormat */
|
||||
jackSr,
|
||||
streamFlags,
|
||||
framesPerBuffer,
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id: pa_unix_oss.c 1385 2008-06-05 21:13:54Z aknudsen $
|
||||
* $Id: pa_unix_oss.c 1509 2010-06-06 17:36:33Z dmitrykos $
|
||||
* PortAudio Portable Real-Time Audio Library
|
||||
* Latest Version at: http://www.portaudio.com
|
||||
* OSS implementation by:
|
||||
|
@ -185,7 +185,7 @@ typedef struct PaOssStream
|
|||
double sampleRate;
|
||||
|
||||
int callbackMode;
|
||||
int callbackStop, callbackAbort;
|
||||
volatile int callbackStop, callbackAbort;
|
||||
|
||||
PaOssStreamComponent *capture, *playback;
|
||||
unsigned long pollTimeout;
|
||||
|
@ -1317,7 +1317,17 @@ static PaError PaOssStream_WaitForFrames( PaOssStream *stream, unsigned long *fr
|
|||
|
||||
while( pollPlayback || pollCapture )
|
||||
{
|
||||
#ifdef PTHREAD_CANCELED
|
||||
pthread_testcancel();
|
||||
#else
|
||||
/* avoid indefinite waiting on thread not supporting cancelation */
|
||||
if( stream->callbackStop || stream->callbackAbort )
|
||||
{
|
||||
PA_DEBUG(( "Cancelling PaOssStream_WaitForFrames\n" ));
|
||||
(*frames) = 0;
|
||||
return paNoError;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* select may modify the timeout parameter */
|
||||
selectTimeval.tv_usec = timeout;
|
||||
|
@ -1341,8 +1351,17 @@ static PaError PaOssStream_WaitForFrames( PaOssStream *stream, unsigned long *fr
|
|||
ENSURE_( -1, paUnanticipatedHostError );
|
||||
}
|
||||
*/
|
||||
#ifdef PTHREAD_CANCELED
|
||||
pthread_testcancel();
|
||||
|
||||
#else
|
||||
/* avoid indefinite waiting on thread not supporting cancelation */
|
||||
if( stream->callbackStop || stream->callbackAbort )
|
||||
{
|
||||
PA_DEBUG(( "Cancelling PaOssStream_WaitForFrames\n" ));
|
||||
(*frames) = 0;
|
||||
return paNoError;
|
||||
}
|
||||
#endif
|
||||
if( pollCapture )
|
||||
{
|
||||
if( FD_ISSET( captureFd, &readFds ) )
|
||||
|
@ -1603,8 +1622,15 @@ static void *PaOSS_AudioThreadProc( void *userData )
|
|||
|
||||
while( 1 )
|
||||
{
|
||||
#ifdef PTHREAD_CANCELED
|
||||
pthread_testcancel();
|
||||
|
||||
#else
|
||||
if( stream->callbackAbort ) /* avoid indefinite waiting on thread not supporting cancelation */
|
||||
{
|
||||
PA_DEBUG(( "Aborting callback thread\n" ));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if( stream->callbackStop && callbackResult == paContinue )
|
||||
{
|
||||
PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
|
||||
|
@ -1631,8 +1657,21 @@ static void *PaOSS_AudioThreadProc( void *userData )
|
|||
{
|
||||
unsigned long frames = framesAvail;
|
||||
|
||||
#ifdef PTHREAD_CANCELED
|
||||
pthread_testcancel();
|
||||
#else
|
||||
if( stream->callbackStop )
|
||||
{
|
||||
PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
|
||||
callbackResult = paComplete;
|
||||
}
|
||||
|
||||
if( stream->callbackAbort ) /* avoid indefinite waiting on thread not supporting cancelation */
|
||||
{
|
||||
PA_DEBUG(( "Aborting callback thread\n" ));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
|
||||
|
||||
/* Read data */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* $Id: pa_unix_util.c 1419 2009-10-22 17:28:35Z bjornroche $
|
||||
* $Id: pa_unix_util.c 1510 2010-06-10 08:05:29Z dmitrykos $
|
||||
* Portable Audio I/O Library
|
||||
* UNIX platform-specific support functions
|
||||
*
|
||||
|
@ -193,9 +193,15 @@ PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *e
|
|||
if( exitResult )
|
||||
*exitResult = paNoError;
|
||||
|
||||
/* If pthread_cancel is not supported (Android platform) whole this function can lead to indefinite waiting if
|
||||
working thread (callbackThread) has'n received any stop signals from outside, please keep
|
||||
this in mind when considering using PaUtil_CancelThreading
|
||||
*/
|
||||
#ifdef PTHREAD_CANCELED
|
||||
/* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
|
||||
if( !wait )
|
||||
pthread_cancel( threading->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */
|
||||
#endif
|
||||
pthread_join( threading->callbackThread, &pret );
|
||||
|
||||
#ifdef PTHREAD_CANCELED
|
||||
|
@ -427,12 +433,19 @@ PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResul
|
|||
{
|
||||
PA_DEBUG(( "%s: Canceling thread %d\n", __FUNCTION__, self->thread ));
|
||||
/* XXX: Safe to call this if the thread has exited on its own? */
|
||||
#ifdef PTHREAD_CANCELED
|
||||
pthread_cancel( self->thread );
|
||||
#endif
|
||||
}
|
||||
PA_DEBUG(( "%s: Joining thread %d\n", __FUNCTION__, self->thread ));
|
||||
PA_ENSURE_SYSTEM( pthread_join( self->thread, &pret ), 0 );
|
||||
|
||||
#ifdef PTHREAD_CANCELED
|
||||
if( pret && PTHREAD_CANCELED != pret )
|
||||
#else
|
||||
/* !wait means the thread may have been canceled */
|
||||
if( pret && wait )
|
||||
#endif
|
||||
{
|
||||
if( exitResult )
|
||||
{
|
||||
|
@ -506,9 +519,11 @@ PaError PaUnixMutex_Terminate( PaUnixMutex* self )
|
|||
PaError PaUnixMutex_Lock( PaUnixMutex* self )
|
||||
{
|
||||
PaError result = paNoError;
|
||||
int oldState;
|
||||
|
||||
#ifdef PTHREAD_CANCEL
|
||||
int oldState;
|
||||
PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldState ), 0 );
|
||||
#endif
|
||||
PA_ENSURE_SYSTEM( pthread_mutex_lock( &self->mtx ), 0 );
|
||||
|
||||
error:
|
||||
|
@ -522,10 +537,12 @@ error:
|
|||
PaError PaUnixMutex_Unlock( PaUnixMutex* self )
|
||||
{
|
||||
PaError result = paNoError;
|
||||
int oldState;
|
||||
|
||||
PA_ENSURE_SYSTEM( pthread_mutex_unlock( &self->mtx ), 0 );
|
||||
#ifdef PTHREAD_CANCEL
|
||||
int oldState;
|
||||
PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldState ), 0 );
|
||||
#endif
|
||||
|
||||
error:
|
||||
return result;
|
||||
|
|
|
@ -37,6 +37,16 @@
|
|||
|
||||
#include <windows.h>
|
||||
#include <mmreg.h>
|
||||
#ifndef WAVE_FORMAT_IEEE_FLOAT
|
||||
#define WAVE_FORMAT_IEEE_FLOAT 0x0003 // MinGW32 does not define this
|
||||
#endif
|
||||
#ifndef _WAVEFORMATEXTENSIBLE_
|
||||
#define _WAVEFORMATEXTENSIBLE_ // MinGW32 does not define this
|
||||
#endif
|
||||
#ifndef _INC_MMREG
|
||||
#define _INC_MMREG // for STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
|
||||
#endif
|
||||
#include <winioctl.h> // MinGW32 does not define this automatically
|
||||
#include <ks.h>
|
||||
#include <ksmedia.h>
|
||||
#include <stdio.h> // just for some development printfs
|
||||
|
@ -45,13 +55,10 @@
|
|||
#include "pa_util.h"
|
||||
#include "pa_win_wdmks_utils.h"
|
||||
|
||||
|
||||
#ifndef PA_WDMKS_NO_KSGUID_LIB
|
||||
|
||||
#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
|
||||
|
@ -59,9 +66,7 @@
|
|||
#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 };
|
||||
|
@ -69,7 +74,6 @@ static const GUID pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX = { STATIC_KSDATAFORMAT_
|
|||
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
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue