461
HwDevInfo predefinedNames[] = {
462
{ "center_lfe", NULL, 0, 1, 0 },
463
/* { "default", NULL, 0, 1, 0 }, */
464
/* { "dmix", NULL, 0, 1, 0 }, */
465
/* { "dpl", NULL, 0, 1, 0 }, */
466
/* { "dsnoop", NULL, 0, 1, 0 }, */
467
{ "front", NULL, 0, 1, 0 },
468
{ "iec958", NULL, 0, 1, 0 },
469
/* { "modem", NULL, 0, 1, 0 }, */
470
{ "rear", NULL, 0, 1, 0 },
471
{ "side", NULL, 0, 1, 0 },
472
/* { "spdif", NULL, 0, 0, 0 }, */
473
{ "surround40", NULL, 0, 1, 0 },
474
{ "surround41", NULL, 0, 1, 0 },
475
{ "surround50", NULL, 0, 1, 0 },
476
{ "surround51", NULL, 0, 1, 0 },
477
{ "surround71", NULL, 0, 1, 0 },
478
{ NULL, NULL, 0, 1, 0 }
481
static const HwDevInfo *FindDeviceName( const char *name )
485
for( i = 0; predefinedNames[i].alsaName; i++ )
487
if( strcmp( name, predefinedNames[i].alsaName ) == 0 )
489
return &predefinedNames[i];
449
496
static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi,
485
static int snd_pcm_open_with_retry(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)
487
int ret = snd_pcm_open(pcmp, name, stream, mode);
490
int ret = snd_pcm_open(pcmp, name, stream, mode);
534
* Wrapper around snd_pcm_open which may repeatedly retry opening a device if it is busy, for
535
* a certain time. This is because dmix may temporarily hold on to a device after it (dmix)
536
* has been opened and closed.
537
* @param mode: Open mode (e.g., SND_PCM_BLOCKING).
538
* @param waitOnBusy: Retry opening busy device for up to one second?
540
static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode, int waitOnBusy )
542
int tries = 0, maxTries = waitOnBusy ? 100 : 0;
543
int ret = snd_pcm_open( pcmp, name, stream, mode );
544
for( tries = 0; tries < maxTries && -EBUSY == ret; ++tries )
547
ret = snd_pcm_open( pcmp, name, stream, mode );
550
PA_DEBUG(( "%s: Successfully opened initially busy device after %d tries\n",
551
__FUNCTION__, tries ));
556
PA_DEBUG(( "%s: Failed to open busy device '%s'\n",
557
__FUNCTION__, name ));
563
static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* deviceName, int blocking,
564
PaAlsaDeviceInfo* devInfo, int* devIdx )
567
PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo;
570
PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
573
InitializeDeviceInfo( baseDeviceInfo );
575
/* to determine device capabilities, we must open the device and query the
576
* hardware parameter configuration space */
579
if( deviceName->hasCapture &&
580
OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 )
583
if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_In, blocking, devInfo,
584
&canMmap ) != paNoError )
587
PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceName->alsaName));
593
if( deviceName->hasPlayback &&
594
OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 )
597
if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out, blocking, devInfo,
598
&canMmap ) != paNoError )
601
PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceName->alsaName));
608
PA_DEBUG(("%s: Device %s doesn't support mmap\n", __FUNCTION__, deviceName->alsaName));
612
baseDeviceInfo->structVersion = 2;
613
baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
614
baseDeviceInfo->name = deviceName->name;
615
devInfo->alsaName = deviceName->alsaName;
616
devInfo->isPlug = deviceName->isPlug;
618
/* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object.
619
* Should now be safe to add device info, unless the device supports neither capture nor playback
621
if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 )
623
/* Make device default if there isn't already one or it is the ALSA "default" device */
624
if( (baseApi->info.defaultInputDevice == paNoDevice || !strcmp(deviceName->alsaName,
625
"default" )) && baseDeviceInfo->maxInputChannels > 0 )
627
baseApi->info.defaultInputDevice = *devIdx;
628
PA_DEBUG(("Default input device: %s\n", deviceName->name));
630
if( (baseApi->info.defaultOutputDevice == paNoDevice || !strcmp(deviceName->alsaName,
631
"default" )) && baseDeviceInfo->maxOutputChannels > 0 )
633
baseApi->info.defaultOutputDevice = *devIdx;
634
PA_DEBUG(("Default output device: %s\n", deviceName->name));
636
PA_DEBUG(("%s: Adding device %s: %d\n", __FUNCTION__, deviceName->name, *devIdx));
637
baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo;
495
645
/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */
496
646
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
580
735
snd_pcm_info_get_name( pcmInfo ), buf );
582
737
++numDeviceNames;
583
if( !deviceNames || numDeviceNames > maxDeviceNames )
738
if( !hwDevInfos || numDeviceNames > maxDeviceNames )
585
740
maxDeviceNames *= 2;
586
PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames, maxDeviceNames * sizeof (DeviceNames) ),
741
PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ),
587
742
paInsufficientMemory );
590
745
PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) );
592
deviceNames[ numDeviceNames - 1 ].alsaName = alsaDeviceName;
593
deviceNames[ numDeviceNames - 1 ].name = deviceName;
594
deviceNames[ numDeviceNames - 1 ].isPlug = 0;
595
deviceNames[ numDeviceNames - 1 ].hasPlayback = hasPlayback;
596
deviceNames[ numDeviceNames - 1 ].hasCapture = hasCapture;
747
hwDevInfos[ numDeviceNames - 1 ].alsaName = alsaDeviceName;
748
hwDevInfos[ numDeviceNames - 1 ].name = deviceName;
749
hwDevInfos[ numDeviceNames - 1 ].isPlug = 0;
750
hwDevInfos[ numDeviceNames - 1 ].hasPlayback = hasPlayback;
751
hwDevInfos[ numDeviceNames - 1 ].hasCapture = hasCapture;
598
753
snd_ctl_close( ctl );
601
756
/* Iterate over plugin devices */
602
758
if( NULL == snd_config )
604
760
/* snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */
645
802
strcpy( deviceName, idStr );
647
804
++numDeviceNames;
648
if( !deviceNames || numDeviceNames > maxDeviceNames )
805
if( !hwDevInfos || numDeviceNames > maxDeviceNames )
650
807
maxDeviceNames *= 2;
651
PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames, maxDeviceNames * sizeof (DeviceNames) ),
808
PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ),
652
809
paInsufficientMemory );
655
deviceNames[numDeviceNames - 1].alsaName = alsaDeviceName;
656
deviceNames[numDeviceNames - 1].name = deviceName;
657
deviceNames[numDeviceNames - 1].isPlug = 1;
658
deviceNames[numDeviceNames - 1].hasPlayback = 1;
659
deviceNames[numDeviceNames - 1].hasCapture = 1;
812
predefined = FindDeviceName( alsaDeviceName );
814
hwDevInfos[numDeviceNames - 1].alsaName = alsaDeviceName;
815
hwDevInfos[numDeviceNames - 1].name = deviceName;
816
hwDevInfos[numDeviceNames - 1].isPlug = 1;
820
hwDevInfos[numDeviceNames - 1].hasPlayback =
821
predefined->hasPlayback;
822
hwDevInfos[numDeviceNames - 1].hasCapture =
823
predefined->hasCapture;
827
hwDevInfos[numDeviceNames - 1].hasPlayback = 1;
828
hwDevInfos[numDeviceNames - 1].hasCapture = 1;
670
840
PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory(
671
841
alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ), paInsufficientMemory );
673
/* Loop over list of cards, filling in info, if a device is deemed unavailable (can't get name),
843
/* Loop over list of cards, filling in info. If a device is deemed unavailable (can't get name),
846
* Note that we do this in two stages. This is a workaround owing to the fact that the 'dmix'
847
* plugin may cause the underlying hardware device to be busy for a short while even after it
848
* (dmix) is closed. The 'default' plugin may also point to the dmix plugin, so the same goes
676
/* while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) */
677
852
for( i = 0, devIdx = 0; i < numDeviceNames; ++i )
680
PaAlsaDeviceInfo *deviceInfo = &deviceInfoArray[devIdx];
681
PaDeviceInfo *baseDeviceInfo = &deviceInfo->baseDeviceInfo;
685
InitializeDeviceInfo( baseDeviceInfo );
687
/* to determine device capabilities, we must open the device and query the
688
* hardware parameter configuration space */
691
if( deviceNames[i].hasCapture &&
692
snd_pcm_open_with_retry( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_CAPTURE, blocking ) >= 0 )
694
if( GropeDevice( pcm, deviceNames[i].isPlug, StreamDirection_In, blocking, deviceInfo,
695
&canMmap ) != paNoError )
698
PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceNames[i].alsaName));
704
if( deviceNames[i].hasPlayback &&
705
snd_pcm_open_with_retry( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_PLAYBACK, blocking ) >= 0 )
707
if( GropeDevice( pcm, deviceNames[i].isPlug, StreamDirection_Out, blocking, deviceInfo,
708
&canMmap ) != paNoError )
711
PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceNames[i].alsaName));
718
PA_DEBUG(("%s: Device %s doesn't support mmap\n", __FUNCTION__, deviceNames[i].alsaName));
722
baseDeviceInfo->structVersion = 2;
723
baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
724
baseDeviceInfo->name = deviceNames[i].name;
725
deviceInfo->alsaName = deviceNames[i].alsaName;
726
deviceInfo->isPlug = deviceNames[i].isPlug;
728
/* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object.
729
* Should now be safe to add device info, unless the device supports neither capture nor playback
731
if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 )
733
if( baseApi->info.defaultInputDevice == paNoDevice && baseDeviceInfo->maxInputChannels > 0 )
734
baseApi->info.defaultInputDevice = devIdx;
735
if( baseApi->info.defaultOutputDevice == paNoDevice && baseDeviceInfo->maxOutputChannels > 0 )
736
baseApi->info.defaultOutputDevice = devIdx;
737
if( strcmp(deviceNames[i].alsaName, "default")==0 )
738
baseApi->info.defaultOutputDevice = devIdx;
739
PA_DEBUG(("%s: Adding device %s\n", __FUNCTION__, deviceNames[i].name));
740
baseApi->deviceInfos[devIdx++] = (PaDeviceInfo *) deviceInfo;
854
PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
855
HwDevInfo* hwInfo = &hwDevInfos[i];
856
if( !strcmp( hwInfo->name, "dmix" ) || !strcmp( hwInfo->name, "default" ) )
861
PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) );
863
assert( devIdx < numDeviceNames );
864
/* Now inspect 'dmix' and 'default' plugins */
865
for( i = 0; i < numDeviceNames; ++i )
867
PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
868
HwDevInfo* hwInfo = &hwDevInfos[i];
869
if( strcmp( hwInfo->name, "dmix" ) && strcmp( hwInfo->name, "default" ) )
874
PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo,
745
879
baseApi->info.deviceCount = devIdx; /* Number of successfully queried devices */
881
#ifdef PA_ENABLE_DEBUG_OUTPUT
882
PA_DEBUG(( "%s: Building device list took %f seconds\n", __FUNCTION__, PaUtil_GetTime() - startTime ));
879
1026
deviceName = streamInfo->deviceString;
881
1028
PA_DEBUG(( "%s: Opening device %s\n", __FUNCTION__, deviceName ));
882
if( (ret = snd_pcm_open_with_retry( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
883
SND_PCM_NONBLOCK )) < 0 )
1029
if( (ret = OpenPcm( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
1030
SND_PCM_NONBLOCK, 1 )) < 0 )
885
1032
/* Not to be closed */
887
ENSURE_( ret, ret == -EBUSY ? paDeviceUnavailable : paBadIODeviceCombination );
1034
ENSURE_( ret, -EBUSY == ret ? paDeviceUnavailable : paBadIODeviceCombination );
889
1036
ENSURE_( snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError );
1158
1325
snd_pcm_sw_params_alloca( &swParams );
1160
bufSz = (params->suggestedLatency * sampleRate) + self->framesPerBuffer; /* One period does not count as latency */
1327
bufSz = params->suggestedLatency * sampleRate;
1161
1328
ENSURE_( snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError );
1163
1330
/* Set the parameters! */
1164
ENSURE_( snd_pcm_hw_params( self->pcm, hwParams ), paUnanticipatedHostError );
1332
int r = snd_pcm_hw_params( self->pcm, hwParams );
1333
#ifdef PA_ENABLE_DEBUG_OUTPUT
1336
snd_output_t *output = NULL;
1337
snd_output_stdio_attach( &output, stderr, 0 );
1338
snd_pcm_hw_params_dump( hwParams, output );
1341
ENSURE_(r, paUnanticipatedHostError );
1165
1343
ENSURE_( snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError );
1166
/* Latency in seconds, one period is not counted as latency */
1167
*latency = (self->bufferSize - self->framesPerBuffer) / sampleRate;
1344
/* Latency in seconds */
1345
*latency = self->bufferSize / sampleRate;
1169
1347
/* Now software parameters... */
1170
1348
ENSURE_( snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError );
1346
/* Using 5 as a base number of periods, we try to approximate the suggested latency (+1 period),
1524
/* Using the base number of periods, we try to approximate the suggested latency (+1 period),
1347
1525
finding a combination of period/buffer size which best fits these constraints */
1349
unsigned numPeriods = 4, maxPeriods = 0;
1527
unsigned numPeriods = numPeriods_, maxPeriods = 0;
1350
1528
/* It may be that the device only supports 2 periods for instance */
1352
1530
ENSURE_( snd_pcm_hw_params_get_periods_max( hwParams, &maxPeriods, &dir ), paUnanticipatedHostError );
1353
1531
assert( maxPeriods > 1 );
1354
/* One period is not counted as latency */
1356
1532
numPeriods = PA_MIN( maxPeriods, numPeriods );
1358
1534
if( framesPerUserBuffer != paFramesPerBufferUnspecified )
1536
/* Try to get a power-of-two of the user buffer size. */
1360
1537
framesPerHostBuffer = framesPerUserBuffer;
1361
1538
if( framesPerHostBuffer < bufferSize )
1484
1666
unsigned long framesPerHostBuffer = 0;
1486
1668
int accurate = 1;
1669
unsigned numPeriods = numPeriods_;
1488
1671
if( self->capture.pcm && self->playback.pcm )
1490
1673
if( framesPerUserBuffer == paFramesPerBufferUnspecified )
1492
snd_pcm_uframes_t desiredLatency, e, minPeriodSize, maxPeriodSize, optimalPeriodSize, periodSize,
1675
/* Come up with a common desired latency */
1676
snd_pcm_uframes_t desiredBufSz, e, minPeriodSize, maxPeriodSize, optimalPeriodSize, periodSize,
1493
1677
minCapture, minPlayback, maxCapture, maxPlayback;
1495
/* Come up with a common desired latency */
1498
1680
ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );
1547
1731
while( optimalPeriodSize >= periodSize )
1549
if( snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 ) < 0 )
1551
if( snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, optimalPeriodSize, 0 ) >= 0 )
1733
if( snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 )
1734
>= 0 && snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback,
1735
optimalPeriodSize, 0 ) >= 0 )
1553
1739
optimalPeriodSize /= 2;
1555
1742
if( optimalPeriodSize > periodSize )
1556
1743
periodSize = optimalPeriodSize;
3321
3516
void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable )
3324
3518
PaAlsaStream *stream = (PaAlsaStream *) s;
3325
stream->threading.rtSched = enable;
3519
stream->rtSched = enable;
3329
3523
void PaAlsa_EnableWatchdog( PaStream *s, int enable )
3332
3525
PaAlsaStream *stream = (PaAlsaStream *) s;
3333
stream->threading.useWatchdog = enable;
3526
stream->thread.useWatchdog = enable;
3337
int PaAlsa_GetInputCard( PaStream *s )
3339
PaAlsaStream *stream = (PaAlsaStream *) s;
3340
snd_pcm_info_t *pcmInfo;
3343
if( stream->capture.pcm )
3345
snd_pcm_info_alloca( &pcmInfo );
3346
if( snd_pcm_info( stream->capture.pcm, pcmInfo ) >= 0 )
3348
card = snd_pcm_info_get_card( pcmInfo );
3355
int PaAlsa_GetOutputCard( PaStream *s )
3357
PaAlsaStream *stream = (PaAlsaStream *) s;
3358
snd_pcm_info_t *pcmInfo;
3361
if( stream->playback.pcm )
3363
snd_pcm_info_alloca( &pcmInfo );
3364
if( snd_pcm_info( stream->playback.pcm, pcmInfo ) >= 0 )
3366
card = snd_pcm_info_get_card( pcmInfo );
3530
PaError PaAlsa_GetStreamInputCard(PaStream* s, int* card) {
3531
PaAlsaStream *stream = (PaAlsaStream *) s;
3532
snd_pcm_info_t* pcmInfo;
3533
PaError result = paNoError;
3535
/* XXX: More descriptive error? */
3536
PA_UNLESS( stream->capture.pcm, paDeviceUnavailable );
3538
snd_pcm_info_alloca( &pcmInfo );
3539
PA_ENSURE( snd_pcm_info( stream->capture.pcm, pcmInfo ) );
3540
*card = snd_pcm_info_get_card( pcmInfo );
3546
PaError PaAlsa_GetStreamOutputCard(PaStream* s, int* card) {
3547
PaAlsaStream *stream = (PaAlsaStream *) s;
3548
snd_pcm_info_t* pcmInfo;
3549
PaError result = paNoError;
3551
/* XXX: More descriptive error? */
3552
PA_UNLESS( stream->playback.pcm, paDeviceUnavailable );
3554
snd_pcm_info_alloca( &pcmInfo );
3555
PA_ENSURE( snd_pcm_info( stream->playback.pcm, pcmInfo ) );
3556
*card = snd_pcm_info_get_card( pcmInfo );