mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-16 16:10:06 +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:
parent
f7aca4b474
commit
e5719621c2
@ -208,7 +208,7 @@ case "${host_os}" in
|
|||||||
LIBS="-framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon"
|
LIBS="-framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon"
|
||||||
|
|
||||||
if test "x$enable_mac_universal" = "xyes" ; then
|
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)
|
[12]*|3.0|3.1)
|
||||||
dnl In pre-3.2 versions of Xcode, xcodebuild doesn't
|
dnl In pre-3.2 versions of Xcode, xcodebuild doesn't
|
||||||
|
@ -107,7 +107,12 @@ int main(void)
|
|||||||
PaError err;
|
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",
|
printf( "PortAudio version number = %d\nPortAudio version text = '%s'\n",
|
||||||
Pa_GetVersion(), Pa_GetVersionText() );
|
Pa_GetVersion(), Pa_GetVersionText() );
|
||||||
@ -242,7 +247,6 @@ int main(void)
|
|||||||
|
|
||||||
error:
|
error:
|
||||||
Pa_Terminate();
|
Pa_Terminate();
|
||||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
|
||||||
fprintf( stderr, "Error number: %d\n", err );
|
fprintf( stderr, "Error number: %d\n", err );
|
||||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||||
return err;
|
return err;
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
/****************************************** Definitions ***********/
|
/****************************************** Definitions ***********/
|
||||||
#define MODE_INPUT (0)
|
#define MODE_INPUT (0)
|
||||||
#define MODE_OUTPUT (1)
|
#define MODE_OUTPUT (1)
|
||||||
|
#define MAX_TEST_CHANNELS 4
|
||||||
|
|
||||||
typedef struct PaQaData
|
typedef struct PaQaData
|
||||||
{
|
{
|
||||||
@ -235,6 +236,8 @@ static void TestDevices( int mode )
|
|||||||
pdi = Pa_GetDeviceInfo( id );
|
pdi = Pa_GetDeviceInfo( id );
|
||||||
/* Try 1 to maxChannels on each device. */
|
/* Try 1 to maxChannels on each device. */
|
||||||
maxChannels = (( mode == MODE_INPUT ) ? pdi->maxInputChannels : pdi->maxOutputChannels);
|
maxChannels = (( mode == MODE_INPUT ) ? pdi->maxInputChannels : pdi->maxOutputChannels);
|
||||||
|
if( maxChannels > MAX_TEST_CHANNELS )
|
||||||
|
maxChannels = MAX_TEST_CHANNELS;
|
||||||
|
|
||||||
for( jc=1; jc<=maxChannels; jc++ )
|
for( jc=1; jc<=maxChannels; jc++ )
|
||||||
{
|
{
|
||||||
@ -350,7 +353,7 @@ static int TestAdvance( int mode, PaDeviceIndex deviceID, double sampleRate,
|
|||||||
oldStamp = Pa_GetStreamTime(stream);
|
oldStamp = Pa_GetStreamTime(stream);
|
||||||
Pa_Sleep(msec);
|
Pa_Sleep(msec);
|
||||||
newStamp = Pa_GetStreamTime(stream);
|
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) );
|
EXPECT( (oldStamp < newStamp) );
|
||||||
/* Check to make sure callback is decrementing framesLeft. */
|
/* Check to make sure callback is decrementing framesLeft. */
|
||||||
oldFrames = myData.framesLeft;
|
oldFrames = myData.framesLeft;
|
||||||
|
@ -361,15 +361,15 @@ static int paqaVerifyDeviceInfoLatency( void )
|
|||||||
printf(" Output defaultHighOutputLatency = %f seconds\n", pdi->defaultHighOutputLatency);
|
printf(" Output defaultHighOutputLatency = %f seconds\n", pdi->defaultHighOutputLatency);
|
||||||
QA_ASSERT_TRUE( "defaultLowOutputLatency should be > 0", (pdi->defaultLowOutputLatency > 0.0) );
|
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 > 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 )
|
if( pdi->maxInputChannels > 0 )
|
||||||
{
|
{
|
||||||
printf(" Input defaultLowOutputLatency = %f seconds\n", pdi->defaultLowInputLatency);
|
printf(" Input defaultLowInputLatency = %f seconds\n", pdi->defaultLowInputLatency);
|
||||||
printf(" Input defaultHighOutputLatency = %f seconds\n", pdi->defaultHighInputLatency);
|
printf(" Input defaultHighInputLatency = %f seconds\n", pdi->defaultHighInputLatency);
|
||||||
QA_ASSERT_TRUE( "defaultLowOutputLatency should be > 0", (pdi->defaultLowInputLatency > 0.0) );
|
QA_ASSERT_TRUE( "defaultLowInputLatency should be > 0", (pdi->defaultLowInputLatency > 0.0) );
|
||||||
QA_ASSERT_TRUE( "defaultHighOutputLatency should be > 0", (pdi->defaultHighInputLatency > 0.0) );
|
QA_ASSERT_TRUE( "defaultHighInputLatency should be > 0", (pdi->defaultHighInputLatency > 0.0) );
|
||||||
//QA_ASSERT_TRUE( "defaultHighOutputLatency should be > Low", (pdi->defaultHighInputLatency > pdi->defaultLowInputLatency) );
|
QA_ASSERT_TRUE( "defaultHighInputLatency should be >= Low", (pdi->defaultHighInputLatency >= pdi->defaultLowInputLatency) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -238,7 +238,7 @@ PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
|
|||||||
bp->inputConverter =
|
bp->inputConverter =
|
||||||
PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, tempInputStreamFlags );
|
PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, tempInputStreamFlags );
|
||||||
|
|
||||||
bp->inputZeroer = PaUtil_SelectZeroer( hostInputSampleFormat );
|
bp->inputZeroer = PaUtil_SelectZeroer( userInputSampleFormat );
|
||||||
|
|
||||||
bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
|
bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
|
||||||
|
|
||||||
|
@ -602,7 +602,6 @@ typedef enum
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
PaSampleFormat hostSampleFormat;
|
PaSampleFormat hostSampleFormat;
|
||||||
unsigned long framesPerBuffer;
|
|
||||||
int numUserChannels, numHostChannels;
|
int numUserChannels, numHostChannels;
|
||||||
int userInterleaved, hostInterleaved;
|
int userInterleaved, hostInterleaved;
|
||||||
int canMmap;
|
int canMmap;
|
||||||
@ -613,7 +612,7 @@ typedef struct
|
|||||||
int useReventFix; /* Alsa older than 1.0.16, plug devices need a fix */
|
int useReventFix; /* Alsa older than 1.0.16, plug devices need a fix */
|
||||||
|
|
||||||
snd_pcm_t *pcm;
|
snd_pcm_t *pcm;
|
||||||
snd_pcm_uframes_t bufferSize;
|
snd_pcm_uframes_t framesPerPeriod, alsaBufferSize;
|
||||||
snd_pcm_format_t nativeFormat;
|
snd_pcm_format_t nativeFormat;
|
||||||
unsigned int nfds;
|
unsigned int nfds;
|
||||||
int ready; /* Marked ready from poll */
|
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;
|
PaError result = paNoError;
|
||||||
snd_pcm_hw_params_t *hwParams;
|
snd_pcm_hw_params_t *hwParams;
|
||||||
snd_pcm_uframes_t lowLatency = 512, highLatency = 2048;
|
snd_pcm_uframes_t alsaBufferFrames, alsaPeriodFrames;
|
||||||
unsigned int minChans, maxChans;
|
unsigned int minChans, maxChans;
|
||||||
int* minChannels, * maxChannels;
|
int* minChannels, * maxChannels;
|
||||||
double * defaultLowLatency, * defaultHighLatency, * defaultSampleRate =
|
double * defaultLowLatency, * defaultHighLatency, * defaultSampleRate =
|
||||||
&devInfo->baseDeviceInfo.defaultSampleRate;
|
&devInfo->baseDeviceInfo.defaultSampleRate;
|
||||||
double defaultSr = *defaultSampleRate;
|
double defaultSr = *defaultSampleRate;
|
||||||
|
int dir;
|
||||||
|
|
||||||
assert( pcm );
|
assert( pcm );
|
||||||
|
|
||||||
@ -909,36 +909,34 @@ static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, in
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TWEAKME:
|
/* TWEAKME:
|
||||||
*
|
* Giving values for default min and max latency is not straightforward.
|
||||||
* Giving values for default min and max latency is not
|
* * for low latency, we want to give the lowest value that will work reliably.
|
||||||
* straightforward. Here are our objectives:
|
* 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 low latency, we want to give the lowest value
|
* * for high latency we want to give a large enough value that dropouts are basically impossible.
|
||||||
* that will work reliably. This varies based on the
|
* This doesn't really require as much tweaking, since providing too large a number will
|
||||||
* sound card, kernel, CPU, etc. I think it is better
|
* just cause us to select the nearest setting that will work at stream config time.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
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 */
|
/* Have to reset hwParams, to set new buffer size; need to also set sample rate again */
|
||||||
ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
|
ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
|
||||||
ENSURE_( SetApproximateSampleRate( pcm, hwParams, defaultSr ), 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;
|
*minChannels = (int)minChans;
|
||||||
*maxChannels = (int)maxChans;
|
*maxChannels = (int)maxChans;
|
||||||
*defaultSampleRate = defaultSr;
|
*defaultSampleRate = defaultSr;
|
||||||
*defaultLowLatency = (double) lowLatency / *defaultSampleRate;
|
|
||||||
*defaultHighLatency = (double) highLatency / *defaultSampleRate;
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
alsa_snd_pcm_close( pcm );
|
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
|
/* 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 )
|
static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo )
|
||||||
{
|
{
|
||||||
deviceInfo->structVersion = -1;
|
deviceInfo->structVersion = -1;
|
||||||
@ -1081,6 +1079,38 @@ static int IgnorePlugin( const char *pluginId )
|
|||||||
return 0;
|
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.
|
/** Open PCM device.
|
||||||
*
|
*
|
||||||
* Wrapper around alsa_snd_pcm_open which may repeatedly retry opening a device if it is busy, for
|
* 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 )
|
while( alsa_snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 )
|
||||||
{
|
{
|
||||||
char *alsaDeviceName, *deviceName;
|
char *alsaDeviceName, *deviceName, *infoName;
|
||||||
size_t len;
|
size_t len;
|
||||||
int hasPlayback = 0, hasCapture = 0;
|
int hasPlayback = 0, hasCapture = 0;
|
||||||
snprintf( buf, sizeof (buf), "hw:%d,%d", cardIdx, devIdx );
|
snprintf( buf, sizeof (buf), "hw:%d,%d", cardIdx, devIdx );
|
||||||
@ -1277,12 +1307,13 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infoName = SkipCardDetailsInName( (char *)alsa_snd_pcm_info_get_name( pcmInfo ), cardName );
|
||||||
|
|
||||||
/* The length of the string written by snprintf plus terminating 0 */
|
/* 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 ),
|
PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
|
||||||
paInsufficientMemory );
|
paInsufficientMemory );
|
||||||
snprintf( deviceName, len, "%s: %s (%s)", cardName,
|
snprintf( deviceName, len, "%s: %s (%s)", cardName, infoName, buf );
|
||||||
alsa_snd_pcm_info_get_name( pcmInfo ), buf );
|
|
||||||
|
|
||||||
++numDeviceNames;
|
++numDeviceNames;
|
||||||
if( !hwDevInfos || numDeviceNames > maxDeviceNames )
|
if( !hwDevInfos || numDeviceNames > maxDeviceNames )
|
||||||
@ -1905,8 +1936,8 @@ error:
|
|||||||
static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self )
|
static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self )
|
||||||
{
|
{
|
||||||
alsa_snd_pcm_close( self->pcm );
|
alsa_snd_pcm_close( self->pcm );
|
||||||
if( self->userBuffers )
|
PaUtil_FreeMemory( self->userBuffers ); /* (Ptr can be NULL; PaUtil_FreeMemory includes a NULL check) */
|
||||||
PaUtil_FreeMemory( self->userBuffers );
|
PaUtil_FreeMemory( self->nonMmapBuffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1937,7 +1968,7 @@ static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *se
|
|||||||
double sr = *sampleRate;
|
double sr = *sampleRate;
|
||||||
unsigned int minPeriods = 2;
|
unsigned int minPeriods = 2;
|
||||||
|
|
||||||
/* self->framesPerBuffer = framesPerHostBuffer; */
|
/* self->framesPerPeriod = framesPerHostBuffer; */
|
||||||
|
|
||||||
/* ... fill up the configuration space with all possibile
|
/* ... fill up the configuration space with all possibile
|
||||||
* combinations of parameters this device will accept */
|
* combinations of parameters this device will accept */
|
||||||
@ -2032,7 +2063,7 @@ error:
|
|||||||
|
|
||||||
/** Finish the configuration of the component's ALSA device.
|
/** 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.
|
* @param latency: The latency for this component.
|
||||||
*/
|
*/
|
||||||
static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *self, snd_pcm_hw_params_t* hwParams,
|
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 );
|
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 );
|
ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError );
|
||||||
|
|
||||||
/* Set the parameters! */
|
/* Set the parameters! */
|
||||||
@ -2063,21 +2094,21 @@ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *sel
|
|||||||
}
|
}
|
||||||
if( alsa_snd_pcm_hw_params_get_buffer_size != NULL )
|
if( alsa_snd_pcm_hw_params_get_buffer_size != NULL )
|
||||||
{
|
{
|
||||||
ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError );
|
ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size( hwParams, &self->alsaBufferSize ), paUnanticipatedHostError );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
self->bufferSize = bufSz;
|
self->alsaBufferSize = bufSz;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Latency in seconds */
|
/* Latency in seconds */
|
||||||
*latency = self->bufferSize / sampleRate;
|
*latency = (self->alsaBufferSize - self->framesPerPeriod) / sampleRate;
|
||||||
|
|
||||||
/* Now software parameters... */
|
/* Now software parameters... */
|
||||||
ENSURE_( alsa_snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError );
|
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_start_threshold( self->pcm, swParams, self->framesPerPeriod ), paUnanticipatedHostError );
|
||||||
ENSURE_( alsa_snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->bufferSize ), paUnanticipatedHostError );
|
ENSURE_( alsa_snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->alsaBufferSize ), paUnanticipatedHostError );
|
||||||
|
|
||||||
/* Silence buffer in the case of underrun */
|
/* Silence buffer in the case of underrun */
|
||||||
if( !primeBuffers ) /* XXX: Make sense? */
|
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_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_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError );
|
||||||
ENSURE_( alsa_snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), 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.
|
/** 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.
|
* gets configured for the device.
|
||||||
* @param accurate: If the configured period size is non-integer, this will be set to 0.
|
* @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 */
|
/* Set result */
|
||||||
self->framesPerBuffer = framesPerHostBuffer;
|
self->framesPerPeriod = framesPerHostBuffer;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
return result;
|
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
|
* 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.
|
* 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
|
* values determined here. Since these should be reported as
|
||||||
*
|
*
|
||||||
* This is one of those blocks of code that will just take a lot of
|
* 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 );
|
paUnanticipatedHostError );
|
||||||
ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ),
|
ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ),
|
||||||
paUnanticipatedHostError );
|
paUnanticipatedHostError );
|
||||||
self->capture.framesPerBuffer = self->playback.framesPerBuffer = periodSize;
|
self->capture.framesPerPeriod = self->playback.framesPerPeriod = periodSize;
|
||||||
framesPerHostBuffer = periodSize;
|
framesPerHostBuffer = periodSize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2579,15 +2610,15 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double
|
|||||||
optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize );
|
optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize );
|
||||||
optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
|
optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
|
||||||
|
|
||||||
self->capture.framesPerBuffer = optimalPeriodSize;
|
self->capture.framesPerPeriod = optimalPeriodSize;
|
||||||
dir = 0;
|
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 );
|
paUnanticipatedHostError );
|
||||||
self->playback.framesPerBuffer = optimalPeriodSize;
|
self->playback.framesPerPeriod = optimalPeriodSize;
|
||||||
dir = 0;
|
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 );
|
paUnanticipatedHostError );
|
||||||
framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer );
|
framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod );
|
||||||
*hostBufferSizeMode = paUtilBoundedHostBufferSize;
|
*hostBufferSizeMode = paUtilBoundedHostBufferSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2617,17 +2648,17 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double
|
|||||||
PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( first, firstStreamParams, framesPerUserBuffer,
|
PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( first, firstStreamParams, framesPerUserBuffer,
|
||||||
sampleRate, firstHwParams, &accurate ) );
|
sampleRate, firstHwParams, &accurate ) );
|
||||||
|
|
||||||
second->framesPerBuffer = first->framesPerBuffer;
|
second->framesPerPeriod = first->framesPerPeriod;
|
||||||
dir = 0;
|
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 );
|
paUnanticipatedHostError );
|
||||||
if( self->capture.framesPerBuffer == self->playback.framesPerBuffer )
|
if( self->capture.framesPerPeriod == self->playback.framesPerPeriod )
|
||||||
{
|
{
|
||||||
framesPerHostBuffer = self->capture.framesPerBuffer;
|
framesPerHostBuffer = self->capture.framesPerPeriod;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer );
|
framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod );
|
||||||
*hostBufferSizeMode = paUtilBoundedHostBufferSize;
|
*hostBufferSizeMode = paUtilBoundedHostBufferSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2638,14 +2669,14 @@ static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double
|
|||||||
{
|
{
|
||||||
PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->capture, inputParameters, framesPerUserBuffer,
|
PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->capture, inputParameters, framesPerUserBuffer,
|
||||||
sampleRate, hwParamsCapture, &accurate) );
|
sampleRate, hwParamsCapture, &accurate) );
|
||||||
framesPerHostBuffer = self->capture.framesPerBuffer;
|
framesPerHostBuffer = self->capture.framesPerPeriod;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert( self->playback.pcm );
|
assert( self->playback.pcm );
|
||||||
PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->playback, outputParameters, framesPerUserBuffer,
|
PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->playback, outputParameters, framesPerUserBuffer,
|
||||||
sampleRate, hwParamsPlayback, &accurate ) );
|
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 )
|
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,
|
PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->capture, hwParamsCapture, inParams, self->primeBuffers, realSr,
|
||||||
inputLatency ) );
|
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 )
|
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,
|
PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->playback, hwParamsPlayback, outParams, self->primeBuffers, realSr,
|
||||||
outputLatency ) );
|
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 */
|
/* 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,
|
unsigned long minFramesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerPeriod : ULONG_MAX,
|
||||||
self->playback.pcm ? self->playback.framesPerBuffer : ULONG_MAX );
|
self->playback.pcm ? self->playback.framesPerPeriod : ULONG_MAX );
|
||||||
self->pollTimeout = CalculatePollTimeout( self, minFramesPerHostBuffer ); /* Period in msecs, rounded up */
|
self->pollTimeout = CalculatePollTimeout( self, minFramesPerHostBuffer ); /* Period in msecs, rounded up */
|
||||||
|
|
||||||
/* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */
|
/* 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( self->callbackMode )
|
||||||
{
|
{
|
||||||
/* If the user expects a certain number of frames per callback we will either have to rely on block adaption
|
/* 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 */
|
* of host buffer frames with what the user specified */
|
||||||
if( self->framesPerUserBuffer != paFramesPerBufferUnspecified )
|
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
|
/* Unless the ratio between number of host and user buffer frames is an integer we will have to rely
|
||||||
* on block adaption */
|
* on block adaption */
|
||||||
/*
|
/*
|
||||||
if( framesPerHostBuffer % framesPerBuffer != 0 || (self->capture.pcm && self->playback.pcm &&
|
if( framesPerHostBuffer % framesPerPeriod != 0 || (self->capture.pcm && self->playback.pcm &&
|
||||||
self->capture.framesPerBuffer != self->playback.framesPerBuffer) )
|
self->capture.framesPerPeriod != self->playback.framesPerPeriod) )
|
||||||
self->useBlockAdaption = 1;
|
self->useBlockAdaption = 1;
|
||||||
else
|
else
|
||||||
self->alignFrames = 1;
|
self->alignFrames = 1;
|
||||||
@ -2796,7 +2827,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||||||
/* XXX: Why do we support this anyway? */
|
/* XXX: Why do we support this anyway? */
|
||||||
if( framesPerBuffer == paFramesPerBufferUnspecified && getenv( "PA_ALSA_PERIODSIZE" ) != NULL )
|
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") );
|
framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2823,7 +2854,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
|
|||||||
stream->streamRepresentation.streamInfo.outputLatency = outputLatency + (PaTime)(
|
stream->streamRepresentation.streamInfo.outputLatency = outputLatency + (PaTime)(
|
||||||
PaUtil_GetBufferProcessorOutputLatencyFrames( &stream->bufferProcessor ) / sampleRate);
|
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;
|
*s = (PaStream*)stream;
|
||||||
|
|
||||||
@ -2864,7 +2895,7 @@ static void SilenceBuffer( PaAlsaStream *stream )
|
|||||||
|
|
||||||
/** Start/prepare pcm(s) for streaming.
|
/** 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
|
* 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
|
* 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.
|
* be started automatically as the user writes to output.
|
||||||
@ -2950,7 +2981,7 @@ static PaError StartStream( PaStream *s )
|
|||||||
{
|
{
|
||||||
PaError result = paNoError;
|
PaError result = paNoError;
|
||||||
PaAlsaStream* stream = (PaAlsaStream*)s;
|
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 */
|
/* Ready the processor */
|
||||||
PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
|
PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
|
||||||
@ -3041,7 +3072,7 @@ error:
|
|||||||
|
|
||||||
/** Stop or abort stream.
|
/** 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
|
* 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
|
* returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish
|
||||||
* buffers (drain)
|
* buffers (drain)
|
||||||
@ -3323,16 +3354,16 @@ static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamD
|
|||||||
if( StreamDirection_Out == streamDir )
|
if( StreamDirection_Out == streamDir )
|
||||||
{
|
{
|
||||||
/* Number of eligible frames before capture overrun */
|
/* 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 )
|
if( margin < 0 )
|
||||||
{
|
{
|
||||||
PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" ));
|
PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" ));
|
||||||
*continuePoll = 0;
|
*continuePoll = 0;
|
||||||
}
|
}
|
||||||
else if( margin < otherComponent->framesPerBuffer )
|
else if( margin < otherComponent->framesPerPeriod )
|
||||||
{
|
{
|
||||||
*pollTimeout = CalculatePollTimeout( stream, margin );
|
*pollTimeout = CalculatePollTimeout( stream, margin );
|
||||||
PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n",
|
PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n",
|
||||||
@ -3443,7 +3474,7 @@ static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
void *bufs[self->numHostChannels];
|
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;
|
unsigned char *buffer = self->nonMmapBuffer;
|
||||||
int i;
|
int i;
|
||||||
for( i = 0; i < self->numHostChannels; ++i )
|
for( i = 0; i < self->numHostChannels; ++i )
|
||||||
@ -3457,13 +3488,6 @@ static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self,
|
|||||||
|
|
||||||
if( self->canMmap )
|
if( self->canMmap )
|
||||||
res = alsa_snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
|
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 )
|
if( res == -EPIPE || res == -ESTRPIPE )
|
||||||
{
|
{
|
||||||
@ -3776,7 +3800,8 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
|
|||||||
}
|
}
|
||||||
if( pollPlayback )
|
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 ) );
|
PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) );
|
||||||
totalFds += self->playback.nfds;
|
totalFds += self->playback.nfds;
|
||||||
}
|
}
|
||||||
@ -3875,7 +3900,7 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
|
|||||||
{
|
{
|
||||||
/* Drop input, a period's worth */
|
/* Drop input, a period's worth */
|
||||||
assert( self->capture.ready );
|
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 ), &xrun );
|
||||||
*framesAvail = 0;
|
*framesAvail = 0;
|
||||||
self->capture.ready = 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
|
/* We can't be certain that the whole ring buffer is available for priming, but there should be
|
||||||
* at least one period */
|
* at least one period */
|
||||||
avail = alsa_snd_pcm_avail_update( stream->playback.pcm );
|
avail = alsa_snd_pcm_avail_update( stream->playback.pcm );
|
||||||
startThreshold = avail - (avail % stream->playback.framesPerBuffer);
|
startThreshold = avail - (avail % stream->playback.framesPerPeriod);
|
||||||
assert( startThreshold >= stream->playback.framesPerBuffer );
|
assert( startThreshold >= stream->playback.framesPerPeriod );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -4444,10 +4469,10 @@ static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frame
|
|||||||
/* Frames residing in buffer */
|
/* Frames residing in buffer */
|
||||||
PA_ENSURE( err = GetStreamWriteAvailable( stream ) );
|
PA_ENSURE( err = GetStreamWriteAvailable( stream ) );
|
||||||
framesAvail = err;
|
framesAvail = err;
|
||||||
hwAvail = stream->playback.bufferSize - framesAvail;
|
hwAvail = stream->playback.alsaBufferSize - framesAvail;
|
||||||
|
|
||||||
if( alsa_snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED &&
|
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 );
|
ENSURE_( alsa_snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
|
||||||
}
|
}
|
||||||
|
@ -1019,6 +1019,149 @@ static ASIOSampleRate defaultSampleRateSearchOrder_[]
|
|||||||
192000.0, 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
|
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) */
|
/* we look up IsDebuggerPresent at runtime incase it isn't present (on Win95 for example) */
|
||||||
typedef BOOL (WINAPI *IsDebuggerPresentPtr)(VOID);
|
typedef BOOL (WINAPI *IsDebuggerPresentPtr)(VOID);
|
||||||
IsDebuggerPresentPtr IsDebuggerPresent_ = 0;
|
IsDebuggerPresentPtr IsDebuggerPresent_ = 0;
|
||||||
@ -1142,14 +1285,6 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||||||
|
|
||||||
for( i=0; i < driverCount; ++i )
|
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]));
|
PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i]));
|
||||||
|
|
||||||
// Since portaudio opens ALL ASIO drivers, and no one else does that,
|
// Since portaudio opens ALL ASIO drivers, and no one else does that,
|
||||||
@ -1182,8 +1317,7 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Attempt to load the asio driver... */
|
/* Attempt to init device info from the asio driver... */
|
||||||
if( LoadAsioDriver( asioHostApi, names[i], &paAsioDriver.info, asioHostApi->systemSpecific ) == paNoError )
|
|
||||||
{
|
{
|
||||||
PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
|
PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
|
||||||
PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
|
PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
|
||||||
@ -1192,119 +1326,17 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
|
|||||||
deviceInfo->hostApi = hostApiIndex;
|
deviceInfo->hostApi = hostApiIndex;
|
||||||
|
|
||||||
deviceInfo->name = names[i];
|
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;
|
if( InitPaDeviceInfoFromAsioDriver( asioHostApi, names[i], i, deviceInfo, asioDeviceInfo ) == paNoError )
|
||||||
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] );
|
(*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
|
||||||
if( asioError != ASE_NoClock && asioError != ASE_NotPresent )
|
++(*hostApi)->info.deviceCount;
|
||||||
{
|
|
||||||
deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
|
|
||||||
foundDefaultSampleRate = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
PA_DEBUG(("PaAsio_Initialize: drv:%d defaultSampleRate = %f\n", i, deviceInfo->defaultSampleRate));
|
{
|
||||||
|
PA_DEBUG(("Skipping ASIO device:%s\n",names[i]));
|
||||||
if( foundDefaultSampleRate ){
|
continue;
|
||||||
|
|
||||||
/* 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", 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;
|
return result;
|
||||||
|
|
||||||
error_unload:
|
|
||||||
UnloadAsioDriver();
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if( asioHostApi )
|
if( asioHostApi )
|
||||||
{
|
{
|
||||||
|
@ -661,7 +661,7 @@ static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi,
|
|||||||
|
|
||||||
VVDBUG(("InitializeDeviceInfo(): macCoreDeviceId=%ld\n", macCoreDeviceId));
|
VVDBUG(("InitializeDeviceInfo(): macCoreDeviceId=%ld\n", macCoreDeviceId));
|
||||||
|
|
||||||
memset(deviceInfo, 0, sizeof(deviceInfo));
|
memset(deviceInfo, 0, sizeof(PaDeviceInfo));
|
||||||
|
|
||||||
deviceInfo->structVersion = 2;
|
deviceInfo->structVersion = 2;
|
||||||
deviceInfo->hostApi = hostApiIndex;
|
deviceInfo->hostApi = hostApiIndex;
|
||||||
|
@ -318,6 +318,13 @@ error:
|
|||||||
return result;
|
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,
|
static PaError QueryDirection( const char *deviceName, StreamMode mode, double *defaultSampleRate, int *maxChannelCount,
|
||||||
double *defaultLowLatency, double *defaultHighLatency )
|
double *defaultLowLatency, double *defaultHighLatency )
|
||||||
{
|
{
|
||||||
@ -327,6 +334,8 @@ static PaError QueryDirection( const char *deviceName, StreamMode mode, double *
|
|||||||
int devHandle = -1;
|
int devHandle = -1;
|
||||||
int sr;
|
int sr;
|
||||||
*maxChannelCount = 0; /* Default value in case this fails */
|
*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 )
|
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;
|
maxNumChannels = 0;
|
||||||
for( numChannels = 1; numChannels <= 16; numChannels++ )
|
for( numChannels = 1; numChannels <= 16; numChannels++ )
|
||||||
{
|
{
|
||||||
int temp = numChannels;
|
temp = numChannels;
|
||||||
if( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ) < 0 )
|
if( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ) < 0 )
|
||||||
{
|
{
|
||||||
busy = EAGAIN == errno || EBUSY == errno;
|
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 */
|
* to a supported number of channels. SG20011005 */
|
||||||
{
|
{
|
||||||
/* use most reasonable default value */
|
/* use most reasonable default value */
|
||||||
int temp = PA_MIN( maxNumChannels, 2 );
|
numChannels = PA_MIN( maxNumChannels, 2 );
|
||||||
ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ), paUnanticipatedHostError );
|
ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &numChannels ), paUnanticipatedHostError );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get supported sample rate closest to 44100 Hz */
|
/* Get supported sample rate closest to 44100 Hz */
|
||||||
@ -415,9 +424,21 @@ static PaError QueryDirection( const char *deviceName, StreamMode mode, double *
|
|||||||
}
|
}
|
||||||
|
|
||||||
*maxChannelCount = maxNumChannels;
|
*maxChannelCount = maxNumChannels;
|
||||||
/* TODO */
|
|
||||||
*defaultLowLatency = 512. / *defaultSampleRate;
|
/* Attempt to set low latency with 4 frags-per-buffer, 128 frames-per-frag (total buffer 512 frames)
|
||||||
*defaultHighLatency = 2048. / *defaultSampleRate;
|
* 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:
|
error:
|
||||||
if( devHandle >= 0 )
|
if( devHandle >= 0 )
|
||||||
@ -962,13 +983,6 @@ static unsigned long PaOssStreamComponent_BufferSize( PaOssStreamComponent *comp
|
|||||||
return PaOssStreamComponent_FrameSize( component ) * component->hostFrames * component->numBufs;
|
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.
|
/** Configure stream component device parameters.
|
||||||
*/
|
*/
|
||||||
static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component, double sampleRate, unsigned long
|
static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component, double sampleRate, unsigned long
|
||||||
@ -995,8 +1009,9 @@ static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component,
|
|||||||
*/
|
*/
|
||||||
if( framesPerBuffer == paFramesPerBufferUnspecified )
|
if( framesPerBuffer == paFramesPerBufferUnspecified )
|
||||||
{
|
{
|
||||||
bufSz = (unsigned long)(component->latency * sampleRate);
|
/* Aim for 4 fragments in the complete buffer; the latency comes from 3 of these */
|
||||||
fragSz = bufSz / 4;
|
fragSz = (unsigned long)(component->latency * sampleRate / 3);
|
||||||
|
bufSz = fragSz * 4;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -112,6 +112,18 @@ TODO:
|
|||||||
0011 1111 1000 0000 0000 0000 0000 0000 => 0x3F800000
|
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*/
|
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(
|
static void Float32_To_Int32(
|
||||||
void *destinationBuffer, signed int destinationStride,
|
void *destinationBuffer, signed int destinationStride,
|
||||||
void *sourceBuffer, signed int sourceStride,
|
void *sourceBuffer, signed int sourceStride,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user