~ubuntu-branches/ubuntu/wily/sflphone/wily

1.1.12 by Francois Marier
Import upstream version 1.4.1
1
/*
2
 * $Id: pa_linux_alsa.c 1415 2009-06-03 18:57:56Z aknudsen $
3
 * PortAudio Portable Real-Time Audio Library
4
 * Latest Version at: http://www.portaudio.com
5
 * ALSA implementation by Joshua Haberman and Arve Knudsen
6
 *
7
 * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
8
 * Copyright (c) 2005-2009 Arve Knudsen <arve.knudsen@gmail.com>
9
 * Copyright (c) 2008 Kevin Kofler <kevin.kofler@chello.at>
10
 *
11
 * Based on the Open Source API proposed by Ross Bencina
12
 * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
13
 *
14
 * Permission is hereby granted, free of charge, to any person obtaining
15
 * a copy of this software and associated documentation files
16
 * (the "Software"), to deal in the Software without restriction,
17
 * including without limitation the rights to use, copy, modify, merge,
18
 * publish, distribute, sublicense, and/or sell copies of the Software,
19
 * and to permit persons to whom the Software is furnished to do so,
20
 * subject to the following conditions:
21
 *
22
 * The above copyright notice and this permission notice shall be
23
 * included in all copies or substantial portions of the Software.
24
 *
25
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
28
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
29
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
30
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32
 */
33
34
/*
35
 * The text above constitutes the entire PortAudio license; however, 
36
 * the PortAudio community also makes the following non-binding requests:
37
 *
38
 * Any person wishing to distribute modifications to the Software is
39
 * requested to send the modifications to the original developer so that
40
 * they can be incorporated into the canonical version. It is also 
41
 * requested that these non-binding requests be included along with the 
42
 * license above.
43
 */
44
45
/**
46
 @file
47
 @ingroup hostapi_src
48
*/
49
50
#define ALSA_PCM_NEW_HW_PARAMS_API
51
#define ALSA_PCM_NEW_SW_PARAMS_API
52
#include <alsa/asoundlib.h>
53
#undef ALSA_PCM_NEW_HW_PARAMS_API
54
#undef ALSA_PCM_NEW_SW_PARAMS_API
55
56
#include <sys/poll.h>
57
#include <string.h> /* strlen() */
58
#include <limits.h>
59
#include <math.h>
60
#include <pthread.h>
61
#include <signal.h>
62
#include <time.h>
63
#include <sys/mman.h>
64
#include <signal.h> /* For sig_atomic_t */
65
66
#include "portaudio.h"
67
#include "pa_util.h"
68
#include "pa_unix_util.h"
69
#include "pa_allocation.h"
70
#include "pa_hostapi.h"
71
#include "pa_stream.h"
72
#include "pa_cpuload.h"
73
#include "pa_process.h"
74
#include "pa_endianness.h"
75
#include "pa_debugprint.h"
76
77
#include "pa_linux_alsa.h"
78
79
/* Check return value of ALSA function, and map it to PaError */
80
#define ENSURE_(expr, code) \
81
    do { \
82
        if( UNLIKELY( (aErr_ = (expr)) < 0 ) ) \
83
        { \
84
            /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
85
            if( (code) == paUnanticipatedHostError && pthread_equal( pthread_self(), paUnixMainThread) ) \
86
            { \
87
                PaUtil_SetLastHostErrorInfo( paALSA, aErr_, snd_strerror( aErr_ ) ); \
88
            } \
89
            PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \
90
            if( (code) == paUnanticipatedHostError ) \
91
                PA_DEBUG(( "Host error description: %s\n", snd_strerror( aErr_ ) )); \
92
            result = (code); \
93
            goto error; \
94
        } \
95
    } while( 0 );
96
97
#define ASSERT_CALL_(expr, success) \
98
    aErr_ = (expr); \
99
    assert( success == aErr_ );
100
101
static int aErr_;               /* Used with ENSURE_ */
102
static int numPeriods_ = 4;
103
static int busyRetries_ = 100;
104
105
int PaAlsa_SetNumPeriods( int numPeriods )
106
{
107
    numPeriods_ = numPeriods;
108
    return paNoError;
109
}
110
111
typedef enum
112
{
113
    StreamDirection_In,
114
    StreamDirection_Out
115
} StreamDirection;
116
117
typedef struct
118
{
119
    PaSampleFormat hostSampleFormat;
120
    unsigned long framesPerBuffer;
121
    int numUserChannels, numHostChannels;
122
    int userInterleaved, hostInterleaved;
123
    int canMmap;
124
    void *nonMmapBuffer;
125
    PaDeviceIndex device;     /* Keep the device index */
126
127
    snd_pcm_t *pcm;
128
    snd_pcm_uframes_t bufferSize;
129
    snd_pcm_format_t nativeFormat;
130
    unsigned int nfds;
131
    int ready;  /* Marked ready from poll */
132
    void **userBuffers;
133
    snd_pcm_uframes_t offset;
134
    StreamDirection streamDir;
135
136
    snd_pcm_channel_area_t *channelAreas;  /* Needed for channel adaption */
137
} PaAlsaStreamComponent;
138
139
/* Implementation specific stream structure */
140
typedef struct PaAlsaStream
141
{
142
    PaUtilStreamRepresentation streamRepresentation;
143
    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
144
    PaUtilBufferProcessor bufferProcessor;
145
    PaUnixThread thread;
146
147
    unsigned long framesPerUserBuffer, maxFramesPerHostBuffer;
148
149
    int primeBuffers;
150
    int callbackMode;              /* bool: are we running in callback mode? */
151
    int pcmsSynced;	            /* Have we successfully synced pcms */
152
    int rtSched;
153
154
    /* the callback thread uses these to poll the sound device(s), waiting
155
     * for data to be ready/available */
156
    struct pollfd* pfds;
157
    int pollTimeout;
158
159
    /* Used in communication between threads */
160
    volatile sig_atomic_t callback_finished; /* bool: are we in the "callback finished" state? */
161
    volatile sig_atomic_t callbackAbort;    /* Drop frames? */
162
    volatile sig_atomic_t isActive;         /* Is stream in active state? (Between StartStream and StopStream || !paContinue) */
163
    PaUnixMutex stateMtx;                   /* Used to synchronize access to stream state */
164
165
    int neverDropInput;
166
167
    PaTime underrun;
168
    PaTime overrun;
169
170
    PaAlsaStreamComponent capture, playback;
171
}
172
PaAlsaStream;
173
174
/* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */
175
176
typedef struct PaAlsaHostApiRepresentation
177
{
178
    PaUtilHostApiRepresentation baseHostApiRep;
179
    PaUtilStreamInterface callbackStreamInterface;
180
    PaUtilStreamInterface blockingStreamInterface;
181
182
    PaUtilAllocationGroup *allocations;
183
184
    PaHostApiIndex hostApiIndex;
185
}
186
PaAlsaHostApiRepresentation;
187
188
typedef struct PaAlsaDeviceInfo
189
{
190
    PaDeviceInfo baseDeviceInfo;
191
    char *alsaName;
192
    int isPlug;
193
    int minInputChannels;
194
    int minOutputChannels;
195
}
196
PaAlsaDeviceInfo;
197
198
/* prototypes for functions declared in this file */
199
200
static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
201
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
202
                                  const PaStreamParameters *inputParameters,
203
                                  const PaStreamParameters *outputParameters,
204
                                  double sampleRate );
205
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
206
                           PaStream** s,
207
                           const PaStreamParameters *inputParameters,
208
                           const PaStreamParameters *outputParameters,
209
                           double sampleRate,
210
                           unsigned long framesPerBuffer,
211
                           PaStreamFlags streamFlags,
212
                           PaStreamCallback *callback,
213
                           void *userData );
214
static PaError CloseStream( PaStream* stream );
215
static PaError StartStream( PaStream *stream );
216
static PaError StopStream( PaStream *stream );
217
static PaError AbortStream( PaStream *stream );
218
static PaError IsStreamStopped( PaStream *s );
219
static PaError IsStreamActive( PaStream *stream );
220
static PaTime GetStreamTime( PaStream *stream );
221
static double GetStreamCpuLoad( PaStream* stream );
222
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi );
223
static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate );
224
static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate );
225
226
/* Callback prototypes */
227
static void *CallbackThreadFunc( void *userData );
228
229
/* Blocking prototypes */
230
static signed long GetStreamReadAvailable( PaStream* s );
231
static signed long GetStreamWriteAvailable( PaStream* s );
232
static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
233
static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
234
235
236
static const PaAlsaDeviceInfo *GetDeviceInfo( const PaUtilHostApiRepresentation *hostApi, int device )
237
{
238
    return (const PaAlsaDeviceInfo *)hostApi->deviceInfos[device];
239
}
240
241
static void AlsaErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...)
242
{
243
}
244
245
PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
246
{
247
    PaError result = paNoError;
248
    PaAlsaHostApiRepresentation *alsaHostApi = NULL;
249
250
    PA_UNLESS( alsaHostApi = (PaAlsaHostApiRepresentation*) PaUtil_AllocateMemory(
251
                sizeof(PaAlsaHostApiRepresentation) ), paInsufficientMemory );
252
    PA_UNLESS( alsaHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
253
    alsaHostApi->hostApiIndex = hostApiIndex;
254
255
    *hostApi = (PaUtilHostApiRepresentation*)alsaHostApi;
256
    (*hostApi)->info.structVersion = 1;
257
    (*hostApi)->info.type = paALSA;
258
    (*hostApi)->info.name = "ALSA";
259
260
    (*hostApi)->Terminate = Terminate;
261
    (*hostApi)->OpenStream = OpenStream;
262
    (*hostApi)->IsFormatSupported = IsFormatSupported;
263
264
    ENSURE_( snd_lib_error_set_handler(AlsaErrorHandler), paUnanticipatedHostError );
265
266
    PA_ENSURE( BuildDeviceList( alsaHostApi ) );
267
268
    PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface,
269
                                      CloseStream, StartStream,
270
                                      StopStream, AbortStream,
271
                                      IsStreamStopped, IsStreamActive,
272
                                      GetStreamTime, GetStreamCpuLoad,
273
                                      PaUtil_DummyRead, PaUtil_DummyWrite,
274
                                      PaUtil_DummyGetReadAvailable,
275
                                      PaUtil_DummyGetWriteAvailable );
276
277
    PaUtil_InitializeStreamInterface( &alsaHostApi->blockingStreamInterface,
278
                                      CloseStream, StartStream,
279
                                      StopStream, AbortStream,
280
                                      IsStreamStopped, IsStreamActive,
281
                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
282
                                      ReadStream, WriteStream,
283
                                      GetStreamReadAvailable,
284
                                      GetStreamWriteAvailable );
285
286
    PA_ENSURE( PaUnixThreading_Initialize() );
287
288
    return result;
289
290
error:
291
    if( alsaHostApi )
292
    {
293
        if( alsaHostApi->allocations )
294
        {
295
            PaUtil_FreeAllAllocations( alsaHostApi->allocations );
296
            PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );
297
        }
298
299
        PaUtil_FreeMemory( alsaHostApi );
300
    }
301
302
    return result;
303
}
304
305
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
306
{
307
    PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
308
309
    assert( hostApi );
310
311
    if( alsaHostApi->allocations )
312
    {
313
        PaUtil_FreeAllAllocations( alsaHostApi->allocations );
314
        PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );
315
    }
316
317
    PaUtil_FreeMemory( alsaHostApi );
318
    snd_config_update_free_global();
319
}
320
321
/** Determine max channels and default latencies.
322
 *
323
 * This function provides functionality to grope an opened (might be opened for capture or playback) pcm device for 
324
 * traits like max channels, suitable default latencies and default sample rate. Upon error, max channels is set to zero,
325
 * and a suitable result returned. The device is closed before returning.
326
 */
327
static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking,
328
        PaAlsaDeviceInfo* devInfo )
329
{
330
    PaError result = paNoError;
331
    snd_pcm_hw_params_t *hwParams;
332
    snd_pcm_uframes_t lowLatency = 512, highLatency = 2048;
333
    unsigned int minChans, maxChans;
334
    int* minChannels, * maxChannels;
335
    double * defaultLowLatency, * defaultHighLatency, * defaultSampleRate =
336
        &devInfo->baseDeviceInfo.defaultSampleRate;
337
    double defaultSr = *defaultSampleRate;
338
339
    assert( pcm );
340
341
    if( StreamDirection_In == mode )
342
    {
343
        minChannels = &devInfo->minInputChannels;
344
        maxChannels = &devInfo->baseDeviceInfo.maxInputChannels;
345
        defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowInputLatency;
346
        defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighInputLatency;
347
    }
348
    else
349
    {
350
        minChannels = &devInfo->minOutputChannels;
351
        maxChannels = &devInfo->baseDeviceInfo.maxOutputChannels;
352
        defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowOutputLatency;
353
        defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighOutputLatency;
354
    }
355
356
    ENSURE_( snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError );
357
358
    snd_pcm_hw_params_alloca( &hwParams );
359
    snd_pcm_hw_params_any( pcm, hwParams );
360
361
    if( defaultSr >= 0 )
362
    {
363
        /* Could be that the device opened in one mode supports samplerates that the other mode wont have,
364
         * so try again .. */
365
        if( SetApproximateSampleRate( pcm, hwParams, defaultSr ) < 0 )
366
        {
367
            defaultSr = -1.;
368
            PA_DEBUG(( "%s: Original default samplerate failed, trying again ..\n", __FUNCTION__ ));
369
        }
370
    }
371
372
    if( defaultSr < 0. )           /* Default sample rate not set */
373
    {
374
        unsigned int sampleRate = 44100;        /* Will contain approximate rate returned by alsa-lib */
375
        if( snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ) < 0)
376
        {
377
            result = paUnanticipatedHostError;
378
            goto error;
379
        }
380
        ENSURE_( GetExactSampleRate( hwParams, &defaultSr ), paUnanticipatedHostError );
381
    }
382
    
383
    ENSURE_( snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError );
384
    ENSURE_( snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError );
385
    assert( maxChans <= INT_MAX );
386
    assert( maxChans > 0 );    /* Weird linking issue could cause wrong version of ALSA symbols to be called,
387
                                   resulting in zeroed values */
388
389
    /* XXX: Limit to sensible number (ALSA plugins accept a crazy amount of channels)? */
390
    if( isPlug && maxChans > 128 )
391
    {
392
        maxChans = 128;
393
        PA_DEBUG(( "%s: Limiting number of plugin channels to %u\n", __FUNCTION__, maxChans ));
394
    }
395
396
    /* TWEAKME:
397
     *
398
     * Giving values for default min and max latency is not
399
     * straightforward.  Here are our objectives:
400
     *
401
     *         * for low latency, we want to give the lowest value
402
     *         that will work reliably.  This varies based on the
403
     *         sound card, kernel, CPU, etc.  I think it is better
404
     *         to give sub-optimal latency than to give a number
405
     *         too low and cause dropouts.  My conservative
406
     *         estimate at this point is to base it on 4096-sample
407
     *         latency at 44.1 kHz, which gives a latency of 23ms.
408
     *         * for high latency we want to give a large enough
409
     *         value that dropouts are basically impossible.  This
410
     *         doesn't really require as much tweaking, since
411
     *         providing too large a number will just cause us to
412
     *         select the nearest setting that will work at stream
413
     *         config time.
414
     */
415
    ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &lowLatency ), paUnanticipatedHostError );
416
417
    /* Have to reset hwParams, to set new buffer size */
418
    ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); 
419
    ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &highLatency ), paUnanticipatedHostError );
420
421
    *minChannels = (int)minChans;
422
    *maxChannels = (int)maxChans;
423
    *defaultSampleRate = defaultSr;
424
    *defaultLowLatency = (double) lowLatency / *defaultSampleRate;
425
    *defaultHighLatency = (double) highLatency / *defaultSampleRate;
426
427
end:
428
    snd_pcm_close( pcm );
429
    return result;
430
431
error:
432
    goto end;
433
}
434
435
/* Initialize device info with invalid values (maxInputChannels and maxOutputChannels are set to zero since these indicate
436
 * wether input/output is available) */
437
static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo )
438
{
439
    deviceInfo->structVersion = -1;
440
    deviceInfo->name = NULL;
441
    deviceInfo->hostApi = -1;
442
    deviceInfo->maxInputChannels = 0;
443
    deviceInfo->maxOutputChannels = 0;
444
    deviceInfo->defaultLowInputLatency = -1.;
445
    deviceInfo->defaultLowOutputLatency = -1.;
446
    deviceInfo->defaultHighInputLatency = -1.;
447
    deviceInfo->defaultHighOutputLatency = -1.;
448
    deviceInfo->defaultSampleRate = -1.;
449
}
450
451
/* Helper struct */
452
typedef struct
453
{
454
    char *alsaName;
455
    char *name;
456
    int isPlug;
457
    int hasPlayback;
458
    int hasCapture;
459
} HwDevInfo;
460
461
462
HwDevInfo predefinedNames[] = {
463
    { "center_lfe", NULL, 0, 1, 0 },
464
/* { "default", NULL, 0, 1, 0 }, */
465
/* { "dmix", NULL, 0, 1, 0 }, */
466
/* { "dpl", NULL, 0, 1, 0 }, */
467
/* { "dsnoop", NULL, 0, 1, 0 }, */
468
    { "front", NULL, 0, 1, 0 },
469
    { "iec958", NULL, 0, 1, 0 },
470
/* { "modem", NULL, 0, 1, 0 }, */
471
    { "rear", NULL, 0, 1, 0 },
472
    { "side", NULL, 0, 1, 0 },
473
/*     { "spdif", NULL, 0, 0, 0 }, */
474
    { "surround40", NULL, 0, 1, 0 },
475
    { "surround41", NULL, 0, 1, 0 },
476
    { "surround50", NULL, 0, 1, 0 },
477
    { "surround51", NULL, 0, 1, 0 },
478
    { "surround71", NULL, 0, 1, 0 },
479
    { NULL, NULL, 0, 1, 0 }
480
};
481
482
static const HwDevInfo *FindDeviceName( const char *name )
483
{
484
    int i;
485
486
    for( i = 0; predefinedNames[i].alsaName; i++ )
487
    {
488
	if( strcmp( name, predefinedNames[i].alsaName ) == 0 )
489
	{
490
	    return &predefinedNames[i];
491
	}
492
    }
493
494
    return NULL;
495
}
496
497
static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi,
498
        char **dst,
499
        const char *src)
500
{
501
    PaError result = paNoError;
502
    int len = strlen( src ) + 1;
503
504
    /* PA_DEBUG(("PaStrDup %s %d\n", src, len)); */
505
506
    PA_UNLESS( *dst = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
507
            paInsufficientMemory );
508
    strncpy( *dst, src, len );
509
510
error:
511
    return result;
512
}
513
514
/* Disregard some standard plugins
515
 */
516
static int IgnorePlugin( const char *pluginId )
517
{
518
    static const char *ignoredPlugins[] = {"hw", "plughw", "plug", "dsnoop", "tee",
519
        "file", "null", "shm", "cards", "rate_convert", NULL};
520
    int i = 0;
521
    while( ignoredPlugins[i] )
522
    {
523
        if( !strcmp( pluginId, ignoredPlugins[i] ) )
524
        {
525
            return 1;
526
        }
527
        ++i;
528
    }
529
530
    return 0;
531
}
532
533
/** Open PCM device.
534
 *
535
 * Wrapper around snd_pcm_open which may repeatedly retry opening a device if it is busy, for
536
 * a certain time. This is because dmix may temporarily hold on to a device after it (dmix)
537
 * has been opened and closed.
538
 * @param mode: Open mode (e.g., SND_PCM_BLOCKING).
539
 * @param waitOnBusy: Retry opening busy device for up to one second?
540
 **/
541
static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode, int waitOnBusy )
542
{
543
    int tries = 0, maxTries = waitOnBusy ? busyRetries_ : 0;
544
    int ret = snd_pcm_open( pcmp, name, stream, mode );
545
    for( tries = 0; tries < maxTries && -EBUSY == ret; ++tries )
546
    {
547
        Pa_Sleep( 10 );
548
        ret = snd_pcm_open( pcmp, name, stream, mode );
549
        if( -EBUSY != ret )
550
        {
551
            PA_DEBUG(( "%s: Successfully opened initially busy device after %d tries\n",
552
                        __FUNCTION__, tries ));
553
        }
554
    }
555
    if( -EBUSY == ret )
556
    {
557
        PA_DEBUG(( "%s: Failed to open busy device '%s'\n",
558
                    __FUNCTION__, name ));
559
    }
560
561
    return ret;
562
}
563
564
static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* deviceName, int blocking,
565
        PaAlsaDeviceInfo* devInfo, int* devIdx )
566
{
567
    PaError result = 0;
568
    PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo;
569
    snd_pcm_t *pcm;
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 ) != paNoError )
584
        {
585
            /* Error */
586
            PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceName->alsaName));
587
            goto end;
588
        }
589
    }
590
591
    /* Query playback */
592
    if( deviceName->hasPlayback &&
593
            OpenPcm( &pcm, deviceName->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 )
594
            >= 0 )
595
    {
596
        if( GropeDevice( pcm, deviceName->isPlug, StreamDirection_Out, blocking, devInfo ) != paNoError )
597
        {
598
            /* Error */
599
            PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceName->alsaName));
600
            goto end;
601
        }
602
    }
603
604
    baseDeviceInfo->structVersion = 2;
605
    baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
606
    baseDeviceInfo->name = deviceName->name;
607
    devInfo->alsaName = deviceName->alsaName;
608
    devInfo->isPlug = deviceName->isPlug;
609
610
    /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object.
611
     * Should now be safe to add device info, unless the device supports neither capture nor playback
612
     */
613
    if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 )
614
    {
615
        /* Make device default if there isn't already one or it is the ALSA "default" device */
616
        if( (baseApi->info.defaultInputDevice == paNoDevice || !strcmp(deviceName->alsaName,
617
                        "default" )) && baseDeviceInfo->maxInputChannels > 0 )
618
        {
619
            baseApi->info.defaultInputDevice = *devIdx;
620
            PA_DEBUG(("Default input device: %s\n", deviceName->name));
621
        }
622
        if( (baseApi->info.defaultOutputDevice == paNoDevice || !strcmp(deviceName->alsaName,
623
                        "default" )) && baseDeviceInfo->maxOutputChannels > 0 )
624
        {
625
            baseApi->info.defaultOutputDevice = *devIdx;
626
            PA_DEBUG(("Default output device: %s\n", deviceName->name));
627
        }
628
        PA_DEBUG(("%s: Adding device %s: %d\n", __FUNCTION__, deviceName->name, *devIdx));
629
        baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo;
630
        (*devIdx) += 1;
631
    }
632
633
end:
634
    return result;
635
}
636
637
/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */
638
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
639
{
640
    PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
641
    PaAlsaDeviceInfo *deviceInfoArray;
642
    int cardIdx = -1, devIdx = 0;
643
    snd_ctl_card_info_t *cardInfo;
644
    PaError result = paNoError;
645
    size_t numDeviceNames = 0, maxDeviceNames = 1, i;
646
    HwDevInfo *hwDevInfos = NULL;
647
    snd_config_t *topNode = NULL;
648
    snd_pcm_info_t *pcmInfo;
649
    int res;
650
    int blocking = SND_PCM_NONBLOCK;
651
    char alsaCardName[50];
652
#ifdef PA_ENABLE_DEBUG_OUTPUT
653
    PaTime startTime = PaUtil_GetTime();
654
#endif
655
656
    if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) )
657
        blocking = 0;
658
659
    /* These two will be set to the first working input and output device, respectively */
660
    baseApi->info.defaultInputDevice = paNoDevice;
661
    baseApi->info.defaultOutputDevice = paNoDevice;
662
663
    /* Gather info about hw devices
664
665
     * snd_card_next() modifies the integer passed to it to be:
666
     *      the index of the first card if the parameter is -1
667
     *      the index of the next card if the parameter is the index of a card
668
     *      -1 if there are no more cards
669
     *
670
     * The function itself returns 0 if it succeeded. */
671
    cardIdx = -1;
672
    snd_ctl_card_info_alloca( &cardInfo );
673
    snd_pcm_info_alloca( &pcmInfo );
674
    while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 )
675
    {
676
        char *cardName;
677
        int devIdx = -1;
678
        snd_ctl_t *ctl;
679
        char buf[50];
680
681
        snprintf( alsaCardName, sizeof (alsaCardName), "hw:%d", cardIdx );
682
683
        /* Acquire name of card */
684
        if( snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 )
685
        {
686
            /* Unable to open card :( */
687
            PA_DEBUG(( "%s: Unable to open device %s\n", __FUNCTION__, alsaCardName ));
688
            continue;
689
        }
690
        snd_ctl_card_info( ctl, cardInfo );
691
692
        PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, snd_ctl_card_info_get_name( cardInfo )) );
693
694
        while( snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 )
695
        {
696
            char *alsaDeviceName, *deviceName;
697
            size_t len;
698
            int hasPlayback = 0, hasCapture = 0;
699
            snprintf( buf, sizeof (buf), "hw:%d,%d", cardIdx, devIdx );
700
701
            /* Obtain info about this particular device */
702
            snd_pcm_info_set_device( pcmInfo, devIdx );
703
            snd_pcm_info_set_subdevice( pcmInfo, 0 );
704
            snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE );
705
            if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
706
            {
707
                hasCapture = 1;
708
            }
709
            
710
            snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK );
711
            if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
712
            {
713
                hasPlayback = 1;
714
            }
715
716
            if( !hasPlayback && !hasCapture )
717
            {
718
                /* Error */
719
                continue;
720
            }
721
722
            /* The length of the string written by snprintf plus terminating 0 */
723
            len = snprintf( NULL, 0, "%s: %s (%s)", cardName, snd_pcm_info_get_name( pcmInfo ), buf ) + 1;
724
            PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
725
                    paInsufficientMemory );
726
            snprintf( deviceName, len, "%s: %s (%s)", cardName,
727
                    snd_pcm_info_get_name( pcmInfo ), buf );
728
729
            ++numDeviceNames;
730
            if( !hwDevInfos || numDeviceNames > maxDeviceNames )
731
            {
732
                maxDeviceNames *= 2;
733
                PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ),
734
                        paInsufficientMemory );
735
            }
736
737
            PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) );
738
739
            hwDevInfos[ numDeviceNames - 1 ].alsaName = alsaDeviceName;
740
            hwDevInfos[ numDeviceNames - 1 ].name = deviceName;
741
            hwDevInfos[ numDeviceNames - 1 ].isPlug = 0;
742
            hwDevInfos[ numDeviceNames - 1 ].hasPlayback = hasPlayback;
743
            hwDevInfos[ numDeviceNames - 1 ].hasCapture = hasCapture;
744
        }
745
        snd_ctl_close( ctl );
746
    }
747
748
    /* Iterate over plugin devices */
749
750
    if( NULL == snd_config )
751
    {
752
        /* snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */
753
        ENSURE_( snd_config_update(), paUnanticipatedHostError );
754
        PA_DEBUG(( "Updating snd_config\n" ));
755
    }
756
    assert( snd_config );
757
    if( (res = snd_config_search( snd_config, "pcm", &topNode )) >= 0 )
758
    {
759
        snd_config_iterator_t i, next;
760
761
        snd_config_for_each( i, next, topNode )
762
        {
763
            const char *tpStr = "unknown", *idStr = NULL;
764
            int err = 0;
765
766
            char *alsaDeviceName, *deviceName;
767
	    const HwDevInfo *predefined = NULL;
768
            snd_config_t *n = snd_config_iterator_entry( i ), * tp = NULL;;
769
770
            if( (err = snd_config_search( n, "type", &tp )) < 0 )
771
            {
772
                if( -ENOENT != err )
773
                {
774
                    ENSURE_(err, paUnanticipatedHostError);
775
                }
776
            }
777
            else 
778
            {
779
                ENSURE_( snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError );
780
            }
781
            ENSURE_( snd_config_get_id( n, &idStr ), paUnanticipatedHostError );
782
            if( IgnorePlugin( idStr ) )
783
            {
784
                PA_DEBUG(( "%s: Ignoring ALSA plugin device %s of type %s\n", __FUNCTION__, idStr, tpStr ));
785
                continue;
786
            }
787
            PA_DEBUG(( "%s: Found plugin %s of type %s\n", __FUNCTION__, idStr, tpStr ));
788
789
            PA_UNLESS( alsaDeviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
790
                                                            strlen(idStr) + 6 ), paInsufficientMemory );
791
            strcpy( alsaDeviceName, idStr );
792
            PA_UNLESS( deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
793
                                                            strlen(idStr) + 1 ), paInsufficientMemory );
794
            strcpy( deviceName, idStr );
795
796
            ++numDeviceNames;
797
            if( !hwDevInfos || numDeviceNames > maxDeviceNames )
798
            {
799
                maxDeviceNames *= 2;
800
                PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ),
801
                        paInsufficientMemory );
802
            }
803
804
	    predefined = FindDeviceName( alsaDeviceName );
805
806
            hwDevInfos[numDeviceNames - 1].alsaName = alsaDeviceName;
807
            hwDevInfos[numDeviceNames - 1].name = deviceName;
808
            hwDevInfos[numDeviceNames - 1].isPlug = 1;
809
810
	    if( predefined )
811
	    {
812
		hwDevInfos[numDeviceNames - 1].hasPlayback =
813
		    predefined->hasPlayback;
814
		hwDevInfos[numDeviceNames - 1].hasCapture =
815
		    predefined->hasCapture;
816
	    }
817
	    else
818
	    {
819
		hwDevInfos[numDeviceNames - 1].hasPlayback = 1;
820
		hwDevInfos[numDeviceNames - 1].hasCapture = 1;
821
	    }
822
        }
823
    }
824
    else
825
        PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, snd_strerror( res ) ));
826
827
    /* allocate deviceInfo memory based on the number of devices */
828
    PA_UNLESS( baseApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
829
            alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory );
830
831
    /* allocate all device info structs in a contiguous block */
832
    PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory(
833
            alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ), paInsufficientMemory );
834
835
    /* Loop over list of cards, filling in info. If a device is deemed unavailable (can't get name),
836
     * it's ignored.
837
     *
838
     * Note that we do this in two stages. This is a workaround owing to the fact that the 'dmix'
839
     * plugin may cause the underlying hardware device to be busy for a short while even after it
840
     * (dmix) is closed. The 'default' plugin may also point to the dmix plugin, so the same goes
841
     * for this.
842
     */
843
844
    for( i = 0, devIdx = 0; i < numDeviceNames; ++i )
845
    {
846
        PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
847
        HwDevInfo* hwInfo = &hwDevInfos[i];
848
        if( !strcmp( hwInfo->name, "dmix" ) || !strcmp( hwInfo->name, "default" ) )
849
        {
850
            continue;
851
        }
852
853
        PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) );
854
    }
855
    assert( devIdx < numDeviceNames );
856
    /* Now inspect 'dmix' and 'default' plugins */
857
    for( i = 0; i < numDeviceNames; ++i )
858
    {
859
        PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
860
        HwDevInfo* hwInfo = &hwDevInfos[i];
861
        if( strcmp( hwInfo->name, "dmix" ) && strcmp( hwInfo->name, "default" ) )
862
        {
863
            continue;
864
        }
865
866
        PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo,
867
                    &devIdx ) );
868
    }
869
    free( hwDevInfos );
870
871
    baseApi->info.deviceCount = devIdx;   /* Number of successfully queried devices */
872
873
#ifdef PA_ENABLE_DEBUG_OUTPUT
874
    PA_DEBUG(( "%s: Building device list took %f seconds\n", __FUNCTION__, PaUtil_GetTime() - startTime ));
875
#endif
876
877
end:
878
    return result;
879
880
error:
881
    /* No particular action */
882
    goto end;
883
}
884
885
/* Check against known device capabilities */
886
static PaError ValidateParameters( const PaStreamParameters *parameters, PaUtilHostApiRepresentation *hostApi, StreamDirection mode )
887
{
888
    PaError result = paNoError;
889
    int maxChans;
890
    const PaAlsaDeviceInfo *deviceInfo = NULL;
891
    assert( parameters );
892
893
    if( parameters->device != paUseHostApiSpecificDeviceSpecification )
894
    {
895
        assert( parameters->device < hostApi->info.deviceCount );
896
        PA_UNLESS( parameters->hostApiSpecificStreamInfo == NULL, paBadIODeviceCombination );
897
        deviceInfo = GetDeviceInfo( hostApi, parameters->device );
898
    }
899
    else
900
    {
901
        const PaAlsaStreamInfo *streamInfo = parameters->hostApiSpecificStreamInfo;
902
903
        PA_UNLESS( parameters->device == paUseHostApiSpecificDeviceSpecification, paInvalidDevice );
904
        PA_UNLESS( streamInfo->size == sizeof (PaAlsaStreamInfo) && streamInfo->version == 1,
905
                paIncompatibleHostApiSpecificStreamInfo );
906
        PA_UNLESS( streamInfo->deviceString != NULL, paInvalidDevice );
907
908
        /* Skip further checking */
909
        return paNoError;
910
    }
911
912
    assert( deviceInfo );
913
    assert( parameters->hostApiSpecificStreamInfo == NULL );
914
    maxChans = (StreamDirection_In == mode ? deviceInfo->baseDeviceInfo.maxInputChannels :
915
        deviceInfo->baseDeviceInfo.maxOutputChannels);
916
    PA_UNLESS( parameters->channelCount <= maxChans, paInvalidChannelCount );
917
918
error:
919
    return result;
920
}
921
922
/* Given an open stream, what sample formats are available? */
923
static PaSampleFormat GetAvailableFormats( snd_pcm_t *pcm )
924
{
925
    PaSampleFormat available = 0;
926
    snd_pcm_hw_params_t *hwParams;
927
    snd_pcm_hw_params_alloca( &hwParams );
928
929
    snd_pcm_hw_params_any( pcm, hwParams );
930
931
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0)
932
        available |= paFloat32;
933
934
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0)
935
        available |= paInt32;
936
937
#ifdef PA_LITTLE_ENDIAN
938
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0)
939
        available |= paInt24;
940
#elif defined PA_BIG_ENDIAN
941
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0)
942
        available |= paInt24;
943
#endif
944
945
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0)
946
        available |= paInt16;
947
948
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0)
949
        available |= paUInt8;
950
951
    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0)
952
        available |= paInt8;
953
954
    return available;
955
}
956
957
static snd_pcm_format_t Pa2AlsaFormat( PaSampleFormat paFormat )
958
{
959
    switch( paFormat )
960
    {
961
        case paFloat32:
962
            return SND_PCM_FORMAT_FLOAT;
963
964
        case paInt16:
965
            return SND_PCM_FORMAT_S16;
966
967
        case paInt24:
968
#ifdef PA_LITTLE_ENDIAN
969
            return SND_PCM_FORMAT_S24_3LE;
970
#elif defined PA_BIG_ENDIAN
971
            return SND_PCM_FORMAT_S24_3BE;
972
#endif
973
974
        case paInt32:
975
            return SND_PCM_FORMAT_S32;
976
977
        case paInt8:
978
            return SND_PCM_FORMAT_S8;
979
980
        case paUInt8:
981
            return SND_PCM_FORMAT_U8;
982
983
        default:
984
            return SND_PCM_FORMAT_UNKNOWN;
985
    }
986
}
987
988
/** Open an ALSA pcm handle.
989
 * 
990
 * The device to be open can be specified in a custom PaAlsaStreamInfo struct, or it will be a device number. In case of a
991
 * device number, it maybe specified through an env variable (PA_ALSA_PLUGHW) that we should open the corresponding plugin
992
 * device.
993
 */
994
static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *params, StreamDirection
995
        streamDir, snd_pcm_t **pcm )
996
{
997
    PaError result = paNoError;
998
    int ret;
999
    char dnameArray[50];
1000
    const char* deviceName = dnameArray;
1001
    const PaAlsaDeviceInfo *deviceInfo = NULL;
1002
    PaAlsaStreamInfo *streamInfo = (PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo;
1003
1004
    if( !streamInfo )
1005
    {
1006
        int usePlug = 0;
1007
        deviceInfo = GetDeviceInfo( hostApi, params->device );
1008
        
1009
        /* If device name starts with hw: and PA_ALSA_PLUGHW is 1, we open the plughw device instead */
1010
        if( !strncmp( "hw:", deviceInfo->alsaName, 3 ) && getenv( "PA_ALSA_PLUGHW" ) )
1011
            usePlug = atoi( getenv( "PA_ALSA_PLUGHW" ) );
1012
        if( usePlug )
1013
            snprintf( dnameArray, 50, "plug%s", deviceInfo->alsaName );
1014
        else
1015
            deviceName = deviceInfo->alsaName;
1016
    }
1017
    else
1018
        deviceName = streamInfo->deviceString;
1019
1020
    PA_DEBUG(( "%s: Opening device %s\n", __FUNCTION__, deviceName ));
1021
    if( (ret = OpenPcm( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
1022
                    SND_PCM_NONBLOCK, 1 )) < 0 )
1023
    {
1024
        /* Not to be closed */
1025
        *pcm = NULL;
1026
        ENSURE_( ret, -EBUSY == ret ? paDeviceUnavailable : paBadIODeviceCombination );
1027
    }
1028
    ENSURE_( snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError );
1029
1030
end:
1031
    return result;
1032
1033
error:
1034
    goto end;
1035
}
1036
1037
static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters,
1038
        double sampleRate, StreamDirection streamDir )
1039
{
1040
    PaError result = paNoError;
1041
    snd_pcm_t *pcm = NULL;
1042
    PaSampleFormat availableFormats;
1043
    /* We are able to adapt to a number of channels less than what the device supports */
1044
    unsigned int numHostChannels;
1045
    PaSampleFormat hostFormat;
1046
    snd_pcm_hw_params_t *hwParams;
1047
    snd_pcm_hw_params_alloca( &hwParams );
1048
    
1049
    if( !parameters->hostApiSpecificStreamInfo )
1050
    {
1051
        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, parameters->device );
1052
        numHostChannels = PA_MAX( parameters->channelCount, StreamDirection_In == streamDir ?
1053
                devInfo->minInputChannels : devInfo->minOutputChannels );
1054
    }
1055
    else
1056
        numHostChannels = parameters->channelCount;
1057
1058
    PA_ENSURE( AlsaOpen( hostApi, parameters, streamDir, &pcm ) );
1059
1060
    snd_pcm_hw_params_any( pcm, hwParams );
1061
1062
    if( SetApproximateSampleRate( pcm, hwParams, sampleRate ) < 0 )
1063
    {
1064
        result = paInvalidSampleRate;
1065
        goto error;
1066
    }
1067
1068
    if( snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 )
1069
    {
1070
        result = paInvalidChannelCount;
1071
        goto error;
1072
    }
1073
1074
    /* See if we can find a best possible match */
1075
    availableFormats = GetAvailableFormats( pcm );
1076
    PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) );
1077
    ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError );
1078
1079
    {
1080
        /* It happens that this call fails because the device is busy */
1081
        int ret = 0;
1082
        if( (ret = snd_pcm_hw_params( pcm, hwParams )) < 0)
1083
        {
1084
            if( -EINVAL == ret )
1085
            {
1086
                /* Don't know what to return here */
1087
                result = paBadIODeviceCombination;
1088
                goto error;
1089
            }
1090
            else if( -EBUSY == ret )
1091
            {
1092
                result = paDeviceUnavailable;
1093
                PA_DEBUG(( "%s: Device is busy\n", __FUNCTION__ ));
1094
            }
1095
            else
1096
            {
1097
                result = paUnanticipatedHostError;
1098
            }
1099
1100
            ENSURE_( ret, result );
1101
        }
1102
    }
1103
1104
end:
1105
    if( pcm )
1106
    {
1107
        snd_pcm_close( pcm );
1108
    }
1109
    return result;
1110
1111
error:
1112
    goto end;
1113
}
1114
1115
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
1116
                                  const PaStreamParameters *inputParameters,
1117
                                  const PaStreamParameters *outputParameters,
1118
                                  double sampleRate )
1119
{
1120
    int inputChannelCount = 0, outputChannelCount = 0;
1121
    PaSampleFormat inputSampleFormat, outputSampleFormat;
1122
    PaError result = paFormatIsSupported;
1123
1124
    if( inputParameters )
1125
    {
1126
        PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );
1127
1128
        inputChannelCount = inputParameters->channelCount;
1129
        inputSampleFormat = inputParameters->sampleFormat;
1130
    }
1131
1132
    if( outputParameters )
1133
    {
1134
        PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );
1135
1136
        outputChannelCount = outputParameters->channelCount;
1137
        outputSampleFormat = outputParameters->sampleFormat;
1138
    }
1139
1140
    if( inputChannelCount )
1141
    {
1142
        if( (result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In ))
1143
                != paNoError )
1144
            goto error;
1145
    }
1146
    if ( outputChannelCount )
1147
    {
1148
        if( (result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out ))
1149
                != paNoError )
1150
            goto error;
1151
    }
1152
1153
    return paFormatIsSupported;
1154
1155
error:
1156
    return result;
1157
}
1158
1159
static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, PaAlsaHostApiRepresentation *alsaApi,
1160
        const PaStreamParameters *params, StreamDirection streamDir, int callbackMode )
1161
{
1162
    PaError result = paNoError;
1163
    PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat;
1164
    assert( params->channelCount > 0 );
1165
1166
    /* Make sure things have an initial value */
1167
    memset( self, 0, sizeof (PaAlsaStreamComponent) );
1168
1169
    if( NULL == params->hostApiSpecificStreamInfo )
1170
    {
1171
        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->baseHostApiRep, params->device );
1172
        self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels
1173
                : devInfo->minOutputChannels );
1174
    }
1175
    else
1176
    {
1177
        /* We're blissfully unaware of the minimum channelCount */
1178
        self->numHostChannels = params->channelCount;
1179
    }
1180
1181
    self->device = params->device;
1182
1183
    PA_ENSURE( AlsaOpen( &alsaApi->baseHostApiRep, params, streamDir, &self->pcm ) );
1184
    self->nfds = snd_pcm_poll_descriptors_count( self->pcm );
1185
    hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat );
1186
1187
    self->hostSampleFormat = hostSampleFormat;
1188
    self->nativeFormat = Pa2AlsaFormat( hostSampleFormat );
1189
    self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved);
1190
    self->numUserChannels = params->channelCount;
1191
    self->streamDir = streamDir;
1192
    self->canMmap = 0;
1193
    self->nonMmapBuffer = NULL;
1194
1195
    if( !callbackMode && !self->userInterleaved )
1196
    {
1197
        /* Pre-allocate non-interleaved user provided buffers */
1198
        PA_UNLESS( self->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * self->numUserChannels ),
1199
                paInsufficientMemory );
1200
    }
1201
1202
error:
1203
    return result;
1204
}
1205
1206
static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self )
1207
{
1208
    snd_pcm_close( self->pcm );
1209
    if( self->userBuffers )
1210
        PaUtil_FreeMemory( self->userBuffers );
1211
}
1212
1213
/*
1214
static int nearbyint_(float value) {
1215
    if(  value - (int)value > .5 )
1216
        return (int)ceil( value );
1217
    return (int)floor( value );
1218
}
1219
*/
1220
1221
/** Initiate configuration, preparing for determining a period size suitable for both capture and playback components.
1222
 *
1223
 */
1224
static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *self, const PaStreamParameters *params,
1225
        int primeBuffers, snd_pcm_hw_params_t *hwParams, double *sampleRate )
1226
{
1227
    /* Configuration consists of setting all of ALSA's parameters.
1228
     * These parameters come in two flavors: hardware parameters
1229
     * and software paramters.  Hardware parameters will affect
1230
     * the way the device is initialized, software parameters
1231
     * affect the way ALSA interacts with me, the user-level client.
1232
     */
1233
1234
    PaError result = paNoError;
1235
    snd_pcm_access_t accessMode, alternateAccessMode;
1236
    snd_pcm_access_t rwAccessMode, alternateRwAccessMode;
1237
    int dir = 0;
1238
    snd_pcm_t *pcm = self->pcm;
1239
    double sr = *sampleRate;
1240
    unsigned int minPeriods = 2;
1241
1242
    /* self->framesPerBuffer = framesPerHostBuffer; */
1243
1244
    /* ... fill up the configuration space with all possibile
1245
     * combinations of parameters this device will accept */
1246
    ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
1247
1248
    ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );
1249
    /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */
1250
    dir = 0;
1251
    ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError );
1252
1253
    if( self->userInterleaved )
1254
    {
1255
        accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
1256
        rwAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
1257
        alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
1258
        alternateRwAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;
1259
    }
1260
    else
1261
    {
1262
        accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
1263
        rwAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;
1264
        alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
1265
        alternateRwAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
1266
    }
1267
    /* If requested access mode fails, try alternate mode */
1268
    self->canMmap = 1;
1269
    if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )
1270
    {
1271
        if( snd_pcm_hw_params_set_access( pcm, hwParams, rwAccessMode ) >= 0 )
1272
            self->canMmap = 0;
1273
        else
1274
        {
1275
            if( snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode ) < 0 )
1276
            {
1277
                int err = 0;
1278
                if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateRwAccessMode )) >= 0)
1279
                    self->canMmap = 0;
1280
                else
1281
                {
1282
                    result = paUnanticipatedHostError;
1283
                    PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) );
1284
                    goto error;
1285
                }
1286
            }
1287
            /* Flip mode */
1288
            self->hostInterleaved = !self->userInterleaved;
1289
        }
1290
    }
1291
1292
    ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );
1293
1294
    ENSURE_( SetApproximateSampleRate( pcm, hwParams, sr ), paInvalidSampleRate );
1295
    ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError );
1296
    /* reject if there's no sample rate within 1% of the one requested */
1297
    if( (fabs( *sampleRate - sr ) / *sampleRate) > 0.01 )
1298
    {
1299
        PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr ));                 
1300
        PA_ENSURE( paInvalidSampleRate );
1301
    }
1302
1303
    ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount );
1304
1305
    *sampleRate = sr;
1306
1307
end:
1308
    return result;
1309
1310
error:
1311
    /* No particular action */
1312
    goto end;
1313
}
1314
1315
/** Finish the configuration of the component's ALSA device.
1316
 *
1317
 * As part of this method, the component's bufferSize attribute will be set.
1318
 * @param latency: The latency for this component.
1319
 */
1320
static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *self, snd_pcm_hw_params_t* hwParams,
1321
        const PaStreamParameters *params, int primeBuffers, double sampleRate, PaTime* latency )
1322
{
1323
    PaError result = paNoError;
1324
    snd_pcm_sw_params_t* swParams;
1325
    snd_pcm_uframes_t bufSz = 0;
1326
    *latency = -1.;
1327
1328
    snd_pcm_sw_params_alloca( &swParams );
1329
1330
    bufSz = params->suggestedLatency * sampleRate;
1331
    ENSURE_( snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError );
1332
1333
    /* Set the parameters! */
1334
    {
1335
        int r = snd_pcm_hw_params( self->pcm, hwParams );
1336
#ifdef PA_ENABLE_DEBUG_OUTPUT
1337
        if( r < 0 )
1338
        {
1339
            snd_output_t *output = NULL;
1340
            snd_output_stdio_attach( &output, stderr, 0 );
1341
            snd_pcm_hw_params_dump( hwParams, output );
1342
        }
1343
#endif
1344
        ENSURE_(r, paUnanticipatedHostError );
1345
    }
1346
    ENSURE_( snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError );
1347
    /* Latency in seconds */
1348
    *latency = self->bufferSize / sampleRate;
1349
1350
    /* Now software parameters... */
1351
    ENSURE_( snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError );
1352
1353
    ENSURE_( snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
1354
    ENSURE_( snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->bufferSize ), paUnanticipatedHostError );
1355
1356
    /* Silence buffer in the case of underrun */
1357
    if( !primeBuffers ) /* XXX: Make sense? */
1358
    {
1359
        snd_pcm_uframes_t boundary;
1360
        ENSURE_( snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError );
1361
        ENSURE_( snd_pcm_sw_params_set_silence_threshold( self->pcm, swParams, 0 ), paUnanticipatedHostError );
1362
        ENSURE_( snd_pcm_sw_params_set_silence_size( self->pcm, swParams, boundary ), paUnanticipatedHostError );
1363
    }
1364
        
1365
    ENSURE_( snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
1366
    ENSURE_( snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError );
1367
    ENSURE_( snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError );
1368
1369
    /* Set the parameters! */
1370
    ENSURE_( snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError );
1371
1372
error:
1373
    return result;
1374
}
1375
1376
static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *inParams,
1377
        const PaStreamParameters *outParams, double sampleRate, unsigned long framesPerUserBuffer, PaStreamCallback callback,
1378
        PaStreamFlags streamFlags, void *userData )
1379
{
1380
    PaError result = paNoError;
1381
    assert( self );
1382
1383
    memset( self, 0, sizeof (PaAlsaStream) );
1384
1385
    if( NULL != callback )
1386
    {
1387
        PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,
1388
                                               &alsaApi->callbackStreamInterface,
1389
                                               callback, userData );
1390
        self->callbackMode = 1;
1391
    }
1392
    else
1393
    {
1394
        PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,
1395
                                               &alsaApi->blockingStreamInterface,
1396
                                               NULL, userData );
1397
    }
1398
1399
    self->framesPerUserBuffer = framesPerUserBuffer;
1400
    self->neverDropInput = streamFlags & paNeverDropInput;
1401
    /* XXX: Ignore paPrimeOutputBuffersUsingStreamCallback untill buffer priming is fully supported in pa_process.c */
1402
    /*
1403
    if( outParams & streamFlags & paPrimeOutputBuffersUsingStreamCallback )
1404
        self->primeBuffers = 1;
1405
        */
1406
    memset( &self->capture, 0, sizeof (PaAlsaStreamComponent) );
1407
    memset( &self->playback, 0, sizeof (PaAlsaStreamComponent) );
1408
    if( inParams )
1409
    {
1410
        PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->capture, alsaApi, inParams, StreamDirection_In, NULL != callback ) );
1411
    }
1412
    if( outParams )
1413
    {
1414
        PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->playback, alsaApi, outParams, StreamDirection_Out, NULL != callback ) );
1415
    }
1416
1417
    assert( self->capture.nfds || self->playback.nfds );
1418
1419
    PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( (self->capture.nfds +
1420
                    self->playback.nfds) * sizeof (struct pollfd) ), paInsufficientMemory );
1421
1422
    PaUtil_InitializeCpuLoadMeasurer( &self->cpuLoadMeasurer, sampleRate );
1423
    ASSERT_CALL_( PaUnixMutex_Initialize( &self->stateMtx ), paNoError );
1424
1425
error:
1426
    return result;
1427
}
1428
1429
/** Free resources associated with stream, and eventually stream itself.
1430
 *
1431
 * Frees allocated memory, and terminates individual StreamComponents.
1432
 */
1433
static void PaAlsaStream_Terminate( PaAlsaStream *self )
1434
{
1435
    assert( self );
1436
1437
    if( self->capture.pcm )
1438
    {
1439
        PaAlsaStreamComponent_Terminate( &self->capture );
1440
    }
1441
    if( self->playback.pcm )
1442
    {
1443
        PaAlsaStreamComponent_Terminate( &self->playback );
1444
    }
1445
1446
    PaUtil_FreeMemory( self->pfds );
1447
    ASSERT_CALL_( PaUnixMutex_Terminate( &self->stateMtx ), paNoError );
1448
1449
    PaUtil_FreeMemory( self );
1450
}
1451
1452
/** Calculate polling timeout
1453
 *
1454
 * @param frames Time to wait
1455
 * @return Polling timeout in milliseconds
1456
 */
1457
static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frames )
1458
{
1459
    assert( stream->streamRepresentation.streamInfo.sampleRate > 0.0 );
1460
    /* Period in msecs, rounded up */
1461
    return (int)ceil( 1000 * frames / stream->streamRepresentation.streamInfo.sampleRate );
1462
}
1463
1464
/** Determine size per host buffer.
1465
 *
1466
 * During this method call, the component's framesPerBuffer attribute gets computed, and the corresponding period size
1467
 * gets configured for the device.
1468
 * @param accurate: If the configured period size is non-integer, this will be set to 0.
1469
 */
1470
static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamComponent* self, const PaStreamParameters* params,
1471
        unsigned long framesPerUserBuffer, double sampleRate, snd_pcm_hw_params_t* hwParams, int* accurate )
1472
{
1473
    PaError result = paNoError;
1474
    unsigned long bufferSize = params->suggestedLatency * sampleRate, framesPerHostBuffer;
1475
    int dir = 0;
1476
    
1477
    {
1478
        snd_pcm_uframes_t tmp;
1479
        snd_pcm_hw_params_get_buffer_size_min( hwParams, &tmp );
1480
        bufferSize = PA_MAX( bufferSize, tmp );
1481
        snd_pcm_hw_params_get_buffer_size_max( hwParams, &tmp );
1482
        bufferSize = PA_MIN( bufferSize, tmp );
1483
    }
1484
1485
    assert( bufferSize > 0 );
1486
1487
    if( framesPerUserBuffer != paFramesPerBufferUnspecified )
1488
    {
1489
        /* Preferably the host buffer size should be a multiple of the user buffer size */
1490
1491
        if( bufferSize > framesPerUserBuffer )
1492
        {
1493
            snd_pcm_uframes_t remainder = bufferSize % framesPerUserBuffer;
1494
            if( remainder > framesPerUserBuffer / 2. )
1495
                bufferSize += framesPerUserBuffer - remainder;
1496
            else
1497
                bufferSize -= remainder;
1498
1499
            assert( bufferSize % framesPerUserBuffer == 0 );
1500
        }
1501
        else if( framesPerUserBuffer % bufferSize != 0 )
1502
        {
1503
            /*  Find a good compromise between user specified latency and buffer size */
1504
            if( bufferSize > framesPerUserBuffer * .75 )
1505
            {
1506
                bufferSize = framesPerUserBuffer;
1507
            }
1508
            else
1509
            {
1510
                snd_pcm_uframes_t newSz = framesPerUserBuffer;
1511
                while( newSz / 2 >= bufferSize )
1512
                {
1513
                    if( framesPerUserBuffer % (newSz / 2) != 0 )
1514
                    {
1515
                        /* No use dividing any further */
1516
                        break;
1517
                    }
1518
                    newSz /= 2;
1519
                }
1520
                bufferSize = newSz;
1521
            }
1522
1523
            assert( framesPerUserBuffer % bufferSize == 0 );
1524
        }
1525
    }
1526
1527
    /* Using the base number of periods, we try to approximate the suggested latency (+1 period),
1528
       finding a combination of period/buffer size which best fits these constraints */
1529
    {
1530
        unsigned numPeriods = numPeriods_, maxPeriods = 0;
1531
        /* It may be that the device only supports 2 periods for instance */
1532
        dir = 0;
1533
        ENSURE_( snd_pcm_hw_params_get_periods_max( hwParams, &maxPeriods, &dir ), paUnanticipatedHostError );
1534
        assert( maxPeriods > 1 );
1535
        numPeriods = PA_MIN( maxPeriods, numPeriods );
1536
1537
        if( framesPerUserBuffer != paFramesPerBufferUnspecified )
1538
        {
1539
            /* Try to get a power-of-two of the user buffer size. */
1540
            framesPerHostBuffer = framesPerUserBuffer;
1541
            if( framesPerHostBuffer < bufferSize )
1542
            {
1543
                while( bufferSize / framesPerHostBuffer > numPeriods )
1544
                {
1545
                    framesPerHostBuffer *= 2;
1546
                }
1547
                /* One extra period is preferrable to one less (should be more robust) */
1548
                if( bufferSize / framesPerHostBuffer < numPeriods )
1549
                {
1550
                    framesPerHostBuffer /= 2;
1551
                }
1552
            }
1553
            else
1554
            {
1555
                while( bufferSize / framesPerHostBuffer < numPeriods )
1556
                {
1557
                    if( framesPerUserBuffer % (framesPerHostBuffer / 2) != 0 )
1558
                    {
1559
                        /* Can't be divided any further */
1560
                        break;
1561
                    }
1562
                    framesPerHostBuffer /= 2;
1563
                }
1564
            }
1565
1566
            if( framesPerHostBuffer < framesPerUserBuffer )
1567
            {
1568
                assert( framesPerUserBuffer % framesPerHostBuffer == 0 );
1569
                if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
1570
                {
1571
                    if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 )
1572
                        framesPerHostBuffer *= 2;
1573
                    else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 )
1574
                        framesPerHostBuffer /= 2;
1575
                }
1576
            }
1577
            else
1578
            {
1579
                assert( framesPerHostBuffer % framesPerUserBuffer == 0 );
1580
                if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
1581
                {
1582
                    if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 )
1583
                        framesPerHostBuffer += framesPerUserBuffer;
1584
                    else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 )
1585
                        framesPerHostBuffer -= framesPerUserBuffer;
1586
                }
1587
            }
1588
        }
1589
        else
1590
        {
1591
            framesPerHostBuffer = bufferSize / numPeriods;
1592
        }
1593
    }
1594
1595
    /* non-mmap mode needs a reasonably-sized buffer or it'll stutter */
1596
    if( !self->canMmap && framesPerHostBuffer < 2048 )
1597
        framesPerHostBuffer = 2048;
1598
1599
    assert( framesPerHostBuffer > 0 );
1600
    {
1601
        snd_pcm_uframes_t min = 0, max = 0;
1602
        ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParams, &min, NULL ), paUnanticipatedHostError );
1603
        ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParams, &max, NULL ), paUnanticipatedHostError );
1604
1605
        if( framesPerHostBuffer < min )
1606
        {
1607
            PA_DEBUG(( "%s: The determined period size (%lu) is less than minimum (%lu)\n", __FUNCTION__,
1608
                        framesPerHostBuffer, min ));
1609
            framesPerHostBuffer = min;
1610
        }
1611
        else if( framesPerHostBuffer > max )
1612
        {
1613
            PA_DEBUG(( "%s: The determined period size (%lu) is greater than maximum (%lu)\n", __FUNCTION__,
1614
                        framesPerHostBuffer, max ));
1615
            framesPerHostBuffer = max;
1616
        }
1617
1618
        assert( framesPerHostBuffer >= min && framesPerHostBuffer <= max );
1619
        dir = 0;
1620
        ENSURE_( snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ),
1621
                paUnanticipatedHostError );
1622
        if( dir != 0 )
1623
        {
1624
            PA_DEBUG(( "%s: The configured period size is non-integer.\n", __FUNCTION__, dir ));
1625
            *accurate = 0;
1626
        }
1627
    }
1628
    self->framesPerBuffer = framesPerHostBuffer;
1629
1630
error:
1631
    return result;
1632
}
1633
1634
/* We need to determine how many frames per host buffer (period) to use.  Our
1635
 * goals are to provide the best possible performance, but also to
1636
 * honor the requested latency settings as closely as we can. Therefore this
1637
 * decision is based on:
1638
 *
1639
 *   - the period sizes that playback and/or capture support.  The
1640
 *     host buffer size has to be one of these.
1641
 *   - the number of periods that playback and/or capture support.
1642
 *
1643
 * We want to make period_size*(num_periods-1) to be as close as possible
1644
 * to latency*rate for both playback and capture.
1645
 *
1646
 * This method will determine suitable period sizes for capture and playback handles, and report the maximum number of
1647
 * frames per host buffer. The latter is relevant, in case we should be so unfortunate that the period size differs
1648
 * between capture and playback. If this should happen, the stream's hostBufferSizeMode attribute will be set to
1649
 * paUtilBoundedHostBufferSize, because the best we can do is limit the size of individual host buffers to the upper
1650
 * bound. The size of host buffers scheduled for processing should only matter if the user has specified a buffer size,
1651
 * but when he/she does we must strive for an optimal configuration. By default we'll opt for a fixed host buffer size,
1652
 * which should be fine if the period size is the same for capture and playback. In general, if there is a specified user
1653
 * buffer size, this method tries it best to determine a period size which is a multiple of the user buffer size.
1654
 *
1655
 * The framesPerBuffer attributes of the individual capture and playback components of the stream are set to corresponding
1656
 * values determined here. Since these should be reported as 
1657
 *
1658
 * This is one of those blocks of code that will just take a lot of
1659
 * refinement to be any good.
1660
 *
1661
 * In the full-duplex case it is possible that the routine was unable
1662
 * to find a number of frames per buffer acceptable to both devices
1663
 * TODO: Implement an algorithm to find the value closest to acceptance
1664
 * by both devices, to minimize difference between period sizes?
1665
 *
1666
 * @param determinedFramesPerHostBuffer: The determined host buffer size.
1667
 */
1668
static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double sampleRate, const PaStreamParameters* inputParameters,
1669
        const PaStreamParameters* outputParameters, unsigned long framesPerUserBuffer, snd_pcm_hw_params_t* hwParamsCapture,
1670
        snd_pcm_hw_params_t* hwParamsPlayback, PaUtilHostBufferSizeMode* hostBufferSizeMode )
1671
{
1672
    PaError result = paNoError;
1673
    unsigned long framesPerHostBuffer = 0;
1674
    int dir = 0;
1675
    int accurate = 1;
1676
    unsigned numPeriods = numPeriods_;
1677
1678
    if( self->capture.pcm && self->playback.pcm )
1679
    {
1680
        if( framesPerUserBuffer == paFramesPerBufferUnspecified )
1681
        {
1682
            /* Come up with a common desired latency */
1683
            snd_pcm_uframes_t desiredBufSz, e, minPeriodSize, maxPeriodSize, optimalPeriodSize, periodSize,
1684
                              minCapture, minPlayback, maxCapture, maxPlayback;
1685
1686
            dir = 0;
1687
            ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );
1688
            dir = 0;
1689
            ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError );
1690
            dir = 0;
1691
            ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError );
1692
            dir = 0;
1693
            ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError );
1694
            minPeriodSize = PA_MAX( minPlayback, minCapture );
1695
            maxPeriodSize = PA_MIN( maxPlayback, maxCapture );
1696
            PA_UNLESS( minPeriodSize <= maxPeriodSize, paBadIODeviceCombination );
1697
1698
            desiredBufSz = (snd_pcm_uframes_t)(PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )
1699
                    * sampleRate);
1700
            /* Clamp desiredBufSz */
1701
            {
1702
                snd_pcm_uframes_t maxBufferSize;
1703
                snd_pcm_uframes_t maxBufferSizeCapture, maxBufferSizePlayback;
1704
                ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &maxBufferSizeCapture ), paUnanticipatedHostError );
1705
                ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSizePlayback ), paUnanticipatedHostError );
1706
                maxBufferSize = PA_MIN( maxBufferSizeCapture, maxBufferSizePlayback );
1707
1708
                desiredBufSz = PA_MIN( desiredBufSz, maxBufferSize );
1709
            }
1710
1711
            /* Find the closest power of 2 */
1712
            e = ilogb( minPeriodSize );
1713
            if( minPeriodSize & (minPeriodSize - 1) )
1714
                e += 1;
1715
            periodSize = (snd_pcm_uframes_t)pow( 2, e );
1716
1717
            while( periodSize <= maxPeriodSize )
1718
            {
1719
                if( snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 &&
1720
                        snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 )
1721
                {
1722
                    /* OK! */
1723
                    break;
1724
                }
1725
1726
                periodSize *= 2;
1727
            }
1728
1729
            optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize );
1730
            optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
1731
1732
            /* Find the closest power of 2 */
1733
            e = ilogb( optimalPeriodSize );
1734
            if( optimalPeriodSize & (optimalPeriodSize - 1) )
1735
                e += 1;
1736
            optimalPeriodSize = (snd_pcm_uframes_t)pow( 2, e );
1737
1738
            while( optimalPeriodSize >= periodSize )
1739
            {
1740
                if( snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 )
1741
                        >= 0 && snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback,
1742
                            optimalPeriodSize, 0 ) >= 0 )
1743
                {
1744
                    break;
1745
                }
1746
                optimalPeriodSize /= 2;
1747
            }
1748
        
1749
            if( optimalPeriodSize > periodSize )
1750
                periodSize = optimalPeriodSize;
1751
1752
            if( periodSize <= maxPeriodSize )
1753
            {
1754
                /* Looks good, the periodSize _should_ be acceptable by both devices */
1755
                ENSURE_( snd_pcm_hw_params_set_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ),
1756
                        paUnanticipatedHostError );
1757
                ENSURE_( snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ),
1758
                        paUnanticipatedHostError );
1759
                self->capture.framesPerBuffer = self->playback.framesPerBuffer = periodSize;
1760
                framesPerHostBuffer = periodSize;
1761
            }
1762
            else
1763
            {
1764
                /* Unable to find a common period size, oh well */
1765
                optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize );
1766
                optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
1767
1768
                self->capture.framesPerBuffer = optimalPeriodSize;
1769
                dir = 0;
1770
                ENSURE_( snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerBuffer, &dir ),
1771
                        paUnanticipatedHostError );
1772
                self->playback.framesPerBuffer = optimalPeriodSize;
1773
                dir = 0;
1774
                ENSURE_( snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerBuffer, &dir ),
1775
                        paUnanticipatedHostError );
1776
                framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer );
1777
                *hostBufferSizeMode = paUtilBoundedHostBufferSize;
1778
            }
1779
        }
1780
        else
1781
        {
1782
            /* We choose the simple route and determine a suitable number of frames per buffer for one component of
1783
             * the stream, then we hope that this will work for the other component too (it should!).
1784
             */
1785
1786
            unsigned maxPeriods = 0;
1787
            PaAlsaStreamComponent* first = &self->capture, * second = &self->playback;
1788
            const PaStreamParameters* firstStreamParams = inputParameters;
1789
            snd_pcm_hw_params_t* firstHwParams = hwParamsCapture, * secondHwParams = hwParamsPlayback;
1790
1791
            dir = 0;
1792
            ENSURE_( snd_pcm_hw_params_get_periods_max( hwParamsPlayback, &maxPeriods, &dir ), paUnanticipatedHostError );
1793
            if( maxPeriods < numPeriods )
1794
            {
1795
                /* The playback component is trickier to get right, try that first */
1796
                first = &self->playback;
1797
                second = &self->capture;
1798
                firstStreamParams = outputParameters;
1799
                firstHwParams = hwParamsPlayback;
1800
                secondHwParams = hwParamsCapture;
1801
            }
1802
1803
            PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( first, firstStreamParams, framesPerUserBuffer,
1804
                        sampleRate, firstHwParams, &accurate ) );
1805
1806
            second->framesPerBuffer = first->framesPerBuffer;
1807
            dir = 0;
1808
            ENSURE_( snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerBuffer, &dir ),
1809
                    paUnanticipatedHostError );
1810
            if( self->capture.framesPerBuffer == self->playback.framesPerBuffer )
1811
            {
1812
                framesPerHostBuffer = self->capture.framesPerBuffer;
1813
            }
1814
            else
1815
            {
1816
                framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer );
1817
                *hostBufferSizeMode = paUtilBoundedHostBufferSize;
1818
            }
1819
        }
1820
    }
1821
    else    /* half-duplex is a slightly simpler case */
1822
    {
1823
        if( self->capture.pcm )
1824
        {
1825
            PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->capture, inputParameters, framesPerUserBuffer,
1826
                        sampleRate, hwParamsCapture, &accurate) );
1827
            framesPerHostBuffer = self->capture.framesPerBuffer;
1828
        }
1829
        else
1830
        {
1831
            assert( self->playback.pcm );
1832
            PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->playback, outputParameters, framesPerUserBuffer,
1833
                        sampleRate, hwParamsPlayback, &accurate ) );
1834
            framesPerHostBuffer = self->playback.framesPerBuffer;
1835
        }
1836
    }
1837
1838
    PA_UNLESS( framesPerHostBuffer != 0, paInternalError );
1839
    self->maxFramesPerHostBuffer = framesPerHostBuffer;
1840
1841
    if( !self->playback.canMmap || !accurate )
1842
    {
1843
        /* Don't know the exact size per host buffer */
1844
        *hostBufferSizeMode = paUtilBoundedHostBufferSize;
1845
        /* Raise upper bound */
1846
        if( !accurate )
1847
            ++self->maxFramesPerHostBuffer;
1848
    }
1849
1850
error:
1851
    return result;
1852
}
1853
1854
/** Set up ALSA stream parameters.
1855
 *
1856
 */
1857
static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParameters *inParams, const PaStreamParameters*
1858
        outParams, double sampleRate, unsigned long framesPerUserBuffer, double* inputLatency, double* outputLatency,
1859
        PaUtilHostBufferSizeMode* hostBufferSizeMode )
1860
{
1861
    PaError result = paNoError;
1862
    double realSr = sampleRate;
1863
    snd_pcm_hw_params_t* hwParamsCapture, * hwParamsPlayback;
1864
1865
    snd_pcm_hw_params_alloca( &hwParamsCapture );
1866
    snd_pcm_hw_params_alloca( &hwParamsPlayback );
1867
1868
    if( self->capture.pcm )
1869
        PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->capture, inParams, self->primeBuffers, hwParamsCapture,
1870
                    &realSr ) );
1871
    if( self->playback.pcm )
1872
        PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->playback, outParams, self->primeBuffers, hwParamsPlayback,
1873
                    &realSr ) );
1874
1875
    PA_ENSURE( PaAlsaStream_DetermineFramesPerBuffer( self, realSr, inParams, outParams, framesPerUserBuffer,
1876
                hwParamsCapture, hwParamsPlayback, hostBufferSizeMode ) );
1877
1878
    if( self->capture.pcm )
1879
    {
1880
        assert( self->capture.framesPerBuffer != 0 );
1881
        PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->capture, hwParamsCapture, inParams, self->primeBuffers, realSr,
1882
                    inputLatency ) );
1883
        PA_DEBUG(( "%s: Capture period size: %lu, latency: %f\n", __FUNCTION__, self->capture.framesPerBuffer, *inputLatency ));
1884
    }
1885
    if( self->playback.pcm )
1886
    {
1887
        assert( self->playback.framesPerBuffer != 0 );
1888
        PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->playback, hwParamsPlayback, outParams, self->primeBuffers, realSr,
1889
                    outputLatency ) );
1890
        PA_DEBUG(( "%s: Playback period size: %lu, latency: %f\n", __FUNCTION__, self->playback.framesPerBuffer, *outputLatency ));
1891
    }
1892
1893
    /* Should be exact now */
1894
    self->streamRepresentation.streamInfo.sampleRate = realSr;
1895
1896
    /* this will cause the two streams to automatically start/stop/prepare in sync.
1897
     * We only need to execute these operations on one of the pair.
1898
     * A: We don't want to do this on a blocking stream.
1899
     */
1900
    if( self->callbackMode && self->capture.pcm && self->playback.pcm )
1901
    {
1902
        int err = snd_pcm_link( self->capture.pcm, self->playback.pcm );
1903
        if( err == 0 )
1904
            self->pcmsSynced = 1;
1905
        else
1906
            PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, snd_strerror( err ) ));
1907
    }
1908
1909
    {
1910
        unsigned long minFramesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerBuffer : ULONG_MAX,
1911
            self->playback.pcm ? self->playback.framesPerBuffer : ULONG_MAX );
1912
        self->pollTimeout = CalculatePollTimeout( self, minFramesPerHostBuffer );    /* Period in msecs, rounded up */
1913
1914
        /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */
1915
        /* self->threading.throttledSleepTime = (unsigned long) (minFramesPerHostBuffer / sampleRate / 4 * 1000); */
1916
    }
1917
1918
    if( self->callbackMode )
1919
    {
1920
        /* If the user expects a certain number of frames per callback we will either have to rely on block adaption
1921
         * (framesPerHostBuffer is not an integer multiple of framesPerBuffer) or we can simply align the number
1922
         * of host buffer frames with what the user specified */
1923
        if( self->framesPerUserBuffer != paFramesPerBufferUnspecified )
1924
        {
1925
            /* self->alignFrames = 1; */
1926
1927
            /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely
1928
             * on block adaption */
1929
        /*
1930
            if( framesPerHostBuffer % framesPerBuffer != 0 || (self->capture.pcm && self->playback.pcm &&
1931
                        self->capture.framesPerBuffer != self->playback.framesPerBuffer) )
1932
                self->useBlockAdaption = 1;
1933
            else
1934
                self->alignFrames = 1;
1935
        */
1936
        }
1937
    }
1938
1939
error:
1940
    return result;
1941
}
1942
1943
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
1944
                           PaStream** s,
1945
                           const PaStreamParameters *inputParameters,
1946
                           const PaStreamParameters *outputParameters,
1947
                           double sampleRate,
1948
                           unsigned long framesPerBuffer,
1949
                           PaStreamFlags streamFlags,
1950
                           PaStreamCallback* callback,
1951
                           void *userData )
1952
{
1953
    PaError result = paNoError;
1954
    PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
1955
    PaAlsaStream *stream = NULL;
1956
    PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0;
1957
    PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0;
1958
    int numInputChannels = 0, numOutputChannels = 0;
1959
    PaTime inputLatency, outputLatency;
1960
    /* Operate with fixed host buffer size by default, since other modes will invariably lead to block adaption */
1961
    /* XXX: Use Bounded by default? Output tends to get stuttery with Fixed ... */
1962
    PaUtilHostBufferSizeMode hostBufferSizeMode = paUtilFixedHostBufferSize;
1963
1964
    if( (streamFlags & paPlatformSpecificFlags) != 0 )
1965
        return paInvalidFlag;
1966
1967
    if( inputParameters )
1968
    {
1969
        PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );
1970
1971
        numInputChannels = inputParameters->channelCount;
1972
        inputSampleFormat = inputParameters->sampleFormat;
1973
    }
1974
    if( outputParameters )
1975
    {
1976
        PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );
1977
1978
        numOutputChannels = outputParameters->channelCount;
1979
        outputSampleFormat = outputParameters->sampleFormat;
1980
    }
1981
1982
    /* XXX: Why do we support this anyway? */
1983
    if( framesPerBuffer == paFramesPerBufferUnspecified && getenv( "PA_ALSA_PERIODSIZE" ) != NULL )
1984
    {
1985
        PA_DEBUG(( "%s: Getting framesPerBuffer from environment\n", __FUNCTION__ ));
1986
        framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") );
1987
    }
1988
1989
    PA_UNLESS( stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) ), paInsufficientMemory );
1990
    PA_ENSURE( PaAlsaStream_Initialize( stream, alsaHostApi, inputParameters, outputParameters, sampleRate,
1991
                framesPerBuffer, callback, streamFlags, userData ) );
1992
1993
    PA_ENSURE( PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerBuffer,
1994
                &inputLatency, &outputLatency, &hostBufferSizeMode ) );
1995
    hostInputSampleFormat = stream->capture.hostSampleFormat;
1996
    hostOutputSampleFormat = stream->playback.hostSampleFormat;
1997
1998
    PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
1999
                    numInputChannels, inputSampleFormat, hostInputSampleFormat,
2000
                    numOutputChannels, outputSampleFormat, hostOutputSampleFormat,
2001
                    sampleRate, streamFlags, framesPerBuffer, stream->maxFramesPerHostBuffer,
2002
                    hostBufferSizeMode, callback, userData ) );
2003
2004
    /* Ok, buffer processor is initialized, now we can deduce it's latency */
2005
    if( numInputChannels > 0 )
2006
        stream->streamRepresentation.streamInfo.inputLatency = inputLatency + (PaTime)(
2007
                PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor ) / sampleRate);
2008
    if( numOutputChannels > 0 )
2009
        stream->streamRepresentation.streamInfo.outputLatency = outputLatency + (PaTime)(
2010
                PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor ) / sampleRate);
2011
2012
    *s = (PaStream*)stream;
2013
2014
    return result;
2015
2016
error:
2017
    if( stream )
2018
    {
2019
        PA_DEBUG(( "%s: Stream in error, terminating\n", __FUNCTION__ ));
2020
        PaAlsaStream_Terminate( stream );
2021
    }
2022
2023
    return result;
2024
}
2025
2026
static PaError CloseStream( PaStream* s )
2027
{
2028
    PaError result = paNoError;
2029
    PaAlsaStream *stream = (PaAlsaStream*)s;
2030
2031
    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
2032
    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
2033
2034
    PaAlsaStream_Terminate( stream );
2035
2036
    return result;
2037
}
2038
2039
static void SilenceBuffer( PaAlsaStream *stream )
2040
{
2041
    const snd_pcm_channel_area_t *areas;
2042
    snd_pcm_uframes_t frames = (snd_pcm_uframes_t)snd_pcm_avail_update( stream->playback.pcm ), offset;
2043
2044
    snd_pcm_mmap_begin( stream->playback.pcm, &areas, &offset, &frames );
2045
    snd_pcm_areas_silence( areas, offset, stream->playback.numHostChannels, frames, stream->playback.nativeFormat );
2046
    snd_pcm_mmap_commit( stream->playback.pcm, offset, frames );
2047
}
2048
2049
/** Start/prepare pcm(s) for streaming.
2050
 *
2051
 * Depending on wether the stream is in callback or blocking mode, we will respectively start or simply
2052
 * prepare the playback pcm. If the buffer has _not_ been primed, we will in callback mode prepare and
2053
 * silence the buffer before starting playback. In blocking mode we simply prepare, as the playback will
2054
 * be started automatically as the user writes to output. 
2055
 *
2056
 * The capture pcm, however, will simply be prepared and started.
2057
 */
2058
static PaError AlsaStart( PaAlsaStream *stream, int priming )
2059
{
2060
    PaError result = paNoError;
2061
2062
    if( stream->playback.pcm )
2063
    {
2064
        if( stream->callbackMode )
2065
        {
2066
            if( !priming )
2067
            {
2068
                /* Buffer isn't primed, so prepare and silence */
2069
                ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
2070
                if( stream->playback.canMmap )
2071
                    SilenceBuffer( stream );
2072
            }
2073
            if( stream->playback.canMmap )
2074
                ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
2075
        }
2076
        else
2077
            ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
2078
    }
2079
    if( stream->capture.pcm && !stream->pcmsSynced )
2080
    {
2081
        ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );
2082
        /* For a blocking stream we want to start capture as well, since nothing will happen otherwise */
2083
        ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );
2084
    }
2085
2086
end:
2087
    return result;
2088
error:
2089
    goto end;
2090
}
2091
2092
/** Utility function for determining if pcms are in running state.
2093
 *
2094
 */
2095
#if 0
2096
static int IsRunning( PaAlsaStream *stream )
2097
{
2098
    int result = 0;
2099
2100
    PA_ENSURE( PaUnixMutex_Lock( &stream->stateMtx ) );
2101
    if( stream->capture.pcm )
2102
    {
2103
        snd_pcm_state_t capture_state = snd_pcm_state( stream->capture.pcm );
2104
2105
        if( capture_state == SND_PCM_STATE_RUNNING || capture_state == SND_PCM_STATE_XRUN
2106
                || capture_state == SND_PCM_STATE_DRAINING )
2107
        {
2108
            result = 1;
2109
            goto end;
2110
        }
2111
    }
2112
2113
    if( stream->playback.pcm )
2114
    {
2115
        snd_pcm_state_t playback_state = snd_pcm_state( stream->playback.pcm );
2116
2117
        if( playback_state == SND_PCM_STATE_RUNNING || playback_state == SND_PCM_STATE_XRUN
2118
                || playback_state == SND_PCM_STATE_DRAINING )
2119
        {
2120
            result = 1;
2121
            goto end;
2122
        }
2123
    }
2124
2125
end:
2126
    ASSERT_CALL_( PaUnixMutex_Unlock( &stream->stateMtx ), paNoError );
2127
    return result;
2128
error:
2129
    goto error;
2130
}
2131
#endif
2132
2133
static PaError StartStream( PaStream *s )
2134
{
2135
    PaError result = paNoError;
2136
    PaAlsaStream* stream = (PaAlsaStream*)s;
2137
    int streamStarted = 0;  /* So we can know wether we need to take the stream down */
2138
2139
    /* Ready the processor */
2140
    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
2141
2142
    /* Set now, so we can test for activity further down */
2143
    stream->isActive = 1;
2144
2145
    if( stream->callbackMode )
2146
    {
2147
        PA_ENSURE( PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1., stream->rtSched ) );
2148
    }
2149
    else
2150
    {
2151
        PA_ENSURE( AlsaStart( stream, 0 ) );
2152
        streamStarted = 1;
2153
    }
2154
2155
end:
2156
    return result;
2157
error:
2158
    if( streamStarted )
2159
    {
2160
        AbortStream( stream );
2161
    }
2162
    stream->isActive = 0;
2163
    
2164
    goto end;
2165
}
2166
2167
/** Stop PCM handle, either softly or abruptly.
2168
 */
2169
static PaError AlsaStop( PaAlsaStream *stream, int abort )
2170
{
2171
    PaError result = paNoError;
2172
    /* XXX: snd_pcm_drain tends to lock up, avoid it until we find out more */
2173
    abort = 1;
2174
    /*
2175
    if( stream->capture.pcm && !strcmp( Pa_GetDeviceInfo( stream->capture.device )->name,
2176
                "dmix" ) )
2177
    {
2178
        abort = 1;
2179
    }
2180
    else if( stream->playback.pcm && !strcmp( Pa_GetDeviceInfo( stream->playback.device )->name,
2181
                "dmix" ) )
2182
    {
2183
        abort = 1;
2184
    }
2185
    */
2186
2187
    if( abort )
2188
    {
2189
        if( stream->playback.pcm )
2190
        {
2191
            ENSURE_( snd_pcm_drop( stream->playback.pcm ), paUnanticipatedHostError );
2192
        }
2193
        if( stream->capture.pcm && !stream->pcmsSynced )
2194
        {
2195
            ENSURE_( snd_pcm_drop( stream->capture.pcm ), paUnanticipatedHostError );
2196
        }
2197
2198
        PA_DEBUG(( "%s: Dropped frames\n", __FUNCTION__ ));
2199
    }
2200
    else
2201
    {
2202
        if( stream->playback.pcm )
2203
        {
2204
            ENSURE_( snd_pcm_nonblock( stream->playback.pcm, 0 ), paUnanticipatedHostError );
2205
            if( snd_pcm_drain( stream->playback.pcm ) < 0 )
2206
            {
2207
                PA_DEBUG(( "%s: Draining playback handle failed!\n", __FUNCTION__ ));
2208
            }
2209
        }
2210
        if( stream->capture.pcm && !stream->pcmsSynced )
2211
        {
2212
            /* We don't need to retrieve any remaining frames */
2213
            if( snd_pcm_drain( stream->capture.pcm ) < 0 )
2214
            {
2215
                PA_DEBUG(( "%s: Draining capture handle failed!\n", __FUNCTION__ ));
2216
            }
2217
        }
2218
    }
2219
2220
end:
2221
    return result;
2222
error:
2223
    goto end;
2224
}
2225
2226
/** Stop or abort stream.
2227
 *
2228
 * If a stream is in callback mode we will have to inspect wether the background thread has
2229
 * finished, or we will have to take it out. In either case we join the thread before
2230
 * returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish
2231
 * buffers (drain)
2232
 *
2233
 * Stream will be considered inactive (!PaAlsaStream::isActive) after a call to this function
2234
 */
2235
static PaError RealStop( PaAlsaStream *stream, int abort )
2236
{
2237
    PaError result = paNoError;
2238
2239
    /* First deal with the callback thread, cancelling and/or joining
2240
     * it if necessary
2241
     */
2242
    if( stream->callbackMode )
2243
    {
2244
        PaError threadRes;
2245
        stream->callbackAbort = abort;
2246
2247
        if( !abort )
2248
        {
2249
            PA_DEBUG(( "Stopping callback\n" ));
2250
        }
2251
        PA_ENSURE( PaUnixThread_Terminate( &stream->thread, !abort, &threadRes ) );
2252
        if( threadRes != paNoError )
2253
        {
2254
            PA_DEBUG(( "Callback thread returned: %d\n", threadRes ));
2255
        }
2256
#if 0
2257
        if( watchdogRes != paNoError )
2258
            PA_DEBUG(( "Watchdog thread returned: %d\n", watchdogRes ));
2259
#endif
2260
2261
        stream->callback_finished = 0;
2262
    }
2263
    else
2264
    {
2265
        PA_ENSURE( AlsaStop( stream, abort ) );
2266
    }
2267
2268
    stream->isActive = 0;
2269
2270
end:
2271
    return result;
2272
2273
error:
2274
    goto end;
2275
}
2276
2277
static PaError StopStream( PaStream *s )
2278
{
2279
    return RealStop( (PaAlsaStream *) s, 0 );
2280
}
2281
2282
static PaError AbortStream( PaStream *s )
2283
{
2284
    return RealStop( (PaAlsaStream * ) s, 1 );
2285
}
2286
2287
/** The stream is considered stopped before StartStream, or AFTER a call to Abort/StopStream (callback
2288
 * returning !paContinue is not considered)
2289
 *
2290
 */
2291
static PaError IsStreamStopped( PaStream *s )
2292
{
2293
    PaAlsaStream *stream = (PaAlsaStream *)s;
2294
2295
    /* callback_finished indicates we need to join callback thread (ie. in Abort/StopStream) */
2296
    return !IsStreamActive( s ) && !stream->callback_finished;
2297
}
2298
2299
static PaError IsStreamActive( PaStream *s )
2300
{
2301
    PaAlsaStream *stream = (PaAlsaStream*)s;
2302
    return stream->isActive;
2303
}
2304
2305
static PaTime GetStreamTime( PaStream *s )
2306
{
2307
    PaAlsaStream *stream = (PaAlsaStream*)s;
2308
2309
    snd_timestamp_t timestamp;
2310
    snd_pcm_status_t* status;
2311
    snd_pcm_status_alloca( &status );
2312
2313
    /* TODO: what if we have both?  does it really matter? */
2314
2315
    /* TODO: if running in callback mode, this will mean
2316
     * libasound routines are being called from multiple threads.
2317
     * need to verify that libasound is thread-safe. */
2318
2319
    if( stream->capture.pcm )
2320
    {
2321
        snd_pcm_status( stream->capture.pcm, status );
2322
    }
2323
    else if( stream->playback.pcm )
2324
    {
2325
        snd_pcm_status( stream->playback.pcm, status );
2326
    }
2327
2328
    snd_pcm_status_get_tstamp( status, &timestamp );
2329
    return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1e6;
2330
}
2331
2332
static double GetStreamCpuLoad( PaStream* s )
2333
{
2334
    PaAlsaStream *stream = (PaAlsaStream*)s;
2335
2336
    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
2337
}
2338
2339
static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate )
2340
{
2341
    unsigned long approx = (unsigned long) sampleRate;
2342
    int dir = 0;
2343
    double fraction = sampleRate - approx;
2344
2345
    assert( pcm && hwParams );
2346
2347
    if( fraction > 0.0 )
2348
    {
2349
        if( fraction > 0.5 )
2350
        {
2351
            ++approx;
2352
            dir = -1;
2353
        }
2354
        else
2355
            dir = 1;
2356
    }
2357
2358
    return snd_pcm_hw_params_set_rate( pcm, hwParams, approx, dir );
2359
}
2360
2361
/* Return exact sample rate in param sampleRate */
2362
static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate )
2363
{
2364
    unsigned int num, den;
2365
    int err; 
2366
2367
    assert( hwParams );
2368
2369
    err = snd_pcm_hw_params_get_rate_numden( hwParams, &num, &den );
2370
    *sampleRate = (double) num / den;
2371
2372
    return err;
2373
}
2374
2375
/* Utility functions for blocking/callback interfaces */
2376
2377
/* Atomic restart of stream (we don't want the intermediate state visible) */
2378
static PaError AlsaRestart( PaAlsaStream *stream )
2379
{
2380
    PaError result = paNoError;
2381
2382
    PA_ENSURE( PaUnixMutex_Lock( &stream->stateMtx ) );
2383
    PA_ENSURE( AlsaStop( stream, 0 ) );
2384
    PA_ENSURE( AlsaStart( stream, 0 ) );
2385
2386
    PA_DEBUG(( "%s: Restarted audio\n", __FUNCTION__ ));
2387
2388
error:
2389
    PA_ENSURE( PaUnixMutex_Unlock( &stream->stateMtx ) );
2390
2391
    return result;
2392
}
2393
2394
/** Recover from xrun state.
2395
 *
2396
 */
2397
static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self )
2398
{
2399
    PaError result = paNoError;
2400
    snd_pcm_status_t *st;
2401
    PaTime now = PaUtil_GetTime();
2402
    snd_timestamp_t t;
2403
    int errplayback = 0, errcapture = 0;
2404
2405
    snd_pcm_status_alloca( &st );
2406
2407
    if( self->playback.pcm )
2408
    {
2409
        snd_pcm_status( self->playback.pcm, st );
2410
        if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
2411
        {
2412
            snd_pcm_status_get_trigger_tstamp( st, &t );
2413
            self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
2414
            errplayback = snd_pcm_recover( self->playback.pcm, -EPIPE, 0 );
2415
        }
2416
    }
2417
    if( self->capture.pcm )
2418
    {
2419
        snd_pcm_status( self->capture.pcm, st );
2420
        if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
2421
        {
2422
            snd_pcm_status_get_trigger_tstamp( st, &t );
2423
            self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
2424
            errcapture = snd_pcm_recover( self->capture.pcm, -EPIPE, 0 );
2425
        }
2426
    }
2427
2428
    if( errplayback || errcapture )
2429
        PA_ENSURE( AlsaRestart( self ) );
2430
2431
end:
2432
    return result;
2433
error:
2434
    goto end;
2435
}
2436
2437
/** Decide if we should continue polling for specified direction, eventually adjust the poll timeout.
2438
 * 
2439
 */
2440
static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamDir, int *pollTimeout, int *continuePoll )
2441
{
2442
    PaError result = paNoError;
2443
    snd_pcm_sframes_t delay, margin;
2444
    int err;
2445
    const PaAlsaStreamComponent *component = NULL, *otherComponent = NULL;
2446
2447
    *continuePoll = 1;
2448
2449
    if( StreamDirection_In == streamDir )
2450
    {
2451
        component = &stream->capture;
2452
        otherComponent = &stream->playback;
2453
    }
2454
    else
2455
    {
2456
        component = &stream->playback;
2457
        otherComponent = &stream->capture;
2458
    }
2459
2460
    /* ALSA docs say that negative delay should indicate xrun, but in my experience snd_pcm_delay returns -EPIPE */
2461
    if( (err = snd_pcm_delay( otherComponent->pcm, &delay )) < 0 )
2462
    {
2463
        if( err == -EPIPE )
2464
        {
2465
            /* Xrun */
2466
            *continuePoll = 0;
2467
            goto error;
2468
        }
2469
2470
        ENSURE_( err, paUnanticipatedHostError );
2471
    }
2472
2473
    if( StreamDirection_Out == streamDir )
2474
    {
2475
        /* Number of eligible frames before capture overrun */
2476
        delay = otherComponent->bufferSize - delay;
2477
    }
2478
    margin = delay - otherComponent->framesPerBuffer / 2;
2479
2480
    if( margin < 0 )
2481
    {
2482
        PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" ));
2483
        *continuePoll = 0;
2484
    }
2485
    else if( margin < otherComponent->framesPerBuffer )
2486
    {
2487
        *pollTimeout = CalculatePollTimeout( stream, margin );
2488
        PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n",
2489
                    __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback", *pollTimeout ));
2490
    }
2491
2492
error:
2493
    return result;
2494
}
2495
2496
/* Callback interface */
2497
2498
static void OnExit( void *data )
2499
{
2500
    PaAlsaStream *stream = (PaAlsaStream *) data;
2501
2502
    assert( data );
2503
2504
    PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
2505
2506
    stream->callback_finished = 1;  /* Let the outside world know stream was stopped in callback */
2507
    PA_DEBUG(( "%s: Stopping ALSA handles\n", __FUNCTION__ ));
2508
    AlsaStop( stream, stream->callbackAbort );
2509
    
2510
    PA_DEBUG(( "%s: Stoppage\n", __FUNCTION__ ));
2511
2512
    /* Eventually notify user all buffers have played */
2513
    if( stream->streamRepresentation.streamFinishedCallback )
2514
    {
2515
        stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
2516
    }
2517
    stream->isActive = 0;
2518
}
2519
2520
static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *timeInfo )
2521
{
2522
    snd_pcm_status_t *capture_status, *playback_status;
2523
    snd_timestamp_t capture_timestamp, playback_timestamp;
2524
    PaTime capture_time = 0., playback_time = 0.;
2525
2526
    snd_pcm_status_alloca( &capture_status );
2527
    snd_pcm_status_alloca( &playback_status );
2528
2529
    if( stream->capture.pcm )
2530
    {
2531
        snd_pcm_sframes_t capture_delay;
2532
2533
        snd_pcm_status( stream->capture.pcm, capture_status );
2534
        snd_pcm_status_get_tstamp( capture_status, &capture_timestamp );
2535
2536
        capture_time = capture_timestamp.tv_sec +
2537
            ((PaTime)capture_timestamp.tv_usec / 1000000.0);
2538
        timeInfo->currentTime = capture_time;
2539
2540
        capture_delay = snd_pcm_status_get_delay( capture_status );
2541
        timeInfo->inputBufferAdcTime = timeInfo->currentTime -
2542
            (PaTime)capture_delay / stream->streamRepresentation.streamInfo.sampleRate;
2543
    }
2544
    if( stream->playback.pcm )
2545
    {
2546
        snd_pcm_sframes_t playback_delay;
2547
2548
        snd_pcm_status( stream->playback.pcm, playback_status );
2549
        snd_pcm_status_get_tstamp( playback_status, &playback_timestamp );
2550
2551
        playback_time = playback_timestamp.tv_sec +
2552
            ((PaTime)playback_timestamp.tv_usec / 1000000.0);
2553
2554
        if( stream->capture.pcm ) /* Full duplex */
2555
        {
2556
            /* Hmm, we have both a playback and a capture timestamp.
2557
             * Hopefully they are the same... */
2558
            if( fabs( capture_time - playback_time ) > 0.01 )
2559
                PA_DEBUG(("Capture time and playback time differ by %f\n", fabs(capture_time-playback_time)));
2560
        }
2561
        else
2562
            timeInfo->currentTime = playback_time;
2563
2564
        playback_delay = snd_pcm_status_get_delay( playback_status );
2565
        timeInfo->outputBufferDacTime = timeInfo->currentTime +
2566
            (PaTime)playback_delay / stream->streamRepresentation.streamInfo.sampleRate;
2567
    }
2568
}
2569
2570
/** Called after buffer processing is finished.
2571
 *
2572
 * A number of mmapped frames is committed, it is possible that an xrun has occurred in the meantime.
2573
 *
2574
 * @param numFrames The number of frames that has been processed
2575
 * @param xrun Return whether an xrun has occurred
2576
 */
2577
static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun )
2578
{
2579
    PaError result = paNoError;
2580
    int res = 0;
2581
2582
    /* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed
2583
     * afterwards
2584
     */
2585
    if( !self->ready )
2586
        goto end;
2587
2588
    if( !self->canMmap && StreamDirection_Out == self->streamDir )
2589
    {
2590
        /* Play sound */
2591
        if( self->hostInterleaved )
2592
            res = snd_pcm_writei( self->pcm, self->nonMmapBuffer, numFrames );
2593
        else
2594
        {
2595
            void *bufs[self->numHostChannels];
2596
            int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
2597
            unsigned char *buffer = self->nonMmapBuffer;
2598
            int i;
2599
            for( i = 0; i < self->numHostChannels; ++i )
2600
            {
2601
                bufs[i] = buffer;
2602
                buffer += bufsize;
2603
            }
2604
            res = snd_pcm_writen( self->pcm, bufs, numFrames );
2605
        }
2606
    }
2607
2608
    if( self->canMmap )
2609
        res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
2610
    else
2611
    {
2612
        free( self->nonMmapBuffer );
2613
        self->nonMmapBuffer = NULL;
2614
    }
2615
2616
    if( res == -EPIPE || res == -ESTRPIPE )
2617
    {
2618
        *xrun = 1;
2619
    }
2620
    else
2621
    {
2622
        ENSURE_( res, paUnanticipatedHostError );
2623
    }
2624
2625
end:
2626
error:
2627
    return result;
2628
}
2629
2630
/* Extract buffer from channel area */
2631
static unsigned char *ExtractAddress( const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset )
2632
{
2633
    return (unsigned char *) area->addr + (area->first + offset * area->step) / 8;
2634
}
2635
2636
/** Do necessary adaption between user and host channels.
2637
 *
2638
    @concern ChannelAdaption Adapting between user and host channels can involve silencing unused channels and
2639
    duplicating mono information if host outputs come in pairs.
2640
 */
2641
static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp, int numFrames )
2642
{
2643
    PaError result = paNoError;
2644
    unsigned char *p;
2645
    int i;
2646
    int unusedChans = self->numHostChannels - self->numUserChannels;
2647
    unsigned char *src, *dst;
2648
    int convertMono = (self->numHostChannels % 2) == 0 && (self->numUserChannels % 2) != 0;
2649
2650
    assert( StreamDirection_Out == self->streamDir );
2651
2652
    if( self->hostInterleaved )
2653
    {
2654
        int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
2655
        unsigned char *buffer = self->canMmap ? ExtractAddress( self->channelAreas, self->offset ) : self->nonMmapBuffer;
2656
2657
        /* Start after the last user channel */
2658
        p = buffer + self->numUserChannels * swidth;
2659
2660
        if( convertMono )
2661
        {
2662
            /* Convert the last user channel into stereo pair */
2663
            src = buffer + (self->numUserChannels - 1) * swidth;
2664
            for( i = 0; i < numFrames; ++i )
2665
            {
2666
                dst = src + swidth;
2667
                memcpy( dst, src, swidth );
2668
                src += self->numHostChannels * swidth;
2669
            }
2670
2671
            /* Don't touch the channel we just wrote to */
2672
            p += swidth;
2673
            --unusedChans;
2674
        }
2675
2676
        if( unusedChans > 0 )
2677
        {
2678
            /* Silence unused output channels */
2679
            for( i = 0; i < numFrames; ++i )
2680
            {
2681
                memset( p, 0, swidth * unusedChans );
2682
                p += self->numHostChannels * swidth;
2683
            }
2684
        }
2685
    }
2686
    else
2687
    {
2688
        /* We extract the last user channel */
2689
        if( convertMono )
2690
        {
2691
            ENSURE_( snd_pcm_area_copy( self->channelAreas + self->numUserChannels, self->offset, self->channelAreas +
2692
                    (self->numUserChannels - 1), self->offset, numFrames, self->nativeFormat ), paUnanticipatedHostError );
2693
            --unusedChans;
2694
        }
2695
        if( unusedChans > 0 )
2696
        {
2697
            snd_pcm_areas_silence( self->channelAreas + (self->numHostChannels - unusedChans), self->offset, unusedChans, numFrames,
2698
                    self->nativeFormat );
2699
        }
2700
    }
2701
2702
error:
2703
    return result;
2704
}
2705
2706
static PaError PaAlsaStream_EndProcessing( PaAlsaStream *self, unsigned long numFrames, int *xrunOccurred )
2707
{
2708
    PaError result = paNoError;
2709
    int xrun = 0;
2710
2711
    if( self->capture.pcm )
2712
    {
2713
        PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->capture, numFrames, &xrun ) );
2714
    }
2715
    if( self->playback.pcm )
2716
    {
2717
        if( self->playback.numHostChannels > self->playback.numUserChannels )
2718
        {
2719
            PA_ENSURE( PaAlsaStreamComponent_DoChannelAdaption( &self->playback, &self->bufferProcessor, numFrames ) );
2720
        }
2721
        PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->playback, numFrames, &xrun ) );
2722
    }
2723
2724
error:
2725
    *xrunOccurred = xrun;
2726
    return result;
2727
}
2728
2729
/** Update the number of available frames.
2730
 *
2731
 */
2732
static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent *self, unsigned long *numFrames, int *xrunOccurred )
2733
{
2734
    PaError result = paNoError;
2735
    snd_pcm_sframes_t framesAvail = snd_pcm_avail_update( self->pcm );
2736
    *xrunOccurred = 0;
2737
2738
    if( -EPIPE == framesAvail )
2739
    {
2740
        *xrunOccurred = 1;
2741
        framesAvail = 0;
2742
    }
2743
    else
2744
    {
2745
        ENSURE_( framesAvail, paUnanticipatedHostError );
2746
    }
2747
2748
    *numFrames = framesAvail;
2749
2750
error:
2751
    return result;
2752
}
2753
2754
/** Fill in pollfd objects.
2755
 */
2756
static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent* self, struct pollfd* pfds )
2757
{
2758
    PaError result = paNoError;
2759
    int ret = snd_pcm_poll_descriptors( self->pcm, pfds, self->nfds );
2760
    (void)ret;  /* Prevent unused variable warning if asserts are turned off */
2761
    assert( ret == self->nfds );
2762
2763
    self->ready = 0;
2764
2765
    return result;
2766
}
2767
2768
/** Examine results from poll().
2769
 *
2770
 * @param pfds pollfds to inspect
2771
 * @param shouldPoll Should we continue to poll
2772
 * @param xrun Has an xrun occurred
2773
 */
2774
static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent* self, struct pollfd* pfds, int* shouldPoll, int* xrun )
2775
{
2776
    PaError result = paNoError;
2777
    unsigned short revents;
2778
2779
    ENSURE_( snd_pcm_poll_descriptors_revents( self->pcm, pfds, self->nfds, &revents ), paUnanticipatedHostError );
2780
    if( revents != 0 )
2781
    {
2782
        if( revents & POLLERR )
2783
        {
2784
            *xrun = 1;
2785
        }
2786
        else
2787
            self->ready = 1;
2788
2789
        *shouldPoll = 0;
2790
    }
2791
2792
error:
2793
    return result;
2794
}
2795
2796
/** Return the number of available frames for this stream.
2797
 *
2798
 * @concern FullDuplex The minimum available for the two directions is calculated, it might be desirable to ignore
2799
 * one direction however (not marked ready from poll), so this is controlled by queryCapture and queryPlayback.
2800
 *
2801
 * @param queryCapture Check available for capture
2802
 * @param queryPlayback Check available for playback
2803
 * @param available The returned number of frames
2804
 * @param xrunOccurred Return whether an xrun has occurred
2805
 */
2806
static PaError PaAlsaStream_GetAvailableFrames( PaAlsaStream *self, int queryCapture, int queryPlayback, unsigned long
2807
        *available, int *xrunOccurred )
2808
{
2809
    PaError result = paNoError;
2810
    unsigned long captureFrames, playbackFrames;
2811
    *xrunOccurred = 0;
2812
2813
    assert( queryCapture || queryPlayback );
2814
2815
    if( queryCapture )
2816
    {
2817
        assert( self->capture.pcm );
2818
        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->capture, &captureFrames, xrunOccurred ) );
2819
        if( *xrunOccurred )
2820
        {
2821
            goto end;
2822
        }
2823
    }
2824
    if( queryPlayback )
2825
    {
2826
        assert( self->playback.pcm );
2827
        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->playback, &playbackFrames, xrunOccurred ) );
2828
        if( *xrunOccurred )
2829
        {
2830
            goto end;
2831
        }
2832
    }
2833
2834
    if( queryCapture && queryPlayback )
2835
    {
2836
        *available = PA_MIN( captureFrames, playbackFrames );
2837
        /*PA_DEBUG(("capture: %lu, playback: %lu, combined: %lu\n", captureFrames, playbackFrames, *available));*/
2838
    }
2839
    else if( queryCapture )
2840
    {
2841
        *available = captureFrames;
2842
    }
2843
    else
2844
    {
2845
        *available = playbackFrames;
2846
    }
2847
2848
end:
2849
error:
2850
    return result;
2851
}
2852
2853
/** Wait for and report available buffer space from ALSA.
2854
 *
2855
 * Unless ALSA reports a minimum of frames available for I/O, we poll the ALSA filedescriptors for more.
2856
 * Both of these operations can uncover xrun conditions.
2857
 *
2858
 * @concern Xruns Both polling and querying available frames can report an xrun condition.
2859
 *
2860
 * @param framesAvail Return the number of available frames
2861
 * @param xrunOccurred Return whether an xrun has occurred
2862
 */ 
2863
static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *framesAvail, int *xrunOccurred )
2864
{
2865
    PaError result = paNoError;
2866
    int pollPlayback = self->playback.pcm != NULL, pollCapture = self->capture.pcm != NULL;
2867
    int pollTimeout = self->pollTimeout;
2868
    int xrun = 0;
2869
2870
    assert( self );
2871
    assert( framesAvail );
2872
2873
    if( !self->callbackMode )
2874
    {
2875
        /* In blocking mode we will only wait if necessary */
2876
        PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, self->capture.pcm != NULL, self->playback.pcm != NULL,
2877
                    framesAvail, &xrun ) );
2878
        if( xrun )
2879
        {
2880
            goto end;
2881
        }
2882
2883
        if( *framesAvail > 0 )
2884
        {
2885
            /* Mark pcms ready from poll */
2886
            if( self->capture.pcm )
2887
                self->capture.ready = 1;
2888
            if( self->playback.pcm )
2889
                self->playback.ready = 1;
2890
2891
            goto end;
2892
        }
2893
    }
2894
2895
    while( pollPlayback || pollCapture )
2896
    {
2897
        int totalFds = 0;
2898
        struct pollfd *capturePfds = NULL, *playbackPfds = NULL;
2899
2900
        pthread_testcancel();
2901
2902
        if( pollCapture )
2903
        {
2904
            capturePfds = self->pfds;
2905
            PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->capture, capturePfds ) );
2906
            totalFds += self->capture.nfds;
2907
        }
2908
        if( pollPlayback )
2909
        {
2910
            playbackPfds = self->pfds + (self->capture.pcm ? self->capture.nfds : 0);
2911
            PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) );
2912
            totalFds += self->playback.nfds;
2913
        }
2914
        
2915
        if( poll( self->pfds, totalFds, pollTimeout ) < 0 )
2916
        {
2917
            /*  XXX: Depend on preprocessor condition? */
2918
            if( errno == EINTR )
2919
            {
2920
                /* gdb */
2921
                continue;
2922
            }
2923
2924
            /* TODO: Add macro for checking system calls */
2925
            PA_ENSURE( paInternalError );
2926
        }
2927
2928
        /* check the return status of our pfds */
2929
        if( pollCapture )
2930
        {
2931
            PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->capture, capturePfds, &pollCapture, &xrun ) );
2932
        }
2933
        if( pollPlayback )
2934
        {
2935
            PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->playback, playbackPfds, &pollPlayback, &xrun ) );
2936
        }
2937
        if( xrun )
2938
        {
2939
            break;
2940
        }
2941
2942
        /* @concern FullDuplex If only one of two pcms is ready we may want to compromise between the two.
2943
         * If there is less than half a period's worth of samples left of frames in the other pcm's buffer we will
2944
         * stop polling.
2945
         */
2946
        if( self->capture.pcm && self->playback.pcm )
2947
        {
2948
            if( pollCapture && !pollPlayback )
2949
            {
2950
                PA_ENSURE( ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture ) );
2951
            }
2952
            else if( pollPlayback && !pollCapture )
2953
            {
2954
                PA_ENSURE( ContinuePoll( self, StreamDirection_Out, &pollTimeout, &pollPlayback ) );
2955
            }
2956
        }
2957
    }
2958
2959
    if( !xrun )
2960
    {
2961
        /* Get the number of available frames for the pcms that are marked ready.
2962
         * @concern FullDuplex If only one direction is marked ready (from poll), the number of frames available for
2963
         * the other direction is returned. Output is normally preferred over capture however, so capture frames may be
2964
         * discarded to avoid overrun unless paNeverDropInput is specified.
2965
         */
2966
        int captureReady = self->capture.pcm ? self->capture.ready : 0,
2967
            playbackReady = self->playback.pcm ? self->playback.ready : 0;
2968
        PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, captureReady, playbackReady, framesAvail, &xrun ) );
2969
2970
        if( self->capture.pcm && self->playback.pcm )
2971
        {
2972
            if( !self->playback.ready && !self->neverDropInput )
2973
            {
2974
                /* Drop input, a period's worth */
2975
                assert( self->capture.ready );
2976
                PaAlsaStreamComponent_EndProcessing( &self->capture, PA_MIN( self->capture.framesPerBuffer,
2977
                            *framesAvail ), &xrun );
2978
                *framesAvail = 0;
2979
                self->capture.ready = 0;
2980
            }
2981
        }
2982
        else if( self->capture.pcm )
2983
            assert( self->capture.ready );
2984
        else
2985
            assert( self->playback.ready );
2986
    }
2987
2988
end:
2989
error:
2990
    if( xrun )
2991
    {
2992
        /* Recover from the xrun state */
2993
        PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
2994
        *framesAvail = 0;
2995
    }
2996
    else
2997
    {
2998
        if( 0 != *framesAvail )
2999
        {
3000
            /* If we're reporting frames eligible for processing, one of the handles better be ready */
3001
            PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError );
3002
        }
3003
    }
3004
    *xrunOccurred = xrun;
3005
3006
    return result;
3007
}
3008
3009
/** Register per-channel ALSA buffer information with buffer processor.
3010
 *
3011
 * Mmapped buffer space is acquired from ALSA, and registered with the buffer processor. Differences between the
3012
 * number of host and user channels is taken into account.
3013
 * 
3014
 * @param numFrames On entrance the number of requested frames, on exit the number of contiguously accessible frames.
3015
 */
3016
static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* self, PaUtilBufferProcessor* bp,
3017
        unsigned long* numFrames, int* xrun )
3018
{
3019
    PaError result = paNoError;
3020
    const snd_pcm_channel_area_t *areas, *area;
3021
    void (*setChannel)(PaUtilBufferProcessor *, unsigned int, void *, unsigned int) =
3022
        StreamDirection_In == self->streamDir ? PaUtil_SetInputChannel : PaUtil_SetOutputChannel;
3023
    unsigned char *buffer, *p;
3024
    int i;
3025
    unsigned long framesAvail;
3026
3027
    /* This _must_ be called before mmap_begin */
3028
    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( self, &framesAvail, xrun ) );
3029
    if( *xrun )
3030
    {
3031
        *numFrames = 0;
3032
        goto end;
3033
    }
3034
3035
    if( self->canMmap )
3036
    {
3037
        ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError );
3038
        /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */
3039
        self->channelAreas = (snd_pcm_channel_area_t *)areas;
3040
    }
3041
    else
3042
    {
3043
        free( self->nonMmapBuffer );
3044
        self->nonMmapBuffer = calloc( self->numHostChannels, snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 ) );
3045
    }
3046
3047
    if( self->hostInterleaved )
3048
    {
3049
        int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
3050
3051
        p = buffer = self->canMmap ? ExtractAddress( areas, self->offset ) : self->nonMmapBuffer;
3052
        for( i = 0; i < self->numUserChannels; ++i )
3053
        {
3054
            /* We're setting the channels up to userChannels, but the stride will be hostChannels samples */
3055
            setChannel( bp, i, p, self->numHostChannels );
3056
            p += swidth;
3057
        }
3058
    }
3059
    else
3060
    {
3061
        if( self->canMmap )
3062
            for( i = 0; i < self->numUserChannels; ++i )
3063
            {
3064
                area = areas + i;
3065
                buffer = ExtractAddress( area, self->offset );
3066
                setChannel( bp, i, buffer, 1 );
3067
            }
3068
        else
3069
        {
3070
            int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
3071
            buffer = self->nonMmapBuffer;
3072
            for( i = 0; i < self->numUserChannels; ++i )
3073
            {
3074
                setChannel( bp, i, buffer, 1 );
3075
                buffer += bufsize;
3076
            }
3077
        }
3078
    }
3079
3080
    if( !self->canMmap && StreamDirection_In == self->streamDir )
3081
    {
3082
        /* Read sound */
3083
        int res;
3084
        if( self->hostInterleaved )
3085
            res = snd_pcm_readi( self->pcm, self->nonMmapBuffer, *numFrames );
3086
        else
3087
        {
3088
            void *bufs[self->numHostChannels];
3089
            int bufsize = snd_pcm_format_size( self->nativeFormat, self->framesPerBuffer + 1 );
3090
            unsigned char *buffer = self->nonMmapBuffer;
3091
            int i;
3092
            for( i = 0; i < self->numHostChannels; ++i )
3093
            {
3094
                bufs[i] = buffer;
3095
                buffer += bufsize;
3096
            }
3097
            res = snd_pcm_readn( self->pcm, bufs, *numFrames );
3098
        }
3099
        if( res == -EPIPE || res == -ESTRPIPE )
3100
        {
3101
            *xrun = 1;
3102
            *numFrames = 0;
3103
            free( self->nonMmapBuffer );
3104
            self->nonMmapBuffer = NULL;
3105
        }
3106
    }
3107
3108
end:
3109
error:
3110
    return result;
3111
}
3112
3113
/** Initiate buffer processing.
3114
 *
3115
 * ALSA buffers are registered with the PA buffer processor and the buffer size (in frames) set.
3116
 *
3117
 * @concern FullDuplex If both directions are being processed, the minimum amount of frames for the two directions is
3118
 * calculated.
3119
 *
3120
 * @param numFrames On entrance the number of available frames, on exit the number of received frames
3121
 * @param xrunOccurred Return whether an xrun has occurred
3122
 */
3123
static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream* self, unsigned long* numFrames, int* xrunOccurred )
3124
{
3125
    PaError result = paNoError;
3126
    unsigned long captureFrames = ULONG_MAX, playbackFrames = ULONG_MAX, commonFrames = 0;
3127
    int xrun = 0;
3128
3129
    if( *xrunOccurred )
3130
    {
3131
        *numFrames = 0;
3132
        return result;
3133
    }
3134
    /* If we got here at least one of the pcm's should be marked ready */
3135
    PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError );
3136
3137
    /* Extract per-channel ALSA buffer pointers and register them with the buffer processor.
3138
     * It is possible that a direction is not marked ready however, because it is out of sync with the other.
3139
     */
3140
    if( self->capture.pcm && self->capture.ready )
3141
    {
3142
        captureFrames = *numFrames;
3143
        PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->capture, &self->bufferProcessor, &captureFrames, 
3144
                    &xrun ) );
3145
    }
3146
    if( self->playback.pcm && self->playback.ready )
3147
    {
3148
        playbackFrames = *numFrames;
3149
        PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->playback, &self->bufferProcessor, &playbackFrames, 
3150
                    &xrun ) );
3151
    }
3152
    if( xrun )
3153
    {
3154
        /* Nothing more to do */
3155
        assert( 0 == commonFrames );
3156
        goto end;
3157
    }
3158
3159
    commonFrames = PA_MIN( captureFrames, playbackFrames );
3160
    /* assert( commonFrames <= *numFrames ); */
3161
    if( commonFrames > *numFrames )
3162
    {
3163
        /* Hmmm ... how come there are more frames available than we requested!? Blah. */
3164
        PA_DEBUG(( "%s: Common available frames are reported to be more than number requested: %lu, %lu, callbackMode: %d\n", __FUNCTION__,
3165
                    commonFrames, *numFrames, self->callbackMode ));
3166
        if( self->capture.pcm )
3167
        {
3168
            PA_DEBUG(( "%s: captureFrames: %lu, capture.ready: %d\n", __FUNCTION__, captureFrames, self->capture.ready ));
3169
        }
3170
        if( self->playback.pcm )
3171
        {
3172
            PA_DEBUG(( "%s: playbackFrames: %lu, playback.ready: %d\n", __FUNCTION__, playbackFrames, self->playback.ready ));
3173
        }
3174
        
3175
        commonFrames = 0;
3176
        goto end;
3177
    }
3178
3179
    /* Inform PortAudio of the number of frames we got.
3180
     * @concern FullDuplex We might be experiencing underflow in either end; if its an input underflow, we go on
3181
     * with output. If its output underflow however, depending on the paNeverDropInput flag, we may want to simply
3182
     * discard the excess input or call the callback with paOutputOverflow flagged.
3183
     */
3184
    if( self->capture.pcm )
3185
    {
3186
        if( self->capture.ready )
3187
        {
3188
            PaUtil_SetInputFrameCount( &self->bufferProcessor, commonFrames );
3189
        }
3190
        else
3191
        {
3192
            /* We have input underflow */
3193
            PaUtil_SetNoInput( &self->bufferProcessor );
3194
        }
3195
    }
3196
    if( self->playback.pcm )
3197
    {
3198
        if( self->playback.ready )
3199
        {
3200
            PaUtil_SetOutputFrameCount( &self->bufferProcessor, commonFrames );
3201
        }
3202
        else
3203
        {
3204
            /* We have output underflow, but keeping input data (paNeverDropInput) */
3205
            assert( self->neverDropInput );
3206
            assert( self->capture.pcm != NULL );
3207
            PA_DEBUG(( "%s: Setting output buffers to NULL\n", __FUNCTION__ ));
3208
            PaUtil_SetNoOutput( &self->bufferProcessor );
3209
        }
3210
    }
3211
    
3212
end:
3213
    *numFrames = commonFrames;
3214
error:
3215
    if( xrun )
3216
    {
3217
        PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
3218
        *numFrames = 0;
3219
    }
3220
    *xrunOccurred = xrun;
3221
3222
    return result;
3223
}
3224
3225
/** Callback thread's function.
3226
 *
3227
 * Roughly, the workflow can be described in the following way: The number of available frames that can be processed
3228
 * directly is obtained from ALSA, we then request as much directly accessible memory as possible within this amount
3229
 * from ALSA. The buffer memory is registered with the PA buffer processor and processing is carried out with
3230
 * PaUtil_EndBufferProcessing. Finally, the number of processed frames is reported to ALSA. The processing can
3231
 * happen in several iterations untill we have consumed the known number of available frames (or an xrun is detected).
3232
 */
3233
static void *CallbackThreadFunc( void *userData )
3234
{
3235
    PaError result = paNoError;
3236
    PaAlsaStream *stream = (PaAlsaStream*) userData;
3237
    PaStreamCallbackTimeInfo timeInfo = {0, 0, 0};
3238
    snd_pcm_sframes_t startThreshold = 0;
3239
    int callbackResult = paContinue;
3240
    PaStreamCallbackFlags cbFlags = 0;  /* We might want to keep state across iterations */
3241
    int streamStarted = 0;
3242
3243
    assert( stream );
3244
3245
    /* Execute OnExit when exiting */
3246
    pthread_cleanup_push( &OnExit, stream );
3247
3248
    /* Not implemented */
3249
    assert( !stream->primeBuffers );
3250
3251
    /* @concern StreamStart If the output is being primed the output pcm needs to be prepared, otherwise the
3252
     * stream is started immediately. The latter involves signaling the waiting main thread.
3253
     */
3254
    if( stream->primeBuffers )
3255
    {
3256
        snd_pcm_sframes_t avail;
3257
        
3258
        if( stream->playback.pcm )
3259
            ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
3260
        if( stream->capture.pcm && !stream->pcmsSynced )
3261
            ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );
3262
3263
        /* We can't be certain that the whole ring buffer is available for priming, but there should be
3264
         * at least one period */
3265
        avail = snd_pcm_avail_update( stream->playback.pcm );
3266
        startThreshold = avail - (avail % stream->playback.framesPerBuffer);
3267
        assert( startThreshold >= stream->playback.framesPerBuffer );
3268
    }
3269
    else
3270
    {
3271
        PA_ENSURE( PaUnixThread_PrepareNotify( &stream->thread ) );
3272
        /* Buffer will be zeroed */
3273
        PA_ENSURE( AlsaStart( stream, 0 ) );
3274
        PA_ENSURE( PaUnixThread_NotifyParent( &stream->thread ) );
3275
3276
        streamStarted = 1;
3277
    }
3278
3279
    while( 1 )
3280
    {
3281
        unsigned long framesAvail, framesGot;
3282
        int xrun = 0;
3283
3284
        pthread_testcancel();
3285
3286
        /* @concern StreamStop if the main thread has requested a stop and the stream has not been effectively
3287
         * stopped we signal this condition by modifying callbackResult (we'll want to flush buffered output).
3288
         */
3289
        if( PaUnixThread_StopRequested( &stream->thread ) && paContinue == callbackResult )
3290
        {
3291
            PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
3292
            callbackResult = paComplete;
3293
        }
3294
3295
        if( paContinue != callbackResult )
3296
        {
3297
            stream->callbackAbort = (paAbort == callbackResult);
3298
            if( stream->callbackAbort ||
3299
                    /** @concern BlockAdaption: Go on if adaption buffers are empty */
3300
                    PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) 
3301
            {
3302
                goto end;
3303
            }
3304
3305
            PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ ));
3306
            /* There is still buffered output that needs to be processed */
3307
        }
3308
3309
        /* Wait for data to become available, this comes down to polling the ALSA file descriptors untill we have
3310
         * a number of available frames.
3311
         */
3312
        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
3313
        if( xrun )
3314
        {
3315
            assert( 0 == framesAvail );
3316
            continue;
3317
3318
            /* XXX: Report xruns to the user? A situation is conceivable where the callback is never invoked due
3319
             * to constant xruns, it might be desirable to notify the user of this.
3320
             */
3321
        }
3322
3323
        /* Consume buffer space. Once we have a number of frames available for consumption we must retrieve the
3324
         * mmapped buffers from ALSA, this is contiguously accessible memory however, so we may receive smaller
3325
         * portions at a time than is available as a whole. Therefore we should be prepared to process several
3326
         * chunks successively. The buffers are passed to the PA buffer processor.
3327
         */
3328
        while( framesAvail > 0 )
3329
        {
3330
            xrun = 0;
3331
3332
            pthread_testcancel();
3333
3334
            /** @concern Xruns Under/overflows are to be reported to the callback */
3335
            if( stream->underrun > 0.0 )
3336
            {
3337
                cbFlags |= paOutputUnderflow;
3338
                stream->underrun = 0.0;
3339
            }
3340
            if( stream->overrun > 0.0 )
3341
            {
3342
                cbFlags |= paInputOverflow;
3343
                stream->overrun = 0.0;
3344
            }
3345
            if( stream->capture.pcm && stream->playback.pcm )
3346
            {
3347
                /** @concern FullDuplex It's possible that only one direction is being processed to avoid an
3348
                 * under- or overflow, this should be reported correspondingly */
3349
                if( !stream->capture.ready )
3350
                {
3351
                    cbFlags |= paInputUnderflow;
3352
                    PA_DEBUG(( "%s: Input underflow\n", __FUNCTION__ ));
3353
                }
3354
                else if( !stream->playback.ready )
3355
                {
3356
                    cbFlags |= paOutputOverflow;
3357
                    PA_DEBUG(( "%s: Output overflow\n", __FUNCTION__ ));
3358
                }
3359
            }
3360
3361
#if 0
3362
            CallbackUpdate( &stream->threading );
3363
#endif
3364
            CalculateTimeInfo( stream, &timeInfo );
3365
            PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags );
3366
            cbFlags = 0;
3367
3368
            /* CPU load measurement should include processing activivity external to the stream callback */
3369
            PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
3370
3371
            framesGot = framesAvail;
3372
            if( paUtilFixedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode )
3373
            {
3374
                /* We've committed to a fixed host buffer size, stick to that */
3375
                framesGot = framesGot >= stream->maxFramesPerHostBuffer ? stream->maxFramesPerHostBuffer : 0;
3376
            }
3377
            else
3378
            {
3379
                /* We've committed to an upper bound on the size of host buffers */
3380
                assert( paUtilBoundedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode );
3381
                framesGot = PA_MIN( framesGot, stream->maxFramesPerHostBuffer );
3382
            }
3383
            PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
3384
            /* Check the host buffer size against the buffer processor configuration */
3385
            framesAvail -= framesGot;
3386
3387
            if( framesGot > 0 )
3388
            {
3389
                assert( !xrun );
3390
                PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
3391
                PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
3392
            }
3393
            PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot );
3394
3395
            if( 0 == framesGot )
3396
            {
3397
                /* Go back to polling for more frames */
3398
                break;
3399
3400
            }
3401
3402
            if( paContinue != callbackResult )
3403
                break;
3404
        }
3405
    }
3406
3407
    /* Match pthread_cleanup_push */
3408
    pthread_cleanup_pop( 1 );
3409
3410
end:
3411
    PA_DEBUG(( "%s: Thread %d exiting\n ", __FUNCTION__, pthread_self() ));
3412
    PaUnixThreading_EXIT( result );
3413
error:
3414
    goto end;
3415
}
3416
3417
/* Blocking interface */
3418
3419
static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames )
3420
{
3421
    PaError result = paNoError;
3422
    PaAlsaStream *stream = (PaAlsaStream*)s;
3423
    unsigned long framesGot, framesAvail;
3424
    void *userBuffer;
3425
    snd_pcm_t *save = stream->playback.pcm;
3426
3427
    assert( stream );
3428
3429
    PA_UNLESS( stream->capture.pcm, paCanNotReadFromAnOutputOnlyStream );
3430
3431
    /* Disregard playback */
3432
    stream->playback.pcm = NULL;
3433
3434
    if( stream->overrun > 0. )
3435
    {
3436
        result = paInputOverflowed;
3437
        stream->overrun = 0.0;
3438
    }
3439
3440
    if( stream->capture.userInterleaved )
3441
    {
3442
        userBuffer = buffer;
3443
    }
3444
    else
3445
    {
3446
        /* Copy channels into local array */
3447
        userBuffer = stream->capture.userBuffers;
3448
        memcpy( userBuffer, buffer, sizeof (void *) * stream->capture.numUserChannels );
3449
    }
3450
3451
    /* Start stream if in prepared state */
3452
    if( snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED )
3453
    {
3454
        ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );
3455
    }
3456
3457
    while( frames > 0 )
3458
    {
3459
        int xrun = 0;
3460
        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
3461
        framesGot = PA_MIN( framesAvail, frames );
3462
3463
        PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
3464
        if( framesGot > 0 )
3465
        {
3466
            framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot );
3467
            PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
3468
            frames -= framesGot;
3469
        }
3470
    }
3471
3472
end:
3473
    stream->playback.pcm = save;
3474
    return result;
3475
error:
3476
    goto end;
3477
}
3478
3479
static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames )
3480
{
3481
    PaError result = paNoError;
3482
    signed long err;
3483
    PaAlsaStream *stream = (PaAlsaStream*)s;
3484
    snd_pcm_uframes_t framesGot, framesAvail;
3485
    const void *userBuffer;
3486
    snd_pcm_t *save = stream->capture.pcm;
3487
    
3488
    assert( stream );
3489
3490
    PA_UNLESS( stream->playback.pcm, paCanNotWriteToAnInputOnlyStream );
3491
3492
    /* Disregard capture */
3493
    stream->capture.pcm = NULL;
3494
3495
    if( stream->underrun > 0. )
3496
    {
3497
        result = paOutputUnderflowed;
3498
        stream->underrun = 0.0;
3499
    }
3500
3501
    if( stream->playback.userInterleaved )
3502
        userBuffer = buffer;
3503
    else /* Copy channels into local array */
3504
    {
3505
        userBuffer = stream->playback.userBuffers;
3506
        memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback.numUserChannels );
3507
    }
3508
3509
    while( frames > 0 )
3510
    {
3511
        int xrun = 0;
3512
        snd_pcm_uframes_t hwAvail;
3513
3514
        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
3515
        framesGot = PA_MIN( framesAvail, frames );
3516
3517
        PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
3518
        if( framesGot > 0 )
3519
        {
3520
            framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot );
3521
            PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
3522
            frames -= framesGot;
3523
        }
3524
3525
        /* Start stream after one period of samples worth */
3526
3527
        /* Frames residing in buffer */
3528
        PA_ENSURE( err = GetStreamWriteAvailable( stream ) );
3529
        framesAvail = err;
3530
        hwAvail = stream->playback.bufferSize - framesAvail;
3531
3532
        if( snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED &&
3533
                hwAvail >= stream->playback.framesPerBuffer )
3534
        {
3535
            ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
3536
        }
3537
    }
3538
3539
end:
3540
    stream->capture.pcm = save;
3541
    return result;
3542
error:
3543
    goto end;
3544
}
3545
3546
/* Return frames available for reading. In the event of an overflow, the capture pcm will be restarted */
3547
static signed long GetStreamReadAvailable( PaStream* s )
3548
{
3549
    PaError result = paNoError;
3550
    PaAlsaStream *stream = (PaAlsaStream*)s;
3551
    unsigned long avail;
3552
    int xrun;
3553
3554
    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );
3555
    if( xrun )
3556
    {
3557
        PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );
3558
        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );
3559
        if( xrun )
3560
            PA_ENSURE( paInputOverflowed );
3561
    }
3562
3563
    return (signed long)avail;
3564
3565
error:
3566
    return result;
3567
}
3568
3569
static signed long GetStreamWriteAvailable( PaStream* s )
3570
{
3571
    PaError result = paNoError;
3572
    PaAlsaStream *stream = (PaAlsaStream*)s;
3573
    unsigned long avail;
3574
    int xrun;
3575
3576
    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->playback, &avail, &xrun ) );
3577
    if( xrun )
3578
    {
3579
        snd_pcm_sframes_t savail;
3580
3581
        PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );
3582
        savail = snd_pcm_avail_update( stream->playback.pcm );
3583
3584
        /* savail should not contain -EPIPE now, since PaAlsaStream_HandleXrun will only prepare the pcm */
3585
        ENSURE_( savail, paUnanticipatedHostError );
3586
3587
        avail = (unsigned long) savail;
3588
    }
3589
3590
    return (signed long)avail;
3591
3592
error:
3593
    return result;
3594
}
3595
3596
/* Extensions */
3597
3598
void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info )
3599
{
3600
    info->size = sizeof (PaAlsaStreamInfo);
3601
    info->hostApiType = paALSA;
3602
    info->version = 1;
3603
    info->deviceString = NULL;
3604
}
3605
3606
void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable )
3607
{
3608
    PaAlsaStream *stream = (PaAlsaStream *) s;
3609
    stream->rtSched = enable;
3610
}
3611
3612
#if 0
3613
void PaAlsa_EnableWatchdog( PaStream *s, int enable )
3614
{
3615
    PaAlsaStream *stream = (PaAlsaStream *) s;
3616
    stream->thread.useWatchdog = enable;
3617
}
3618
#endif
3619
3620
static PaError GetAlsaStreamPointer( PaStream* s, PaAlsaStream** stream )
3621
{
3622
    PaError result = paNoError;
3623
    PaUtilHostApiRepresentation* hostApi;
3624
    PaAlsaHostApiRepresentation* alsaHostApi;
3625
    
3626
    PA_ENSURE( PaUtil_ValidateStreamPointer( s ) );
3627
    PA_ENSURE( PaUtil_GetHostApiRepresentation( &hostApi, paALSA ) );
3628
    alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
3629
    
3630
    PA_UNLESS( PA_STREAM_REP( s )->streamInterface == &alsaHostApi->callbackStreamInterface
3631
            || PA_STREAM_REP( s )->streamInterface == &alsaHostApi->blockingStreamInterface,
3632
        paIncompatibleStreamHostApi );
3633
3634
    *stream = (PaAlsaStream*)s;
3635
error:
3636
    return paNoError;
3637
}
3638
3639
PaError PaAlsa_GetStreamInputCard(PaStream* s, int* card) {
3640
    PaAlsaStream *stream;
3641
    PaError result = paNoError;
3642
    snd_pcm_info_t* pcmInfo;
3643
3644
    PA_ENSURE( GetAlsaStreamPointer( s, &stream ) );
3645
3646
    /* XXX: More descriptive error? */
3647
    PA_UNLESS( stream->capture.pcm, paDeviceUnavailable );
3648
3649
    snd_pcm_info_alloca( &pcmInfo );
3650
    PA_ENSURE( snd_pcm_info( stream->capture.pcm, pcmInfo ) );
3651
    *card = snd_pcm_info_get_card( pcmInfo );
3652
3653
error:
3654
    return result;
3655
}
3656
3657
PaError PaAlsa_GetStreamOutputCard(PaStream* s, int* card) {
3658
    PaAlsaStream *stream;
3659
    PaError result = paNoError;
3660
    snd_pcm_info_t* pcmInfo;
3661
3662
    PA_ENSURE( GetAlsaStreamPointer( s, &stream ) );
3663
3664
    /* XXX: More descriptive error? */
3665
    PA_UNLESS( stream->playback.pcm, paDeviceUnavailable );
3666
3667
    snd_pcm_info_alloca( &pcmInfo );
3668
    PA_ENSURE( snd_pcm_info( stream->playback.pcm, pcmInfo ) );
3669
    *card = snd_pcm_info_get_card( pcmInfo );
3670
3671
error:
3672
    return result;
3673
}
3674
3675
PaError PaAlsa_SetRetriesBusy( int retries )
3676
{
3677
    busyRetries_ = retries;
3678
    return paNoError;
3679
}