Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 275490
Collapse All | Expand All

(-)audacity-1.3.5/lib-src/portaudio-v19/src/hostapi/alsa/pa_linux_alsa.c (-43 / +128 lines)
Lines 6-11 Link Here
6
 *
6
 *
7
 * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
7
 * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
8
 * Copyright (c) 2005-2007 Arve Knudsen <aknuds-1@broadpark.no>
8
 * Copyright (c) 2005-2007 Arve Knudsen <aknuds-1@broadpark.no>
9
 * Copyright (c) 2008 Kevin Kofler <kevin.kofler@chello.at>
9
 *
10
 *
10
 * Based on the Open Source API proposed by Ross Bencina
11
 * Based on the Open Source API proposed by Ross Bencina
11
 * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
12
 * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
Lines 118-123 Link Here
118
    unsigned long framesPerBuffer;
119
    unsigned long framesPerBuffer;
119
    int numUserChannels, numHostChannels;
120
    int numUserChannels, numHostChannels;
120
    int userInterleaved, hostInterleaved;
121
    int userInterleaved, hostInterleaved;
122
    int canMmap;
123
    void *nonMmapBuffer;
121
    PaDeviceIndex device;     /* Keep the device index */
124
    PaDeviceIndex device;     /* Keep the device index */
122
125
123
    snd_pcm_t *pcm;
126
    snd_pcm_t *pcm;
Lines 321-327 Link Here
321
 * and a suitable result returned. The device is closed before returning.
324
 * and a suitable result returned. The device is closed before returning.
322
 */
325
 */
323
static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking,
326
static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking,
324
        PaAlsaDeviceInfo* devInfo, int* canMmap )
327
        PaAlsaDeviceInfo* devInfo )
325
{
328
{
326
    PaError result = paNoError;
329
    PaError result = paNoError;
327
    snd_pcm_hw_params_t *hwParams;
330
    snd_pcm_hw_params_t *hwParams;
Lines 354-362 Link Here
354
    snd_pcm_hw_params_alloca( &hwParams );
357
    snd_pcm_hw_params_alloca( &hwParams );
355
    snd_pcm_hw_params_any( pcm, hwParams );
358
    snd_pcm_hw_params_any( pcm, hwParams );
356
359
357
    *canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_INTERLEAVED ) >= 0 ||
358
            snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_NONINTERLEAVED ) >= 0;
359
360
    if( defaultSr >= 0 )
360
    if( defaultSr >= 0 )
361
    {
361
    {
362
        /* Could be that the device opened in one mode supports samplerates that the other mode wont have,
362
        /* Could be that the device opened in one mode supports samplerates that the other mode wont have,
Lines 566-572 Link Here
566
    PaError result = 0;
566
    PaError result = 0;
567
    PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo;
567
    PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo;
568
    snd_pcm_t *pcm;
568
    snd_pcm_t *pcm;
569
    int canMmap = -1;
570
    PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
569
    PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
571
570
572
    /* Zero fields */
571
    /* Zero fields */
Lines 580-587 Link Here
580
            OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 )
579
            OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 )
581
            >= 0 )
580
            >= 0 )
582
    {
581
    {
583
        if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_In, blocking, devInfo,
582
        if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_In, blocking, devInfo ) != paNoError )
584
                    &canMmap ) != paNoError )
585
        {
583
        {
586
            /* Error */
584
            /* Error */
587
            PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceName->alsaName));
585
            PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceName->alsaName));
Lines 594-601 Link Here
594
            OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 )
592
            OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 )
595
            >= 0 )
593
            >= 0 )
596
    {
594
    {
597
        if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out, blocking, devInfo,
595
        if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out, blocking, devInfo ) != paNoError )
598
                    &canMmap ) != paNoError )
599
        {
596
        {
600
            /* Error */
597
            /* Error */
601
            PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceName->alsaName));
598
            PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceName->alsaName));
Lines 603-614 Link Here
603
        }
600
        }
604
    }
601
    }
605
602
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;
603
    baseDeviceInfo->structVersion = 2;
613
    baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
604
    baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
614
    baseDeviceInfo->name = deviceName->name;
605
    baseDeviceInfo->name = deviceName->name;
Lines 1197-1202 Link Here
1197
    self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved);
1188
    self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved);
1198
    self->numUserChannels = params->channelCount;
1189
    self->numUserChannels = params->channelCount;
1199
    self->streamDir = streamDir;
1190
    self->streamDir = streamDir;
1191
    self->canMmap = 0;
1192
    self->nonMmapBuffer = NULL;
1200
1193
1201
    if( !callbackMode && !self->userInterleaved )
1194
    if( !callbackMode && !self->userInterleaved )
1202
    {
1195
    {
Lines 1239-1244 Link Here
1239
1232
1240
    PaError result = paNoError;
1233
    PaError result = paNoError;
1241
    snd_pcm_access_t accessMode, alternateAccessMode;
1234
    snd_pcm_access_t accessMode, alternateAccessMode;
1235
    snd_pcm_access_t rwAccessMode, alternateRwAccessMode;
1242
    int dir = 0;
1236
    int dir = 0;
1243
    snd_pcm_t *pcm = self->pcm;
1237
    snd_pcm_t *pcm = self->pcm;
1244
    double sr = *sampleRate;
1238
    double sr = *sampleRate;
Lines 1258-1289 Link Here
1258
    if( self->userInterleaved )
1252
    if( self->userInterleaved )
1259
    {
1253
    {
1260
        accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
1254
        accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
1255
        rwAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
1261
        alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
1256
        alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
1257
        alternateRwAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;
1262
    }
1258
    }
1263
    else
1259
    else
1264
    {
1260
    {
1265
        accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
1261
        accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
1262
        rwAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;
1266
        alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
1263
        alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
1264
        alternateRwAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
1267
    }
1265
    }
1268
    /* If requested access mode fails, try alternate mode */
1266
    /* If requested access mode fails, try alternate mode */
1267
    self->canMmap = 1;
1269
    if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )
1268
    if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )
1270
    {
1269
    {
1271
        int err = 0;
1270
        if( snd_pcm_hw_params_set_access( pcm, hwParams, rwAccessMode ) >= 0 )
1272
        if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0)
1271
            self->canMmap = 0;
1272
        else
1273
        {
1273
        {
1274
            result = paUnanticipatedHostError;
1274
            if( snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode ) < 0 )
1275
            if( -EINVAL == err )
1276
            {
1275
            {
1277
                PaUtil_SetLastHostErrorInfo( paALSA, err, "PA ALSA requires that a device supports mmap access" );
1276
                int err = 0;
1278
            }
1277
                if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateRwAccessMode )) >= 0)
1279
            else
1278
                    self->canMmap = 0;
1280
            {
1279
                else
1281
                PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) );
1280
                {
1281
                    result = paUnanticipatedHostError;
1282
                    PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) );
1283
                    goto error;
1284
                }
1282
            }
1285
            }
1283
            goto error;
1286
            /* Flip mode */
1287
            self->hostInterleaved = !self->userInterleaved;
1284
        }
1288
        }
1285
        /* Flip mode */
1286
        self->hostInterleaved = !self->userInterleaved;
1287
    }
1289
    }
1288
1290
1289
    ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );
1291
    ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );
Lines 1361-1367 Link Here
1361
        
1363
        
1362
    ENSURE_( snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
1364
    ENSURE_( snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
1363
    ENSURE_( snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError );
1365
    ENSURE_( snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError );
1364
    ENSURE_( snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError );
1366
    ENSURE_( snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError );
1365
1367
1366
    /* Set the parameters! */
1368
    /* Set the parameters! */
1367
    ENSURE_( snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError );
1369
    ENSURE_( snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError );
Lines 1589-1594 Link Here
1589
        }
1591
        }
1590
    }
1592
    }
1591
1593
1594
    /* non-mmap mode needs a reasonably-sized buffer or it'll stutter */
1595
    /*if( !self->canMmap && framesPerHostBuffer < 2048 )
1596
        framesPerHostBuffer = 2048; */ /* This above was commented out by David Henningsson, for Audacity - users need to be able to tweak latency themselves */
1597
1592
    assert( framesPerHostBuffer > 0 );
1598
    assert( framesPerHostBuffer > 0 );
1593
    {
1599
    {
1594
        snd_pcm_uframes_t min = 0, max = 0;
1600
        snd_pcm_uframes_t min = 0, max = 0;
Lines 1831-1837 Link Here
1831
    PA_UNLESS( framesPerHostBuffer != 0, paInternalError );
1837
    PA_UNLESS( framesPerHostBuffer != 0, paInternalError );
1832
    self->maxFramesPerHostBuffer = framesPerHostBuffer;
1838
    self->maxFramesPerHostBuffer = framesPerHostBuffer;
1833
1839
1834
    if( !accurate )
1840
    if( !self->playback.canMmap || !accurate )
1835
    {
1841
    {
1836
        /* Don't know the exact size per host buffer */
1842
        /* Don't know the exact size per host buffer */
1837
        *hostBufferSizeMode = paUtilBoundedHostBufferSize;
1843
        *hostBufferSizeMode = paUtilBoundedHostBufferSize;
Lines 2059-2067 Link Here
2059
            {
2065
            {
2060
                /* Buffer isn't primed, so prepare and silence */
2066
                /* Buffer isn't primed, so prepare and silence */
2061
                ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
2067
                ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
2062
                SilenceBuffer( stream );
2068
                if( stream->playback.canMmap )
2069
                    SilenceBuffer( stream );
2063
            }
2070
            }
2064
            ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
2071
            if( stream->playback.canMmap )
2072
                ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
2065
        }
2073
        }
2066
        else
2074
        else
2067
            ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
2075
            ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
Lines 2390-2395 Link Here
2390
    snd_pcm_status_t *st;
2398
    snd_pcm_status_t *st;
2391
    PaTime now = PaUtil_GetTime();
2399
    PaTime now = PaUtil_GetTime();
2392
    snd_timestamp_t t;
2400
    snd_timestamp_t t;
2401
    int errplayback = 0, errcapture = 0;
2393
2402
2394
    snd_pcm_status_alloca( &st );
2403
    snd_pcm_status_alloca( &st );
2395
2404
Lines 2400-2405 Link Here
2400
        {
2409
        {
2401
            snd_pcm_status_get_trigger_tstamp( st, &t );
2410
            snd_pcm_status_get_trigger_tstamp( st, &t );
2402
            self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
2411
            self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
2412
            errplayback = snd_pcm_recover( self->playback.pcm, -EPIPE, 0 );
2403
        }
2413
        }
2404
    }
2414
    }
2405
    if( self->capture.pcm )
2415
    if( self->capture.pcm )
Lines 2409-2418 Link Here
2409
        {
2419
        {
2410
            snd_pcm_status_get_trigger_tstamp( st, &t );
2420
            snd_pcm_status_get_trigger_tstamp( st, &t );
2411
            self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
2421
            self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
2422
            errcapture = snd_pcm_recover( self->capture.pcm, -EPIPE, 0 );
2412
        }
2423
        }
2413
    }
2424
    }
2414
2425
2415
    PA_ENSURE( AlsaRestart( self ) );
2426
    if( errplayback || errcapture )
2427
        PA_ENSURE( AlsaRestart( self ) );
2416
2428
2417
end:
2429
end:
2418
    return result;
2430
    return result;
Lines 2563-2569 Link Here
2563
static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun )
2575
static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun )
2564
{
2576
{
2565
    PaError result = paNoError;
2577
    PaError result = paNoError;
2566
    int res;
2578
    int res = 0;
2567
2579
2568
    /* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed
2580
    /* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed
2569
     * afterwards
2581
     * afterwards
Lines 2571-2577 Link Here
2571
    if( !self->ready )
2583
    if( !self->ready )
2572
        goto end;
2584
        goto end;
2573
2585
2574
    res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
2586
    if( !self->canMmap && StreamDirection_Out == self->streamDir )
2587
    {
2588
        /* Play sound */
2589
        if( self->hostInterleaved )
2590
            res = snd_pcm_writei( self->pcm, self->nonMmapBuffer, numFrames );
2591
        else
2592
        {
2593
            void *bufs[self->numHostChannels];
2594
            int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
2595
            unsigned char *buffer = self->nonMmapBuffer;
2596
            int i;
2597
            for( i = 0; i < self->numHostChannels; ++i )
2598
            {
2599
                bufs[i] = buffer;
2600
                buffer += bufsize;
2601
            }
2602
            res = snd_pcm_writen( self->pcm, bufs, numFrames );
2603
        }
2604
    }
2605
2606
    if( self->canMmap )
2607
        res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
2608
    else
2609
    {
2610
        free( self->nonMmapBuffer );
2611
        self->nonMmapBuffer = NULL;
2612
    }
2613
2575
    if( res == -EPIPE || res == -ESTRPIPE )
2614
    if( res == -EPIPE || res == -ESTRPIPE )
2576
    {
2615
    {
2577
        *xrun = 1;
2616
        *xrun = 1;
Lines 2611-2617 Link Here
2611
    if( self->hostInterleaved )
2650
    if( self->hostInterleaved )
2612
    {
2651
    {
2613
        int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
2652
        int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
2614
        unsigned char *buffer = ExtractAddress( self->channelAreas, self->offset );
2653
        unsigned char *buffer = self->canMmap ? ExtractAddress( self->channelAreas, self->offset ) : self->nonMmapBuffer;
2615
2654
2616
        /* Start after the last user channel */
2655
        /* Start after the last user channel */
2617
        p = buffer + self->numUserChannels * swidth;
2656
        p = buffer + self->numUserChannels * swidth;
Lines 2991-3003 Link Here
2991
        goto end;
3030
        goto end;
2992
    }
3031
    }
2993
3032
2994
    ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError );
3033
    if( self->canMmap )
3034
    {
3035
        ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError );
3036
        /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */
3037
        self->channelAreas = (snd_pcm_channel_area_t *)areas;
3038
    }
3039
    else
3040
    {
3041
        free( self->nonMmapBuffer );
3042
        self->nonMmapBuffer = calloc( self->numHostChannels, snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ) );
3043
    }
2995
3044
2996
    if( self->hostInterleaved )
3045
    if( self->hostInterleaved )
2997
    {
3046
    {
2998
        int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
3047
        int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
2999
3048
3000
        p = buffer = ExtractAddress( areas, self->offset );
3049
        p = buffer = self->canMmap ? ExtractAddress( areas, self->offset ) : self->nonMmapBuffer;
3001
        for( i = 0; i < self->numUserChannels; ++i )
3050
        for( i = 0; i < self->numUserChannels; ++i )
3002
        {
3051
        {
3003
            /* We're setting the channels up to userChannels, but the stride will be hostChannels samples */
3052
            /* We're setting the channels up to userChannels, but the stride will be hostChannels samples */
Lines 3007-3022 Link Here
3007
    }
3056
    }
3008
    else
3057
    else
3009
    {
3058
    {
3010
        for( i = 0; i < self->numUserChannels; ++i )
3059
        if( self->canMmap )
3060
            for( i = 0; i < self->numUserChannels; ++i )
3061
            {
3062
                area = areas + i;
3063
                buffer = ExtractAddress( area, self->offset );
3064
                setChannel( bp, i, buffer, 1 );
3065
            }
3066
        else
3011
        {
3067
        {
3012
            area = areas + i;
3068
            int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
3013
            buffer = ExtractAddress( area, self->offset );
3069
            buffer = self->nonMmapBuffer;
3014
            setChannel( bp, i, buffer, 1 );
3070
            for( i = 0; i < self->numUserChannels; ++i )
3071
            {
3072
                setChannel( bp, i, buffer, 1 );
3073
                buffer += bufsize;
3074
            }
3015
        }
3075
        }
3016
    }
3076
    }
3017
3077
3018
    /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */
3078
    if( !self->canMmap && StreamDirection_In == self->streamDir )
3019
    self->channelAreas = (snd_pcm_channel_area_t *)areas;
3079
    {
3080
        /* Read sound */
3081
        int res;
3082
        if( self->hostInterleaved )
3083
            res = snd_pcm_readi( self->pcm, self->nonMmapBuffer, *numFrames );
3084
        else
3085
        {
3086
            void *bufs[self->numHostChannels];
3087
            int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
3088
            unsigned char *buffer = self->nonMmapBuffer;
3089
            int i;
3090
            for( i = 0; i < self->numHostChannels; ++i )
3091
            {
3092
                bufs[i] = buffer;
3093
                buffer += bufsize;
3094
            }
3095
            res = snd_pcm_readn( self->pcm, bufs, *numFrames );
3096
        }
3097
        if( res == -EPIPE || res == -ESTRPIPE )
3098
        {
3099
            *xrun = 1;
3100
            *numFrames = 0;
3101
            free( self->nonMmapBuffer );
3102
            self->nonMmapBuffer = NULL;
3103
        }
3104
    }
3020
3105
3021
end:
3106
end:
3022
error:
3107
error:

Return to bug 275490