Update of /cvsroot/audacity/lib-src/portaudio-v19/src/hostapi/alsa
In directory
sc8-pr-cvs11.sourceforge.net:/tmp/cvs-serv27584/portaudio-v19/src/hostapi/alsa
Modified Files:
pa_linux_alsa.c
Log Message:
Update portaudio to 2007-jun-01 snapshot
Index: pa_linux_alsa.c
===================================================================
RCS file:
/cvsroot/audacity/lib-src/portaudio-v19/src/hostapi/alsa/pa_linux_alsa.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- pa_linux_alsa.c 6 Nov 2006 11:28:17 -0000 1.4
+++ pa_linux_alsa.c 3 Jun 2007 08:30:30 -0000 1.5
@@ -70,6 +70,7 @@
#include "pa_stream.h"
#include "pa_cpuload.h"
#include "pa_process.h"
+#include "pa_endianness.h"
#include "pa_linux_alsa.h"
@@ -109,6 +110,7 @@
unsigned long framesPerBuffer;
int numUserChannels, numHostChannels;
int userInterleaved, hostInterleaved;
+ PaDeviceIndex device; /* Keep the device index */
snd_pcm_t *pcm;
snd_pcm_uframes_t bufferSize;
@@ -135,6 +137,7 @@
int primeBuffers;
int callbackMode; /* bool: are we running in callback mode? */
int pcmsSynced; /* Have we successfully synced pcms */
+ int rtSched;
/* the callback thread uses these to poll the sound device(s), waiting
* for data to be ready/available */
@@ -444,7 +447,43 @@
int isPlug;
int hasPlayback;
int hasCapture;
-} DeviceNames;
+} HwDevInfo;
+
+
+HwDevInfo predefinedNames[] = {
+ { "center_lfe", NULL, 0, 1, 0 },
+/* { "default", NULL, 0, 1, 0 }, */
+/* { "dmix", NULL, 0, 1, 0 }, */
+/* { "dpl", NULL, 0, 1, 0 }, */
+/* { "dsnoop", NULL, 0, 1, 0 }, */
+ { "front", NULL, 0, 1, 0 },
+ { "iec958", NULL, 0, 1, 0 },
+/* { "modem", NULL, 0, 1, 0 }, */
+ { "rear", NULL, 0, 1, 0 },
+ { "side", NULL, 0, 1, 0 },
+/* { "spdif", NULL, 0, 0, 0 }, */
+ { "surround40", NULL, 0, 1, 0 },
+ { "surround41", NULL, 0, 1, 0 },
+ { "surround50", NULL, 0, 1, 0 },
+ { "surround51", NULL, 0, 1, 0 },
+ { "surround71", NULL, 0, 1, 0 },
+ { NULL, NULL, 0, 1, 0 }
+};
+
+static const HwDevInfo *FindDeviceName( const char *name )
+{
+ int i;
+
+ for( i = 0; predefinedNames[i].alsaName; i++ )
+ {
+ if( strcmp( name, predefinedNames[i].alsaName ) == 0 )
+ {
+ return &predefinedNames[i];
+ }
+ }
+
+ return NULL;
+}
static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi,
char **dst,
@@ -468,7 +507,7 @@
static int IgnorePlugin( const char *pluginId )
{
static const char *ignoredPlugins[] = {"hw", "plughw", "plug", "dsnoop",
"tee",
- "file", "null", "shm", "cards", NULL};
+ "file", "null", "shm", "cards", "rate_convert", NULL};
int i = 0;
while( ignoredPlugins[i] )
{
@@ -482,16 +521,115 @@
return 0;
}
-static int snd_pcm_open_with_retry(snd_pcm_t **pcmp, const char *name,
snd_pcm_stream_t stream, int mode)
+/** Open PCM device.
+ *
+ * Wrapper around snd_pcm_open which may repeatedly retry opening a device if
it is busy, for
+ * a certain time. This is because dmix may temporarily hold on to a device
after it (dmix)
+ * has been opened and closed.
+ * @param mode: Open mode (e.g., SND_PCM_BLOCKING).
+ * @param waitOnBusy: Retry opening busy device for up to one second?
+ **/
+static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t
stream, int mode, int waitOnBusy )
{
- int ret = snd_pcm_open(pcmp, name, stream, mode);
- if (ret==EBUSY) {
- sleep(1);
- int ret = snd_pcm_open(pcmp, name, stream, mode);
- }
- return ret;
+ int tries = 0, maxTries = waitOnBusy ? 100 : 0;
+ int ret = snd_pcm_open( pcmp, name, stream, mode );
+ for( tries = 0; tries < maxTries && -EBUSY == ret; ++tries )
+ {
+ Pa_Sleep( 10 );
+ ret = snd_pcm_open( pcmp, name, stream, mode );
+ if( -EBUSY != ret )
+ {
+ PA_DEBUG(( "%s: Successfully opened initially busy device after %d
tries\n",
+ __FUNCTION__, tries ));
+ }
+ }
+ if( -EBUSY == ret )
+ {
+ PA_DEBUG(( "%s: Failed to open busy device '%s'\n",
+ __FUNCTION__, name ));
+ }
+
+ return ret;
}
-
+
+static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo*
deviceName, int blocking,
+ PaAlsaDeviceInfo* devInfo, int* devIdx )
+{
+ PaError result = 0;
+ PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo;
+ snd_pcm_t *pcm;
+ int canMmap = -1;
+ PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
+
+ /* Zero fields */
+ InitializeDeviceInfo( baseDeviceInfo );
+
+ /* to determine device capabilities, we must open the device and query the
+ * hardware parameter configuration space */
+
+ /* Query capture */
+ if( deviceName->hasCapture &&
+ OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_CAPTURE,
blocking, 0 )
+ >= 0 )
+ {
+ if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_In,
blocking, devInfo,
+ &canMmap ) != paNoError )
+ {
+ /* Error */
+ PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__,
deviceName->alsaName));
+ goto end;
+ }
+ }
+
+ /* Query playback */
+ if( deviceName->hasPlayback &&
+ OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_PLAYBACK,
blocking, 0 )
+ >= 0 )
+ {
+ if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out,
blocking, devInfo,
+ &canMmap ) != paNoError )
+ {
+ /* Error */
+ PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__,
deviceName->alsaName));
+ goto end;
+ }
+ }
+
+ if( 0 == canMmap )
+ {
+ PA_DEBUG(("%s: Device %s doesn't support mmap\n", __FUNCTION__,
deviceName->alsaName));
+ goto end;
+ }
+
+ baseDeviceInfo->structVersion = 2;
+ baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
+ baseDeviceInfo->name = deviceName->name;
+ devInfo->alsaName = deviceName->alsaName;
+ devInfo->isPlug = deviceName->isPlug;
+
+ /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to
PaDeviceInfo object.
+ * Should now be safe to add device info, unless the device supports
neither capture nor playback
+ */
+ if( baseDeviceInfo->maxInputChannels > 0 ||
baseDeviceInfo->maxOutputChannels > 0 )
+ {
+ /* Make device default if there isn't already one or it is the ALSA
"default" device */
+ if( baseApi->info.defaultInputDevice == paNoDevice &&
baseDeviceInfo->maxInputChannels > 0 )
+ baseApi->info.defaultInputDevice = *devIdx;
+ if( (baseApi->info.defaultOutputDevice == paNoDevice ||
!strcmp(deviceName->alsaName,
+ "default" )) && baseDeviceInfo->maxOutputChannels > 0 )
+ {
+ baseApi->info.defaultOutputDevice = *devIdx;
+ PA_DEBUG(("Default output device: %s\n", deviceName->name));
+ }
+ PA_DEBUG(("%s: Adding device %s: %d\n", __FUNCTION__,
deviceName->name, *devIdx));
+ baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo;
+ (*devIdx) += 1;
+ }
+
+end:
+ return result;
+}
+
/* Build PaDeviceInfo list, ignore devices for which we cannot determine
capabilities (possibly busy, sigh) */
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
{
@@ -501,12 +639,16 @@
snd_ctl_card_info_t *cardInfo;
PaError result = paNoError;
size_t numDeviceNames = 0, maxDeviceNames = 1, i;
- DeviceNames *deviceNames = NULL;
+ HwDevInfo *hwDevInfos = NULL;
snd_config_t *topNode = NULL;
snd_pcm_info_t *pcmInfo;
int res;
int blocking = SND_PCM_NONBLOCK;
char alsaCardName[50];
+#ifdef PA_ENABLE_DEBUG_OUTPUT
+ PaTime startTime = PaUtil_GetTime();
+#endif
+
if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv(
"PA_ALSA_INITIALIZE_BLOCK" ) ) )
blocking = 0;
@@ -514,9 +656,9 @@
baseApi->info.defaultInputDevice = paNoDevice;
baseApi->info.defaultOutputDevice = paNoDevice;
- /* count the devices by enumerating all the card numbers */
+ /* Gather info about hw devices
- /* snd_card_next() modifies the integer passed to it to be:
+ * snd_card_next() modifies the integer passed to it to be:
* the index of the first card if the parameter is -1
* the index of the next card if the parameter is the index of a card
* -1 if there are no more cards
@@ -550,7 +692,7 @@
char *alsaDeviceName, *deviceName;
size_t len;
int hasPlayback = 0, hasCapture = 0;
- snprintf( buf, sizeof (buf), "%s:%d,%d", "hw", cardIdx, devIdx );
+ snprintf( buf, sizeof (buf), "hw:%d,%d", cardIdx, devIdx );
/* Obtain info about this particular device */
snd_pcm_info_set_device( pcmInfo, devIdx );
@@ -569,7 +711,8 @@
if( !hasPlayback && !hasCapture )
{
- continue; /* Error */
+ /* Error */
+ continue;
}
/* The length of the string written by snprintf plus terminating 0
*/
@@ -580,25 +723,26 @@
snd_pcm_info_get_name( pcmInfo ), buf );
++numDeviceNames;
- if( !deviceNames || numDeviceNames > maxDeviceNames )
+ if( !hwDevInfos || numDeviceNames > maxDeviceNames )
{
maxDeviceNames *= 2;
- PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames,
maxDeviceNames * sizeof (DeviceNames) ),
+ PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos,
maxDeviceNames * sizeof (HwDevInfo) ),
paInsufficientMemory );
}
PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) );
- deviceNames[ numDeviceNames - 1 ].alsaName = alsaDeviceName;
- deviceNames[ numDeviceNames - 1 ].name = deviceName;
- deviceNames[ numDeviceNames - 1 ].isPlug = 0;
- deviceNames[ numDeviceNames - 1 ].hasPlayback = hasPlayback;
- deviceNames[ numDeviceNames - 1 ].hasCapture = hasCapture;
+ hwDevInfos[ numDeviceNames - 1 ].alsaName = alsaDeviceName;
+ hwDevInfos[ numDeviceNames - 1 ].name = deviceName;
+ hwDevInfos[ numDeviceNames - 1 ].isPlug = 0;
+ hwDevInfos[ numDeviceNames - 1 ].hasPlayback = hasPlayback;
+ hwDevInfos[ numDeviceNames - 1 ].hasCapture = hasCapture;
}
snd_ctl_close( ctl );
}
/* Iterate over plugin devices */
+
if( NULL == snd_config )
{
/* snd_config_update is called implicitly by some functions, if this
hasn't happened snd_config will be NULL (bleh) */
@@ -616,6 +760,7 @@
int err = 0;
char *alsaDeviceName, *deviceName;
+ const HwDevInfo *predefined = NULL;
snd_config_t *n = snd_config_iterator_entry( i ), * tp = NULL;;
if( (err = snd_config_search( n, "type", &tp )) < 0 )
@@ -645,18 +790,31 @@
strcpy( deviceName, idStr );
++numDeviceNames;
- if( !deviceNames || numDeviceNames > maxDeviceNames )
+ if( !hwDevInfos || numDeviceNames > maxDeviceNames )
{
maxDeviceNames *= 2;
- PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames,
maxDeviceNames * sizeof (DeviceNames) ),
+ PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos,
maxDeviceNames * sizeof (HwDevInfo) ),
paInsufficientMemory );
}
- deviceNames[numDeviceNames - 1].alsaName = alsaDeviceName;
- deviceNames[numDeviceNames - 1].name = deviceName;
- deviceNames[numDeviceNames - 1].isPlug = 1;
- deviceNames[numDeviceNames - 1].hasPlayback = 1;
- deviceNames[numDeviceNames - 1].hasCapture = 1;
+ predefined = FindDeviceName( alsaDeviceName );
+
+ hwDevInfos[numDeviceNames - 1].alsaName = alsaDeviceName;
+ hwDevInfos[numDeviceNames - 1].name = deviceName;
+ hwDevInfos[numDeviceNames - 1].isPlug = 1;
+
+ if( predefined )
+ {
+ hwDevInfos[numDeviceNames - 1].hasPlayback =
+ predefined->hasPlayback;
+ hwDevInfos[numDeviceNames - 1].hasCapture =
+ predefined->hasCapture;
+ }
+ else
+ {
+ hwDevInfos[numDeviceNames - 1].hasPlayback = 1;
+ hwDevInfos[numDeviceNames - 1].hasCapture = 1;
+ }
}
}
else
@@ -670,80 +828,48 @@
PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory(
alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ),
paInsufficientMemory );
- /* Loop over list of cards, filling in info, if a device is deemed
unavailable (can't get name),
+ /* Loop over list of cards, filling in info. If a device is deemed
unavailable (can't get name),
* it's ignored.
+ *
+ * Note that we do this in two stages. This is a workaround owing to the
fact that the 'dmix'
+ * plugin may cause the underlying hardware device to be busy for a short
while even after it
+ * (dmix) is closed. The 'default' plugin may also point to the dmix
plugin, so the same goes
+ * for this.
*/
- /* while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) */
+
for( i = 0, devIdx = 0; i < numDeviceNames; ++i )
{
- snd_pcm_t *pcm;
- PaAlsaDeviceInfo *deviceInfo = &deviceInfoArray[devIdx];
- PaDeviceInfo *baseDeviceInfo = &deviceInfo->baseDeviceInfo;
- int canMmap = -1;
-
- /* Zero fields */
- InitializeDeviceInfo( baseDeviceInfo );
-
- /* to determine device capabilities, we must open the device and query
the
- * hardware parameter configuration space */
-
- /* Query capture */
- if( deviceNames[i].hasCapture &&
- snd_pcm_open_with_retry( &pcm, deviceNames[i].alsaName,
SND_PCM_STREAM_CAPTURE, blocking ) >= 0 )
- {
- if( GropeDevice( pcm, deviceNames[i].isPlug, StreamDirection_In,
blocking, deviceInfo,
- &canMmap ) != paNoError )
- {
- /* Error */
- PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__,
deviceNames[i].alsaName));
- continue;
- }
- }
-
- /* Query playback */
- if( deviceNames[i].hasPlayback &&
- snd_pcm_open_with_retry( &pcm, deviceNames[i].alsaName,
SND_PCM_STREAM_PLAYBACK, blocking ) >= 0 )
+ PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
+ HwDevInfo* hwInfo = &hwDevInfos[i];
+ if( !strcmp( hwInfo->name, "dmix" ) || !strcmp( hwInfo->name,
"default" ) )
{
- if( GropeDevice( pcm, deviceNames[i].isPlug, StreamDirection_Out,
blocking, deviceInfo,
- &canMmap ) != paNoError )
- {
- /* Error */
- PA_DEBUG(("%s: Failed groping %s for playback\n",
__FUNCTION__, deviceNames[i].alsaName));
- continue;
- }
+ continue;
}
- if( 0 == canMmap )
+ PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx
) );
+ }
+ assert( devIdx < numDeviceNames );
+ /* Now inspect 'dmix' and 'default' plugins */
+ for( i = 0; i < numDeviceNames; ++i )
+ {
+ PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
+ HwDevInfo* hwInfo = &hwDevInfos[i];
+ if( strcmp( hwInfo->name, "dmix" ) && strcmp( hwInfo->name, "default"
) )
{
- PA_DEBUG(("%s: Device %s doesn't support mmap\n", __FUNCTION__,
deviceNames[i].alsaName));
continue;
}
- baseDeviceInfo->structVersion = 2;
- baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
- baseDeviceInfo->name = deviceNames[i].name;
- deviceInfo->alsaName = deviceNames[i].alsaName;
- deviceInfo->isPlug = deviceNames[i].isPlug;
-
- /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to
PaDeviceInfo object.
- * Should now be safe to add device info, unless the device supports
neither capture nor playback
- */
- if( baseDeviceInfo->maxInputChannels > 0 ||
baseDeviceInfo->maxOutputChannels > 0 )
- {
- if( baseApi->info.defaultInputDevice == paNoDevice &&
baseDeviceInfo->maxInputChannels > 0 )
- baseApi->info.defaultInputDevice = devIdx;
- if( baseApi->info.defaultOutputDevice == paNoDevice &&
baseDeviceInfo->maxOutputChannels > 0 )
- baseApi->info.defaultOutputDevice = devIdx;
- if( strcmp(deviceNames[i].alsaName, "default")==0 )
- baseApi->info.defaultOutputDevice = devIdx;
- PA_DEBUG(("%s: Adding device %s\n", __FUNCTION__,
deviceNames[i].name));
- baseApi->deviceInfos[devIdx++] = (PaDeviceInfo *) deviceInfo;
- }
+ PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo,
+ &devIdx ) );
}
- free( deviceNames );
+ free( hwDevInfos );
baseApi->info.deviceCount = devIdx; /* Number of successfully queried
devices */
+#ifdef PA_ENABLE_DEBUG_OUTPUT
+ PA_DEBUG(( "%s: Building device list took %f seconds\n", __FUNCTION__,
PaUtil_GetTime() - startTime ));
+#endif
+
end:
return result;
@@ -804,8 +930,13 @@
if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >=
0)
available |= paInt32;
- if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24 ) >=
0)
+#ifdef PA_LITTLE_ENDIAN
+ if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE )
>= 0)
available |= paInt24;
+#elif defined PA_BIG_ENDIAN
+ if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE )
>= 0)
+ available |= paInt24;
+#endif
if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >=
0)
available |= paInt16;
@@ -830,7 +961,11 @@
return SND_PCM_FORMAT_S16;
case paInt24:
- return SND_PCM_FORMAT_S24;
+#ifdef PA_LITTLE_ENDIAN
+ return SND_PCM_FORMAT_S24_3LE;
+#elif defined PA_BIG_ENDIAN
+ return SND_PCM_FORMAT_S24_3BE;
+#endif
case paInt32:
return SND_PCM_FORMAT_S32;
@@ -879,12 +1014,16 @@
deviceName = streamInfo->deviceString;
PA_DEBUG(( "%s: Opening device %s\n", __FUNCTION__, deviceName ));
- if( (ret = snd_pcm_open_with_retry( pcm, deviceName, streamDir ==
StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
- SND_PCM_NONBLOCK )) < 0 )
+ if( (ret = OpenPcm( pcm, deviceName, streamDir == StreamDirection_In ?
SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
+ SND_PCM_NONBLOCK, 1 )) < 0 )
{
/* Not to be closed */
*pcm = NULL;
- ENSURE_( ret, ret == -EBUSY ? paDeviceUnavailable :
paBadIODeviceCombination );
+ if( -EBUSY == ret )
+ {
+ PA_DEBUG(( "%s: Device is busy\n", __FUNCTION__ ));
+ }
+ ENSURE_( ret, -EBUSY == ret ? paDeviceUnavailable :
paBadIODeviceCombination );
}
ENSURE_( snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError );
@@ -942,7 +1081,23 @@
int ret = 0;
if( (ret = snd_pcm_hw_params( pcm, hwParams )) < 0)
{
- ENSURE_( ret, ret == -EBUSY ? paDeviceUnavailable :
paUnanticipatedHostError );
+ if( -EINVAL == ret )
+ {
+ /* Don't know what to return here */
+ result = paBadIODeviceCombination;
+ goto error;
+ }
+ else if( -EBUSY == ret )
+ {
+ result = paDeviceUnavailable;
+ PA_DEBUG(( "%s: Device is busy\n", __FUNCTION__ ));
+ }
+ else
+ {
+ result = paUnanticipatedHostError;
+ }
+
+ ENSURE_( ret, result );
}
}
@@ -1023,6 +1178,8 @@
self->numHostChannels = params->channelCount;
}
+ self->device = params->device;
+
PA_ENSURE( AlsaOpen( &alsaApi->baseHostApiRep, params, streamDir,
&self->pcm ) );
self->nfds = snd_pcm_poll_descriptors_count( self->pcm );
hostSampleFormat = PaUtil_SelectClosestAvailableFormat(
GetAvailableFormats( self->pcm ), userSampleFormat );
@@ -1051,11 +1208,13 @@
PaUtil_FreeMemory( self->userBuffers );
}
-int nearbyint_(float value) {
+/*
+static int nearbyint_(float value) {
if( value - (int)value > .5 )
return (int)ceil( value );
return (int)floor( value );
}
+*/
/** Initiate configuration, preparing for determining a period size suitable
for both capture and playback components.
*
@@ -1161,7 +1320,18 @@
ENSURE_( snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams,
&bufSz ), paUnanticipatedHostError );
/* Set the parameters! */
- ENSURE_( snd_pcm_hw_params( self->pcm, hwParams ),
paUnanticipatedHostError );
+ {
+ int r = snd_pcm_hw_params( self->pcm, hwParams );
+#ifdef PA_ENABLE_DEBUG_OUTPUT
+ if( r < 0 )
+ {
+ snd_output_t *output = NULL;
+ snd_output_stdio_attach( &output, stderr, 0 );
+ snd_pcm_hw_params_dump( hwParams, output );
+ }
+#endif
+ ENSURE_(r, paUnanticipatedHostError );
+ }
ENSURE_( snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ),
paUnanticipatedHostError );
/* Latency in seconds, one period is not counted as latency */
*latency = (self->bufferSize - self->framesPerBuffer) / sampleRate;
@@ -1415,15 +1585,15 @@
if( framesPerHostBuffer < min )
{
- framesPerHostBuffer = min;
PA_DEBUG(( "%s: The determined period size (%lu) is less than
minimum (%lu)\n", __FUNCTION__,
framesPerHostBuffer, min ));
+ framesPerHostBuffer = min;
}
else if( framesPerHostBuffer > max )
{
- framesPerHostBuffer = max;
PA_DEBUG(( "%s: The determined period size (%lu) is greater than
maximum (%lu)\n", __FUNCTION__,
framesPerHostBuffer, max ));
+ framesPerHostBuffer = max;
}
assert( framesPerHostBuffer >= min && framesPerHostBuffer <= max );
@@ -1947,7 +2117,7 @@
if( stream->callbackMode )
{
- PA_ENSURE( PaUnixThread_New( &stream->thread, &CallbackThreadFunc,
stream, 1. ) );
+ PA_ENSURE( PaUnixThread_New( &stream->thread, &CallbackThreadFunc,
stream, 1., stream->rtSched ) );
}
else
{
@@ -1972,6 +2142,17 @@
static PaError AlsaStop( PaAlsaStream *stream, int abort )
{
PaError result = paNoError;
+ /* XXX: Seems that draining the dmix device may trigger a race condition
in ALSA */
+ if( stream->capture.pcm && !strcmp( Pa_GetDeviceInfo(
stream->capture.device )->name,
+ "dmix" ) )
+ {
+ abort = 1;
+ }
+ else if( stream->playback.pcm && !strcmp( Pa_GetDeviceInfo(
stream->playback.device )->name,
+ "dmix" ) )
+ {
+ abort = 1;
+ }
if( abort )
{
@@ -1991,9 +2172,7 @@
if( stream->playback.pcm )
{
ENSURE_( snd_pcm_nonblock( stream->playback.pcm, 0 ),
paUnanticipatedHostError );
- /* draining causes deadlock when we are using dmix */
- /* if( snd_pcm_drain( stream->playback.pcm ) < 0 ) */
- if( snd_pcm_drop( stream->playback.pcm ) < 0 )
+ if( snd_pcm_drain( stream->playback.pcm ) < 0 )
{
PA_DEBUG(( "%s: Draining playback handle failed!\n",
__FUNCTION__ ));
}
@@ -2001,7 +2180,7 @@
if( stream->capture.pcm && !stream->pcmsSynced )
{
/* We don't need to retrieve any remaining frames */
- if( snd_pcm_drop( stream->capture.pcm ) < 0 )
+ if( snd_pcm_drain( stream->capture.pcm ) < 0 )
{
PA_DEBUG(( "%s: Draining capture handle failed!\n",
__FUNCTION__ ));
}
@@ -3309,7 +3488,7 @@
/* Extensions */
-/* Initialize host api specific structure */
+/** Initialize host API specific structure, call this before setting relevant
attributes. */
void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info )
{
info->size = sizeof (PaAlsaStreamInfo);
@@ -3318,55 +3497,55 @@
info->deviceString = NULL;
}
+/** Instruct whether to enable real-time priority when starting the audio
thread.
+ *
+ * If this is turned on by the stream is started, the audio callback thread
will be created
+ * with the FIFO scheduling policy, which is suitable for realtime operation.
+ **/
void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable )
{
-#if 0
PaAlsaStream *stream = (PaAlsaStream *) s;
- stream->threading.rtSched = enable;
-#endif
+ stream->rtSched = enable;
}
+#if 0
void PaAlsa_EnableWatchdog( PaStream *s, int enable )
{
-#if 0
PaAlsaStream *stream = (PaAlsaStream *) s;
- stream->threading.useWatchdog = enable;
-#endif
+ stream->thread.useWatchdog = enable;
}
+#endif
-int PaAlsa_GetInputCard( PaStream *s )
-{
+/** Get the ALSA-lib card index of this stream's input device. */
+PaError PaAlsa_GetStreamInputCard(PaStream* s, int* card) {
PaAlsaStream *stream = (PaAlsaStream *) s;
- snd_pcm_info_t *pcmInfo;
- int card = -1;
+ snd_pcm_info_t* pcmInfo;
+ PaError result = paNoError;
- if( stream->capture.pcm )
- {
- snd_pcm_info_alloca( &pcmInfo );
- if( snd_pcm_info( stream->capture.pcm, pcmInfo ) >= 0 )
- {
- card = snd_pcm_info_get_card( pcmInfo );
- }
- }
+ /* XXX: More descriptive error? */
+ PA_UNLESS( stream->capture.pcm, paDeviceUnavailable );
- return card;
+ snd_pcm_info_alloca( &pcmInfo );
+ PA_ENSURE( snd_pcm_info( stream->capture.pcm, pcmInfo ) );
+ *card = snd_pcm_info_get_card( pcmInfo );
+
+error:
+ return result;
}
-int PaAlsa_GetOutputCard( PaStream *s )
-{
+/** Get the ALSA-lib card index of this stream's output device. */
+PaError PaAlsa_GetStreamOutputCard(PaStream* s, int* card) {
PaAlsaStream *stream = (PaAlsaStream *) s;
- snd_pcm_info_t *pcmInfo;
- int card = -1;
+ snd_pcm_info_t* pcmInfo;
+ PaError result = paNoError;
- if( stream->playback.pcm )
- {
- snd_pcm_info_alloca( &pcmInfo );
- if( snd_pcm_info( stream->playback.pcm, pcmInfo ) >= 0 )
- {
- card = snd_pcm_info_get_card( pcmInfo );
- }
- }
+ /* XXX: More descriptive error? */
+ PA_UNLESS( stream->playback.pcm, paDeviceUnavailable );
- return card;
-}
+ snd_pcm_info_alloca( &pcmInfo );
+ PA_ENSURE( snd_pcm_info( stream->playback.pcm, pcmInfo ) );
+ *card = snd_pcm_info_get_card( pcmInfo );
+error:
+ return result;
+}
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Audacity-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/audacity-cvs