~ubuntu-branches/ubuntu/gutsy/audacity/gutsy-backports

« back to all changes in this revision

Viewing changes to lib-src/portaudio-v19/src/hostapi/alsa/pa_linux_alsa.c

  • Committer: Bazaar Package Importer
  • Author(s): John Dong
  • Date: 2008-02-18 21:58:19 UTC
  • mfrom: (13.1.2 hardy)
  • Revision ID: james.westby@ubuntu.com-20080218215819-tmbcf1rx238r8gdv
Tags: 1.3.4-1.1ubuntu1~gutsy1
Automated backport upload; no source changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * $Id: pa_linux_alsa.c,v 1.4 2006/11/06 11:28:17 msmeyer Exp $
 
2
 * $Id: pa_linux_alsa.c,v 1.7 2007/08/16 20:45:35 richardash1981 Exp $
3
3
 * PortAudio Portable Real-Time Audio Library
4
4
 * Latest Version at: http://www.portaudio.com
5
5
 * ALSA implementation by Joshua Haberman and Arve Knudsen
6
6
 *
7
7
 * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
8
 
 * Copyright (c) 2005-2006 Arve Knudsen <aknuds-1@broadpark.no>
 
8
 * Copyright (c) 2005-2007 Arve Knudsen <aknuds-1@broadpark.no>
9
9
 *
10
10
 * Based on the Open Source API proposed by Ross Bencina
11
11
 * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
70
70
#include "pa_stream.h"
71
71
#include "pa_cpuload.h"
72
72
#include "pa_process.h"
 
73
#include "pa_endianness.h"
 
74
#include "pa_debugprint.h"
73
75
 
74
76
#include "pa_linux_alsa.h"
75
77
 
96
98
    assert( success == aErr_ );
97
99
 
98
100
static int aErr_;               /* Used with ENSURE_ */
 
101
static int numPeriods_ = 4;
 
102
 
 
103
int PaAlsa_SetNumPeriods( int numPeriods )
 
104
{
 
105
    numPeriods_ = numPeriods;
 
106
    return paNoError;
 
107
}
99
108
 
100
109
typedef enum
101
110
{
109
118
    unsigned long framesPerBuffer;
110
119
    int numUserChannels, numHostChannels;
111
120
    int userInterleaved, hostInterleaved;
 
121
    PaDeviceIndex device;     /* Keep the device index */
112
122
 
113
123
    snd_pcm_t *pcm;
114
124
    snd_pcm_uframes_t bufferSize;
135
145
    int primeBuffers;
136
146
    int callbackMode;              /* bool: are we running in callback mode? */
137
147
    int pcmsSynced;                 /* Have we successfully synced pcms */
 
148
    int rtSched;
138
149
 
139
150
    /* the callback thread uses these to poll the sound device(s), waiting
140
151
     * for data to be ready/available */
444
455
    int isPlug;
445
456
    int hasPlayback;
446
457
    int hasCapture;
447
 
} DeviceNames;
 
458
} HwDevInfo;
 
459
 
 
460
 
 
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 }
 
479
};
 
480
 
 
481
static const HwDevInfo *FindDeviceName( const char *name )
 
482
{
 
483
    int i;
 
484
 
 
485
    for( i = 0; predefinedNames[i].alsaName; i++ )
 
486
    {
 
487
        if( strcmp( name, predefinedNames[i].alsaName ) == 0 )
 
488
        {
 
489
            return &predefinedNames[i];
 
490
        }
 
491
    }
 
492
 
 
493
    return NULL;
 
494
}
448
495
 
449
496
static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi,
450
497
        char **dst,
468
515
static int IgnorePlugin( const char *pluginId )
469
516
{
470
517
    static const char *ignoredPlugins[] = {"hw", "plughw", "plug", "dsnoop", "tee",
471
 
        "file", "null", "shm", "cards", NULL};
 
518
        "file", "null", "shm", "cards", "rate_convert", NULL};
472
519
    int i = 0;
473
520
    while( ignoredPlugins[i] )
474
521
    {
482
529
    return 0;
483
530
}
484
531
 
485
 
static int snd_pcm_open_with_retry(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)
486
 
{
487
 
        int ret = snd_pcm_open(pcmp, name, stream, mode);
488
 
        if (ret==EBUSY) {
489
 
                sleep(1);
490
 
                int ret = snd_pcm_open(pcmp, name, stream, mode);
491
 
        }
492
 
        return ret;
493
 
}
494
 
                                                                          
 
532
/** Open PCM device.
 
533
 *
 
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?
 
539
 **/
 
540
static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode, int waitOnBusy )
 
541
{
 
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 )
 
545
    {
 
546
        Pa_Sleep( 10 );
 
547
        ret = snd_pcm_open( pcmp, name, stream, mode );
 
548
        if( -EBUSY != ret )
 
549
        {
 
550
            PA_DEBUG(( "%s: Successfully opened initially busy device after %d tries\n",
 
551
                        __FUNCTION__, tries ));
 
552
        }
 
553
    }
 
554
    if( -EBUSY == ret )
 
555
    {
 
556
        PA_DEBUG(( "%s: Failed to open busy device '%s'\n",
 
557
                    __FUNCTION__, name ));
 
558
    }
 
559
 
 
560
    return ret;
 
561
}
 
562
 
 
563
static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* deviceName, int blocking,
 
564
        PaAlsaDeviceInfo* devInfo, int* devIdx )
 
565
{
 
566
    PaError result = 0;
 
567
    PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo;
 
568
    snd_pcm_t *pcm;
 
569
    int canMmap = -1;
 
570
    PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
 
571
 
 
572
    /* Zero fields */
 
573
    InitializeDeviceInfo( baseDeviceInfo );
 
574
 
 
575
    /* to determine device capabilities, we must open the device and query the
 
576
     * hardware parameter configuration space */
 
577
 
 
578
    /* Query capture */
 
579
    if( deviceName->hasCapture &&
 
580
            OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 )
 
581
            >= 0 )
 
582
    {
 
583
        if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_In, blocking, devInfo,
 
584
                    &canMmap ) != paNoError )
 
585
        {
 
586
            /* Error */
 
587
            PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceName->alsaName));
 
588
            goto end;
 
589
        }
 
590
    }
 
591
 
 
592
    /* Query playback */
 
593
    if( deviceName->hasPlayback &&
 
594
            OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 )
 
595
            >= 0 )
 
596
    {
 
597
        if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out, blocking, devInfo,
 
598
                    &canMmap ) != paNoError )
 
599
        {
 
600
            /* Error */
 
601
            PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceName->alsaName));
 
602
            goto end;
 
603
        }
 
604
    }
 
605
 
 
606
    if( 0 == canMmap )
 
607
    {
 
608
        PA_DEBUG(("%s: Device %s doesn't support mmap\n", __FUNCTION__, deviceName->alsaName));
 
609
        goto end;
 
610
    }
 
611
 
 
612
    baseDeviceInfo->structVersion = 2;
 
613
    baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
 
614
    baseDeviceInfo->name = deviceName->name;
 
615
    devInfo->alsaName = deviceName->alsaName;
 
616
    devInfo->isPlug = deviceName->isPlug;
 
617
 
 
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
 
620
     */
 
621
    if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 )
 
622
    {
 
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 )
 
626
        {
 
627
            baseApi->info.defaultInputDevice = *devIdx;
 
628
            PA_DEBUG(("Default input device: %s\n", deviceName->name));
 
629
        }
 
630
        if( (baseApi->info.defaultOutputDevice == paNoDevice || !strcmp(deviceName->alsaName,
 
631
                        "default" )) && baseDeviceInfo->maxOutputChannels > 0 )
 
632
        {
 
633
            baseApi->info.defaultOutputDevice = *devIdx;
 
634
            PA_DEBUG(("Default output device: %s\n", deviceName->name));
 
635
        }
 
636
        PA_DEBUG(("%s: Adding device %s: %d\n", __FUNCTION__, deviceName->name, *devIdx));
 
637
        baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo;
 
638
        (*devIdx) += 1;
 
639
    }
 
640
 
 
641
end:
 
642
    return result;
 
643
}
 
644
 
495
645
/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */
496
646
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
497
647
{
501
651
    snd_ctl_card_info_t *cardInfo;
502
652
    PaError result = paNoError;
503
653
    size_t numDeviceNames = 0, maxDeviceNames = 1, i;
504
 
    DeviceNames *deviceNames = NULL;
 
654
    HwDevInfo *hwDevInfos = NULL;
505
655
    snd_config_t *topNode = NULL;
506
656
    snd_pcm_info_t *pcmInfo;
507
657
    int res;
508
658
    int blocking = SND_PCM_NONBLOCK;
509
659
    char alsaCardName[50];
 
660
#ifdef PA_ENABLE_DEBUG_OUTPUT
 
661
    PaTime startTime = PaUtil_GetTime();
 
662
#endif
 
663
 
510
664
    if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) )
511
665
        blocking = 0;
512
666
 
514
668
    baseApi->info.defaultInputDevice = paNoDevice;
515
669
    baseApi->info.defaultOutputDevice = paNoDevice;
516
670
 
517
 
    /* count the devices by enumerating all the card numbers */
 
671
    /* Gather info about hw devices
518
672
 
519
 
    /* snd_card_next() modifies the integer passed to it to be:
 
673
     * snd_card_next() modifies the integer passed to it to be:
520
674
     *      the index of the first card if the parameter is -1
521
675
     *      the index of the next card if the parameter is the index of a card
522
676
     *      -1 if there are no more cards
550
704
            char *alsaDeviceName, *deviceName;
551
705
            size_t len;
552
706
            int hasPlayback = 0, hasCapture = 0;
553
 
            snprintf( buf, sizeof (buf), "%s:%d,%d", "hw", cardIdx, devIdx );
 
707
            snprintf( buf, sizeof (buf), "hw:%d,%d", cardIdx, devIdx );
554
708
 
555
709
            /* Obtain info about this particular device */
556
710
            snd_pcm_info_set_device( pcmInfo, devIdx );
569
723
 
570
724
            if( !hasPlayback && !hasCapture )
571
725
            {
572
 
                continue;   /* Error */
 
726
                /* Error */
 
727
                continue;
573
728
            }
574
729
 
575
730
            /* The length of the string written by snprintf plus terminating 0 */
580
735
                    snd_pcm_info_get_name( pcmInfo ), buf );
581
736
 
582
737
            ++numDeviceNames;
583
 
            if( !deviceNames || numDeviceNames > maxDeviceNames )
 
738
            if( !hwDevInfos || numDeviceNames > maxDeviceNames )
584
739
            {
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 );
588
743
            }
589
744
 
590
745
            PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) );
591
746
 
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;
597
752
        }
598
753
        snd_ctl_close( ctl );
599
754
    }
600
755
 
601
756
    /* Iterate over plugin devices */
 
757
 
602
758
    if( NULL == snd_config )
603
759
    {
604
760
        /* snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */
616
772
            int err = 0;
617
773
 
618
774
            char *alsaDeviceName, *deviceName;
 
775
            const HwDevInfo *predefined = NULL;
619
776
            snd_config_t *n = snd_config_iterator_entry( i ), * tp = NULL;;
620
777
 
621
778
            if( (err = snd_config_search( n, "type", &tp )) < 0 )
645
802
            strcpy( deviceName, idStr );
646
803
 
647
804
            ++numDeviceNames;
648
 
            if( !deviceNames || numDeviceNames > maxDeviceNames )
 
805
            if( !hwDevInfos || numDeviceNames > maxDeviceNames )
649
806
            {
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 );
653
810
            }
654
811
 
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 );
 
813
 
 
814
            hwDevInfos[numDeviceNames - 1].alsaName = alsaDeviceName;
 
815
            hwDevInfos[numDeviceNames - 1].name = deviceName;
 
816
            hwDevInfos[numDeviceNames - 1].isPlug = 1;
 
817
 
 
818
            if( predefined )
 
819
            {
 
820
                hwDevInfos[numDeviceNames - 1].hasPlayback =
 
821
                    predefined->hasPlayback;
 
822
                hwDevInfos[numDeviceNames - 1].hasCapture =
 
823
                    predefined->hasCapture;
 
824
            }
 
825
            else
 
826
            {
 
827
                hwDevInfos[numDeviceNames - 1].hasPlayback = 1;
 
828
                hwDevInfos[numDeviceNames - 1].hasCapture = 1;
 
829
            }
660
830
        }
661
831
    }
662
832
    else
670
840
    PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory(
671
841
            alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ), paInsufficientMemory );
672
842
 
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),
674
844
     * it's ignored.
 
845
     *
 
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
 
849
     * for this.
675
850
     */
676
 
    /* while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) */
 
851
 
677
852
    for( i = 0, devIdx = 0; i < numDeviceNames; ++i )
678
853
    {
679
 
        snd_pcm_t *pcm;
680
 
        PaAlsaDeviceInfo *deviceInfo = &deviceInfoArray[devIdx];
681
 
        PaDeviceInfo *baseDeviceInfo = &deviceInfo->baseDeviceInfo;
682
 
        int canMmap = -1;
683
 
 
684
 
        /* Zero fields */
685
 
        InitializeDeviceInfo( baseDeviceInfo );
686
 
 
687
 
        /* to determine device capabilities, we must open the device and query the
688
 
         * hardware parameter configuration space */
689
 
 
690
 
        /* Query capture */
691
 
        if( deviceNames[i].hasCapture &&
692
 
                snd_pcm_open_with_retry( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_CAPTURE, blocking ) >= 0 )
693
 
        {
694
 
            if( GropeDevice( pcm, deviceNames[i].isPlug, StreamDirection_In, blocking, deviceInfo,
695
 
                        &canMmap ) != paNoError )
696
 
            {
697
 
                /* Error */
698
 
                PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceNames[i].alsaName));
699
 
                continue;
700
 
            }
701
 
        }
702
 
 
703
 
        /* Query playback */
704
 
        if( deviceNames[i].hasPlayback &&
705
 
                snd_pcm_open_with_retry( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_PLAYBACK, blocking ) >= 0 )
706
 
        {
707
 
            if( GropeDevice( pcm, deviceNames[i].isPlug, StreamDirection_Out, blocking, deviceInfo,
708
 
                        &canMmap ) != paNoError )
709
 
            {
710
 
                /* Error */
711
 
                PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceNames[i].alsaName));
712
 
                continue;
713
 
            }
714
 
        }
715
 
 
716
 
        if( 0 == canMmap )
717
 
        {
718
 
            PA_DEBUG(("%s: Device %s doesn't support mmap\n", __FUNCTION__, deviceNames[i].alsaName));
719
 
            continue;
720
 
        }
721
 
 
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;
727
 
 
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
730
 
         */
731
 
        if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 )
732
 
        {
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;
741
 
        }
742
 
    }
743
 
    free( deviceNames );
 
854
        PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
 
855
        HwDevInfo* hwInfo = &hwDevInfos[i];
 
856
        if( !strcmp( hwInfo->name, "dmix" ) || !strcmp( hwInfo->name, "default" ) )
 
857
        {
 
858
            continue;
 
859
        }
 
860
 
 
861
        PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) );
 
862
    }
 
863
    assert( devIdx < numDeviceNames );
 
864
    /* Now inspect 'dmix' and 'default' plugins */
 
865
    for( i = 0; i < numDeviceNames; ++i )
 
866
    {
 
867
        PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
 
868
        HwDevInfo* hwInfo = &hwDevInfos[i];
 
869
        if( strcmp( hwInfo->name, "dmix" ) && strcmp( hwInfo->name, "default" ) )
 
870
        {
 
871
            continue;
 
872
        }
 
873
 
 
874
        PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo,
 
875
                    &devIdx ) );
 
876
    }
 
877
    free( hwDevInfos );
744
878
 
745
879
    baseApi->info.deviceCount = devIdx;   /* Number of successfully queried devices */
746
880
 
 
881
#ifdef PA_ENABLE_DEBUG_OUTPUT
 
882
    PA_DEBUG(( "%s: Building device list took %f seconds\n", __FUNCTION__, PaUtil_GetTime() - startTime ));
 
883
#endif
 
884
 
747
885
end:
748
886
    return result;
749
887
 
804
942
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0)
805
943
        available |= paInt32;
806
944
 
807
 
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24 ) >= 0)
808
 
        available |= paInt24;
 
945
#ifdef PA_LITTLE_ENDIAN
 
946
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0)
 
947
        available |= paInt24;
 
948
#elif defined PA_BIG_ENDIAN
 
949
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0)
 
950
        available |= paInt24;
 
951
#endif
809
952
 
810
953
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0)
811
954
        available |= paInt16;
830
973
            return SND_PCM_FORMAT_S16;
831
974
 
832
975
        case paInt24:
833
 
            return SND_PCM_FORMAT_S24;
 
976
#ifdef PA_LITTLE_ENDIAN
 
977
            return SND_PCM_FORMAT_S24_3LE;
 
978
#elif defined PA_BIG_ENDIAN
 
979
            return SND_PCM_FORMAT_S24_3BE;
 
980
#endif
834
981
 
835
982
        case paInt32:
836
983
            return SND_PCM_FORMAT_S32;
879
1026
        deviceName = streamInfo->deviceString;
880
1027
 
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 )
884
1031
    {
885
1032
        /* Not to be closed */
886
1033
        *pcm = NULL;
887
 
        ENSURE_( ret, ret == -EBUSY ? paDeviceUnavailable : paBadIODeviceCombination );
 
1034
        ENSURE_( ret, -EBUSY == ret ? paDeviceUnavailable : paBadIODeviceCombination );
888
1035
    }
889
1036
    ENSURE_( snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError );
890
1037
 
942
1089
        int ret = 0;
943
1090
        if( (ret = snd_pcm_hw_params( pcm, hwParams )) < 0)
944
1091
        {
945
 
            ENSURE_( ret, ret == -EBUSY ? paDeviceUnavailable : paUnanticipatedHostError );
 
1092
            if( -EINVAL == ret )
 
1093
            {
 
1094
                /* Don't know what to return here */
 
1095
                result = paBadIODeviceCombination;
 
1096
                goto error;
 
1097
            }
 
1098
            else if( -EBUSY == ret )
 
1099
            {
 
1100
                result = paDeviceUnavailable;
 
1101
                PA_DEBUG(( "%s: Device is busy\n", __FUNCTION__ ));
 
1102
            }
 
1103
            else
 
1104
            {
 
1105
                result = paUnanticipatedHostError;
 
1106
            }
 
1107
 
 
1108
            ENSURE_( ret, result );
946
1109
        }
947
1110
    }
948
1111
 
1023
1186
        self->numHostChannels = params->channelCount;
1024
1187
    }
1025
1188
 
 
1189
    self->device = params->device;
 
1190
 
1026
1191
    PA_ENSURE( AlsaOpen( &alsaApi->baseHostApiRep, params, streamDir, &self->pcm ) );
1027
1192
    self->nfds = snd_pcm_poll_descriptors_count( self->pcm );
1028
1193
    hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat );
1051
1216
        PaUtil_FreeMemory( self->userBuffers );
1052
1217
}
1053
1218
 
1054
 
int nearbyint_(float value) {
 
1219
/*
 
1220
static int nearbyint_(float value) {
1055
1221
    if(  value - (int)value > .5 )
1056
1222
        return (int)ceil( value );
1057
1223
    return (int)floor( value );
1058
1224
}
 
1225
*/
1059
1226
 
1060
1227
/** Initiate configuration, preparing for determining a period size suitable for both capture and playback components.
1061
1228
 *
1157
1324
 
1158
1325
    snd_pcm_sw_params_alloca( &swParams );
1159
1326
 
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 );
1162
1329
 
1163
1330
    /* Set the parameters! */
1164
 
    ENSURE_( snd_pcm_hw_params( self->pcm, hwParams ), paUnanticipatedHostError );
 
1331
    {
 
1332
        int r = snd_pcm_hw_params( self->pcm, hwParams );
 
1333
#ifdef PA_ENABLE_DEBUG_OUTPUT
 
1334
        if( r < 0 )
 
1335
        {
 
1336
            snd_output_t *output = NULL;
 
1337
            snd_output_stdio_attach( &output, stderr, 0 );
 
1338
            snd_pcm_hw_params_dump( hwParams, output );
 
1339
        }
 
1340
#endif
 
1341
        ENSURE_(r, paUnanticipatedHostError );
 
1342
    }
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;
1168
1346
 
1169
1347
    /* Now software parameters... */
1170
1348
    ENSURE_( snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError );
1343
1521
        }
1344
1522
    }
1345
1523
 
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 */
1348
1526
    {
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 */
1351
1529
        dir = 0;
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 */
1355
 
        maxPeriods -= 1;
1356
1532
        numPeriods = PA_MIN( maxPeriods, numPeriods );
1357
1533
 
1358
1534
        if( framesPerUserBuffer != paFramesPerBufferUnspecified )
1359
1535
        {
 
1536
            /* Try to get a power-of-two of the user buffer size. */
1360
1537
            framesPerHostBuffer = framesPerUserBuffer;
1361
1538
            if( framesPerHostBuffer < bufferSize )
1362
1539
            {
1364
1541
                {
1365
1542
                    framesPerHostBuffer *= 2;
1366
1543
                }
 
1544
                /* One extra period is preferrable to one less (should be more robust) */
 
1545
                if( bufferSize / framesPerHostBuffer < numPeriods )
 
1546
                {
 
1547
                    framesPerHostBuffer /= 2;
 
1548
                }
1367
1549
            }
1368
1550
            else
1369
1551
            {
1415
1597
 
1416
1598
        if( framesPerHostBuffer < min )
1417
1599
        {
1418
 
            framesPerHostBuffer = min;
1419
1600
            PA_DEBUG(( "%s: The determined period size (%lu) is less than minimum (%lu)\n", __FUNCTION__,
1420
1601
                        framesPerHostBuffer, min ));
 
1602
            framesPerHostBuffer = min;
1421
1603
        }
1422
1604
        else if( framesPerHostBuffer > max )
1423
1605
        {
1424
 
            framesPerHostBuffer = max;
1425
1606
            PA_DEBUG(( "%s: The determined period size (%lu) is greater than maximum (%lu)\n", __FUNCTION__,
1426
1607
                        framesPerHostBuffer, max ));
 
1608
            framesPerHostBuffer = max;
1427
1609
        }
1428
1610
 
1429
1611
        assert( framesPerHostBuffer >= min && framesPerHostBuffer <= max );
1484
1666
    unsigned long framesPerHostBuffer = 0;
1485
1667
    int dir = 0;
1486
1668
    int accurate = 1;
 
1669
    unsigned numPeriods = numPeriods_;
1487
1670
 
1488
1671
    if( self->capture.pcm && self->playback.pcm )
1489
1672
    {
1490
1673
        if( framesPerUserBuffer == paFramesPerBufferUnspecified )
1491
1674
        {
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;
1494
1678
 
1495
 
            /* Come up with a common desired latency */
1496
 
 
1497
1679
            dir = 0;
1498
1680
            ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );
1499
1681
            dir = 0;
1506
1688
            maxPeriodSize = PA_MIN( maxPlayback, maxCapture );
1507
1689
            PA_UNLESS( minPeriodSize <= maxPeriodSize, paBadIODeviceCombination );
1508
1690
 
1509
 
            desiredLatency = (snd_pcm_uframes_t)(PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )
 
1691
            desiredBufSz = (snd_pcm_uframes_t)(PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )
1510
1692
                    * sampleRate);
1511
 
            /* Clamp desiredLatency */
 
1693
            /* Clamp desiredBufSz */
1512
1694
            {
1513
1695
                snd_pcm_uframes_t maxBufferSize;
1514
1696
                snd_pcm_uframes_t maxBufferSizeCapture, maxBufferSizePlayback;
1516
1698
                ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSizePlayback ), paUnanticipatedHostError );
1517
1699
                maxBufferSize = PA_MIN( maxBufferSizeCapture, maxBufferSizePlayback );
1518
1700
 
1519
 
                desiredLatency = PA_MIN( desiredLatency, maxBufferSize );
 
1701
                desiredBufSz = PA_MIN( desiredBufSz, maxBufferSize );
1520
1702
            }
1521
1703
 
1522
1704
            /* Find the closest power of 2 */
1529
1711
            {
1530
1712
                if( snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 &&
1531
1713
                        snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 )
1532
 
                    break;  /* Ok! */
 
1714
                {
 
1715
                    /* OK! */
 
1716
                    break;
 
1717
                }
1533
1718
 
1534
1719
                periodSize *= 2;
1535
1720
            }
1536
1721
 
1537
 
            /* 4 periods considered optimal */
1538
 
            optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );
 
1722
            optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize );
1539
1723
            optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
1540
1724
 
1541
1725
            /* Find the closest power of 2 */
1546
1730
 
1547
1731
            while( optimalPeriodSize >= periodSize )
1548
1732
            {
1549
 
                if( snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 ) < 0 )
1550
 
                    continue;
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 )
 
1736
                {
1552
1737
                    break;
 
1738
                }
1553
1739
                optimalPeriodSize /= 2;
1554
1740
            }
 
1741
        
1555
1742
            if( optimalPeriodSize > periodSize )
1556
1743
                periodSize = optimalPeriodSize;
1557
1744
 
1568
1755
            else
1569
1756
            {
1570
1757
                /* Unable to find a common period size, oh well */
1571
 
                optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );
 
1758
                optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize );
1572
1759
                optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
1573
1760
 
1574
1761
                self->capture.framesPerBuffer = optimalPeriodSize;
1596
1783
 
1597
1784
            dir = 0;
1598
1785
            ENSURE_( snd_pcm_hw_params_get_periods_max( hwParamsPlayback, &maxPeriods, &dir ), paUnanticipatedHostError );
1599
 
            if( maxPeriods < 4 )
 
1786
            if( maxPeriods < numPeriods )
1600
1787
            {
1601
1788
                /* The playback component is trickier to get right, try that first */
1602
1789
                first = &self->playback;
1947
2134
 
1948
2135
    if( stream->callbackMode )
1949
2136
    {
1950
 
        PA_ENSURE( PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1. ) );
 
2137
        PA_ENSURE( PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1., stream->rtSched ) );
1951
2138
    }
1952
2139
    else
1953
2140
    {
1972
2159
static PaError AlsaStop( PaAlsaStream *stream, int abort )
1973
2160
{
1974
2161
    PaError result = paNoError;
 
2162
    /* XXX: Seems that draining the dmix device may trigger a race condition in ALSA */
 
2163
    if( stream->capture.pcm && !strcmp( Pa_GetDeviceInfo( stream->capture.device )->name,
 
2164
                "dmix" ) )
 
2165
    {
 
2166
        abort = 1;
 
2167
    }
 
2168
    else if( stream->playback.pcm && !strcmp( Pa_GetDeviceInfo( stream->playback.device )->name,
 
2169
                "dmix" ) )
 
2170
    {
 
2171
        abort = 1;
 
2172
    }
1975
2173
 
1976
2174
    if( abort )
1977
2175
    {
1991
2189
        if( stream->playback.pcm )
1992
2190
        {
1993
2191
            ENSURE_( snd_pcm_nonblock( stream->playback.pcm, 0 ), paUnanticipatedHostError );
1994
 
            /* draining causes deadlock when we are using dmix */
1995
 
            /* if( snd_pcm_drain( stream->playback.pcm ) < 0 ) */
1996
 
            if( snd_pcm_drop( stream->playback.pcm ) < 0 )
 
2192
            if( snd_pcm_drain( stream->playback.pcm ) < 0 )
1997
2193
            {
1998
2194
                PA_DEBUG(( "%s: Draining playback handle failed!\n", __FUNCTION__ ));
1999
2195
            }
2001
2197
        if( stream->capture.pcm && !stream->pcmsSynced )
2002
2198
        {
2003
2199
            /* We don't need to retrieve any remaining frames */
2004
 
            if( snd_pcm_drop( stream->capture.pcm ) < 0 )
 
2200
            if( snd_pcm_drain( stream->capture.pcm ) < 0 )
2005
2201
            {
2006
2202
                PA_DEBUG(( "%s: Draining capture handle failed!\n", __FUNCTION__ ));
2007
2203
            }
3309
3505
 
3310
3506
/* Extensions */
3311
3507
 
3312
 
/* Initialize host api specific structure */
3313
3508
void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info )
3314
3509
{
3315
3510
    info->size = sizeof (PaAlsaStreamInfo);
3320
3515
 
3321
3516
void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable )
3322
3517
{
3323
 
#if 0
3324
3518
    PaAlsaStream *stream = (PaAlsaStream *) s;
3325
 
    stream->threading.rtSched = enable;
3326
 
#endif
 
3519
    stream->rtSched = enable;
3327
3520
}
3328
3521
 
 
3522
#if 0
3329
3523
void PaAlsa_EnableWatchdog( PaStream *s, int enable )
3330
3524
{
3331
 
#if 0
3332
3525
    PaAlsaStream *stream = (PaAlsaStream *) s;
3333
 
    stream->threading.useWatchdog = enable;
 
3526
    stream->thread.useWatchdog = enable;
 
3527
}
3334
3528
#endif
3335
 
}
3336
 
 
3337
 
int PaAlsa_GetInputCard( PaStream *s )
3338
 
{
3339
 
    PaAlsaStream *stream = (PaAlsaStream *) s;
3340
 
    snd_pcm_info_t *pcmInfo;
3341
 
    int card = -1;
3342
 
 
3343
 
    if( stream->capture.pcm )
3344
 
    {
3345
 
        snd_pcm_info_alloca( &pcmInfo );
3346
 
        if( snd_pcm_info( stream->capture.pcm, pcmInfo ) >= 0 )
3347
 
        {
3348
 
            card = snd_pcm_info_get_card( pcmInfo );
3349
 
        }
3350
 
    }
3351
 
 
3352
 
    return card;
3353
 
}
3354
 
 
3355
 
int PaAlsa_GetOutputCard( PaStream *s )
3356
 
{
3357
 
    PaAlsaStream *stream = (PaAlsaStream *) s;
3358
 
    snd_pcm_info_t *pcmInfo;
3359
 
    int card = -1;
3360
 
 
3361
 
    if( stream->playback.pcm )
3362
 
    {
3363
 
        snd_pcm_info_alloca( &pcmInfo );
3364
 
        if( snd_pcm_info( stream->playback.pcm, pcmInfo ) >= 0 )
3365
 
        {
3366
 
            card = snd_pcm_info_get_card( pcmInfo );
3367
 
        }
3368
 
    }
3369
 
 
3370
 
    return card;
3371
 
}
3372
 
 
 
3529
 
 
3530
PaError PaAlsa_GetStreamInputCard(PaStream* s, int* card) {
 
3531
    PaAlsaStream *stream = (PaAlsaStream *) s;
 
3532
    snd_pcm_info_t* pcmInfo;
 
3533
    PaError result = paNoError;
 
3534
 
 
3535
    /* XXX: More descriptive error? */
 
3536
    PA_UNLESS( stream->capture.pcm, paDeviceUnavailable );
 
3537
 
 
3538
    snd_pcm_info_alloca( &pcmInfo );
 
3539
    PA_ENSURE( snd_pcm_info( stream->capture.pcm, pcmInfo ) );
 
3540
    *card = snd_pcm_info_get_card( pcmInfo );
 
3541
 
 
3542
error:
 
3543
    return result;
 
3544
}
 
3545
 
 
3546
PaError PaAlsa_GetStreamOutputCard(PaStream* s, int* card) {
 
3547
    PaAlsaStream *stream = (PaAlsaStream *) s;
 
3548
    snd_pcm_info_t* pcmInfo;
 
3549
    PaError result = paNoError;
 
3550
 
 
3551
    /* XXX: More descriptive error? */
 
3552
    PA_UNLESS( stream->playback.pcm, paDeviceUnavailable );
 
3553
 
 
3554
    snd_pcm_info_alloca( &pcmInfo );
 
3555
    PA_ENSURE( snd_pcm_info( stream->playback.pcm, pcmInfo ) );
 
3556
    *card = snd_pcm_info_get_card( pcmInfo );
 
3557
 
 
3558
error:
 
3559
    return result;
 
3560
}