1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-15 23:59:37 +02:00

Update portaudio to r1910 which brings in these changes:

------------------------------------------------------------------------
r1910 | gineera | 2013-09-07 05:14:52 -0500 (Sat, 07 Sep 2013) | 1 line

paqa_devs: limit max number of channels tested (to 4); add a fixed decimal format to the timestamp printout.
------------------------------------------------------------------------
r1909 | rbencina | 2013-08-28 19:36:56 -0500 (Wed, 28 Aug 2013) | 1 line

pa_mac_core.c line 664 fixed incorrect memset size (was using sizeof(ptr) not sizeof(struct type)
------------------------------------------------------------------------
r1908 | gineera | 2013-08-27 12:14:51 -0500 (Tue, 27 Aug 2013) | 1 line

Alsa: Add function to prevent duplicate parts in the visible pa device name string, that occur when the pcm-device name starts with the card name (since they are both used).  Achieved by trimming the pcm-device string beginning.
------------------------------------------------------------------------
r1907 | gineera | 2013-08-22 17:01:17 -0500 (Thu, 22 Aug 2013) | 1 line

Alsa: Fix memory leak as nonMmapBuffers were not freed (since change to realloc).  Clean out corresponding dead code chunk.
------------------------------------------------------------------------
r1906 | gineera | 2013-08-22 14:43:07 -0500 (Thu, 22 Aug 2013) | 1 line

Alsa: Rename some variables in pa_linux_alsa where the meaning is mis-leading or wrong in the Alsa context.  Also tweak one debug message and a few typos.
------------------------------------------------------------------------
r1897 | gineera | 2013-08-13 15:37:04 -0500 (Tue, 13 Aug 2013) | 1 line

Alsa: Fix handling of poll descriptors in PaAlsaStream_WaitForFrames().  Otherwise if capture signals before playback a duplex stream could poll the wrong descriptor, causing a loop (reported by Alexander Kartashov).
------------------------------------------------------------------------
r1896 | rbencina | 2013-08-06 03:26:55 -0500 (Tue, 06 Aug 2013) | 1 line

fixed bug that was causing memory corruption in PA/ALSA when host sample format was lager than user format. e.g. using 16 bit output with a sound card that used 24 bit buffers. the incorrect input zeroer was being used. Thanks to Anders Tornvig for identifying the problem
------------------------------------------------------------------------
r1895 | rbencina | 2013-07-24 10:37:15 -0500 (Wed, 24 Jul 2013) | 1 line

fixed doxygen markup for a few line breaks in the tutorial
------------------------------------------------------------------------
r1894 | gineera | 2013-06-08 14:30:41 -0500 (Sat, 08 Jun 2013) | 1 line

OSS: revise default latency reporting: previous fixed values could not actually be achieved with OSS power-of-2 sizes.  Instead try a configuration and correctly report the default latency based on one less than the number of fragments; also fix the stream component 'bufSz' calculation.
------------------------------------------------------------------------
r1893 | gineera | 2013-06-08 14:12:25 -0500 (Sat, 08 Jun 2013) | 1 line

Alsa: revise latency use and calculations, since the latency should be equivalent to one Alsa period less than the Alsa ringbuffer (was based on the whole).  Also fixes failure if zero latency was specified.
------------------------------------------------------------------------
r1892 | gineera | 2013-05-30 06:30:28 -0500 (Thu, 30 May 2013) | 1 line

qa-latency: fix printout typos; re-enable checks of default high vs low latency - but allow them to be equal; remove rogue tab.
------------------------------------------------------------------------
r1891 | rbencina | 2013-05-05 09:00:02 -0500 (Sun, 05 May 2013) | 1 line

added code to print error result from Pa_Initialize() in pa_devs.c example
------------------------------------------------------------------------
r1890 | rbencina | 2013-05-01 20:06:01 -0500 (Wed, 01 May 2013) | 1 line

factored out InitPaDeviceInfoFromAsioDriver function. skip device rather than failing entire init process if a single ASIO driver returns an error during init. This was happening with MOTU devices if the device wasn't present. See ticket #221
------------------------------------------------------------------------
r1889 | rbencina | 2013-04-07 09:15:24 -0500 (Sun, 07 Apr 2013) | 1 line

move static variables into x86 section so they don't generate warnings when trying to build on 64 bit
------------------------------------------------------------------------
r1888 | rbencina | 2013-04-07 05:20:18 -0500 (Sun, 07 Apr 2013) | 1 line

configure.in fix from Leland '[Portaudio] Small patch to fix Mac build' march 4
This commit is contained in:
lllucius 2013-09-23 21:27:50 +00:00
parent f7aca4b474
commit e5719621c2
10 changed files with 326 additions and 251 deletions

View File

@ -208,7 +208,7 @@ case "${host_os}" in
LIBS="-framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon"
if test "x$enable_mac_universal" = "xyes" ; then
case "xcodebuild -version | sed -n 's/Xcode \(.*\)/\1/p'" in
case `xcodebuild -version | sed -n 's/Xcode \(.*\)/\1/p'` in
[12]*|3.0|3.1)
dnl In pre-3.2 versions of Xcode, xcodebuild doesn't

View File

@ -107,7 +107,12 @@ int main(void)
PaError err;
Pa_Initialize();
err = Pa_Initialize();
if( err != paNoError )
{
printf( "ERROR: Pa_Initialize returned 0x%x\n", err );
goto error;
}
printf( "PortAudio version number = %d\nPortAudio version text = '%s'\n",
Pa_GetVersion(), Pa_GetVersionText() );
@ -242,7 +247,6 @@ int main(void)
error:
Pa_Terminate();
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return err;

View File

@ -59,6 +59,7 @@
/****************************************** Definitions ***********/
#define MODE_INPUT (0)
#define MODE_OUTPUT (1)
#define MAX_TEST_CHANNELS 4
typedef struct PaQaData
{
@ -235,6 +236,8 @@ static void TestDevices( int mode )
pdi = Pa_GetDeviceInfo( id );
/* Try 1 to maxChannels on each device. */
maxChannels = (( mode == MODE_INPUT ) ? pdi->maxInputChannels : pdi->maxOutputChannels);
if( maxChannels > MAX_TEST_CHANNELS )
maxChannels = MAX_TEST_CHANNELS;
for( jc=1; jc<=maxChannels; jc++ )
{
@ -350,7 +353,7 @@ static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
oldStamp = Pa_GetStreamTime(stream);
Pa_Sleep(msec);
newStamp = Pa_GetStreamTime(stream);
printf("oldStamp = %g, newStamp = %g\n", oldStamp, newStamp ); /**/
printf("oldStamp = %9.6f, newStamp = %9.6f\n", oldStamp, newStamp ); /**/
EXPECT( (oldStamp < newStamp) );
/* Check to make sure callback is decrementing framesLeft. */
oldFrames = myData.framesLeft;

View File

@ -255,7 +255,7 @@ static int paqaCheckMultipleSuggested( PaDeviceIndex deviceIndex, int isInput )
{
numLoops = 1;
}
for( i=0; i<numLoops; i++ )
{
if( numLoops == 1 )
@ -361,15 +361,15 @@ static int paqaVerifyDeviceInfoLatency( void )
printf(" Output defaultHighOutputLatency = %f seconds\n", pdi->defaultHighOutputLatency);
QA_ASSERT_TRUE( "defaultLowOutputLatency should be > 0", (pdi->defaultLowOutputLatency > 0.0) );
QA_ASSERT_TRUE( "defaultHighOutputLatency should be > 0", (pdi->defaultHighOutputLatency > 0.0) );
//QA_ASSERT_TRUE( "defaultHighOutputLatency should be > Low", (pdi->defaultHighOutputLatency > pdi->defaultLowOutputLatency) );
QA_ASSERT_TRUE( "defaultHighOutputLatency should be >= Low", (pdi->defaultHighOutputLatency >= pdi->defaultLowOutputLatency) );
}
if( pdi->maxInputChannels > 0 )
{
printf(" Input defaultLowOutputLatency = %f seconds\n", pdi->defaultLowInputLatency);
printf(" Input defaultHighOutputLatency = %f seconds\n", pdi->defaultHighInputLatency);
QA_ASSERT_TRUE( "defaultLowOutputLatency should be > 0", (pdi->defaultLowInputLatency > 0.0) );
QA_ASSERT_TRUE( "defaultHighOutputLatency should be > 0", (pdi->defaultHighInputLatency > 0.0) );
//QA_ASSERT_TRUE( "defaultHighOutputLatency should be > Low", (pdi->defaultHighInputLatency > pdi->defaultLowInputLatency) );
printf(" Input defaultLowInputLatency = %f seconds\n", pdi->defaultLowInputLatency);
printf(" Input defaultHighInputLatency = %f seconds\n", pdi->defaultHighInputLatency);
QA_ASSERT_TRUE( "defaultLowInputLatency should be > 0", (pdi->defaultLowInputLatency > 0.0) );
QA_ASSERT_TRUE( "defaultHighInputLatency should be > 0", (pdi->defaultHighInputLatency > 0.0) );
QA_ASSERT_TRUE( "defaultHighInputLatency should be >= Low", (pdi->defaultHighInputLatency >= pdi->defaultLowInputLatency) );
}
}
return 0;

View File

@ -238,7 +238,7 @@ PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
bp->inputConverter =
PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, tempInputStreamFlags );
bp->inputZeroer = PaUtil_SelectZeroer( hostInputSampleFormat );
bp->inputZeroer = PaUtil_SelectZeroer( userInputSampleFormat );
bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;

View File

@ -602,7 +602,6 @@ typedef enum
typedef struct
{
PaSampleFormat hostSampleFormat;
unsigned long framesPerBuffer;
int numUserChannels, numHostChannels;
int userInterleaved, hostInterleaved;
int canMmap;
@ -613,7 +612,7 @@ typedef struct
int useReventFix; /* Alsa older than 1.0.16, plug devices need a fix */
snd_pcm_t *pcm;
snd_pcm_uframes_t bufferSize;
snd_pcm_uframes_t framesPerPeriod, alsaBufferSize;
snd_pcm_format_t nativeFormat;
unsigned int nfds;
int ready; /* Marked ready from poll */
@ -838,12 +837,13 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in
{
PaError result = paNoError;
snd_pcm_hw_params_t *hwParams;
snd_pcm_uframes_t lowLatency = 512, highLatency = 2048;
snd_pcm_uframes_t alsaBufferFrames, alsaPeriodFrames;
unsigned int minChans, maxChans;
int* minChannels, * maxChannels;
double * defaultLowLatency, * defaultHighLatency, * defaultSampleRate =
&devInfo->baseDeviceInfo.defaultSampleRate;
double defaultSr = *defaultSampleRate;
int dir;
assert( pcm );
@ -909,36 +909,34 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in
}
/* TWEAKME:
*
* Giving values for default min and max latency is not
* straightforward. Here are our objectives:
*
* * for low latency, we want to give the lowest value
* that will work reliably. This varies based on the
* sound card, kernel, CPU, etc. I think it is better
* to give sub-optimal latency than to give a number
* too low and cause dropouts. My conservative
* estimate at this point is to base it on 4096-sample
* latency at 44.1 kHz, which gives a latency of 23ms.
* * for high latency we want to give a large enough
* value that dropouts are basically impossible. This
* doesn't really require as much tweaking, since
* providing too large a number will just cause us to
* select the nearest setting that will work at stream
* config time.
* Giving values for default min and max latency is not straightforward.
* * for low latency, we want to give the lowest value that will work reliably.
* This varies based on the sound card, kernel, CPU, etc. Better to give
* sub-optimal latency than to give a number too low and cause dropouts.
* * for high latency we want to give a large enough value that dropouts are basically impossible.
* This doesn't really require as much tweaking, since providing too large a number will
* just cause us to select the nearest setting that will work at stream config time.
*/
ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &lowLatency ), paUnanticipatedHostError );
/* Try low latency values, (sometimes the buffer & period that result are larger) */
alsaBufferFrames = 512;
alsaPeriodFrames = 128;
ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir ), paUnanticipatedHostError );
*defaultLowLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr;
/* Base the high latency case on values four times larger */
alsaBufferFrames = 2048;
alsaPeriodFrames = 512;
/* Have to reset hwParams, to set new buffer size; need to also set sample rate again */
ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
ENSURE_( SetApproximateSampleRate( pcm, hwParams, defaultSr ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &highLatency ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir ), paUnanticipatedHostError );
*defaultHighLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr;
*minChannels = (int)minChans;
*maxChannels = (int)maxChans;
*defaultSampleRate = defaultSr;
*defaultLowLatency = (double) lowLatency / *defaultSampleRate;
*defaultHighLatency = (double) highLatency / *defaultSampleRate;
end:
alsa_snd_pcm_close( pcm );
@ -949,7 +947,7 @@ error:
}
/* Initialize device info with invalid values (maxInputChannels and maxOutputChannels are set to zero since these indicate
* wether input/output is available) */
* whether input/output is available) */
static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo )
{
deviceInfo->structVersion = -1;
@ -1081,6 +1079,38 @@ static int IgnorePlugin( const char *pluginId )
return 0;
}
/* Skip past parts at the beginning of a (pcm) info name that are already in the card name, to avoid duplication */
static char *SkipCardDetailsInName( char *infoSkipName, char *cardRefName )
{
char *lastSpacePosn = infoSkipName;
/* Skip matching chars; but only in chunks separated by ' ' (not part words etc), so track lastSpacePosn */
while( *cardRefName )
{
while( *infoSkipName && *cardRefName && *infoSkipName == *cardRefName)
{
infoSkipName++;
cardRefName++;
if( *infoSkipName == ' ' || *infoSkipName == '\0' )
lastSpacePosn = infoSkipName;
}
infoSkipName = lastSpacePosn;
/* Look for another chunk; post-increment means ends pointing to next char */
while( *cardRefName && ( *cardRefName++ != ' ' ));
}
if( *infoSkipName == '\0' )
return "-"; /* The 2 names were identical; instead of a nul-string, return a marker string */
/* Now want to move to the first char after any spaces */
while( *lastSpacePosn && *lastSpacePosn == ' ' )
lastSpacePosn++;
/* Skip a single separator char if present in the remaining pcm name; (pa will add its own) */
if(( *lastSpacePosn == '-' || *lastSpacePosn == ':' ) && *(lastSpacePosn + 1) == ' ' )
lastSpacePosn += 2;
return lastSpacePosn;
}
/** Open PCM device.
*
* Wrapper around alsa_snd_pcm_open which may repeatedly retry opening a device if it is busy, for
@ -1251,7 +1281,7 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
while( alsa_snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 )
{
char *alsaDeviceName, *deviceName;
char *alsaDeviceName, *deviceName, *infoName;
size_t len;
int hasPlayback = 0, hasCapture = 0;
snprintf( buf, sizeof (buf), "hw:%d,%d", cardIdx, devIdx );
@ -1277,12 +1307,13 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
continue;
}
infoName = SkipCardDetailsInName( (char *)alsa_snd_pcm_info_get_name( pcmInfo ), cardName );
/* The length of the string written by snprintf plus terminating 0 */
len = snprintf( NULL, 0, "%s: %s (%s)", cardName, alsa_snd_pcm_info_get_name( pcmInfo ), buf ) + 1;
len = snprintf( NULL, 0, "%s: %s (%s)", cardName, infoName, buf ) + 1;
PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
paInsufficientMemory );
snprintf( deviceName, len, "%s: %s (%s)", cardName,
alsa_snd_pcm_info_get_name( pcmInfo ), buf );
snprintf( deviceName, len, "%s: %s (%s)", cardName, infoName, buf );
++numDeviceNames;
if( !hwDevInfos || numDeviceNames > maxDeviceNames )
@ -1905,8 +1936,8 @@ error:
static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self )
{
alsa_snd_pcm_close( self->pcm );
if( self->userBuffers )
PaUtil_FreeMemory( self->userBuffers );
PaUtil_FreeMemory( self->userBuffers ); /* (Ptr can be NULL; PaUtil_FreeMemory includes a NULL check) */
PaUtil_FreeMemory( self->nonMmapBuffer );
}
/*
@ -1937,7 +1968,7 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se
double sr = *sampleRate;
unsigned int minPeriods = 2;
/* self->framesPerBuffer = framesPerHostBuffer; */
/* self->framesPerPeriod = framesPerHostBuffer; */
/* ... fill up the configuration space with all possibile
* combinations of parameters this device will accept */
@ -2032,7 +2063,7 @@ error:
/** Finish the configuration of the component's ALSA device.
*
* As part of this method, the component's bufferSize attribute will be set.
* As part of this method, the component's alsaBufferSize attribute will be set.
* @param latency: The latency for this component.
*/
static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *self, snd_pcm_hw_params_t* hwParams,
@ -2045,7 +2076,7 @@ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *sel
alsa_snd_pcm_sw_params_alloca( &swParams );
bufSz = params->suggestedLatency * sampleRate;
bufSz = params->suggestedLatency * sampleRate + self->framesPerPeriod;
ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError );
/* Set the parameters! */
@ -2063,21 +2094,21 @@ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *sel
}
if( alsa_snd_pcm_hw_params_get_buffer_size != NULL )
{
ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size( hwParams, &self->alsaBufferSize ), paUnanticipatedHostError );
}
else
{
self->bufferSize = bufSz;
self->alsaBufferSize = bufSz;
}
/* Latency in seconds */
*latency = self->bufferSize / sampleRate;
*latency = (self->alsaBufferSize - self->framesPerPeriod) / sampleRate;
/* Now software parameters... */
ENSURE_( alsa_snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->bufferSize ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerPeriod ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->alsaBufferSize ), paUnanticipatedHostError );
/* Silence buffer in the case of underrun */
if( !primeBuffers ) /* XXX: Make sense? */
@ -2088,7 +2119,7 @@ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *sel
ENSURE_( alsa_snd_pcm_sw_params_set_silence_size( self->pcm, swParams, boundary ), paUnanticipatedHostError );
}
ENSURE_( alsa_snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerPeriod ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError );
@ -2223,7 +2254,7 @@ static unsigned long PaAlsa_GetFramesPerHostBuffer(unsigned long userFramesPerBu
/** Determine size per host buffer.
*
* During this method call, the component's framesPerBuffer attribute gets computed, and the corresponding period size
* During this method call, the component's framesPerPeriod attribute gets computed, and the corresponding period size
* gets configured for the device.
* @param accurate: If the configured period size is non-integer, this will be set to 0.
*/
@ -2439,7 +2470,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo
}
/* Set result */
self->framesPerBuffer = framesPerHostBuffer;
self->framesPerPeriod = framesPerHostBuffer;
error:
return result;
@ -2466,7 +2497,7 @@ error:
* which should be fine if the period size is the same for capture and playback. In general, if there is a specified user
* buffer size, this method tries it best to determine a period size which is a multiple of the user buffer size.
*
* The framesPerBuffer attributes of the individual capture and playback components of the stream are set to corresponding
* The framesPerPeriod attributes of the individual capture and playback components of the stream are set to corresponding
* values determined here. Since these should be reported as
*
* This is one of those blocks of code that will just take a lot of
@ -2570,7 +2601,7 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double
paUnanticipatedHostError );
ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ),
paUnanticipatedHostError );
self->capture.framesPerBuffer = self->playback.framesPerBuffer = periodSize;
self->capture.framesPerPeriod = self->playback.framesPerPeriod = periodSize;
framesPerHostBuffer = periodSize;
}
else
@ -2579,15 +2610,15 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double
optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize );
optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
self->capture.framesPerBuffer = optimalPeriodSize;
self->capture.framesPerPeriod = optimalPeriodSize;
dir = 0;
ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerBuffer, &dir ),
ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerPeriod, &dir ),
paUnanticipatedHostError );
self->playback.framesPerBuffer = optimalPeriodSize;
self->playback.framesPerPeriod = optimalPeriodSize;
dir = 0;
ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerBuffer, &dir ),
ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerPeriod, &dir ),
paUnanticipatedHostError );
framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer );
framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod );
*hostBufferSizeMode = paUtilBoundedHostBufferSize;
}
}
@ -2617,17 +2648,17 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double
PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( first, firstStreamParams, framesPerUserBuffer,
sampleRate, firstHwParams, &accurate ) );
second->framesPerBuffer = first->framesPerBuffer;
second->framesPerPeriod = first->framesPerPeriod;
dir = 0;
ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerBuffer, &dir ),
ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerPeriod, &dir ),
paUnanticipatedHostError );
if( self->capture.framesPerBuffer == self->playback.framesPerBuffer )
if( self->capture.framesPerPeriod == self->playback.framesPerPeriod )
{
framesPerHostBuffer = self->capture.framesPerBuffer;
framesPerHostBuffer = self->capture.framesPerPeriod;
}
else
{
framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer );
framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod );
*hostBufferSizeMode = paUtilBoundedHostBufferSize;
}
}
@ -2638,14 +2669,14 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double
{
PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->capture, inputParameters, framesPerUserBuffer,
sampleRate, hwParamsCapture, &accurate) );
framesPerHostBuffer = self->capture.framesPerBuffer;
framesPerHostBuffer = self->capture.framesPerPeriod;
}
else
{
assert( self->playback.pcm );
PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->playback, outputParameters, framesPerUserBuffer,
sampleRate, hwParamsPlayback, &accurate ) );
framesPerHostBuffer = self->playback.framesPerBuffer;
framesPerHostBuffer = self->playback.framesPerPeriod;
}
}
@ -2691,17 +2722,17 @@ static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParamet
if( self->capture.pcm )
{
assert( self->capture.framesPerBuffer != 0 );
assert( self->capture.framesPerPeriod != 0 );
PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->capture, hwParamsCapture, inParams, self->primeBuffers, realSr,
inputLatency ) );
PA_DEBUG(( "%s: Capture period size: %lu, latency: %f\n", __FUNCTION__, self->capture.framesPerBuffer, *inputLatency ));
PA_DEBUG(( "%s: Capture period size: %lu, latency: %f\n", __FUNCTION__, self->capture.framesPerPeriod, *inputLatency ));
}
if( self->playback.pcm )
{
assert( self->playback.framesPerBuffer != 0 );
assert( self->playback.framesPerPeriod != 0 );
PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->playback, hwParamsPlayback, outParams, self->primeBuffers, realSr,
outputLatency ) );
PA_DEBUG(( "%s: Playback period size: %lu, latency: %f\n", __FUNCTION__, self->playback.framesPerBuffer, *outputLatency ));
PA_DEBUG(( "%s: Playback period size: %lu, latency: %f\n", __FUNCTION__, self->playback.framesPerPeriod, *outputLatency ));
}
/* Should be exact now */
@ -2721,8 +2752,8 @@ static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParamet
}
{
unsigned long minFramesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerBuffer : ULONG_MAX,
self->playback.pcm ? self->playback.framesPerBuffer : ULONG_MAX );
unsigned long minFramesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerPeriod : ULONG_MAX,
self->playback.pcm ? self->playback.framesPerPeriod : ULONG_MAX );
self->pollTimeout = CalculatePollTimeout( self, minFramesPerHostBuffer ); /* Period in msecs, rounded up */
/* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */
@ -2732,7 +2763,7 @@ static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParamet
if( self->callbackMode )
{
/* If the user expects a certain number of frames per callback we will either have to rely on block adaption
* (framesPerHostBuffer is not an integer multiple of framesPerBuffer) or we can simply align the number
* (framesPerHostBuffer is not an integer multiple of framesPerPeriod) or we can simply align the number
* of host buffer frames with what the user specified */
if( self->framesPerUserBuffer != paFramesPerBufferUnspecified )
{
@ -2741,8 +2772,8 @@ static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParamet
/* Unless the ratio between number of host and user buffer frames is an integer we will have to rely
* on block adaption */
/*
if( framesPerHostBuffer % framesPerBuffer != 0 || (self->capture.pcm && self->playback.pcm &&
self->capture.framesPerBuffer != self->playback.framesPerBuffer) )
if( framesPerHostBuffer % framesPerPeriod != 0 || (self->capture.pcm && self->playback.pcm &&
self->capture.framesPerPeriod != self->playback.framesPerPeriod) )
self->useBlockAdaption = 1;
else
self->alignFrames = 1;
@ -2796,7 +2827,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
/* XXX: Why do we support this anyway? */
if( framesPerBuffer == paFramesPerBufferUnspecified && getenv( "PA_ALSA_PERIODSIZE" ) != NULL )
{
PA_DEBUG(( "%s: Getting framesPerBuffer from environment\n", __FUNCTION__ ));
PA_DEBUG(( "%s: Getting framesPerBuffer (Alsa period-size) from environment\n", __FUNCTION__ ));
framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") );
}
@ -2823,7 +2854,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
stream->streamRepresentation.streamInfo.outputLatency = outputLatency + (PaTime)(
PaUtil_GetBufferProcessorOutputLatencyFrames( &stream->bufferProcessor ) / sampleRate);
PA_DEBUG(( "%s: Stream: framesPerBuffer = %lu, maxFramesPerHostBuffer = %lu, latency = i(%f)/o(%f), \n", __FUNCTION__, framesPerBuffer, stream->maxFramesPerHostBuffer, stream->streamRepresentation.streamInfo.inputLatency, stream->streamRepresentation.streamInfo.outputLatency));
PA_DEBUG(( "%s: Stream: framesPerBuffer = %lu, maxFramesPerHostBuffer = %lu, latency i=%f, o=%f\n", __FUNCTION__, framesPerBuffer, stream->maxFramesPerHostBuffer, stream->streamRepresentation.streamInfo.inputLatency, stream->streamRepresentation.streamInfo.outputLatency));
*s = (PaStream*)stream;
@ -2864,7 +2895,7 @@ static void SilenceBuffer( PaAlsaStream *stream )
/** Start/prepare pcm(s) for streaming.
*
* Depending on wether the stream is in callback or blocking mode, we will respectively start or simply
* Depending on whether the stream is in callback or blocking mode, we will respectively start or simply
* prepare the playback pcm. If the buffer has _not_ been primed, we will in callback mode prepare and
* silence the buffer before starting playback. In blocking mode we simply prepare, as the playback will
* be started automatically as the user writes to output.
@ -2950,7 +2981,7 @@ static PaError StartStream( PaStream *s )
{
PaError result = paNoError;
PaAlsaStream* stream = (PaAlsaStream*)s;
int streamStarted = 0; /* So we can know wether we need to take the stream down */
int streamStarted = 0; /* So we can know whether we need to take the stream down */
/* Ready the processor */
PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
@ -3041,7 +3072,7 @@ error:
/** Stop or abort stream.
*
* If a stream is in callback mode we will have to inspect wether the background thread has
* If a stream is in callback mode we will have to inspect whether the background thread has
* finished, or we will have to take it out. In either case we join the thread before
* returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish
* buffers (drain)
@ -3323,16 +3354,16 @@ static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamD
if( StreamDirection_Out == streamDir )
{
/* Number of eligible frames before capture overrun */
delay = otherComponent->bufferSize - delay;
delay = otherComponent->alsaBufferSize - delay;
}
margin = delay - otherComponent->framesPerBuffer / 2;
margin = delay - otherComponent->framesPerPeriod / 2;
if( margin < 0 )
{
PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" ));
*continuePoll = 0;
}
else if( margin < otherComponent->framesPerBuffer )
else if( margin < otherComponent->framesPerPeriod )
{
*pollTimeout = CalculatePollTimeout( stream, margin );
PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n",
@ -3443,7 +3474,7 @@ static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self,
else
{
void *bufs[self->numHostChannels];
int bufsize = alsa_snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
int bufsize = alsa_snd_pcm_format_size( self->nativeFormat, self->framesPerPeriod + 1 );
unsigned char *buffer = self->nonMmapBuffer;
int i;
for( i = 0; i < self->numHostChannels; ++i )
@ -3457,13 +3488,6 @@ static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self,
if( self->canMmap )
res = alsa_snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
else
{
/* using realloc for optimisation
free( self->nonMmapBuffer );
self->nonMmapBuffer = NULL;
*/
}
if( res == -EPIPE || res == -ESTRPIPE )
{
@ -3776,7 +3800,8 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
}
if( pollPlayback )
{
playbackPfds = self->pfds + (self->capture.pcm ? self->capture.nfds : 0);
/* self->pfds is in effect an array of fds; if necessary, index past the capture fds */
playbackPfds = self->pfds + (pollCapture ? self->capture.nfds : 0);
PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) );
totalFds += self->playback.nfds;
}
@ -3875,7 +3900,7 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
{
/* Drop input, a period's worth */
assert( self->capture.ready );
PaAlsaStreamComponent_EndProcessing( &self->capture, PA_MIN( self->capture.framesPerBuffer,
PaAlsaStreamComponent_EndProcessing( &self->capture, PA_MIN( self->capture.framesPerPeriod,
*framesAvail ), &xrun );
*framesAvail = 0;
self->capture.ready = 0;
@ -4173,8 +4198,8 @@ static void *CallbackThreadFunc( void *userData )
/* We can't be certain that the whole ring buffer is available for priming, but there should be
* at least one period */
avail = alsa_snd_pcm_avail_update( stream->playback.pcm );
startThreshold = avail - (avail % stream->playback.framesPerBuffer);
assert( startThreshold >= stream->playback.framesPerBuffer );
startThreshold = avail - (avail % stream->playback.framesPerPeriod);
assert( startThreshold >= stream->playback.framesPerPeriod );
}
else
{
@ -4444,10 +4469,10 @@ static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frame
/* Frames residing in buffer */
PA_ENSURE( err = GetStreamWriteAvailable( stream ) );
framesAvail = err;
hwAvail = stream->playback.bufferSize - framesAvail;
hwAvail = stream->playback.alsaBufferSize - framesAvail;
if( alsa_snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED &&
hwAvail >= stream->playback.framesPerBuffer )
hwAvail >= stream->playback.framesPerPeriod )
{
ENSURE_( alsa_snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
}

View File

@ -1019,6 +1019,149 @@ static ASIOSampleRate defaultSampleRateSearchOrder_[]
192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
static PaError InitPaDeviceInfoFromAsioDriver( PaAsioHostApiRepresentation *asioHostApi,
const char *driverName, int driverIndex,
PaDeviceInfo *deviceInfo, PaAsioDeviceInfo *asioDeviceInfo )
{
PaError result = paNoError;
/* Due to the headless design of the ASIO API, drivers are free to write over data given to them (like M-Audio
drivers f.i.). This is an attempt to overcome that. */
union _tag_local {
PaAsioDriverInfo info;
char _padding[4096];
} paAsioDriver;
asioDeviceInfo->asioChannelInfos = 0; /* we check this below to handle error cleanup */
result = LoadAsioDriver( asioHostApi, driverName, &paAsioDriver.info, asioHostApi->systemSpecific );
if( result == paNoError )
{
PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n", driverIndex,deviceInfo->name));
PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels = %d\n", driverIndex, paAsioDriver.info.inputChannelCount));
PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels = %d\n", driverIndex, paAsioDriver.info.outputChannelCount));
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", driverIndex, paAsioDriver.info.bufferMinSize));
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", driverIndex, paAsioDriver.info.bufferMaxSize));
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", driverIndex, paAsioDriver.info.bufferPreferredSize));
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", driverIndex, paAsioDriver.info.bufferGranularity));
deviceInfo->maxInputChannels = paAsioDriver.info.inputChannelCount;
deviceInfo->maxOutputChannels = paAsioDriver.info.outputChannelCount;
deviceInfo->defaultSampleRate = 0.;
bool foundDefaultSampleRate = false;
for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j )
{
ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] );
if( asioError != ASE_NoClock && asioError != ASE_NotPresent )
{
deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
foundDefaultSampleRate = true;
break;
}
}
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", driverIndex, deviceInfo->defaultSampleRate));
if( foundDefaultSampleRate ){
/* calculate default latency values from bufferPreferredSize
for default low latency, and bufferMaxSize
for default high latency.
use the default sample rate to convert from samples to
seconds. Without knowing what sample rate the user will
use this is the best we can do.
*/
double defaultLowLatency =
paAsioDriver.info.bufferPreferredSize / deviceInfo->defaultSampleRate;
deviceInfo->defaultLowInputLatency = defaultLowLatency;
deviceInfo->defaultLowOutputLatency = defaultLowLatency;
double defaultHighLatency =
paAsioDriver.info.bufferMaxSize / deviceInfo->defaultSampleRate;
if( defaultHighLatency < defaultLowLatency )
defaultHighLatency = defaultLowLatency; /* just in case the driver returns something strange */
deviceInfo->defaultHighInputLatency = defaultHighLatency;
deviceInfo->defaultHighOutputLatency = defaultHighLatency;
}else{
deviceInfo->defaultLowInputLatency = 0.;
deviceInfo->defaultLowOutputLatency = 0.;
deviceInfo->defaultHighInputLatency = 0.;
deviceInfo->defaultHighOutputLatency = 0.;
}
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", driverIndex, deviceInfo->defaultLowInputLatency));
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", driverIndex, deviceInfo->defaultLowOutputLatency));
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", driverIndex, deviceInfo->defaultHighInputLatency));
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", driverIndex, deviceInfo->defaultHighOutputLatency));
asioDeviceInfo->minBufferSize = paAsioDriver.info.bufferMinSize;
asioDeviceInfo->maxBufferSize = paAsioDriver.info.bufferMaxSize;
asioDeviceInfo->preferredBufferSize = paAsioDriver.info.bufferPreferredSize;
asioDeviceInfo->bufferGranularity = paAsioDriver.info.bufferGranularity;
asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory(
asioHostApi->allocations,
sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels
+ deviceInfo->maxOutputChannels) );
if( !asioDeviceInfo->asioChannelInfos )
{
result = paInsufficientMemory;
goto error_unload;
}
int a;
for( a=0; a < deviceInfo->maxInputChannels; ++a ){
asioDeviceInfo->asioChannelInfos[a].channel = a;
asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue;
ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] );
if( asioError != ASE_OK )
{
result = paUnanticipatedHostError;
PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
goto error_unload;
}
}
for( a=0; a < deviceInfo->maxOutputChannels; ++a ){
int b = deviceInfo->maxInputChannels + a;
asioDeviceInfo->asioChannelInfos[b].channel = a;
asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse;
ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] );
if( asioError != ASE_OK )
{
result = paUnanticipatedHostError;
PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
goto error_unload;
}
}
/* unload the driver */
UnloadAsioDriver();
}
return result;
error_unload:
UnloadAsioDriver();
if( asioDeviceInfo->asioChannelInfos ){
PaUtil_GroupFreeMemory( asioHostApi->allocations, asioDeviceInfo->asioChannelInfos );
asioDeviceInfo->asioChannelInfos = 0;
}
return result;
}
/* we look up IsDebuggerPresent at runtime incase it isn't present (on Win95 for example) */
typedef BOOL (WINAPI *IsDebuggerPresentPtr)(VOID);
IsDebuggerPresentPtr IsDebuggerPresent_ = 0;
@ -1142,14 +1285,6 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
for( i=0; i < driverCount; ++i )
{
/* Due to the headless design of the ASIO API, drivers are free to write over data given to them (like M-Audio
drivers f.i.). This is an attempt to overcome that. */
union _tag_local {
PaAsioDriverInfo info;
char _padding[4096];
} paAsioDriver;
PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i]));
// Since portaudio opens ALL ASIO drivers, and no one else does that,
@ -1177,13 +1312,12 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
if( strcmp(names[i], "ASIO Digidesign Driver") == 0 )
{
PA_DEBUG(("BLACKLISTED!!! ASIO Digidesign Driver would quit the debugger\n"));
continue;
continue;
}
}
/* Attempt to load the asio driver... */
if( LoadAsioDriver( asioHostApi, names[i], &paAsioDriver.info, asioHostApi->systemSpecific ) == paNoError )
/* Attempt to init device info from the asio driver... */
{
PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
@ -1192,119 +1326,17 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
deviceInfo->hostApi = hostApiIndex;
deviceInfo->name = names[i];
PA_DEBUG(("PaAsio_Initialize: drv:%d name = %s\n", i,deviceInfo->name));
PA_DEBUG(("PaAsio_Initialize: drv:%d inputChannels = %d\n", i, paAsioDriver.info.inputChannelCount));
PA_DEBUG(("PaAsio_Initialize: drv:%d outputChannels = %d\n", i, paAsioDriver.info.outputChannelCount));
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMinSize = %d\n", i, paAsioDriver.info.bufferMinSize));
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferMaxSize = %d\n", i, paAsioDriver.info.bufferMaxSize));
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferPreferredSize = %d\n", i, paAsioDriver.info.bufferPreferredSize));
PA_DEBUG(("PaAsio_Initialize: drv:%d bufferGranularity = %d\n", i, paAsioDriver.info.bufferGranularity));
deviceInfo->maxInputChannels = paAsioDriver.info.inputChannelCount;
deviceInfo->maxOutputChannels = paAsioDriver.info.outputChannelCount;
deviceInfo->defaultSampleRate = 0.;
bool foundDefaultSampleRate = false;
for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j )
if( InitPaDeviceInfoFromAsioDriver( asioHostApi, names[i], i, deviceInfo, asioDeviceInfo ) == paNoError )
{
ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] );
if( asioError != ASE_NoClock && asioError != ASE_NotPresent )
{
deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
foundDefaultSampleRate = true;
break;
}
(*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
++(*hostApi)->info.deviceCount;
}
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", i, deviceInfo->defaultSampleRate));
if( foundDefaultSampleRate ){
/* calculate default latency values from bufferPreferredSize
for default low latency, and bufferMaxSize
for default high latency.
use the default sample rate to convert from samples to
seconds. Without knowing what sample rate the user will
use this is the best we can do.
*/
double defaultLowLatency =
paAsioDriver.info.bufferPreferredSize / deviceInfo->defaultSampleRate;
deviceInfo->defaultLowInputLatency = defaultLowLatency;
deviceInfo->defaultLowOutputLatency = defaultLowLatency;
double defaultHighLatency =
paAsioDriver.info.bufferMaxSize / deviceInfo->defaultSampleRate;
if( defaultHighLatency < defaultLowLatency )
defaultHighLatency = defaultLowLatency; /* just in case the driver returns something strange */
deviceInfo->defaultHighInputLatency = defaultHighLatency;
deviceInfo->defaultHighOutputLatency = defaultHighLatency;
}else{
deviceInfo->defaultLowInputLatency = 0.;
deviceInfo->defaultLowOutputLatency = 0.;
deviceInfo->defaultHighInputLatency = 0.;
deviceInfo->defaultHighOutputLatency = 0.;
else
{
PA_DEBUG(("Skipping ASIO device:%s\n",names[i]));
continue;
}
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowInputLatency = %f\n", i, deviceInfo->defaultLowInputLatency));
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultLowOutputLatency = %f\n", i, deviceInfo->defaultLowOutputLatency));
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighInputLatency = %f\n", i, deviceInfo->defaultHighInputLatency));
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultHighOutputLatency = %f\n", i, deviceInfo->defaultHighOutputLatency));
asioDeviceInfo->minBufferSize = paAsioDriver.info.bufferMinSize;
asioDeviceInfo->maxBufferSize = paAsioDriver.info.bufferMaxSize;
asioDeviceInfo->preferredBufferSize = paAsioDriver.info.bufferPreferredSize;
asioDeviceInfo->bufferGranularity = paAsioDriver.info.bufferGranularity;
asioDeviceInfo->asioChannelInfos = (ASIOChannelInfo*)PaUtil_GroupAllocateMemory(
asioHostApi->allocations,
sizeof(ASIOChannelInfo) * (deviceInfo->maxInputChannels
+ deviceInfo->maxOutputChannels) );
if( !asioDeviceInfo->asioChannelInfos )
{
result = paInsufficientMemory;
goto error_unload;
}
int a;
for( a=0; a < deviceInfo->maxInputChannels; ++a ){
asioDeviceInfo->asioChannelInfos[a].channel = a;
asioDeviceInfo->asioChannelInfos[a].isInput = ASIOTrue;
ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[a] );
if( asioError != ASE_OK )
{
result = paUnanticipatedHostError;
PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
goto error_unload;
}
}
for( a=0; a < deviceInfo->maxOutputChannels; ++a ){
int b = deviceInfo->maxInputChannels + a;
asioDeviceInfo->asioChannelInfos[b].channel = a;
asioDeviceInfo->asioChannelInfos[b].isInput = ASIOFalse;
ASIOError asioError = ASIOGetChannelInfo( &asioDeviceInfo->asioChannelInfos[b] );
if( asioError != ASE_OK )
{
result = paUnanticipatedHostError;
PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
goto error_unload;
}
}
/* unload the driver */
UnloadAsioDriver();
(*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
++(*hostApi)->info.deviceCount;
}
}
}
@ -1338,9 +1370,6 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
return result;
error_unload:
UnloadAsioDriver();
error:
if( asioHostApi )
{

View File

@ -661,7 +661,7 @@ static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi,
VVDBUG(("InitializeDeviceInfo(): macCoreDeviceId=%ld\n", macCoreDeviceId));
memset(deviceInfo, 0, sizeof(deviceInfo));
memset(deviceInfo, 0, sizeof(PaDeviceInfo));
deviceInfo->structVersion = 2;
deviceInfo->hostApi = hostApiIndex;

View File

@ -318,6 +318,13 @@ error:
return result;
}
static int CalcHigherLogTwo( int n )
{
int log2 = 0;
while( (1<<log2) < n ) log2++;
return log2;
}
static PaError QueryDirection( const char *deviceName, StreamMode mode, double *defaultSampleRate, int *maxChannelCount,
double *defaultLowLatency, double *defaultHighLatency )
{
@ -327,6 +334,8 @@ static PaError QueryDirection( const char *deviceName, StreamMode mode, double *
int devHandle = -1;
int sr;
*maxChannelCount = 0; /* Default value in case this fails */
int temp, frgmt;
unsigned long fragFrames;
if ( (devHandle = open( deviceName, (mode == StreamMode_In ? O_RDONLY : O_WRONLY) | O_NONBLOCK )) < 0 )
{
@ -354,7 +363,7 @@ static PaError QueryDirection( const char *deviceName, StreamMode mode, double *
maxNumChannels = 0;
for( numChannels = 1; numChannels <= 16; numChannels++ )
{
int temp = numChannels;
temp = numChannels;
if( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ) < 0 )
{
busy = EAGAIN == errno || EBUSY == errno;
@ -401,8 +410,8 @@ static PaError QueryDirection( const char *deviceName, StreamMode mode, double *
* to a supported number of channels. SG20011005 */
{
/* use most reasonable default value */
int temp = PA_MIN( maxNumChannels, 2 );
ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ), paUnanticipatedHostError );
numChannels = PA_MIN( maxNumChannels, 2 );
ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &numChannels ), paUnanticipatedHostError );
}
/* Get supported sample rate closest to 44100 Hz */
@ -415,9 +424,21 @@ static PaError QueryDirection( const char *deviceName, StreamMode mode, double *
}
*maxChannelCount = maxNumChannels;
/* TODO */
*defaultLowLatency = 512. / *defaultSampleRate;
*defaultHighLatency = 2048. / *defaultSampleRate;
/* Attempt to set low latency with 4 frags-per-buffer, 128 frames-per-frag (total buffer 512 frames)
* since the ioctl sets bytes, multiply by numChannels, and base on 2 bytes-per-sample, */
fragFrames = 128;
frgmt = (4 << 16) + (CalcHigherLogTwo( fragFrames * numChannels * 2 ) & 0xffff);
ENSURE_( ioctl( devHandle, SNDCTL_DSP_SETFRAGMENT, &frgmt ), paUnanticipatedHostError );
/* Use the value set by the ioctl to give the latency achieved */
fragFrames = pow( 2, frgmt & 0xffff ) / (numChannels * 2);
*defaultLowLatency = ((frgmt >> 16) - 1) * fragFrames / *defaultSampleRate;
/* Cannot now try setting a high latency (device would need closing and opening again). Make
* high-latency 4 times the low unless the fragFrames are significantly more than requested 128 */
temp = (fragFrames < 256) ? 4 : (fragFrames < 512) ? 2 : 1;
*defaultHighLatency = temp * *defaultLowLatency;
error:
if( devHandle >= 0 )
@ -962,13 +983,6 @@ static unsigned long PaOssStreamComponent_BufferSize( PaOssStreamComponent *comp
return PaOssStreamComponent_FrameSize( component ) * component->hostFrames * component->numBufs;
}
static int CalcHigherLogTwo( int n )
{
int log2 = 0;
while( (1<<log2) < n ) log2++;
return log2;
}
/** Configure stream component device parameters.
*/
static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component, double sampleRate, unsigned long
@ -995,8 +1009,9 @@ static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component,
*/
if( framesPerBuffer == paFramesPerBufferUnspecified )
{
bufSz = (unsigned long)(component->latency * sampleRate);
fragSz = bufSz / 4;
/* Aim for 4 fragments in the complete buffer; the latency comes from 3 of these */
fragSz = (unsigned long)(component->latency * sampleRate / 3);
bufSz = fragSz * 4;
}
else
{

View File

@ -112,6 +112,18 @@ TODO:
0011 1111 1000 0000 0000 0000 0000 0000 => 0x3F800000
*/
#if defined(_WIN64) || defined(_WIN32_WCE)
/*
-EMT64/AMD64 uses different asm
-VC2005 doesnt allow _WIN64 with inline assembly either!
*/
void PaUtil_InitializeX86PlainConverters( void )
{
}
#else
/* -------------------------------------------------------------------------- */
static const short fpuControlWord_ = 0x033F; /*round to nearest, 64 bit precision, all exceptions masked*/
@ -130,19 +142,6 @@ static const float const_float_dither_scale_ = PA_FLOAT_DITHER_SCALE_;
/* -------------------------------------------------------------------------- */
#if defined(_WIN64) || defined(_WIN32_WCE)
/*
-EMT64/AMD64 uses different asm
-VC2005 doesnt allow _WIN64 with inline assembly either!
*/
void PaUtil_InitializeX86PlainConverters( void )
{
}
#else
static void Float32_To_Int32(
void *destinationBuffer, signed int destinationStride,
void *sourceBuffer, signed int sourceStride,