To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at https://github.com/sonic-visualiser/sv-dependency-builds .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / src / portaudio_20161030_catalina_patch / src / hostapi / alsa / pa_linux_alsa.c @ 164:9fa11135915a

History | View | Annotate | Download (170 KB)

1
/*
2
 * $Id$
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
#ifdef PA_ALSA_DYNAMIC
66
    #include <dlfcn.h> /* For dlXXX functions */
67
#endif
68

    
69
#include "portaudio.h"
70
#include "pa_util.h"
71
#include "pa_unix_util.h"
72
#include "pa_allocation.h"
73
#include "pa_hostapi.h"
74
#include "pa_stream.h"
75
#include "pa_cpuload.h"
76
#include "pa_process.h"
77
#include "pa_endianness.h"
78
#include "pa_debugprint.h"
79

    
80
#include "pa_linux_alsa.h"
81

    
82
/* Add missing define (for compatibility with older ALSA versions) */
83
#ifndef SND_PCM_TSTAMP_ENABLE
84
    #define SND_PCM_TSTAMP_ENABLE SND_PCM_TSTAMP_MMAP
85
#endif
86

    
87
/* Combine version elements into a single (unsigned) integer */
88
#define ALSA_VERSION_INT(major, minor, subminor)  ((major << 16) | (minor << 8) | subminor)
89

    
90
/* The acceptable tolerance of sample rate set, to that requested (as a ratio, eg 50 is 2%, 100 is 1%) */
91
#define RATE_MAX_DEVIATE_RATIO 100
92

    
93
/* Defines Alsa function types and pointers to these functions. */
94
#define _PA_DEFINE_FUNC(x)  typedef typeof(x) x##_ft; static x##_ft *alsa_##x = 0
95

    
96
/* Alloca helper. */
97
#define __alsa_snd_alloca(ptr,type) do { size_t __alsa_alloca_size = alsa_##type##_sizeof(); (*ptr) = (type##_t *) alloca(__alsa_alloca_size); memset(*ptr, 0, __alsa_alloca_size); } while (0)
98

    
99
_PA_DEFINE_FUNC(snd_pcm_open);
100
_PA_DEFINE_FUNC(snd_pcm_close);
101
_PA_DEFINE_FUNC(snd_pcm_nonblock);
102
_PA_DEFINE_FUNC(snd_pcm_frames_to_bytes);
103
_PA_DEFINE_FUNC(snd_pcm_prepare);
104
_PA_DEFINE_FUNC(snd_pcm_start);
105
_PA_DEFINE_FUNC(snd_pcm_resume);
106
_PA_DEFINE_FUNC(snd_pcm_wait);
107
_PA_DEFINE_FUNC(snd_pcm_state);
108
_PA_DEFINE_FUNC(snd_pcm_avail_update);
109
_PA_DEFINE_FUNC(snd_pcm_areas_silence);
110
_PA_DEFINE_FUNC(snd_pcm_mmap_begin);
111
_PA_DEFINE_FUNC(snd_pcm_mmap_commit);
112
_PA_DEFINE_FUNC(snd_pcm_readi);
113
_PA_DEFINE_FUNC(snd_pcm_readn);
114
_PA_DEFINE_FUNC(snd_pcm_writei);
115
_PA_DEFINE_FUNC(snd_pcm_writen);
116
_PA_DEFINE_FUNC(snd_pcm_drain);
117
_PA_DEFINE_FUNC(snd_pcm_recover);
118
_PA_DEFINE_FUNC(snd_pcm_drop);
119
_PA_DEFINE_FUNC(snd_pcm_area_copy);
120
_PA_DEFINE_FUNC(snd_pcm_poll_descriptors);
121
_PA_DEFINE_FUNC(snd_pcm_poll_descriptors_count);
122
_PA_DEFINE_FUNC(snd_pcm_poll_descriptors_revents);
123
_PA_DEFINE_FUNC(snd_pcm_format_size);
124
_PA_DEFINE_FUNC(snd_pcm_link);
125
_PA_DEFINE_FUNC(snd_pcm_delay);
126

    
127
_PA_DEFINE_FUNC(snd_pcm_hw_params_sizeof);
128
_PA_DEFINE_FUNC(snd_pcm_hw_params_malloc);
129
_PA_DEFINE_FUNC(snd_pcm_hw_params_free);
130
_PA_DEFINE_FUNC(snd_pcm_hw_params_any);
131
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_access);
132
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_format);
133
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_channels);
134
//_PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_near);
135
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate_near); //!!!
136
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate);
137
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_rate_resample);
138
//_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_time_near);
139
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size);
140
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size_near); //!!!
141
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_buffer_size_min);
142
//_PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_time_near);
143
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_size_near);
144
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_integer);
145
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_periods_min);
146

    
147
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_buffer_size);
148
//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size);
149
//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_access);
150
//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods);
151
//_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate);
152
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_channels_min);
153
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_channels_max);
154

    
155
_PA_DEFINE_FUNC(snd_pcm_hw_params_test_period_size);
156
_PA_DEFINE_FUNC(snd_pcm_hw_params_test_format);
157
_PA_DEFINE_FUNC(snd_pcm_hw_params_test_access);
158
_PA_DEFINE_FUNC(snd_pcm_hw_params_dump);
159
_PA_DEFINE_FUNC(snd_pcm_hw_params);
160

    
161
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods_min);
162
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_periods_max);
163
_PA_DEFINE_FUNC(snd_pcm_hw_params_set_period_size);
164
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size_min);
165
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_period_size_max);
166
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_buffer_size_max);
167
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_min);
168
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_max);
169
_PA_DEFINE_FUNC(snd_pcm_hw_params_get_rate_numden);
170
#define alsa_snd_pcm_hw_params_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_hw_params)
171

    
172
_PA_DEFINE_FUNC(snd_pcm_sw_params_sizeof);
173
_PA_DEFINE_FUNC(snd_pcm_sw_params_malloc);
174
_PA_DEFINE_FUNC(snd_pcm_sw_params_current);
175
_PA_DEFINE_FUNC(snd_pcm_sw_params_set_avail_min);
176
_PA_DEFINE_FUNC(snd_pcm_sw_params);
177
_PA_DEFINE_FUNC(snd_pcm_sw_params_free);
178
_PA_DEFINE_FUNC(snd_pcm_sw_params_set_start_threshold);
179
_PA_DEFINE_FUNC(snd_pcm_sw_params_set_stop_threshold);
180
_PA_DEFINE_FUNC(snd_pcm_sw_params_get_boundary);
181
_PA_DEFINE_FUNC(snd_pcm_sw_params_set_silence_threshold);
182
_PA_DEFINE_FUNC(snd_pcm_sw_params_set_silence_size);
183
_PA_DEFINE_FUNC(snd_pcm_sw_params_set_xfer_align);
184
_PA_DEFINE_FUNC(snd_pcm_sw_params_set_tstamp_mode);
185
#define alsa_snd_pcm_sw_params_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_sw_params)
186

    
187
_PA_DEFINE_FUNC(snd_pcm_info);
188
_PA_DEFINE_FUNC(snd_pcm_info_sizeof);
189
_PA_DEFINE_FUNC(snd_pcm_info_malloc);
190
_PA_DEFINE_FUNC(snd_pcm_info_free);
191
_PA_DEFINE_FUNC(snd_pcm_info_set_device);
192
_PA_DEFINE_FUNC(snd_pcm_info_set_subdevice);
193
_PA_DEFINE_FUNC(snd_pcm_info_set_stream);
194
_PA_DEFINE_FUNC(snd_pcm_info_get_name);
195
_PA_DEFINE_FUNC(snd_pcm_info_get_card);
196
#define alsa_snd_pcm_info_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_info)
197

    
198
_PA_DEFINE_FUNC(snd_ctl_pcm_next_device);
199
_PA_DEFINE_FUNC(snd_ctl_pcm_info);
200
_PA_DEFINE_FUNC(snd_ctl_open);
201
_PA_DEFINE_FUNC(snd_ctl_close);
202
_PA_DEFINE_FUNC(snd_ctl_card_info_malloc);
203
_PA_DEFINE_FUNC(snd_ctl_card_info_free);
204
_PA_DEFINE_FUNC(snd_ctl_card_info);
205
_PA_DEFINE_FUNC(snd_ctl_card_info_sizeof);
206
_PA_DEFINE_FUNC(snd_ctl_card_info_get_name);
207
#define alsa_snd_ctl_card_info_alloca(ptr) __alsa_snd_alloca(ptr, snd_ctl_card_info)
208

    
209
_PA_DEFINE_FUNC(snd_config);
210
_PA_DEFINE_FUNC(snd_config_update);
211
_PA_DEFINE_FUNC(snd_config_search);
212
_PA_DEFINE_FUNC(snd_config_iterator_entry);
213
_PA_DEFINE_FUNC(snd_config_iterator_first);
214
_PA_DEFINE_FUNC(snd_config_iterator_end);
215
_PA_DEFINE_FUNC(snd_config_iterator_next);
216
_PA_DEFINE_FUNC(snd_config_get_string);
217
_PA_DEFINE_FUNC(snd_config_get_id);
218
_PA_DEFINE_FUNC(snd_config_update_free_global);
219

    
220
_PA_DEFINE_FUNC(snd_pcm_status);
221
_PA_DEFINE_FUNC(snd_pcm_status_sizeof);
222
_PA_DEFINE_FUNC(snd_pcm_status_get_tstamp);
223
_PA_DEFINE_FUNC(snd_pcm_status_get_state);
224
_PA_DEFINE_FUNC(snd_pcm_status_get_trigger_tstamp);
225
_PA_DEFINE_FUNC(snd_pcm_status_get_delay);
226
#define alsa_snd_pcm_status_alloca(ptr) __alsa_snd_alloca(ptr, snd_pcm_status)
227

    
228
_PA_DEFINE_FUNC(snd_card_next);
229
_PA_DEFINE_FUNC(snd_asoundlib_version);
230
_PA_DEFINE_FUNC(snd_strerror);
231
_PA_DEFINE_FUNC(snd_output_stdio_attach);
232

    
233
#define alsa_snd_config_for_each(pos, next, node)\
234
    for (pos = alsa_snd_config_iterator_first(node),\
235
         next = alsa_snd_config_iterator_next(pos);\
236
         pos != alsa_snd_config_iterator_end(node); pos = next, next = alsa_snd_config_iterator_next(pos))
237

    
238
#undef _PA_DEFINE_FUNC
239

    
240
/* Redefine 'PA_ALSA_PATHNAME' to a different Alsa library name if desired. */
241
#ifndef PA_ALSA_PATHNAME
242
    #define PA_ALSA_PATHNAME "libasound.so"
243
#endif
244
static const char *g_AlsaLibName = PA_ALSA_PATHNAME;
245

    
246
/* Handle to dynamically loaded library. */
247
static void *g_AlsaLib = NULL;
248

    
249
#ifdef PA_ALSA_DYNAMIC
250

    
251
#define _PA_LOCAL_IMPL(x) __pa_local_##x
252

    
253
int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_rate_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
254
{
255
    int ret;
256

    
257
    if(( ret = alsa_snd_pcm_hw_params_set_rate(pcm, params, (*val), (*dir)) ) < 0 )
258
        return ret;
259

    
260
    return 0;
261
}
262

    
263
int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_buffer_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
264
{
265
    int ret;
266

    
267
    if(( ret = alsa_snd_pcm_hw_params_set_buffer_size(pcm, params, (*val)) ) < 0 )
268
        return ret;
269

    
270
    return 0;
271
}
272

    
273
int _PA_LOCAL_IMPL(snd_pcm_hw_params_set_period_size_near) (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)
274
{
275
    int ret;
276

    
277
    if(( ret = alsa_snd_pcm_hw_params_set_period_size(pcm, params, (*val), (*dir)) ) < 0 )
278
        return ret;
279

    
280
    return 0;
281
}
282

    
283
int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_channels_min) (const snd_pcm_hw_params_t *params, unsigned int *val)
284
{
285
    (*val) = 1;
286
    return 0;
287
}
288

    
289
int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_channels_max) (const snd_pcm_hw_params_t *params, unsigned int *val)
290
{
291
    (*val) = 2;
292
    return 0;
293
}
294

    
295
int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_min) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
296
{
297
    (*val) = 2;
298
    return 0;
299
}
300

    
301
int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_max) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
302
{
303
    (*val) = 8;
304
    return 0;
305
}
306

    
307
int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_min) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)
308
{
309
    (*frames) = 64;
310
    return 0;
311
}
312

    
313
int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_max) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)
314
{
315
    (*frames) = 512;
316
    return 0;
317
}
318

    
319
int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_buffer_size_max) (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)
320
{
321
    int ret;
322
    int dir                = 0;
323
    snd_pcm_uframes_t pmax = 0;
324
    unsigned int      pcnt = 0;
325

    
326
    if(( ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_period_size_max)(params, &pmax, &dir) ) < 0 )
327
        return ret;
328
    if(( ret = _PA_LOCAL_IMPL(snd_pcm_hw_params_get_periods_max)(params, &pcnt, &dir) ) < 0 )
329
        return ret;
330

    
331
    (*val) = pmax * pcnt;
332
    return 0;
333
}
334

    
335
int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_rate_min) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
336
{
337
    (*val) = 44100;
338
    return 0;
339
}
340

    
341
int _PA_LOCAL_IMPL(snd_pcm_hw_params_get_rate_max) (const snd_pcm_hw_params_t *params, unsigned int *val, int *dir)
342
{
343
    (*val) = 44100;
344
    return 0;
345
}
346

    
347
#endif // PA_ALSA_DYNAMIC
348

    
349
/* Trying to load Alsa library dynamically if 'PA_ALSA_DYNAMIC' is defined, othervise
350
   will link during compilation.
351
*/
352
static int PaAlsa_LoadLibrary()
353
{
354
#ifdef PA_ALSA_DYNAMIC
355

    
356
    PA_DEBUG(( "%s: loading ALSA library file - %s\n", __FUNCTION__, g_AlsaLibName ));
357

    
358
    dlerror();
359
    g_AlsaLib = dlopen(g_AlsaLibName, (RTLD_NOW|RTLD_GLOBAL) );
360
    if (g_AlsaLib == NULL)
361
    {
362
        PA_DEBUG(( "%s: failed dlopen() ALSA library file - %s, error: %s\n", __FUNCTION__, g_AlsaLibName, dlerror() ));
363
        return 0;
364
    }
365

    
366
    PA_DEBUG(( "%s: loading ALSA API\n", __FUNCTION__ ));
367

    
368
    #define _PA_LOAD_FUNC(x) do {             \
369
        alsa_##x = dlsym( g_AlsaLib, #x );      \
370
        if( alsa_##x == NULL ) {               \
371
            PA_DEBUG(( "%s: symbol [%s] not found in - %s, error: %s\n", __FUNCTION__, #x, g_AlsaLibName, dlerror() )); }\
372
        } while(0)
373

    
374
#else
375

    
376
    #define _PA_LOAD_FUNC(x) alsa_##x = &x
377

    
378
#endif
379

    
380
    _PA_LOAD_FUNC(snd_pcm_open);
381
    _PA_LOAD_FUNC(snd_pcm_close);
382
    _PA_LOAD_FUNC(snd_pcm_nonblock);
383
    _PA_LOAD_FUNC(snd_pcm_frames_to_bytes);
384
    _PA_LOAD_FUNC(snd_pcm_prepare);
385
    _PA_LOAD_FUNC(snd_pcm_start);
386
    _PA_LOAD_FUNC(snd_pcm_resume);
387
    _PA_LOAD_FUNC(snd_pcm_wait);
388
    _PA_LOAD_FUNC(snd_pcm_state);
389
    _PA_LOAD_FUNC(snd_pcm_avail_update);
390
    _PA_LOAD_FUNC(snd_pcm_areas_silence);
391
    _PA_LOAD_FUNC(snd_pcm_mmap_begin);
392
    _PA_LOAD_FUNC(snd_pcm_mmap_commit);
393
    _PA_LOAD_FUNC(snd_pcm_readi);
394
    _PA_LOAD_FUNC(snd_pcm_readn);
395
    _PA_LOAD_FUNC(snd_pcm_writei);
396
    _PA_LOAD_FUNC(snd_pcm_writen);
397
    _PA_LOAD_FUNC(snd_pcm_drain);
398
    _PA_LOAD_FUNC(snd_pcm_recover);
399
    _PA_LOAD_FUNC(snd_pcm_drop);
400
    _PA_LOAD_FUNC(snd_pcm_area_copy);
401
    _PA_LOAD_FUNC(snd_pcm_poll_descriptors);
402
    _PA_LOAD_FUNC(snd_pcm_poll_descriptors_count);
403
    _PA_LOAD_FUNC(snd_pcm_poll_descriptors_revents);
404
    _PA_LOAD_FUNC(snd_pcm_format_size);
405
    _PA_LOAD_FUNC(snd_pcm_link);
406
    _PA_LOAD_FUNC(snd_pcm_delay);
407

    
408
    _PA_LOAD_FUNC(snd_pcm_hw_params_sizeof);
409
    _PA_LOAD_FUNC(snd_pcm_hw_params_malloc);
410
    _PA_LOAD_FUNC(snd_pcm_hw_params_free);
411
    _PA_LOAD_FUNC(snd_pcm_hw_params_any);
412
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_access);
413
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_format);
414
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_channels);
415
//    _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_near);
416
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_near);
417
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate);
418
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_rate_resample);
419
//    _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_time_near);
420
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size);
421
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_near);
422
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_buffer_size_min);
423
//    _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_time_near);
424
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size_near);
425
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_integer);
426
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_periods_min);
427

    
428
    _PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size);
429
//    _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size);
430
//    _PA_LOAD_FUNC(snd_pcm_hw_params_get_access);
431
//    _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods);
432
//    _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate);
433
    _PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_min);
434
    _PA_LOAD_FUNC(snd_pcm_hw_params_get_channels_max);
435

    
436
    _PA_LOAD_FUNC(snd_pcm_hw_params_test_period_size);
437
    _PA_LOAD_FUNC(snd_pcm_hw_params_test_format);
438
    _PA_LOAD_FUNC(snd_pcm_hw_params_test_access);
439
    _PA_LOAD_FUNC(snd_pcm_hw_params_dump);
440
    _PA_LOAD_FUNC(snd_pcm_hw_params);
441

    
442
    _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_min);
443
    _PA_LOAD_FUNC(snd_pcm_hw_params_get_periods_max);
444
    _PA_LOAD_FUNC(snd_pcm_hw_params_set_period_size);
445
    _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_min);
446
    _PA_LOAD_FUNC(snd_pcm_hw_params_get_period_size_max);
447
    _PA_LOAD_FUNC(snd_pcm_hw_params_get_buffer_size_max);
448
    _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_min);
449
    _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_max);
450
    _PA_LOAD_FUNC(snd_pcm_hw_params_get_rate_numden);
451

    
452
    _PA_LOAD_FUNC(snd_pcm_sw_params_sizeof);
453
    _PA_LOAD_FUNC(snd_pcm_sw_params_malloc);
454
    _PA_LOAD_FUNC(snd_pcm_sw_params_current);
455
    _PA_LOAD_FUNC(snd_pcm_sw_params_set_avail_min);
456
    _PA_LOAD_FUNC(snd_pcm_sw_params);
457
    _PA_LOAD_FUNC(snd_pcm_sw_params_free);
458
    _PA_LOAD_FUNC(snd_pcm_sw_params_set_start_threshold);
459
    _PA_LOAD_FUNC(snd_pcm_sw_params_set_stop_threshold);
460
    _PA_LOAD_FUNC(snd_pcm_sw_params_get_boundary);
461
    _PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_threshold);
462
    _PA_LOAD_FUNC(snd_pcm_sw_params_set_silence_size);
463
    _PA_LOAD_FUNC(snd_pcm_sw_params_set_xfer_align);
464
    _PA_LOAD_FUNC(snd_pcm_sw_params_set_tstamp_mode);
465

    
466
    _PA_LOAD_FUNC(snd_pcm_info);
467
    _PA_LOAD_FUNC(snd_pcm_info_sizeof);
468
    _PA_LOAD_FUNC(snd_pcm_info_malloc);
469
    _PA_LOAD_FUNC(snd_pcm_info_free);
470
    _PA_LOAD_FUNC(snd_pcm_info_set_device);
471
    _PA_LOAD_FUNC(snd_pcm_info_set_subdevice);
472
    _PA_LOAD_FUNC(snd_pcm_info_set_stream);
473
    _PA_LOAD_FUNC(snd_pcm_info_get_name);
474
    _PA_LOAD_FUNC(snd_pcm_info_get_card);
475

    
476
    _PA_LOAD_FUNC(snd_ctl_pcm_next_device);
477
    _PA_LOAD_FUNC(snd_ctl_pcm_info);
478
    _PA_LOAD_FUNC(snd_ctl_open);
479
    _PA_LOAD_FUNC(snd_ctl_close);
480
    _PA_LOAD_FUNC(snd_ctl_card_info_malloc);
481
    _PA_LOAD_FUNC(snd_ctl_card_info_free);
482
    _PA_LOAD_FUNC(snd_ctl_card_info);
483
    _PA_LOAD_FUNC(snd_ctl_card_info_sizeof);
484
    _PA_LOAD_FUNC(snd_ctl_card_info_get_name);
485

    
486
    _PA_LOAD_FUNC(snd_config);
487
    _PA_LOAD_FUNC(snd_config_update);
488
    _PA_LOAD_FUNC(snd_config_search);
489
    _PA_LOAD_FUNC(snd_config_iterator_entry);
490
    _PA_LOAD_FUNC(snd_config_iterator_first);
491
    _PA_LOAD_FUNC(snd_config_iterator_end);
492
    _PA_LOAD_FUNC(snd_config_iterator_next);
493
    _PA_LOAD_FUNC(snd_config_get_string);
494
    _PA_LOAD_FUNC(snd_config_get_id);
495
    _PA_LOAD_FUNC(snd_config_update_free_global);
496

    
497
    _PA_LOAD_FUNC(snd_pcm_status);
498
    _PA_LOAD_FUNC(snd_pcm_status_sizeof);
499
    _PA_LOAD_FUNC(snd_pcm_status_get_tstamp);
500
    _PA_LOAD_FUNC(snd_pcm_status_get_state);
501
    _PA_LOAD_FUNC(snd_pcm_status_get_trigger_tstamp);
502
    _PA_LOAD_FUNC(snd_pcm_status_get_delay);
503

    
504
    _PA_LOAD_FUNC(snd_card_next);
505
    _PA_LOAD_FUNC(snd_asoundlib_version);
506
    _PA_LOAD_FUNC(snd_strerror);
507
    _PA_LOAD_FUNC(snd_output_stdio_attach);
508
#undef _PA_LOAD_FUNC
509

    
510
#ifdef PA_ALSA_DYNAMIC
511
    PA_DEBUG(( "%s: loaded ALSA API - ok\n", __FUNCTION__ ));
512

    
513
#define _PA_VALIDATE_LOAD_REPLACEMENT(x)\
514
    do {\
515
        if( alsa_##x == NULL )\
516
        {\
517
            alsa_##x = &_PA_LOCAL_IMPL(x);\
518
            PA_DEBUG(( "%s: replacing [%s] with local implementation\n", __FUNCTION__, #x ));\
519
        }\
520
    } while (0)
521

    
522
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_rate_near);
523
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_buffer_size_near);
524
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_set_period_size_near);
525
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_min);
526
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_channels_max);
527
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_min);
528
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_periods_max);
529
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_min);
530
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_period_size_max);
531
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_buffer_size_max);
532
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_min);
533
    _PA_VALIDATE_LOAD_REPLACEMENT(snd_pcm_hw_params_get_rate_max);
534

    
535
#undef _PA_LOCAL_IMPL
536
#undef _PA_VALIDATE_LOAD_REPLACEMENT
537

    
538
#endif // PA_ALSA_DYNAMIC
539

    
540
    return 1;
541
}
542

    
543
void PaAlsa_SetLibraryPathName( const char *pathName )
544
{
545
#ifdef PA_ALSA_DYNAMIC
546
    g_AlsaLibName = pathName;
547
#else
548
    (void)pathName;
549
#endif
550
}
551

    
552
/* Close handle to Alsa library. */
553
static void PaAlsa_CloseLibrary()
554
{
555
#ifdef PA_ALSA_DYNAMIC
556
    dlclose(g_AlsaLib);
557
    g_AlsaLib = NULL;
558
#endif
559
}
560

    
561
/* Check return value of ALSA function, and map it to PaError */
562
#define ENSURE_(expr, code) \
563
    do { \
564
        int __pa_unsure_error_id;\
565
        if( UNLIKELY( (__pa_unsure_error_id = (expr)) < 0 ) ) \
566
        { \
567
            /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
568
            if( (code) == paUnanticipatedHostError && pthread_equal( pthread_self(), paUnixMainThread) ) \
569
            { \
570
                PaUtil_SetLastHostErrorInfo( paALSA, __pa_unsure_error_id, alsa_snd_strerror( __pa_unsure_error_id ) ); \
571
            } \
572
            PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \
573
            if( (code) == paUnanticipatedHostError ) \
574
                PA_DEBUG(( "Host error description: %s\n", alsa_snd_strerror( __pa_unsure_error_id ) )); \
575
            result = (code); \
576
            goto error; \
577
        } \
578
    } while (0)
579

    
580
#define ASSERT_CALL_(expr, success) \
581
    do {\
582
        int __pa_assert_error_id;\
583
        __pa_assert_error_id = (expr);\
584
        assert( success == __pa_assert_error_id );\
585
    } while (0)
586

    
587
static int numPeriods_ = 4;
588
static int busyRetries_ = 100;
589

    
590
int PaAlsa_SetNumPeriods( int numPeriods )
591
{
592
    numPeriods_ = numPeriods;
593
    return paNoError;
594
}
595

    
596
typedef enum
597
{
598
    StreamDirection_In,
599
    StreamDirection_Out
600
} StreamDirection;
601

    
602
typedef struct
603
{
604
    PaSampleFormat hostSampleFormat;
605
    int numUserChannels, numHostChannels;
606
    int userInterleaved, hostInterleaved;
607
    int canMmap;
608
    void *nonMmapBuffer;
609
    unsigned int nonMmapBufferSize;
610
    PaDeviceIndex device;     /* Keep the device index */
611
    int deviceIsPlug; /* Distinguish plug types from direct 'hw:' devices */
612
    int useReventFix; /* Alsa older than 1.0.16, plug devices need a fix */
613

    
614
    snd_pcm_t *pcm;
615
    snd_pcm_uframes_t framesPerPeriod, alsaBufferSize;
616
    snd_pcm_format_t nativeFormat;
617
    unsigned int nfds;
618
    int ready;  /* Marked ready from poll */
619
    void **userBuffers;
620
    snd_pcm_uframes_t offset;
621
    StreamDirection streamDir;
622

    
623
    snd_pcm_channel_area_t *channelAreas;  /* Needed for channel adaption */
624
} PaAlsaStreamComponent;
625

    
626
/* Implementation specific stream structure */
627
typedef struct PaAlsaStream
628
{
629
    PaUtilStreamRepresentation streamRepresentation;
630
    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
631
    PaUtilBufferProcessor bufferProcessor;
632
    PaUnixThread thread;
633

    
634
    unsigned long framesPerUserBuffer, maxFramesPerHostBuffer;
635

    
636
    int primeBuffers;
637
    int callbackMode;              /* bool: are we running in callback mode? */
638
    int pcmsSynced;                /* Have we successfully synced pcms */
639
    int rtSched;
640

    
641
    /* the callback thread uses these to poll the sound device(s), waiting
642
     * for data to be ready/available */
643
    struct pollfd* pfds;
644
    int pollTimeout;
645

    
646
    /* Used in communication between threads */
647
    volatile sig_atomic_t callback_finished; /* bool: are we in the "callback finished" state? */
648
    volatile sig_atomic_t callbackAbort;    /* Drop frames? */
649
    volatile sig_atomic_t isActive;         /* Is stream in active state? (Between StartStream and StopStream || !paContinue) */
650
    PaUnixMutex stateMtx;                   /* Used to synchronize access to stream state */
651

    
652
    int neverDropInput;
653

    
654
    PaTime underrun;
655
    PaTime overrun;
656

    
657
    PaAlsaStreamComponent capture, playback;
658
}
659
PaAlsaStream;
660

    
661
/* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */
662

    
663
typedef struct PaAlsaHostApiRepresentation
664
{
665
    PaUtilHostApiRepresentation baseHostApiRep;
666
    PaUtilStreamInterface callbackStreamInterface;
667
    PaUtilStreamInterface blockingStreamInterface;
668

    
669
    PaUtilAllocationGroup *allocations;
670

    
671
    PaHostApiIndex hostApiIndex;
672
    PaUint32 alsaLibVersion; /* Retrieved from the library at run-time */
673
}
674
PaAlsaHostApiRepresentation;
675

    
676
typedef struct PaAlsaDeviceInfo
677
{
678
    PaDeviceInfo baseDeviceInfo;
679
    char *alsaName;
680
    int isPlug;
681
    int minInputChannels;
682
    int minOutputChannels;
683
}
684
PaAlsaDeviceInfo;
685

    
686
/* prototypes for functions declared in this file */
687

    
688
static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
689
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
690
                                  const PaStreamParameters *inputParameters,
691
                                  const PaStreamParameters *outputParameters,
692
                                  double sampleRate );
693
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
694
                           PaStream** s,
695
                           const PaStreamParameters *inputParameters,
696
                           const PaStreamParameters *outputParameters,
697
                           double sampleRate,
698
                           unsigned long framesPerBuffer,
699
                           PaStreamFlags streamFlags,
700
                           PaStreamCallback *callback,
701
                           void *userData );
702
static PaError CloseStream( PaStream* stream );
703
static PaError StartStream( PaStream *stream );
704
static PaError StopStream( PaStream *stream );
705
static PaError AbortStream( PaStream *stream );
706
static PaError IsStreamStopped( PaStream *s );
707
static PaError IsStreamActive( PaStream *stream );
708
static PaTime GetStreamTime( PaStream *stream );
709
static double GetStreamCpuLoad( PaStream* stream );
710
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi );
711
static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate );
712
static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate );
713
static PaUint32 PaAlsaVersionNum(void);
714

    
715
/* Callback prototypes */
716
static void *CallbackThreadFunc( void *userData );
717

    
718
/* Blocking prototypes */
719
static signed long GetStreamReadAvailable( PaStream* s );
720
static signed long GetStreamWriteAvailable( PaStream* s );
721
static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
722
static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
723

    
724

    
725
static const PaAlsaDeviceInfo *GetDeviceInfo( const PaUtilHostApiRepresentation *hostApi, int device )
726
{
727
    return (const PaAlsaDeviceInfo *)hostApi->deviceInfos[device];
728
}
729

    
730
/** Uncommented because AlsaErrorHandler is unused for anything good yet. If AlsaErrorHandler is
731
    to be used, do not forget to register this callback in PaAlsa_Initialize, and unregister in Terminate.
732
*/
733
/*static void AlsaErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...)
734
{
735
}*/
736

    
737
PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
738
{
739
    PaError result = paNoError;
740
    PaAlsaHostApiRepresentation *alsaHostApi = NULL;
741

    
742
    /* Try loading Alsa library. */
743
    if (!PaAlsa_LoadLibrary())
744
        return paHostApiNotFound;
745

    
746
    PA_UNLESS( alsaHostApi = (PaAlsaHostApiRepresentation*) PaUtil_AllocateMemory(
747
                sizeof(PaAlsaHostApiRepresentation) ), paInsufficientMemory );
748
    PA_UNLESS( alsaHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
749
    alsaHostApi->hostApiIndex = hostApiIndex;
750
    alsaHostApi->alsaLibVersion = PaAlsaVersionNum();
751

    
752
    *hostApi = (PaUtilHostApiRepresentation*)alsaHostApi;
753
    (*hostApi)->info.structVersion = 1;
754
    (*hostApi)->info.type = paALSA;
755
    (*hostApi)->info.name = "ALSA";
756

    
757
    (*hostApi)->Terminate = Terminate;
758
    (*hostApi)->OpenStream = OpenStream;
759
    (*hostApi)->IsFormatSupported = IsFormatSupported;
760

    
761
    /** If AlsaErrorHandler is to be used, do not forget to unregister callback pointer in
762
        Terminate function.
763
    */
764
    /*ENSURE_( snd_lib_error_set_handler(AlsaErrorHandler), paUnanticipatedHostError );*/
765

    
766
    PA_ENSURE( BuildDeviceList( alsaHostApi ) );
767

    
768
    PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface,
769
                                      CloseStream, StartStream,
770
                                      StopStream, AbortStream,
771
                                      IsStreamStopped, IsStreamActive,
772
                                      GetStreamTime, GetStreamCpuLoad,
773
                                      PaUtil_DummyRead, PaUtil_DummyWrite,
774
                                      PaUtil_DummyGetReadAvailable,
775
                                      PaUtil_DummyGetWriteAvailable );
776

    
777
    PaUtil_InitializeStreamInterface( &alsaHostApi->blockingStreamInterface,
778
                                      CloseStream, StartStream,
779
                                      StopStream, AbortStream,
780
                                      IsStreamStopped, IsStreamActive,
781
                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
782
                                      ReadStream, WriteStream,
783
                                      GetStreamReadAvailable,
784
                                      GetStreamWriteAvailable );
785

    
786
    PA_ENSURE( PaUnixThreading_Initialize() );
787

    
788
    return result;
789

    
790
error:
791
    if( alsaHostApi )
792
    {
793
        if( alsaHostApi->allocations )
794
        {
795
            PaUtil_FreeAllAllocations( alsaHostApi->allocations );
796
            PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );
797
        }
798

    
799
        PaUtil_FreeMemory( alsaHostApi );
800
    }
801

    
802
    return result;
803
}
804

    
805
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
806
{
807
    PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
808

    
809
    assert( hostApi );
810

    
811
    /** See AlsaErrorHandler and PaAlsa_Initialize for details.
812
    */
813
    /*snd_lib_error_set_handler(NULL);*/
814

    
815
    if( alsaHostApi->allocations )
816
    {
817
        PaUtil_FreeAllAllocations( alsaHostApi->allocations );
818
        PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );
819
    }
820

    
821
    PaUtil_FreeMemory( alsaHostApi );
822
    alsa_snd_config_update_free_global();
823

    
824
    /* Close Alsa library. */
825
    PaAlsa_CloseLibrary();
826
}
827

    
828
/** Determine max channels and default latencies.
829
 *
830
 * This function provides functionality to grope an opened (might be opened for capture or playback) pcm device for
831
 * traits like max channels, suitable default latencies and default sample rate. Upon error, max channels is set to zero,
832
 * and a suitable result returned. The device is closed before returning.
833
 */
834
static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking,
835
        PaAlsaDeviceInfo* devInfo )
836
{
837
    PaError result = paNoError;
838
    snd_pcm_hw_params_t *hwParams;
839
    snd_pcm_uframes_t alsaBufferFrames, alsaPeriodFrames;
840
    unsigned int minChans, maxChans;
841
    int* minChannels, * maxChannels;
842
    double * defaultLowLatency, * defaultHighLatency, * defaultSampleRate =
843
        &devInfo->baseDeviceInfo.defaultSampleRate;
844
    double defaultSr = *defaultSampleRate;
845
    int dir;
846

    
847
    assert( pcm );
848

    
849
    PA_DEBUG(( "%s: collecting info ..\n", __FUNCTION__ ));
850

    
851
    if( StreamDirection_In == mode )
852
    {
853
        minChannels = &devInfo->minInputChannels;
854
        maxChannels = &devInfo->baseDeviceInfo.maxInputChannels;
855
        defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowInputLatency;
856
        defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighInputLatency;
857
    }
858
    else
859
    {
860
        minChannels = &devInfo->minOutputChannels;
861
        maxChannels = &devInfo->baseDeviceInfo.maxOutputChannels;
862
        defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowOutputLatency;
863
        defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighOutputLatency;
864
    }
865

    
866
    ENSURE_( alsa_snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError );
867

    
868
    alsa_snd_pcm_hw_params_alloca( &hwParams );
869
    alsa_snd_pcm_hw_params_any( pcm, hwParams );
870

    
871
    if( defaultSr >= 0 )
872
    {
873
        /* Could be that the device opened in one mode supports samplerates that the other mode wont have,
874
         * so try again .. */
875
        if( SetApproximateSampleRate( pcm, hwParams, defaultSr ) < 0 )
876
        {
877
            defaultSr = -1.;
878
            alsa_snd_pcm_hw_params_any( pcm, hwParams ); /* Clear any params (rate) that might have been set */
879
            PA_DEBUG(( "%s: Original default samplerate failed, trying again ..\n", __FUNCTION__ ));
880
        }
881
    }
882

    
883
    if( defaultSr < 0. )           /* Default sample rate not set */
884
    {
885
        unsigned int sampleRate = 44100;        /* Will contain approximate rate returned by alsa-lib */
886

    
887
        /* Don't allow rate resampling when probing for the default rate (but ignore if this call fails) */
888
        alsa_snd_pcm_hw_params_set_rate_resample( pcm, hwParams, 0 );
889
        if( alsa_snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ) < 0 )
890
        {
891
            result = paUnanticipatedHostError;
892
            goto error;
893
        }
894
        ENSURE_( GetExactSampleRate( hwParams, &defaultSr ), paUnanticipatedHostError );
895
    }
896

    
897
    ENSURE_( alsa_snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError );
898
    ENSURE_( alsa_snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError );
899
    assert( maxChans <= INT_MAX );
900
    assert( maxChans > 0 );    /* Weird linking issue could cause wrong version of ALSA symbols to be called,
901
                                   resulting in zeroed values */
902

    
903
    /* XXX: Limit to sensible number (ALSA plugins accept a crazy amount of channels)? */
904
    if( isPlug && maxChans > 128 )
905
    {
906
        maxChans = 128;
907
        PA_DEBUG(( "%s: Limiting number of plugin channels to %u\n", __FUNCTION__, maxChans ));
908
    }
909

    
910
    /* TWEAKME:
911
     * Giving values for default min and max latency is not straightforward.
912
     *  * for low latency, we want to give the lowest value that will work reliably.
913
     *      This varies based on the sound card, kernel, CPU, etc.  Better to give
914
     *      sub-optimal latency than to give a number too low and cause dropouts.
915
     *  * for high latency we want to give a large enough value that dropouts are basically impossible.
916
     *      This doesn't really require as much tweaking, since providing too large a number will
917
     *      just cause us to select the nearest setting that will work at stream config time.
918
     */
919
    /* Try low latency values, (sometimes the buffer & period that result are larger) */
920
    alsaBufferFrames = 512;
921
    alsaPeriodFrames = 128;
922
    ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError );
923
    ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir ), paUnanticipatedHostError );
924
    *defaultLowLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr;
925

    
926
    /* Base the high latency case on values four times larger */
927
    alsaBufferFrames = 2048;
928
    alsaPeriodFrames = 512;
929
    /* Have to reset hwParams, to set new buffer size; need to also set sample rate again */
930
    ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
931
    ENSURE_( SetApproximateSampleRate( pcm, hwParams, defaultSr ), paUnanticipatedHostError );
932
    ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &alsaBufferFrames ), paUnanticipatedHostError );
933
    ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir ), paUnanticipatedHostError );
934
    *defaultHighLatency = (double) (alsaBufferFrames - alsaPeriodFrames) / defaultSr;
935

    
936
    *minChannels = (int)minChans;
937
    *maxChannels = (int)maxChans;
938
    *defaultSampleRate = defaultSr;
939

    
940
end:
941
    alsa_snd_pcm_close( pcm );
942
    return result;
943

    
944
error:
945
    goto end;
946
}
947

    
948
/* Initialize device info with invalid values (maxInputChannels and maxOutputChannels are set to zero since these indicate
949
 * whether input/output is available) */
950
static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo )
951
{
952
    deviceInfo->structVersion = -1;
953
    deviceInfo->name = NULL;
954
    deviceInfo->hostApi = -1;
955
    deviceInfo->maxInputChannels = 0;
956
    deviceInfo->maxOutputChannels = 0;
957
    deviceInfo->defaultLowInputLatency = -1.;
958
    deviceInfo->defaultLowOutputLatency = -1.;
959
    deviceInfo->defaultHighInputLatency = -1.;
960
    deviceInfo->defaultHighOutputLatency = -1.;
961
    deviceInfo->defaultSampleRate = -1.;
962
}
963

    
964

    
965
/* Retrieve the version of the runtime Alsa-lib, as a single number equivalent to
966
 * SND_LIB_VERSION.  Only a version string is available ("a.b.c") so this has to be converted.
967
 * Assume 'a' and 'b' are single digits only.
968
 */
969
static PaUint32 PaAlsaVersionNum(void)
970
{
971
    char* verStr;
972
    PaUint32 verNum;
973

    
974
    verStr = (char*) alsa_snd_asoundlib_version();
975
    verNum = ALSA_VERSION_INT( atoi(verStr), atoi(verStr + 2), atoi(verStr + 4) );
976
    PA_DEBUG(( "ALSA version (build): " SND_LIB_VERSION_STR "\nALSA version (runtime): %s\n", verStr ));
977

    
978
    return verNum;
979
}
980

    
981

    
982
/* Helper struct */
983
typedef struct
984
{
985
    char *alsaName;
986
    char *name;
987
    int isPlug;
988
    int hasPlayback;
989
    int hasCapture;
990
} HwDevInfo;
991

    
992

    
993
HwDevInfo predefinedNames[] = {
994
    { "center_lfe", NULL, 0, 1, 0 },
995
/* { "default", NULL, 0, 1, 1 }, */
996
    { "dmix", NULL, 0, 1, 0 },
997
/* { "dpl", NULL, 0, 1, 0 }, */
998
/* { "dsnoop", NULL, 0, 0, 1 }, */
999
    { "front", NULL, 0, 1, 0 },
1000
    { "iec958", NULL, 0, 1, 0 },
1001
/* { "modem", NULL, 0, 1, 0 }, */
1002
    { "rear", NULL, 0, 1, 0 },
1003
    { "side", NULL, 0, 1, 0 },
1004
/*     { "spdif", NULL, 0, 0, 0 }, */
1005
    { "surround40", NULL, 0, 1, 0 },
1006
    { "surround41", NULL, 0, 1, 0 },
1007
    { "surround50", NULL, 0, 1, 0 },
1008
    { "surround51", NULL, 0, 1, 0 },
1009
    { "surround71", NULL, 0, 1, 0 },
1010

    
1011
    { "AndroidPlayback_Earpiece_normal",         NULL, 0, 1, 0 },
1012
    { "AndroidPlayback_Speaker_normal",          NULL, 0, 1, 0 },
1013
    { "AndroidPlayback_Bluetooth_normal",        NULL, 0, 1, 0 },
1014
    { "AndroidPlayback_Headset_normal",          NULL, 0, 1, 0 },
1015
    { "AndroidPlayback_Speaker_Headset_normal",  NULL, 0, 1, 0 },
1016
    { "AndroidPlayback_Bluetooth-A2DP_normal",   NULL, 0, 1, 0 },
1017
    { "AndroidPlayback_ExtraDockSpeaker_normal", NULL, 0, 1, 0 },
1018
    { "AndroidPlayback_TvOut_normal",            NULL, 0, 1, 0 },
1019

    
1020
    { "AndroidRecord_Microphone",                NULL, 0, 0, 1 },
1021
    { "AndroidRecord_Earpiece_normal",           NULL, 0, 0, 1 },
1022
    { "AndroidRecord_Speaker_normal",            NULL, 0, 0, 1 },
1023
    { "AndroidRecord_Headset_normal",            NULL, 0, 0, 1 },
1024
    { "AndroidRecord_Bluetooth_normal",          NULL, 0, 0, 1 },
1025
    { "AndroidRecord_Speaker_Headset_normal",    NULL, 0, 0, 1 },
1026

    
1027
    { NULL, NULL, 0, 1, 0 }
1028
};
1029

    
1030
static const HwDevInfo *FindDeviceName( const char *name )
1031
{
1032
    int i;
1033

    
1034
    for( i = 0; predefinedNames[i].alsaName; i++ )
1035
    {
1036
        if( strcmp( name, predefinedNames[i].alsaName ) == 0 )
1037
        {
1038
            return &predefinedNames[i];
1039
        }
1040
    }
1041

    
1042
    return NULL;
1043
}
1044

    
1045
static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi,
1046
        char **dst,
1047
        const char *src)
1048
{
1049
    PaError result = paNoError;
1050
    int len = strlen( src ) + 1;
1051

    
1052
    /* PA_DEBUG(("PaStrDup %s %d\n", src, len)); */
1053

    
1054
    PA_UNLESS( *dst = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
1055
            paInsufficientMemory );
1056
    strncpy( *dst, src, len );
1057

    
1058
error:
1059
    return result;
1060
}
1061

    
1062
/* Disregard some standard plugins
1063
 */
1064
static int IgnorePlugin( const char *pluginId )
1065
{
1066
    static const char *ignoredPlugins[] = {"hw", "plughw", "plug", "dsnoop", "tee",
1067
        "file", "null", "shm", "cards", "rate_convert", NULL};
1068
    int i = 0;
1069
    while( ignoredPlugins[i] )
1070
    {
1071
        if( !strcmp( pluginId, ignoredPlugins[i] ) )
1072
        {
1073
            return 1;
1074
        }
1075
        ++i;
1076
    }
1077

    
1078
    return 0;
1079
}
1080

    
1081
/* Skip past parts at the beginning of a (pcm) info name that are already in the card name, to avoid duplication */
1082
static char *SkipCardDetailsInName( char *infoSkipName, char *cardRefName )
1083
{
1084
    char *lastSpacePosn = infoSkipName;
1085

    
1086
    /* Skip matching chars; but only in chunks separated by ' ' (not part words etc), so track lastSpacePosn */
1087
    while( *cardRefName )
1088
    {
1089
        while( *infoSkipName && *cardRefName && *infoSkipName == *cardRefName)
1090
        {
1091
            infoSkipName++;
1092
            cardRefName++;
1093
            if( *infoSkipName == ' ' || *infoSkipName == '\0' )
1094
                lastSpacePosn = infoSkipName;
1095
        }
1096
        infoSkipName = lastSpacePosn;
1097
        /* Look for another chunk; post-increment means ends pointing to next char */
1098
        while( *cardRefName && ( *cardRefName++ != ' ' ));
1099
    }
1100
    if( *infoSkipName == '\0' )
1101
        return "-"; /* The 2 names were identical; instead of a nul-string, return a marker string */
1102

    
1103
    /* Now want to move to the first char after any spaces */
1104
    while( *lastSpacePosn && *lastSpacePosn == ' ' )
1105
        lastSpacePosn++;
1106
    /* Skip a single separator char if present in the remaining pcm name; (pa will add its own) */
1107
    if(( *lastSpacePosn == '-' || *lastSpacePosn == ':' ) && *(lastSpacePosn + 1) == ' ' )
1108
        lastSpacePosn += 2;
1109

    
1110
    return lastSpacePosn;
1111
}
1112

    
1113
/** Open PCM device.
1114
 *
1115
 * Wrapper around alsa_snd_pcm_open which may repeatedly retry opening a device if it is busy, for
1116
 * a certain time. This is because dmix may temporarily hold on to a device after it (dmix)
1117
 * has been opened and closed.
1118
 * @param mode: Open mode (e.g., SND_PCM_BLOCKING).
1119
 * @param waitOnBusy: Retry opening busy device for up to one second?
1120
 **/
1121
static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode, int waitOnBusy )
1122
{
1123
    int ret, tries = 0, maxTries = waitOnBusy ? busyRetries_ : 0;
1124

    
1125
    ret = alsa_snd_pcm_open( pcmp, name, stream, mode );
1126

    
1127
    for( tries = 0; tries < maxTries && -EBUSY == ret; ++tries )
1128
    {
1129
        Pa_Sleep( 10 );
1130
        ret = alsa_snd_pcm_open( pcmp, name, stream, mode );
1131
        if( -EBUSY != ret )
1132
        {
1133
            PA_DEBUG(( "%s: Successfully opened initially busy device after %d tries\n", __FUNCTION__, tries ));
1134
        }
1135
    }
1136
    if( -EBUSY == ret )
1137
    {
1138
        PA_DEBUG(( "%s: Failed to open busy device '%s'\n", __FUNCTION__, name ));
1139
    }
1140
    else
1141
    {
1142
        if( ret < 0 )
1143
            PA_DEBUG(( "%s: Opened device '%s' ptr[%p] - result: [%d:%s]\n", __FUNCTION__, name, *pcmp, ret, alsa_snd_strerror(ret) ));
1144
    }
1145

    
1146
    return ret;
1147
}
1148

    
1149
static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* deviceHwInfo, int blocking,
1150
        PaAlsaDeviceInfo* devInfo, int* devIdx )
1151
{
1152
    PaError result = 0;
1153
    PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo;
1154
    snd_pcm_t *pcm = NULL;
1155
    PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
1156

    
1157
    PA_DEBUG(( "%s: Filling device info for: %s\n", __FUNCTION__, deviceHwInfo->name ));
1158

    
1159
    /* Zero fields */
1160
    InitializeDeviceInfo( baseDeviceInfo );
1161

    
1162
    /* To determine device capabilities, we must open the device and query the
1163
     * hardware parameter configuration space */
1164

    
1165
    /* Query capture */
1166
    if( deviceHwInfo->hasCapture &&
1167
        OpenPcm( &pcm, deviceHwInfo->alsaName, SND_PCM_STREAM_CAPTURE, blocking, 0 ) >= 0 )
1168
    {
1169
        if( GropeDevice( pcm, deviceHwInfo->isPlug, StreamDirection_In, blocking, devInfo ) != paNoError )
1170
        {
1171
            /* Error */
1172
            PA_DEBUG(( "%s: Failed groping %s for capture\n", __FUNCTION__, deviceHwInfo->alsaName ));
1173
            goto end;
1174
        }
1175
    }
1176

    
1177
    /* Query playback */
1178
    if( deviceHwInfo->hasPlayback &&
1179
        OpenPcm( &pcm, deviceHwInfo->alsaName, SND_PCM_STREAM_PLAYBACK, blocking, 0 ) >= 0 )
1180
    {
1181
        if( GropeDevice( pcm, deviceHwInfo->isPlug, StreamDirection_Out, blocking, devInfo ) != paNoError )
1182
        {
1183
            /* Error */
1184
            PA_DEBUG(( "%s: Failed groping %s for playback\n", __FUNCTION__, deviceHwInfo->alsaName ));
1185
            goto end;
1186
        }
1187
    }
1188

    
1189
    baseDeviceInfo->structVersion = 2;
1190
    baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
1191
    baseDeviceInfo->name = deviceHwInfo->name;
1192
    devInfo->alsaName = deviceHwInfo->alsaName;
1193
    devInfo->isPlug = deviceHwInfo->isPlug;
1194

    
1195
    /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object.
1196
     * Should now be safe to add device info, unless the device supports neither capture nor playback
1197
     */
1198
    if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 )
1199
    {
1200
        /* Make device default if there isn't already one or it is the ALSA "default" device */
1201
        if( ( baseApi->info.defaultInputDevice == paNoDevice ||
1202
            !strcmp( deviceHwInfo->alsaName, "default" ) ) && baseDeviceInfo->maxInputChannels > 0 )
1203
        {
1204
            baseApi->info.defaultInputDevice = *devIdx;
1205
            PA_DEBUG(( "Default input device: %s\n", deviceHwInfo->name ));
1206
        }
1207
        if( ( baseApi->info.defaultOutputDevice == paNoDevice ||
1208
            !strcmp( deviceHwInfo->alsaName, "default" ) ) && baseDeviceInfo->maxOutputChannels > 0 )
1209
        {
1210
            baseApi->info.defaultOutputDevice = *devIdx;
1211
            PA_DEBUG(( "Default output device: %s\n", deviceHwInfo->name ));
1212
        }
1213
        PA_DEBUG(( "%s: Adding device %s: %d\n", __FUNCTION__, deviceHwInfo->name, *devIdx ));
1214
        baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo;
1215
        (*devIdx) += 1;
1216
    }
1217
    else
1218
    {
1219
        PA_DEBUG(( "%s: Skipped device: %s, all channels == 0\n", __FUNCTION__, deviceHwInfo->name ));
1220
    }
1221

    
1222
end:
1223
    return result;
1224
}
1225

    
1226
/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */
1227
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
1228
{
1229
    PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
1230
    PaAlsaDeviceInfo *deviceInfoArray;
1231
    int cardIdx = -1, devIdx = 0;
1232
    snd_ctl_card_info_t *cardInfo;
1233
    PaError result = paNoError;
1234
    size_t numDeviceNames = 0, maxDeviceNames = 1, i;
1235
    HwDevInfo *hwDevInfos = NULL;
1236
    snd_config_t *topNode = NULL;
1237
    snd_pcm_info_t *pcmInfo;
1238
    int res;
1239
    int blocking = SND_PCM_NONBLOCK;
1240
    int usePlughw = 0;
1241
    char *hwPrefix = "";
1242
    char alsaCardName[50];
1243
#ifdef PA_ENABLE_DEBUG_OUTPUT
1244
    PaTime startTime = PaUtil_GetTime();
1245
#endif
1246

    
1247
    if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) )
1248
        blocking = 0;
1249

    
1250
    /* If PA_ALSA_PLUGHW is 1 (non-zero), use the plughw: pcm throughout instead of hw: */
1251
    if( getenv( "PA_ALSA_PLUGHW" ) && atoi( getenv( "PA_ALSA_PLUGHW" ) ) )
1252
    {
1253
        usePlughw = 1;
1254
        hwPrefix = "plug";
1255
        PA_DEBUG(( "%s: Using Plughw\n", __FUNCTION__ ));
1256
    }
1257

    
1258
    /* These two will be set to the first working input and output device, respectively */
1259
    baseApi->info.defaultInputDevice = paNoDevice;
1260
    baseApi->info.defaultOutputDevice = paNoDevice;
1261

    
1262
    /* Gather info about hw devices
1263

1264
     * alsa_snd_card_next() modifies the integer passed to it to be:
1265
     *      the index of the first card if the parameter is -1
1266
     *      the index of the next card if the parameter is the index of a card
1267
     *      -1 if there are no more cards
1268
     *
1269
     * The function itself returns 0 if it succeeded. */
1270
    cardIdx = -1;
1271
    alsa_snd_ctl_card_info_alloca( &cardInfo );
1272
    alsa_snd_pcm_info_alloca( &pcmInfo );
1273
    while( alsa_snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 )
1274
    {
1275
        char *cardName;
1276
        int devIdx = -1;
1277
        snd_ctl_t *ctl;
1278
        char buf[50];
1279

    
1280
        snprintf( alsaCardName, sizeof (alsaCardName), "hw:%d", cardIdx );
1281

    
1282
        /* Acquire name of card */
1283
        if( alsa_snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 )
1284
        {
1285
            /* Unable to open card :( */
1286
            PA_DEBUG(( "%s: Unable to open device %s\n", __FUNCTION__, alsaCardName ));
1287
            continue;
1288
        }
1289
        alsa_snd_ctl_card_info( ctl, cardInfo );
1290

    
1291
        PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, alsa_snd_ctl_card_info_get_name( cardInfo )) );
1292

    
1293
        while( alsa_snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 )
1294
        {
1295
            char *alsaDeviceName, *deviceName, *infoName;
1296
            size_t len;
1297
            int hasPlayback = 0, hasCapture = 0;
1298

    
1299
            snprintf( buf, sizeof (buf), "%s%s,%d", hwPrefix, alsaCardName, devIdx );
1300

    
1301
            /* Obtain info about this particular device */
1302
            alsa_snd_pcm_info_set_device( pcmInfo, devIdx );
1303
            alsa_snd_pcm_info_set_subdevice( pcmInfo, 0 );
1304
            alsa_snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE );
1305
            if( alsa_snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
1306
            {
1307
                hasCapture = 1;
1308
            }
1309

    
1310
            alsa_snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK );
1311
            if( alsa_snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
1312
            {
1313
                hasPlayback = 1;
1314
            }
1315

    
1316
            if( !hasPlayback && !hasCapture )
1317
            {
1318
                /* Error */
1319
                continue;
1320
            }
1321

    
1322
            infoName = SkipCardDetailsInName( (char *)alsa_snd_pcm_info_get_name( pcmInfo ), cardName );
1323

    
1324
            /* The length of the string written by snprintf plus terminating 0 */
1325
            len = snprintf( NULL, 0, "%s: %s (%s)", cardName, infoName, buf ) + 1;
1326
            PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
1327
                    paInsufficientMemory );
1328
            snprintf( deviceName, len, "%s: %s (%s)", cardName, infoName, buf );
1329

    
1330
            ++numDeviceNames;
1331
            if( !hwDevInfos || numDeviceNames > maxDeviceNames )
1332
            {
1333
                maxDeviceNames *= 2;
1334
                PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ),
1335
                        paInsufficientMemory );
1336
            }
1337

    
1338
            PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) );
1339

    
1340
            hwDevInfos[ numDeviceNames - 1 ].alsaName = alsaDeviceName;
1341
            hwDevInfos[ numDeviceNames - 1 ].name = deviceName;
1342
            hwDevInfos[ numDeviceNames - 1 ].isPlug = usePlughw;
1343
            hwDevInfos[ numDeviceNames - 1 ].hasPlayback = hasPlayback;
1344
            hwDevInfos[ numDeviceNames - 1 ].hasCapture = hasCapture;
1345
        }
1346
        alsa_snd_ctl_close( ctl );
1347
    }
1348

    
1349
    /* Iterate over plugin devices */
1350
    if( NULL == (*alsa_snd_config) )
1351
    {
1352
        /* alsa_snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */
1353
        ENSURE_( alsa_snd_config_update(), paUnanticipatedHostError );
1354
        PA_DEBUG(( "Updating snd_config\n" ));
1355
    }
1356
    assert( *alsa_snd_config );
1357
    if( ( res = alsa_snd_config_search( *alsa_snd_config, "pcm", &topNode ) ) >= 0 )
1358
    {
1359
        snd_config_iterator_t i, next;
1360

    
1361
        alsa_snd_config_for_each( i, next, topNode )
1362
        {
1363
            const char *tpStr = "unknown", *idStr = NULL;
1364
            int err = 0;
1365

    
1366
            char *alsaDeviceName, *deviceName;
1367
            const HwDevInfo *predefined = NULL;
1368
            snd_config_t *n = alsa_snd_config_iterator_entry( i ), * tp = NULL;;
1369

    
1370
            if( (err = alsa_snd_config_search( n, "type", &tp )) < 0 )
1371
            {
1372
                if( -ENOENT != err )
1373
                {
1374
                    ENSURE_(err, paUnanticipatedHostError);
1375
                }
1376
            }
1377
            else
1378
            {
1379
                ENSURE_( alsa_snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError );
1380
            }
1381
            ENSURE_( alsa_snd_config_get_id( n, &idStr ), paUnanticipatedHostError );
1382
            if( IgnorePlugin( idStr ) )
1383
            {
1384
                PA_DEBUG(( "%s: Ignoring ALSA plugin device [%s] of type [%s]\n", __FUNCTION__, idStr, tpStr ));
1385
                continue;
1386
            }
1387
            PA_DEBUG(( "%s: Found plugin [%s] of type [%s]\n", __FUNCTION__, idStr, tpStr ));
1388

    
1389
            PA_UNLESS( alsaDeviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
1390
                                                            strlen(idStr) + 6 ), paInsufficientMemory );
1391
            strcpy( alsaDeviceName, idStr );
1392
            PA_UNLESS( deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
1393
                                                            strlen(idStr) + 1 ), paInsufficientMemory );
1394
            strcpy( deviceName, idStr );
1395

    
1396
            ++numDeviceNames;
1397
            if( !hwDevInfos || numDeviceNames > maxDeviceNames )
1398
            {
1399
                maxDeviceNames *= 2;
1400
                PA_UNLESS( hwDevInfos = (HwDevInfo *) realloc( hwDevInfos, maxDeviceNames * sizeof (HwDevInfo) ),
1401
                        paInsufficientMemory );
1402
            }
1403

    
1404
            predefined = FindDeviceName( alsaDeviceName );
1405

    
1406
            hwDevInfos[numDeviceNames - 1].alsaName = alsaDeviceName;
1407
            hwDevInfos[numDeviceNames - 1].name     = deviceName;
1408
            hwDevInfos[numDeviceNames - 1].isPlug   = 1;
1409

    
1410
            if( predefined )
1411
            {
1412
                hwDevInfos[numDeviceNames - 1].hasPlayback = predefined->hasPlayback;
1413
                hwDevInfos[numDeviceNames - 1].hasCapture  = predefined->hasCapture;
1414
            }
1415
            else
1416
            {
1417
                hwDevInfos[numDeviceNames - 1].hasPlayback = 1;
1418
                hwDevInfos[numDeviceNames - 1].hasCapture  = 1;
1419
            }
1420
        }
1421
    }
1422
    else
1423
        PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, alsa_snd_strerror( res ) ));
1424

    
1425
    /* allocate deviceInfo memory based on the number of devices */
1426
    PA_UNLESS( baseApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
1427
            alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory );
1428

    
1429
    /* allocate all device info structs in a contiguous block */
1430
    PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory(
1431
            alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ), paInsufficientMemory );
1432

    
1433
    /* Loop over list of cards, filling in info. If a device is deemed unavailable (can't get name),
1434
     * it's ignored.
1435
     *
1436
     * Note that we do this in two stages. This is a workaround owing to the fact that the 'dmix'
1437
     * plugin may cause the underlying hardware device to be busy for a short while even after it
1438
     * (dmix) is closed. The 'default' plugin may also point to the dmix plugin, so the same goes
1439
     * for this.
1440
     */
1441
    PA_DEBUG(( "%s: Filling device info for %d devices\n", __FUNCTION__, numDeviceNames ));
1442
    for( i = 0, devIdx = 0; i < numDeviceNames; ++i )
1443
    {
1444
        PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
1445
        HwDevInfo* hwInfo = &hwDevInfos[i];
1446
        if( !strcmp( hwInfo->name, "dmix" ) || !strcmp( hwInfo->name, "default" ) )
1447
        {
1448
            continue;
1449
        }
1450

    
1451
        PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) );
1452
    }
1453
    assert( devIdx < numDeviceNames );
1454
    /* Now inspect 'dmix' and 'default' plugins */
1455
    for( i = 0; i < numDeviceNames; ++i )
1456
    {
1457
        PaAlsaDeviceInfo* devInfo = &deviceInfoArray[i];
1458
        HwDevInfo* hwInfo = &hwDevInfos[i];
1459
        if( strcmp( hwInfo->name, "dmix" ) && strcmp( hwInfo->name, "default" ) )
1460
        {
1461
            continue;
1462
        }
1463

    
1464
        PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) );
1465
    }
1466
    free( hwDevInfos );
1467

    
1468
    baseApi->info.deviceCount = devIdx;   /* Number of successfully queried devices */
1469

    
1470
#ifdef PA_ENABLE_DEBUG_OUTPUT
1471
    PA_DEBUG(( "%s: Building device list took %f seconds\n", __FUNCTION__, PaUtil_GetTime() - startTime ));
1472
#endif
1473

    
1474
end:
1475
    return result;
1476

    
1477
error:
1478
    /* No particular action */
1479
    goto end;
1480
}
1481

    
1482
/* Check against known device capabilities */
1483
static PaError ValidateParameters( const PaStreamParameters *parameters, PaUtilHostApiRepresentation *hostApi, StreamDirection mode )
1484
{
1485
    PaError result = paNoError;
1486
    int maxChans;
1487
    const PaAlsaDeviceInfo *deviceInfo = NULL;
1488
    assert( parameters );
1489

    
1490
    if( parameters->device != paUseHostApiSpecificDeviceSpecification )
1491
    {
1492
        assert( parameters->device < hostApi->info.deviceCount );
1493
        PA_UNLESS( parameters->hostApiSpecificStreamInfo == NULL, paBadIODeviceCombination );
1494
        deviceInfo = GetDeviceInfo( hostApi, parameters->device );
1495
    }
1496
    else
1497
    {
1498
        const PaAlsaStreamInfo *streamInfo = parameters->hostApiSpecificStreamInfo;
1499

    
1500
        PA_UNLESS( parameters->device == paUseHostApiSpecificDeviceSpecification, paInvalidDevice );
1501
        PA_UNLESS( streamInfo->size == sizeof (PaAlsaStreamInfo) && streamInfo->version == 1,
1502
                paIncompatibleHostApiSpecificStreamInfo );
1503
        PA_UNLESS( streamInfo->deviceString != NULL, paInvalidDevice );
1504

    
1505
        /* Skip further checking */
1506
        return paNoError;
1507
    }
1508

    
1509
    assert( deviceInfo );
1510
    assert( parameters->hostApiSpecificStreamInfo == NULL );
1511
    maxChans = ( StreamDirection_In == mode ? deviceInfo->baseDeviceInfo.maxInputChannels :
1512
        deviceInfo->baseDeviceInfo.maxOutputChannels );
1513
    PA_UNLESS( parameters->channelCount <= maxChans, paInvalidChannelCount );
1514

    
1515
error:
1516
    return result;
1517
}
1518

    
1519
/* Given an open stream, what sample formats are available? */
1520
static PaSampleFormat GetAvailableFormats( snd_pcm_t *pcm )
1521
{
1522
    PaSampleFormat available = 0;
1523
    snd_pcm_hw_params_t *hwParams;
1524
    alsa_snd_pcm_hw_params_alloca( &hwParams );
1525

    
1526
    alsa_snd_pcm_hw_params_any( pcm, hwParams );
1527

    
1528
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0)
1529
        available |= paFloat32;
1530

    
1531
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0)
1532
        available |= paInt32;
1533

    
1534
#ifdef PA_LITTLE_ENDIAN
1535
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0)
1536
        available |= paInt24;
1537
#elif defined PA_BIG_ENDIAN
1538
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0)
1539
        available |= paInt24;
1540
#endif
1541

    
1542
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0)
1543
        available |= paInt16;
1544

    
1545
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0)
1546
        available |= paUInt8;
1547

    
1548
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0)
1549
        available |= paInt8;
1550

    
1551
    return available;
1552
}
1553

    
1554
/* Output to console all formats supported by device */
1555
static void LogAllAvailableFormats( snd_pcm_t *pcm )
1556
{
1557
    PaSampleFormat available = 0;
1558
    snd_pcm_hw_params_t *hwParams;
1559
    alsa_snd_pcm_hw_params_alloca( &hwParams );
1560

    
1561
    alsa_snd_pcm_hw_params_any( pcm, hwParams );
1562

    
1563
    PA_DEBUG(( " --- Supported Formats ---\n" ));
1564

    
1565
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0)
1566
        PA_DEBUG(( "SND_PCM_FORMAT_S8\n" ));
1567
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0)
1568
        PA_DEBUG(( "SND_PCM_FORMAT_U8\n" ));
1569

    
1570
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16_LE ) >= 0)
1571
        PA_DEBUG(( "SND_PCM_FORMAT_S16_LE\n" ));
1572
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16_BE ) >= 0)
1573
        PA_DEBUG(( "SND_PCM_FORMAT_S16_BE\n" ));
1574

    
1575
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16_LE ) >= 0)
1576
        PA_DEBUG(( "SND_PCM_FORMAT_U16_LE\n" ));
1577
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16_BE ) >= 0)
1578
        PA_DEBUG(( "SND_PCM_FORMAT_U16_BE\n" ));
1579

    
1580
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_LE ) >= 0)
1581
        PA_DEBUG(( "SND_PCM_FORMAT_S24_LE\n" ));
1582
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_BE ) >= 0)
1583
        PA_DEBUG(( "SND_PCM_FORMAT_S24_BE\n" ));
1584

    
1585
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_LE ) >= 0)
1586
        PA_DEBUG(( "SND_PCM_FORMAT_U24_LE\n" ));
1587
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_BE ) >= 0)
1588
        PA_DEBUG(( "SND_PCM_FORMAT_U24_BE\n" ));
1589

    
1590
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT_LE ) >= 0)
1591
        PA_DEBUG(( "SND_PCM_FORMAT_FLOAT_LE\n" ));
1592
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT_BE ) >= 0)
1593
        PA_DEBUG(( "SND_PCM_FORMAT_FLOAT_BE\n" ));
1594

    
1595
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64_LE ) >= 0)
1596
        PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64_LE\n" ));
1597
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64_BE ) >= 0)
1598
        PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64_BE\n" ));
1599

    
1600
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME_LE ) >= 0)
1601
        PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME_LE\n" ));
1602
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME_BE ) >= 0)
1603
        PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME_BE\n" ));
1604

    
1605
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_MU_LAW ) >= 0)
1606
        PA_DEBUG(( "SND_PCM_FORMAT_MU_LAW\n" ));
1607
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_A_LAW ) >= 0)
1608
        PA_DEBUG(( "SND_PCM_FORMAT_A_LAW\n" ));
1609

    
1610
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IMA_ADPCM ) >= 0)
1611
        PA_DEBUG(( "SND_PCM_FORMAT_IMA_ADPCM\n" ));
1612
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_MPEG ) >= 0)
1613
        PA_DEBUG(( "SND_PCM_FORMAT_MPEG\n" ));
1614

    
1615
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_GSM ) >= 0)
1616
        PA_DEBUG(( "SND_PCM_FORMAT_GSM\n" ));
1617
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_SPECIAL ) >= 0)
1618
        PA_DEBUG(( "SND_PCM_FORMAT_SPECIAL\n" ));
1619

    
1620
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3LE ) >= 0)
1621
        PA_DEBUG(( "SND_PCM_FORMAT_S24_3LE\n" ));
1622
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24_3BE ) >= 0)
1623
        PA_DEBUG(( "SND_PCM_FORMAT_S24_3BE\n" ));
1624

    
1625
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_3LE ) >= 0)
1626
        PA_DEBUG(( "SND_PCM_FORMAT_U24_3LE\n" ));
1627
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24_3BE ) >= 0)
1628
        PA_DEBUG(( "SND_PCM_FORMAT_U24_3BE\n" ));
1629

    
1630
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S20_3LE ) >= 0)
1631
        PA_DEBUG(( "SND_PCM_FORMAT_S20_3LE\n" ));
1632
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S20_3BE ) >= 0)
1633
        PA_DEBUG(( "SND_PCM_FORMAT_S20_3BE\n" ));
1634

    
1635
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U20_3LE ) >= 0)
1636
        PA_DEBUG(( "SND_PCM_FORMAT_U20_3LE\n" ));
1637
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U20_3BE ) >= 0)
1638
        PA_DEBUG(( "SND_PCM_FORMAT_U20_3BE\n" ));
1639

    
1640
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S18_3LE ) >= 0)
1641
        PA_DEBUG(( "SND_PCM_FORMAT_S18_3LE\n" ));
1642
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S18_3BE ) >= 0)
1643
        PA_DEBUG(( "SND_PCM_FORMAT_S18_3BE\n" ));
1644

    
1645
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U18_3LE ) >= 0)
1646
        PA_DEBUG(( "SND_PCM_FORMAT_U18_3LE\n" ));
1647
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U18_3BE ) >= 0)
1648
        PA_DEBUG(( "SND_PCM_FORMAT_U18_3BE\n" ));
1649

    
1650
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0)
1651
        PA_DEBUG(( "SND_PCM_FORMAT_S16\n" ));
1652
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U16 ) >= 0)
1653
        PA_DEBUG(( "SND_PCM_FORMAT_U16\n" ));
1654

    
1655
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24 ) >= 0)
1656
        PA_DEBUG(( "SND_PCM_FORMAT_S24\n" ));
1657
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U24 ) >= 0)
1658
        PA_DEBUG(( "SND_PCM_FORMAT_U24\n" ));
1659

    
1660
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0)
1661
        PA_DEBUG(( "SND_PCM_FORMAT_S32\n" ));
1662
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U32 ) >= 0)
1663
        PA_DEBUG(( "SND_PCM_FORMAT_U32\n" ));
1664

    
1665
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0)
1666
        PA_DEBUG(( "SND_PCM_FORMAT_FLOAT\n" ));
1667
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT64 ) >= 0)
1668
        PA_DEBUG(( "SND_PCM_FORMAT_FLOAT64\n" ));
1669

    
1670
    if( alsa_snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_IEC958_SUBFRAME ) >= 0)
1671
        PA_DEBUG(( "SND_PCM_FORMAT_IEC958_SUBFRAME\n" ));
1672

    
1673
    PA_DEBUG(( " -------------------------\n" ));
1674
}
1675

    
1676
static snd_pcm_format_t Pa2AlsaFormat( PaSampleFormat paFormat )
1677
{
1678
    switch( paFormat )
1679
    {
1680
        case paFloat32:
1681
            return SND_PCM_FORMAT_FLOAT;
1682

    
1683
        case paInt16:
1684
            return SND_PCM_FORMAT_S16;
1685

    
1686
        case paInt24:
1687
#ifdef PA_LITTLE_ENDIAN
1688
            return SND_PCM_FORMAT_S24_3LE;
1689
#elif defined PA_BIG_ENDIAN
1690
            return SND_PCM_FORMAT_S24_3BE;
1691
#endif
1692

    
1693
        case paInt32:
1694
            return SND_PCM_FORMAT_S32;
1695

    
1696
        case paInt8:
1697
            return SND_PCM_FORMAT_S8;
1698

    
1699
        case paUInt8:
1700
            return SND_PCM_FORMAT_U8;
1701

    
1702
        default:
1703
            return SND_PCM_FORMAT_UNKNOWN;
1704
    }
1705
}
1706

    
1707
/** Open an ALSA pcm handle.
1708
 *
1709
 * The device to be open can be specified by name in a custom PaAlsaStreamInfo struct, or it will be by
1710
 * the Portaudio device number supplied in the stream parameters.
1711
 */
1712
static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *params, StreamDirection
1713
        streamDir, snd_pcm_t **pcm )
1714
{
1715
    PaError result = paNoError;
1716
    int ret;
1717
    const char* deviceName = "";
1718
    const PaAlsaDeviceInfo *deviceInfo = NULL;
1719
    PaAlsaStreamInfo *streamInfo = (PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo;
1720

    
1721
    if( !streamInfo )
1722
    {
1723
        deviceInfo = GetDeviceInfo( hostApi, params->device );
1724
        deviceName = deviceInfo->alsaName;
1725
    }
1726
    else
1727
        deviceName = streamInfo->deviceString;
1728

    
1729
    PA_DEBUG(( "%s: Opening device %s\n", __FUNCTION__, deviceName ));
1730
    if( (ret = OpenPcm( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
1731
                    SND_PCM_NONBLOCK, 1 )) < 0 )
1732
    {
1733
        /* Not to be closed */
1734
        *pcm = NULL;
1735
        ENSURE_( ret, -EBUSY == ret ? paDeviceUnavailable : paBadIODeviceCombination );
1736
    }
1737
    ENSURE_( alsa_snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError );
1738

    
1739
end:
1740
    return result;
1741

    
1742
error:
1743
    goto end;
1744
}
1745

    
1746
static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters,
1747
        double sampleRate, StreamDirection streamDir )
1748
{
1749
    PaError result = paNoError;
1750
    snd_pcm_t *pcm = NULL;
1751
    PaSampleFormat availableFormats;
1752
    /* We are able to adapt to a number of channels less than what the device supports */
1753
    unsigned int numHostChannels;
1754
    PaSampleFormat hostFormat;
1755
    snd_pcm_hw_params_t *hwParams;
1756
    alsa_snd_pcm_hw_params_alloca( &hwParams );
1757

    
1758
    if( !parameters->hostApiSpecificStreamInfo )
1759
    {
1760
        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, parameters->device );
1761
        numHostChannels = PA_MAX( parameters->channelCount, StreamDirection_In == streamDir ?
1762
                devInfo->minInputChannels : devInfo->minOutputChannels );
1763
    }
1764
    else
1765
        numHostChannels = parameters->channelCount;
1766

    
1767
    PA_ENSURE( AlsaOpen( hostApi, parameters, streamDir, &pcm ) );
1768

    
1769
    alsa_snd_pcm_hw_params_any( pcm, hwParams );
1770

    
1771
    if( SetApproximateSampleRate( pcm, hwParams, sampleRate ) < 0 )
1772
    {
1773
        result = paInvalidSampleRate;
1774
        goto error;
1775
    }
1776

    
1777
    if( alsa_snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 )
1778
    {
1779
        result = paInvalidChannelCount;
1780
        goto error;
1781
    }
1782

    
1783
    /* See if we can find a best possible match */
1784
    availableFormats = GetAvailableFormats( pcm );
1785
    PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) );
1786

    
1787
    /* Some specific hardware (reported: Audio8 DJ) can fail with assertion during this step. */
1788
    ENSURE_( alsa_snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError );
1789

    
1790
    {
1791
        /* It happens that this call fails because the device is busy */
1792
        int ret = 0;
1793
        if( ( ret = alsa_snd_pcm_hw_params( pcm, hwParams ) ) < 0 )
1794
        {
1795
            if( -EINVAL == ret )
1796
            {
1797
                /* Don't know what to return here */
1798
                result = paBadIODeviceCombination;
1799
                goto error;
1800
            }
1801
            else if( -EBUSY == ret )
1802
            {
1803
                result = paDeviceUnavailable;
1804
                PA_DEBUG(( "%s: Device is busy\n", __FUNCTION__ ));
1805
            }
1806
            else
1807
            {
1808
                result = paUnanticipatedHostError;
1809
            }
1810

    
1811
            ENSURE_( ret, result );
1812
        }
1813
    }
1814

    
1815
end:
1816
    if( pcm )
1817
    {
1818
        alsa_snd_pcm_close( pcm );
1819
    }
1820
    return result;
1821

    
1822
error:
1823
    goto end;
1824
}
1825

    
1826
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
1827
                                  const PaStreamParameters *inputParameters,
1828
                                  const PaStreamParameters *outputParameters,
1829
                                  double sampleRate )
1830
{
1831
    int inputChannelCount = 0, outputChannelCount = 0;
1832
    PaSampleFormat inputSampleFormat, outputSampleFormat;
1833
    PaError result = paFormatIsSupported;
1834

    
1835
    if( inputParameters )
1836
    {
1837
        PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );
1838

    
1839
        inputChannelCount = inputParameters->channelCount;
1840
        inputSampleFormat = inputParameters->sampleFormat;
1841
    }
1842

    
1843
    if( outputParameters )
1844
    {
1845
        PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );
1846

    
1847
        outputChannelCount = outputParameters->channelCount;
1848
        outputSampleFormat = outputParameters->sampleFormat;
1849
    }
1850

    
1851
    if( inputChannelCount )
1852
    {
1853
        if( ( result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In ) )
1854
                != paNoError )
1855
            goto error;
1856
    }
1857
    if ( outputChannelCount )
1858
    {
1859
        if( ( result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out ) )
1860
                != paNoError )
1861
            goto error;
1862
    }
1863

    
1864
    return paFormatIsSupported;
1865

    
1866
error:
1867
    return result;
1868
}
1869

    
1870

    
1871
static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, PaAlsaHostApiRepresentation *alsaApi,
1872
        const PaStreamParameters *params, StreamDirection streamDir, int callbackMode )
1873
{
1874
    PaError result = paNoError;
1875
    PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat = paNoError;
1876
    assert( params->channelCount > 0 );
1877

    
1878
    /* Make sure things have an initial value */
1879
    memset( self, 0, sizeof (PaAlsaStreamComponent) );
1880

    
1881
    if( NULL == params->hostApiSpecificStreamInfo )
1882
    {
1883
        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->baseHostApiRep, params->device );
1884
        self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels
1885
                : devInfo->minOutputChannels );
1886
        self->deviceIsPlug = devInfo->isPlug;
1887
        PA_DEBUG(( "%s: Host Chans %c %i\n", __FUNCTION__, streamDir == StreamDirection_In ? 'C' : 'P', self->numHostChannels ));
1888
    }
1889
    else
1890
    {
1891
        /* We're blissfully unaware of the minimum channelCount */
1892
        self->numHostChannels = params->channelCount;
1893
        /* Check if device name does not start with hw: to determine if it is a 'plug' device */
1894
        if( strncmp( "hw:", ((PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo)->deviceString, 3 ) != 0  )
1895
            self->deviceIsPlug = 1; /* An Alsa plug device, not a direct hw device */
1896
    }
1897
    if( self->deviceIsPlug && alsaApi->alsaLibVersion < ALSA_VERSION_INT( 1, 0, 16 ) )
1898
        self->useReventFix = 1; /* Prior to Alsa1.0.16, plug devices may stutter without this fix */
1899

    
1900
    self->device = params->device;
1901

    
1902
    PA_ENSURE( AlsaOpen( &alsaApi->baseHostApiRep, params, streamDir, &self->pcm ) );
1903
    self->nfds = alsa_snd_pcm_poll_descriptors_count( self->pcm );
1904

    
1905
    PA_ENSURE( hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat ) );
1906

    
1907
    self->hostSampleFormat = hostSampleFormat;
1908
    self->nativeFormat = Pa2AlsaFormat( hostSampleFormat );
1909
    self->hostInterleaved = self->userInterleaved = !( userSampleFormat & paNonInterleaved );
1910
    self->numUserChannels = params->channelCount;
1911
    self->streamDir = streamDir;
1912
    self->canMmap = 0;
1913
    self->nonMmapBuffer = NULL;
1914
    self->nonMmapBufferSize = 0;
1915

    
1916
    if( !callbackMode && !self->userInterleaved )
1917
    {
1918
        /* Pre-allocate non-interleaved user provided buffers */
1919
        PA_UNLESS( self->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * self->numUserChannels ),
1920
                paInsufficientMemory );
1921
    }
1922

    
1923
error:
1924

    
1925
    /* Log all available formats. */
1926
    if ( hostSampleFormat == paSampleFormatNotSupported )
1927
    {
1928
        LogAllAvailableFormats( self->pcm );
1929
        PA_DEBUG(( "%s: Please provide the log output to PortAudio developers, your hardware does not have any sample format implemented yet.\n", __FUNCTION__ ));
1930
    }
1931

    
1932
    return result;
1933
}
1934

    
1935
static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self )
1936
{
1937
    alsa_snd_pcm_close( self->pcm );
1938
    PaUtil_FreeMemory( self->userBuffers ); /* (Ptr can be NULL; PaUtil_FreeMemory includes a NULL check) */
1939
    PaUtil_FreeMemory( self->nonMmapBuffer );
1940
}
1941

    
1942
/*
1943
static int nearbyint_(float value) {
1944
    if(  value - (int)value > .5 )
1945
        return (int)ceil( value );
1946
    return (int)floor( value );
1947
}
1948
*/
1949

    
1950
/** Initiate configuration, preparing for determining a period size suitable for both capture and playback components.
1951
 *
1952
 */
1953
static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *self, const PaStreamParameters *params,
1954
        int primeBuffers, snd_pcm_hw_params_t *hwParams, double *sampleRate )
1955
{
1956
    /* Configuration consists of setting all of ALSA's parameters.
1957
     * These parameters come in two flavors: hardware parameters
1958
     * and software paramters.  Hardware parameters will affect
1959
     * the way the device is initialized, software parameters
1960
     * affect the way ALSA interacts with me, the user-level client.
1961
     */
1962

    
1963
    PaError result = paNoError;
1964
    snd_pcm_access_t accessMode, alternateAccessMode;
1965
    int dir = 0;
1966
    snd_pcm_t *pcm = self->pcm;
1967
    double sr = *sampleRate;
1968
    unsigned int minPeriods = 2;
1969

    
1970
    /* self->framesPerPeriod = framesPerHostBuffer; */
1971

    
1972
    /* ... fill up the configuration space with all possibile
1973
     * combinations of parameters this device will accept */
1974
    ENSURE_( alsa_snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
1975

    
1976
    ENSURE_( alsa_snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );
1977
    /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */
1978
    dir = 0;
1979
    ENSURE_( alsa_snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError );
1980

    
1981
    if( self->userInterleaved )
1982
    {
1983
        accessMode          = SND_PCM_ACCESS_MMAP_INTERLEAVED;
1984
        alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
1985

    
1986
        /* test if MMAP supported */
1987
        self->canMmap = alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ||
1988
                        alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0;
1989

    
1990
        PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO" ) ));
1991
        PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO" ) ));
1992

    
1993
        if( !self->canMmap )
1994
        {
1995
            accessMode          = SND_PCM_ACCESS_RW_INTERLEAVED;
1996
            alternateAccessMode = SND_PCM_ACCESS_RW_NONINTERLEAVED;
1997
        }
1998
    }
1999
    else
2000
    {
2001
        accessMode          = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
2002
        alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
2003

    
2004
        /* test if MMAP supported */
2005
        self->canMmap = alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ||
2006
                        alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0;
2007

    
2008
        PA_DEBUG((" %s: device MMAP SND_PCM_ACCESS_MMAP_NONINTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, accessMode ) >= 0 ? "YES" : "NO" ) ));
2009
        PA_DEBUG(( "%s: device MMAP SND_PCM_ACCESS_MMAP_INTERLEAVED: %s\n", __FUNCTION__, ( alsa_snd_pcm_hw_params_test_access( pcm, hwParams, alternateAccessMode ) >= 0 ? "YES" : "NO" ) ));
2010

    
2011
        if( !self->canMmap )
2012
        {
2013
            accessMode          = SND_PCM_ACCESS_RW_NONINTERLEAVED;
2014
            alternateAccessMode = SND_PCM_ACCESS_RW_INTERLEAVED;
2015
        }
2016
    }
2017

    
2018
    PA_DEBUG(( "%s: device can MMAP: %s\n", __FUNCTION__, ( self->canMmap ? "YES" : "NO" ) ));
2019

    
2020
    /* If requested access mode fails, try alternate mode */
2021
    if( alsa_snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )
2022
    {
2023
        int err = 0;
2024
        if( ( err = alsa_snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0 )
2025
        {
2026
            result = paUnanticipatedHostError;
2027
            PaUtil_SetLastHostErrorInfo( paALSA, err, alsa_snd_strerror( err ) );
2028
            goto error;
2029
        }
2030
        /* Flip mode */
2031
        self->hostInterleaved = !self->userInterleaved;
2032
    }
2033

    
2034
    /* Some specific hardware (reported: Audio8 DJ) can fail with assertion during this step. */
2035
    ENSURE_( alsa_snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );
2036

    
2037
    if( ( result = SetApproximateSampleRate( pcm, hwParams, sr )) != paUnanticipatedHostError )
2038
    {
2039
        ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError );
2040
        if( result == paInvalidSampleRate ) /* From the SetApproximateSampleRate() call above */
2041
        { /* The sample rate was returned as 'out of tolerance' of the one requested */
2042
            PA_DEBUG(( "%s: Wanted %.3f, closest sample rate was %.3f\n", __FUNCTION__, sampleRate, sr ));
2043
            PA_ENSURE( paInvalidSampleRate );
2044
        }
2045
    }
2046
    else
2047
    {
2048
       PA_ENSURE( paUnanticipatedHostError );
2049
    }
2050

    
2051
    ENSURE_( alsa_snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount );
2052

    
2053
    *sampleRate = sr;
2054

    
2055
end:
2056
    return result;
2057

    
2058
error:
2059
    /* No particular action */
2060
    goto end;
2061
}
2062

    
2063
/** Finish the configuration of the component's ALSA device.
2064
 *
2065
 * As part of this method, the component's alsaBufferSize attribute will be set.
2066
 * @param latency: The latency for this component.
2067
 */
2068
static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *self, snd_pcm_hw_params_t* hwParams,
2069
        const PaStreamParameters *params, int primeBuffers, double sampleRate, PaTime* latency )
2070
{
2071
    PaError result = paNoError;
2072
    snd_pcm_sw_params_t* swParams;
2073
    snd_pcm_uframes_t bufSz = 0;
2074
    *latency = -1.;
2075

    
2076
    alsa_snd_pcm_sw_params_alloca( &swParams );
2077

    
2078
    bufSz = params->suggestedLatency * sampleRate + self->framesPerPeriod;
2079
    ENSURE_( alsa_snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError );
2080

    
2081
    /* Set the parameters! */
2082
    {
2083
        int r = alsa_snd_pcm_hw_params( self->pcm, hwParams );
2084
#ifdef PA_ENABLE_DEBUG_OUTPUT
2085
        if( r < 0 )
2086
        {
2087
            snd_output_t *output = NULL;
2088
            alsa_snd_output_stdio_attach( &output, stderr, 0 );
2089
            alsa_snd_pcm_hw_params_dump( hwParams, output );
2090
        }
2091
#endif
2092
        ENSURE_( r, paUnanticipatedHostError );
2093
    }
2094
    if( alsa_snd_pcm_hw_params_get_buffer_size != NULL )
2095
    {
2096
        ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size( hwParams, &self->alsaBufferSize ), paUnanticipatedHostError );
2097
    }
2098
    else
2099
    {
2100
        self->alsaBufferSize = bufSz;
2101
    }
2102

    
2103
    /* Latency in seconds */
2104
    *latency = (self->alsaBufferSize - self->framesPerPeriod) / sampleRate;
2105

    
2106
    /* Now software parameters... */
2107
    ENSURE_( alsa_snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError );
2108

    
2109
    ENSURE_( alsa_snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerPeriod ), paUnanticipatedHostError );
2110
    ENSURE_( alsa_snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->alsaBufferSize ), paUnanticipatedHostError );
2111

    
2112
    /* Silence buffer in the case of underrun */
2113
    if( !primeBuffers ) /* XXX: Make sense? */
2114
    {
2115
        snd_pcm_uframes_t boundary;
2116
        ENSURE_( alsa_snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError );
2117
        ENSURE_( alsa_snd_pcm_sw_params_set_silence_threshold( self->pcm, swParams, 0 ), paUnanticipatedHostError );
2118
        ENSURE_( alsa_snd_pcm_sw_params_set_silence_size( self->pcm, swParams, boundary ), paUnanticipatedHostError );
2119
    }
2120

    
2121
    ENSURE_( alsa_snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerPeriod ), paUnanticipatedHostError );
2122
    ENSURE_( alsa_snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError );
2123
    ENSURE_( alsa_snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError );
2124

    
2125
    /* Set the parameters! */
2126
    ENSURE_( alsa_snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError );
2127

    
2128
error:
2129
    return result;
2130
}
2131

    
2132
static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *inParams,
2133
        const PaStreamParameters *outParams, double sampleRate, unsigned long framesPerUserBuffer, PaStreamCallback callback,
2134
        PaStreamFlags streamFlags, void *userData )
2135
{
2136
    PaError result = paNoError;
2137
    assert( self );
2138

    
2139
    memset( self, 0, sizeof( PaAlsaStream ) );
2140

    
2141
    if( NULL != callback )
2142
    {
2143
        PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,
2144
                                               &alsaApi->callbackStreamInterface,
2145
                                               callback, userData );
2146
        self->callbackMode = 1;
2147
    }
2148
    else
2149
    {
2150
        PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,
2151
                                               &alsaApi->blockingStreamInterface,
2152
                                               NULL, userData );
2153
    }
2154

    
2155
    self->framesPerUserBuffer = framesPerUserBuffer;
2156
    self->neverDropInput = streamFlags & paNeverDropInput;
2157
    /* XXX: Ignore paPrimeOutputBuffersUsingStreamCallback untill buffer priming is fully supported in pa_process.c */
2158
    /*
2159
    if( outParams & streamFlags & paPrimeOutputBuffersUsingStreamCallback )
2160
        self->primeBuffers = 1;
2161
        */
2162
    memset( &self->capture, 0, sizeof (PaAlsaStreamComponent) );
2163
    memset( &self->playback, 0, sizeof (PaAlsaStreamComponent) );
2164
    if( inParams )
2165
    {
2166
        PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->capture, alsaApi, inParams, StreamDirection_In, NULL != callback ) );
2167
    }
2168
    if( outParams )
2169
    {
2170
        PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->playback, alsaApi, outParams, StreamDirection_Out, NULL != callback ) );
2171
    }
2172

    
2173
    assert( self->capture.nfds || self->playback.nfds );
2174

    
2175
    PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( ( self->capture.nfds +
2176
                    self->playback.nfds ) * sizeof( struct pollfd ) ), paInsufficientMemory );
2177

    
2178
    PaUtil_InitializeCpuLoadMeasurer( &self->cpuLoadMeasurer, sampleRate );
2179
    ASSERT_CALL_( PaUnixMutex_Initialize( &self->stateMtx ), paNoError );
2180

    
2181
error:
2182
    return result;
2183
}
2184

    
2185
/** Free resources associated with stream, and eventually stream itself.
2186
 *
2187
 * Frees allocated memory, and terminates individual StreamComponents.
2188
 */
2189
static void PaAlsaStream_Terminate( PaAlsaStream *self )
2190
{
2191
    assert( self );
2192

    
2193
    if( self->capture.pcm )
2194
    {
2195
        PaAlsaStreamComponent_Terminate( &self->capture );
2196
    }
2197
    if( self->playback.pcm )
2198
    {
2199
        PaAlsaStreamComponent_Terminate( &self->playback );
2200
    }
2201

    
2202
    PaUtil_FreeMemory( self->pfds );
2203
    ASSERT_CALL_( PaUnixMutex_Terminate( &self->stateMtx ), paNoError );
2204

    
2205
    PaUtil_FreeMemory( self );
2206
}
2207

    
2208
/** Calculate polling timeout
2209
 *
2210
 * @param frames Time to wait
2211
 * @return Polling timeout in milliseconds
2212
 */
2213
static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frames )
2214
{
2215
    assert( stream->streamRepresentation.streamInfo.sampleRate > 0.0 );
2216
    /* Period in msecs, rounded up */
2217
    return (int)ceil( 1000 * frames / stream->streamRepresentation.streamInfo.sampleRate );
2218
}
2219

    
2220
/** Align value in backward direction.
2221
 *
2222
 * @param v: Value to align.
2223
 * @param align: Alignment.
2224
 */
2225
static unsigned long PaAlsa_AlignBackward(unsigned long v, unsigned long align)
2226
{
2227
    return ( v - ( align ? v % align : 0 ) );
2228
}
2229

    
2230
/** Align value in forward direction.
2231
 *
2232
 * @param v: Value to align.
2233
 * @param align: Alignment.
2234
 */
2235
static unsigned long PaAlsa_AlignForward(unsigned long v, unsigned long align)
2236
{
2237
    unsigned long remainder = ( align ? ( v % align ) : 0);
2238
    return ( remainder != 0 ? v + ( align - remainder ) : v );
2239
}
2240

    
2241
/** Get size of host buffer maintained from the number of user frames, sample rate and suggested latency. Minimum double buffering
2242
 *  is maintained to allow 100% CPU usage inside user callback.
2243
 *
2244
 * @param userFramesPerBuffer: User buffer size in number of frames.
2245
 * @param suggestedLatency: User provided desired latency.
2246
 * @param sampleRate: Sample rate.
2247
 */
2248
static unsigned long PaAlsa_GetFramesPerHostBuffer(unsigned long userFramesPerBuffer, PaTime suggestedLatency, double sampleRate)
2249
{
2250
    unsigned long frames = userFramesPerBuffer + PA_MAX( userFramesPerBuffer, (unsigned long)( suggestedLatency * sampleRate ) );
2251
    return frames;
2252
}
2253

    
2254
/** Determine size per host buffer.
2255
 *
2256
 * During this method call, the component's framesPerPeriod attribute gets computed, and the corresponding period size
2257
 * gets configured for the device.
2258
 * @param accurate: If the configured period size is non-integer, this will be set to 0.
2259
 */
2260
static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamComponent* self, const PaStreamParameters* params,
2261
        unsigned long framesPerUserBuffer, double sampleRate, snd_pcm_hw_params_t* hwParams, int* accurate )
2262
{
2263
    PaError result = paNoError;
2264
    unsigned long bufferSize, framesPerHostBuffer;
2265
    int dir = 0;
2266

    
2267
    /* Calculate host buffer size */
2268
    bufferSize = PaAlsa_GetFramesPerHostBuffer(framesPerUserBuffer, params->suggestedLatency, sampleRate);
2269

    
2270
    /* Log */
2271
    PA_DEBUG(( "%s: user-buffer (frames)           = %lu\n", __FUNCTION__, framesPerUserBuffer ));
2272
    PA_DEBUG(( "%s: user-buffer (sec)              = %f\n",  __FUNCTION__, (double)(framesPerUserBuffer / sampleRate) ));
2273
    PA_DEBUG(( "%s: suggested latency (sec)        = %f\n",  __FUNCTION__, params->suggestedLatency ));
2274
    PA_DEBUG(( "%s: suggested host buffer (frames) = %lu\n", __FUNCTION__, bufferSize ));
2275
    PA_DEBUG(( "%s: suggested host buffer (sec)    = %f\n",  __FUNCTION__, (double)(bufferSize / sampleRate) ));
2276

    
2277
#ifdef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC
2278

    
2279
    if( framesPerUserBuffer != paFramesPerBufferUnspecified )
2280
    {
2281
        /* Preferably the host buffer size should be a multiple of the user buffer size */
2282

    
2283
        if( bufferSize > framesPerUserBuffer )
2284
        {
2285
            snd_pcm_uframes_t remainder = bufferSize % framesPerUserBuffer;
2286
            if( remainder > framesPerUserBuffer / 2. )
2287
                bufferSize += framesPerUserBuffer - remainder;
2288
            else
2289
                bufferSize -= remainder;
2290

    
2291
            assert( bufferSize % framesPerUserBuffer == 0 );
2292
        }
2293
        else if( framesPerUserBuffer % bufferSize != 0 )
2294
        {
2295
            /*  Find a good compromise between user specified latency and buffer size */
2296
            if( bufferSize > framesPerUserBuffer * .75 )
2297
            {
2298
                bufferSize = framesPerUserBuffer;
2299
            }
2300
            else
2301
            {
2302
                snd_pcm_uframes_t newSz = framesPerUserBuffer;
2303
                while( newSz / 2 >= bufferSize )
2304
                {
2305
                    if( framesPerUserBuffer % (newSz / 2) != 0 )
2306
                    {
2307
                        /* No use dividing any further */
2308
                        break;
2309
                    }
2310
                    newSz /= 2;
2311
                }
2312
                bufferSize = newSz;
2313
            }
2314

    
2315
            assert( framesPerUserBuffer % bufferSize == 0 );
2316
        }
2317
    }
2318

    
2319
#endif
2320

    
2321
    {
2322
        unsigned numPeriods = numPeriods_, maxPeriods = 0, minPeriods = numPeriods_;
2323

    
2324
        /* It may be that the device only supports 2 periods for instance */
2325
        dir = 0;
2326
        ENSURE_( alsa_snd_pcm_hw_params_get_periods_min( hwParams, &minPeriods, &dir ), paUnanticipatedHostError );
2327
        ENSURE_( alsa_snd_pcm_hw_params_get_periods_max( hwParams, &maxPeriods, &dir ), paUnanticipatedHostError );
2328
        assert( maxPeriods > 1 );
2329

    
2330
        /* Clamp to min/max */
2331
        numPeriods = PA_MIN(maxPeriods, PA_MAX(minPeriods, numPeriods));
2332

    
2333
        PA_DEBUG(( "%s: periods min = %lu, max = %lu, req = %lu \n", __FUNCTION__, minPeriods, maxPeriods, numPeriods ));
2334

    
2335
#ifndef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC
2336

    
2337
        /* Calculate period size */
2338
        framesPerHostBuffer = (bufferSize / numPeriods);
2339

    
2340
        /* Align & test size */
2341
        if( framesPerUserBuffer != paFramesPerBufferUnspecified )
2342
        {
2343
            /* Align to user buffer size */
2344
            framesPerHostBuffer = PaAlsa_AlignForward(framesPerHostBuffer, framesPerUserBuffer);
2345

    
2346
            /* Test (borrowed from older implementation) */
2347
            if( framesPerHostBuffer < framesPerUserBuffer )
2348
            {
2349
                assert( framesPerUserBuffer % framesPerHostBuffer == 0 );
2350
                if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
2351
                {
2352
                    if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 )
2353
                        framesPerHostBuffer *= 2;
2354
                    else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 )
2355
                        framesPerHostBuffer /= 2;
2356
                }
2357
            }
2358
            else
2359
            {
2360
                assert( framesPerHostBuffer % framesPerUserBuffer == 0 );
2361
                if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
2362
                {
2363
                    if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 )
2364
                        framesPerHostBuffer += framesPerUserBuffer;
2365
                    else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 )
2366
                        framesPerHostBuffer -= framesPerUserBuffer;
2367
                }
2368
            }
2369
        }
2370
#endif
2371

    
2372
#ifdef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC
2373

    
2374
        if( framesPerUserBuffer != paFramesPerBufferUnspecified )
2375
        {
2376
            /* Try to get a power-of-two of the user buffer size. */
2377
            framesPerHostBuffer = framesPerUserBuffer;
2378
            if( framesPerHostBuffer < bufferSize )
2379
            {
2380
                while( bufferSize / framesPerHostBuffer > numPeriods )
2381
                {
2382
                    framesPerHostBuffer *= 2;
2383
                }
2384
                /* One extra period is preferrable to one less (should be more robust) */
2385
                if( bufferSize / framesPerHostBuffer < numPeriods )
2386
                {
2387
                    framesPerHostBuffer /= 2;
2388
                }
2389
            }
2390
            else
2391
            {
2392
                while( bufferSize / framesPerHostBuffer < numPeriods )
2393
                {
2394
                    if( framesPerUserBuffer % ( framesPerHostBuffer / 2 ) != 0 )
2395
                    {
2396
                        /* Can't be divided any further */
2397
                        break;
2398
                    }
2399
                    framesPerHostBuffer /= 2;
2400
                }
2401
            }
2402

    
2403
            if( framesPerHostBuffer < framesPerUserBuffer )
2404
            {
2405
                assert( framesPerUserBuffer % framesPerHostBuffer == 0 );
2406
                if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
2407
                {
2408
                    if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 )
2409
                        framesPerHostBuffer *= 2;
2410
                    else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 )
2411
                        framesPerHostBuffer /= 2;
2412
                }
2413
            }
2414
            else
2415
            {
2416
                assert( framesPerHostBuffer % framesPerUserBuffer == 0 );
2417
                if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
2418
                {
2419
                    if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 )
2420
                        framesPerHostBuffer += framesPerUserBuffer;
2421
                    else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 )
2422
                        framesPerHostBuffer -= framesPerUserBuffer;
2423
                }
2424
            }
2425
        }
2426
        else
2427
        {
2428
            framesPerHostBuffer = bufferSize / numPeriods;
2429
        }
2430

    
2431
        /* non-mmap mode needs a reasonably-sized buffer or it'll stutter */
2432
        if( !self->canMmap && framesPerHostBuffer < 2048 )
2433
            framesPerHostBuffer = 2048;
2434
#endif
2435
        PA_DEBUG(( "%s: suggested host buffer period   = %lu \n", __FUNCTION__, framesPerHostBuffer ));
2436
    }
2437

    
2438
    {
2439
        /* Get min/max period sizes and adjust our chosen */
2440
        snd_pcm_uframes_t min = 0, max = 0, minmax_diff;
2441
        ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParams, &min, NULL ), paUnanticipatedHostError );
2442
        ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParams, &max, NULL ), paUnanticipatedHostError );
2443
        minmax_diff = max - min;
2444

    
2445
        if( framesPerHostBuffer < min )
2446
        {
2447
            PA_DEBUG(( "%s: The determined period size (%lu) is less than minimum (%lu)\n", __FUNCTION__, framesPerHostBuffer, min ));
2448
            framesPerHostBuffer = (( minmax_diff == 2 ) ? min + 1 : min );
2449
        }
2450
        else if( framesPerHostBuffer > max )
2451
        {
2452
            PA_DEBUG(( "%s: The determined period size (%lu) is greater than maximum (%lu)\n", __FUNCTION__, framesPerHostBuffer, max ));
2453
            framesPerHostBuffer = (( minmax_diff == 2 ) ? max - 1 : max );
2454
        }
2455

    
2456
        PA_DEBUG(( "%s: device period minimum          = %lu\n", __FUNCTION__, min ));
2457
        PA_DEBUG(( "%s: device period maximum          = %lu\n", __FUNCTION__, max ));
2458
        PA_DEBUG(( "%s: host buffer period             = %lu\n", __FUNCTION__, framesPerHostBuffer ));
2459
        PA_DEBUG(( "%s: host buffer period latency     = %f\n", __FUNCTION__, (double)( framesPerHostBuffer / sampleRate ) ));
2460

    
2461
        /* Try setting period size */
2462
        dir = 0;
2463
        ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ), paUnanticipatedHostError );
2464
        if( dir != 0 )
2465
        {
2466
            PA_DEBUG(( "%s: The configured period size is non-integer.\n", __FUNCTION__, dir ));
2467
            *accurate = 0;
2468
        }
2469
    }
2470

    
2471
    /* Set result */
2472
    self->framesPerPeriod = framesPerHostBuffer;
2473

    
2474
error:
2475
    return result;
2476
}
2477

    
2478
/* We need to determine how many frames per host buffer (period) to use.  Our
2479
 * goals are to provide the best possible performance, but also to
2480
 * honor the requested latency settings as closely as we can. Therefore this
2481
 * decision is based on:
2482
 *
2483
 *   - the period sizes that playback and/or capture support.  The
2484
 *     host buffer size has to be one of these.
2485
 *   - the number of periods that playback and/or capture support.
2486
 *
2487
 * We want to make period_size*(num_periods-1) to be as close as possible
2488
 * to latency*rate for both playback and capture.
2489
 *
2490
 * This method will determine suitable period sizes for capture and playback handles, and report the maximum number of
2491
 * frames per host buffer. The latter is relevant, in case we should be so unfortunate that the period size differs
2492
 * between capture and playback. If this should happen, the stream's hostBufferSizeMode attribute will be set to
2493
 * paUtilBoundedHostBufferSize, because the best we can do is limit the size of individual host buffers to the upper
2494
 * bound. The size of host buffers scheduled for processing should only matter if the user has specified a buffer size,
2495
 * but when he/she does we must strive for an optimal configuration. By default we'll opt for a fixed host buffer size,
2496
 * which should be fine if the period size is the same for capture and playback. In general, if there is a specified user
2497
 * buffer size, this method tries it best to determine a period size which is a multiple of the user buffer size.
2498
 *
2499
 * The framesPerPeriod attributes of the individual capture and playback components of the stream are set to corresponding
2500
 * values determined here. Since these should be reported as
2501
 *
2502
 * This is one of those blocks of code that will just take a lot of
2503
 * refinement to be any good.
2504
 *
2505
 * In the full-duplex case it is possible that the routine was unable
2506
 * to find a number of frames per buffer acceptable to both devices
2507
 * TODO: Implement an algorithm to find the value closest to acceptance
2508
 * by both devices, to minimize difference between period sizes?
2509
 *
2510
 * @param determinedFramesPerHostBuffer: The determined host buffer size.
2511
 */
2512
static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double sampleRate, const PaStreamParameters* inputParameters,
2513
        const PaStreamParameters* outputParameters, unsigned long framesPerUserBuffer, snd_pcm_hw_params_t* hwParamsCapture,
2514
        snd_pcm_hw_params_t* hwParamsPlayback, PaUtilHostBufferSizeMode* hostBufferSizeMode )
2515
{
2516
    PaError result = paNoError;
2517
    unsigned long framesPerHostBuffer = 0;
2518
    int dir = 0;
2519
    int accurate = 1;
2520
    unsigned numPeriods = numPeriods_;
2521

    
2522
    if( self->capture.pcm && self->playback.pcm )
2523
    {
2524
        if( framesPerUserBuffer == paFramesPerBufferUnspecified )
2525
        {
2526
            /* Come up with a common desired latency */
2527
            snd_pcm_uframes_t desiredBufSz, e, minPeriodSize, maxPeriodSize, optimalPeriodSize, periodSize,
2528
                              minCapture, minPlayback, maxCapture, maxPlayback;
2529

    
2530
            dir = 0;
2531
            ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );
2532
            dir = 0;
2533
            ENSURE_( alsa_snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError );
2534
            dir = 0;
2535
            ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError );
2536
            dir = 0;
2537
            ENSURE_( alsa_snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError );
2538
            minPeriodSize = PA_MAX( minPlayback, minCapture );
2539
            maxPeriodSize = PA_MIN( maxPlayback, maxCapture );
2540
            PA_UNLESS( minPeriodSize <= maxPeriodSize, paBadIODeviceCombination );
2541

    
2542
            desiredBufSz = (snd_pcm_uframes_t)( PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )
2543
                    * sampleRate );
2544
            /* Clamp desiredBufSz */
2545
            {
2546
                snd_pcm_uframes_t maxBufferSize;
2547
                snd_pcm_uframes_t maxBufferSizeCapture, maxBufferSizePlayback;
2548
                ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &maxBufferSizeCapture ), paUnanticipatedHostError );
2549
                ENSURE_( alsa_snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSizePlayback ), paUnanticipatedHostError );
2550
                maxBufferSize = PA_MIN( maxBufferSizeCapture, maxBufferSizePlayback );
2551

    
2552
                desiredBufSz = PA_MIN( desiredBufSz, maxBufferSize );
2553
            }
2554

    
2555
            /* Find the closest power of 2 */
2556
            e = ilogb( minPeriodSize );
2557
            if( minPeriodSize & ( minPeriodSize - 1 ) )
2558
                e += 1;
2559
            periodSize = (snd_pcm_uframes_t)pow( 2, e );
2560

    
2561
            while( periodSize <= maxPeriodSize )
2562
            {
2563
                if( alsa_snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 &&
2564
                        alsa_snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 )
2565
                {
2566
                    /* OK! */
2567
                    break;
2568
                }
2569

    
2570
                periodSize *= 2;
2571
            }
2572

    
2573
            optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize );
2574
            optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
2575

    
2576
            /* Find the closest power of 2 */
2577
            e = ilogb( optimalPeriodSize );
2578
            if( optimalPeriodSize & (optimalPeriodSize - 1) )
2579
                e += 1;
2580
            optimalPeriodSize = (snd_pcm_uframes_t)pow( 2, e );
2581

    
2582
            while( optimalPeriodSize >= periodSize )
2583
            {
2584
                if( alsa_snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 )
2585
                        >= 0 && alsa_snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback,
2586
                            optimalPeriodSize, 0 ) >= 0 )
2587
                {
2588
                    break;
2589
                }
2590
                optimalPeriodSize /= 2;
2591
            }
2592

    
2593
            if( optimalPeriodSize > periodSize )
2594
                periodSize = optimalPeriodSize;
2595

    
2596
            if( periodSize <= maxPeriodSize )
2597
            {
2598
                /* Looks good, the periodSize _should_ be acceptable by both devices */
2599
                ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ),
2600
                        paUnanticipatedHostError );
2601
                ENSURE_( alsa_snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ),
2602
                        paUnanticipatedHostError );
2603
                self->capture.framesPerPeriod = self->playback.framesPerPeriod = periodSize;
2604
                framesPerHostBuffer = periodSize;
2605
            }
2606
            else
2607
            {
2608
                /* Unable to find a common period size, oh well */
2609
                optimalPeriodSize = PA_MAX( desiredBufSz / numPeriods, minPeriodSize );
2610
                optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
2611

    
2612
                self->capture.framesPerPeriod = optimalPeriodSize;
2613
                dir = 0;
2614
                ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerPeriod, &dir ),
2615
                        paUnanticipatedHostError );
2616
                self->playback.framesPerPeriod = optimalPeriodSize;
2617
                dir = 0;
2618
                ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerPeriod, &dir ),
2619
                        paUnanticipatedHostError );
2620
                framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod );
2621
                *hostBufferSizeMode = paUtilBoundedHostBufferSize;
2622
            }
2623
        }
2624
        else
2625
        {
2626
            /* We choose the simple route and determine a suitable number of frames per buffer for one component of
2627
             * the stream, then we hope that this will work for the other component too (it should!).
2628
             */
2629

    
2630
            unsigned maxPeriods = 0;
2631
            PaAlsaStreamComponent* first = &self->capture, * second = &self->playback;
2632
            const PaStreamParameters* firstStreamParams = inputParameters;
2633
            snd_pcm_hw_params_t* firstHwParams = hwParamsCapture, * secondHwParams = hwParamsPlayback;
2634

    
2635
            dir = 0;
2636
            ENSURE_( alsa_snd_pcm_hw_params_get_periods_max( hwParamsPlayback, &maxPeriods, &dir ), paUnanticipatedHostError );
2637
            if( maxPeriods < numPeriods )
2638
            {
2639
                /* The playback component is trickier to get right, try that first */
2640
                first = &self->playback;
2641
                second = &self->capture;
2642
                firstStreamParams = outputParameters;
2643
                firstHwParams = hwParamsPlayback;
2644
                secondHwParams = hwParamsCapture;
2645
            }
2646

    
2647
            PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( first, firstStreamParams, framesPerUserBuffer,
2648
                        sampleRate, firstHwParams, &accurate ) );
2649

    
2650
            second->framesPerPeriod = first->framesPerPeriod;
2651
            dir = 0;
2652
            ENSURE_( alsa_snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerPeriod, &dir ),
2653
                    paUnanticipatedHostError );
2654
            if( self->capture.framesPerPeriod == self->playback.framesPerPeriod )
2655
            {
2656
                framesPerHostBuffer = self->capture.framesPerPeriod;
2657
            }
2658
            else
2659
            {
2660
                framesPerHostBuffer = PA_MAX( self->capture.framesPerPeriod, self->playback.framesPerPeriod );
2661
                *hostBufferSizeMode = paUtilBoundedHostBufferSize;
2662
            }
2663
        }
2664
    }
2665
    else    /* half-duplex is a slightly simpler case */
2666
    {
2667
        if( self->capture.pcm )
2668
        {
2669
            PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->capture, inputParameters, framesPerUserBuffer,
2670
                        sampleRate, hwParamsCapture, &accurate) );
2671
            framesPerHostBuffer = self->capture.framesPerPeriod;
2672
        }
2673
        else
2674
        {
2675
            assert( self->playback.pcm );
2676
            PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->playback, outputParameters, framesPerUserBuffer,
2677
                        sampleRate, hwParamsPlayback, &accurate ) );
2678
            framesPerHostBuffer = self->playback.framesPerPeriod;
2679
        }
2680
    }
2681

    
2682
    PA_UNLESS( framesPerHostBuffer != 0, paInternalError );
2683
    self->maxFramesPerHostBuffer = framesPerHostBuffer;
2684

    
2685
    if( !self->playback.canMmap || !accurate )
2686
    {
2687
        /* Don't know the exact size per host buffer */
2688
        *hostBufferSizeMode = paUtilBoundedHostBufferSize;
2689
        /* Raise upper bound */
2690
        if( !accurate )
2691
            ++self->maxFramesPerHostBuffer;
2692
    }
2693

    
2694
error:
2695
    return result;
2696
}
2697

    
2698
/** Set up ALSA stream parameters.
2699
 *
2700
 */
2701
static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParameters *inParams, const PaStreamParameters*
2702
        outParams, double sampleRate, unsigned long framesPerUserBuffer, double* inputLatency, double* outputLatency,
2703
        PaUtilHostBufferSizeMode* hostBufferSizeMode )
2704
{
2705
    PaError result = paNoError;
2706
    double realSr = sampleRate;
2707
    snd_pcm_hw_params_t* hwParamsCapture, * hwParamsPlayback;
2708

    
2709
    alsa_snd_pcm_hw_params_alloca( &hwParamsCapture );
2710
    alsa_snd_pcm_hw_params_alloca( &hwParamsPlayback );
2711

    
2712
    if( self->capture.pcm )
2713
        PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->capture, inParams, self->primeBuffers, hwParamsCapture,
2714
                    &realSr ) );
2715
    if( self->playback.pcm )
2716
        PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->playback, outParams, self->primeBuffers, hwParamsPlayback,
2717
                    &realSr ) );
2718

    
2719
    PA_ENSURE( PaAlsaStream_DetermineFramesPerBuffer( self, realSr, inParams, outParams, framesPerUserBuffer,
2720
                hwParamsCapture, hwParamsPlayback, hostBufferSizeMode ) );
2721

    
2722
    if( self->capture.pcm )
2723
    {
2724
        assert( self->capture.framesPerPeriod != 0 );
2725
        PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->capture, hwParamsCapture, inParams, self->primeBuffers, realSr,
2726
                    inputLatency ) );
2727
        PA_DEBUG(( "%s: Capture period size: %lu, latency: %f\n", __FUNCTION__, self->capture.framesPerPeriod, *inputLatency ));
2728
    }
2729
    if( self->playback.pcm )
2730
    {
2731
        assert( self->playback.framesPerPeriod != 0 );
2732
        PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->playback, hwParamsPlayback, outParams, self->primeBuffers, realSr,
2733
                    outputLatency ) );
2734
        PA_DEBUG(( "%s: Playback period size: %lu, latency: %f\n", __FUNCTION__, self->playback.framesPerPeriod, *outputLatency ));
2735
    }
2736

    
2737
    /* Should be exact now */
2738
    self->streamRepresentation.streamInfo.sampleRate = realSr;
2739

    
2740
    /* this will cause the two streams to automatically start/stop/prepare in sync.
2741
     * We only need to execute these operations on one of the pair.
2742
     * A: We don't want to do this on a blocking stream.
2743
     */
2744
    if( self->callbackMode && self->capture.pcm && self->playback.pcm )
2745
    {
2746
        int err = alsa_snd_pcm_link( self->capture.pcm, self->playback.pcm );
2747
        if( err == 0 )
2748
            self->pcmsSynced = 1;
2749
        else
2750
            PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, alsa_snd_strerror( err ) ));
2751
    }
2752

    
2753
    {
2754
        unsigned long minFramesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerPeriod : ULONG_MAX,
2755
            self->playback.pcm ? self->playback.framesPerPeriod : ULONG_MAX );
2756
        self->pollTimeout = CalculatePollTimeout( self, minFramesPerHostBuffer );    /* Period in msecs, rounded up */
2757

    
2758
        /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */
2759
        /* self->threading.throttledSleepTime = (unsigned long) (minFramesPerHostBuffer / sampleRate / 4 * 1000); */
2760
    }
2761

    
2762
    if( self->callbackMode )
2763
    {
2764
        /* If the user expects a certain number of frames per callback we will either have to rely on block adaption
2765
         * (framesPerHostBuffer is not an integer multiple of framesPerPeriod) or we can simply align the number
2766
         * of host buffer frames with what the user specified */
2767
        if( self->framesPerUserBuffer != paFramesPerBufferUnspecified )
2768
        {
2769
            /* self->alignFrames = 1; */
2770

    
2771
            /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely
2772
             * on block adaption */
2773
        /*
2774
            if( framesPerHostBuffer % framesPerPeriod != 0 || (self->capture.pcm && self->playback.pcm &&
2775
                        self->capture.framesPerPeriod != self->playback.framesPerPeriod) )
2776
                self->useBlockAdaption = 1;
2777
            else
2778
                self->alignFrames = 1;
2779
        */
2780
        }
2781
    }
2782

    
2783
error:
2784
    return result;
2785
}
2786

    
2787
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
2788
                           PaStream** s,
2789
                           const PaStreamParameters *inputParameters,
2790
                           const PaStreamParameters *outputParameters,
2791
                           double sampleRate,
2792
                           unsigned long framesPerBuffer,
2793
                           PaStreamFlags streamFlags,
2794
                           PaStreamCallback* callback,
2795
                           void *userData )
2796
{
2797
    PaError result = paNoError;
2798
    PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
2799
    PaAlsaStream *stream = NULL;
2800
    PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0;
2801
    PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0;
2802
    int numInputChannels = 0, numOutputChannels = 0;
2803
    PaTime inputLatency, outputLatency;
2804
    /* Operate with fixed host buffer size by default, since other modes will invariably lead to block adaption */
2805
    /* XXX: Use Bounded by default? Output tends to get stuttery with Fixed ... */
2806
    PaUtilHostBufferSizeMode hostBufferSizeMode = paUtilFixedHostBufferSize;
2807

    
2808
    if( ( streamFlags & paPlatformSpecificFlags ) != 0 )
2809
        return paInvalidFlag;
2810

    
2811
    if( inputParameters )
2812
    {
2813
        PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );
2814

    
2815
        numInputChannels = inputParameters->channelCount;
2816
        inputSampleFormat = inputParameters->sampleFormat;
2817
    }
2818
    if( outputParameters )
2819
    {
2820
        PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );
2821

    
2822
        numOutputChannels = outputParameters->channelCount;
2823
        outputSampleFormat = outputParameters->sampleFormat;
2824
    }
2825

    
2826
    /* XXX: Why do we support this anyway? */
2827
    if( framesPerBuffer == paFramesPerBufferUnspecified && getenv( "PA_ALSA_PERIODSIZE" ) != NULL )
2828
    {
2829
        PA_DEBUG(( "%s: Getting framesPerBuffer (Alsa period-size) from environment\n", __FUNCTION__ ));
2830
        framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") );
2831
    }
2832

    
2833
    PA_UNLESS( stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) ), paInsufficientMemory );
2834
    PA_ENSURE( PaAlsaStream_Initialize( stream, alsaHostApi, inputParameters, outputParameters, sampleRate,
2835
                framesPerBuffer, callback, streamFlags, userData ) );
2836

    
2837
    PA_ENSURE( PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerBuffer,
2838
                &inputLatency, &outputLatency, &hostBufferSizeMode ) );
2839
    hostInputSampleFormat = stream->capture.hostSampleFormat | (!stream->capture.hostInterleaved ? paNonInterleaved : 0);
2840
    hostOutputSampleFormat = stream->playback.hostSampleFormat | (!stream->playback.hostInterleaved ? paNonInterleaved : 0);
2841

    
2842
    PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
2843
                    numInputChannels, inputSampleFormat, hostInputSampleFormat,
2844
                    numOutputChannels, outputSampleFormat, hostOutputSampleFormat,
2845
                    sampleRate, streamFlags, framesPerBuffer, stream->maxFramesPerHostBuffer,
2846
                    hostBufferSizeMode, callback, userData ) );
2847

    
2848
    /* Ok, buffer processor is initialized, now we can deduce it's latency */
2849
    if( numInputChannels > 0 )
2850
        stream->streamRepresentation.streamInfo.inputLatency = inputLatency + (PaTime)(
2851
                PaUtil_GetBufferProcessorInputLatencyFrames( &stream->bufferProcessor ) / sampleRate);
2852
    if( numOutputChannels > 0 )
2853
        stream->streamRepresentation.streamInfo.outputLatency = outputLatency + (PaTime)(
2854
                PaUtil_GetBufferProcessorOutputLatencyFrames( &stream->bufferProcessor ) / sampleRate);
2855

    
2856
    PA_DEBUG(( "%s: Stream: framesPerBuffer = %lu, maxFramesPerHostBuffer = %lu, latency i=%f, o=%f\n", __FUNCTION__, framesPerBuffer, stream->maxFramesPerHostBuffer, stream->streamRepresentation.streamInfo.inputLatency, stream->streamRepresentation.streamInfo.outputLatency));
2857

    
2858
    *s = (PaStream*)stream;
2859

    
2860
    return result;
2861

    
2862
error:
2863
    if( stream )
2864
    {
2865
        PA_DEBUG(( "%s: Stream in error, terminating\n", __FUNCTION__ ));
2866
        PaAlsaStream_Terminate( stream );
2867
    }
2868

    
2869
    return result;
2870
}
2871

    
2872
static PaError CloseStream( PaStream* s )
2873
{
2874
    PaError result = paNoError;
2875
    PaAlsaStream *stream = (PaAlsaStream*)s;
2876

    
2877
    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
2878
    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
2879

    
2880
    PaAlsaStream_Terminate( stream );
2881

    
2882
    return result;
2883
}
2884

    
2885
static void SilenceBuffer( PaAlsaStream *stream )
2886
{
2887
    const snd_pcm_channel_area_t *areas;
2888
    snd_pcm_uframes_t frames = (snd_pcm_uframes_t)alsa_snd_pcm_avail_update( stream->playback.pcm ), offset;
2889

    
2890
    alsa_snd_pcm_mmap_begin( stream->playback.pcm, &areas, &offset, &frames );
2891
    alsa_snd_pcm_areas_silence( areas, offset, stream->playback.numHostChannels, frames, stream->playback.nativeFormat );
2892
    alsa_snd_pcm_mmap_commit( stream->playback.pcm, offset, frames );
2893
}
2894

    
2895
/** Start/prepare pcm(s) for streaming.
2896
 *
2897
 * Depending on whether the stream is in callback or blocking mode, we will respectively start or simply
2898
 * prepare the playback pcm. If the buffer has _not_ been primed, we will in callback mode prepare and
2899
 * silence the buffer before starting playback. In blocking mode we simply prepare, as the playback will
2900
 * be started automatically as the user writes to output.
2901
 *
2902
 * The capture pcm, however, will simply be prepared and started.
2903
 */
2904
static PaError AlsaStart( PaAlsaStream *stream, int priming )
2905
{
2906
    PaError result = paNoError;
2907

    
2908
    if( stream->playback.pcm )
2909
    {
2910
        if( stream->callbackMode )
2911
        {
2912
            if( !priming )
2913
            {
2914
                /* Buffer isn't primed, so prepare and silence */
2915
                ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
2916
                if( stream->playback.canMmap )
2917
                    SilenceBuffer( stream );
2918
            }
2919
            if( stream->playback.canMmap )
2920
                ENSURE_( alsa_snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
2921
        }
2922
        else
2923
            ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
2924
    }
2925
    if( stream->capture.pcm && !stream->pcmsSynced )
2926
    {
2927
        ENSURE_( alsa_snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );
2928
        /* For a blocking stream we want to start capture as well, since nothing will happen otherwise */
2929
        ENSURE_( alsa_snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );
2930
    }
2931

    
2932
end:
2933
    return result;
2934
error:
2935
    goto end;
2936
}
2937

    
2938
/** Utility function for determining if pcms are in running state.
2939
 *
2940
 */
2941
#if 0
2942
static int IsRunning( PaAlsaStream *stream )
2943
{
2944
    int result = 0;
2945

2946
    PA_ENSURE( PaUnixMutex_Lock( &stream->stateMtx ) );
2947
    if( stream->capture.pcm )
2948
    {
2949
        snd_pcm_state_t capture_state = alsa_snd_pcm_state( stream->capture.pcm );
2950

2951
        if( capture_state == SND_PCM_STATE_RUNNING || capture_state == SND_PCM_STATE_XRUN
2952
                || capture_state == SND_PCM_STATE_DRAINING )
2953
        {
2954
            result = 1;
2955
            goto end;
2956
        }
2957
    }
2958

2959
    if( stream->playback.pcm )
2960
    {
2961
        snd_pcm_state_t playback_state = alsa_snd_pcm_state( stream->playback.pcm );
2962

2963
        if( playback_state == SND_PCM_STATE_RUNNING || playback_state == SND_PCM_STATE_XRUN
2964
                || playback_state == SND_PCM_STATE_DRAINING )
2965
        {
2966
            result = 1;
2967
            goto end;
2968
        }
2969
    }
2970

2971
end:
2972
    ASSERT_CALL_( PaUnixMutex_Unlock( &stream->stateMtx ), paNoError );
2973
    return result;
2974
error:
2975
    goto error;
2976
}
2977
#endif
2978

    
2979
static PaError StartStream( PaStream *s )
2980
{
2981
    PaError result = paNoError;
2982
    PaAlsaStream* stream = (PaAlsaStream*)s;
2983
    int streamStarted = 0;  /* So we can know whether we need to take the stream down */
2984

    
2985
    /* Ready the processor */
2986
    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
2987

    
2988
    /* Set now, so we can test for activity further down */
2989
    stream->isActive = 1;
2990

    
2991
    if( stream->callbackMode )
2992
    {
2993
        PA_ENSURE( PaUnixThread_New( &stream->thread, &CallbackThreadFunc, stream, 1., stream->rtSched ) );
2994
    }
2995
    else
2996
    {
2997
        PA_ENSURE( AlsaStart( stream, 0 ) );
2998
        streamStarted = 1;
2999
    }
3000

    
3001
end:
3002
    return result;
3003
error:
3004
    if( streamStarted )
3005
    {
3006
        AbortStream( stream );
3007
    }
3008
    stream->isActive = 0;
3009

    
3010
    goto end;
3011
}
3012

    
3013
/** Stop PCM handle, either softly or abruptly.
3014
 */
3015
static PaError AlsaStop( PaAlsaStream *stream, int abort )
3016
{
3017
    PaError result = paNoError;
3018
    /* XXX: alsa_snd_pcm_drain tends to lock up, avoid it until we find out more */
3019
    abort = 1;
3020
    /*
3021
    if( stream->capture.pcm && !strcmp( Pa_GetDeviceInfo( stream->capture.device )->name,
3022
                "dmix" ) )
3023
    {
3024
        abort = 1;
3025
    }
3026
    else if( stream->playback.pcm && !strcmp( Pa_GetDeviceInfo( stream->playback.device )->name,
3027
                "dmix" ) )
3028
    {
3029
        abort = 1;
3030
    }
3031
    */
3032

    
3033
    if( abort )
3034
    {
3035
        if( stream->playback.pcm )
3036
        {
3037
            ENSURE_( alsa_snd_pcm_drop( stream->playback.pcm ), paUnanticipatedHostError );
3038
        }
3039
        if( stream->capture.pcm && !stream->pcmsSynced )
3040
        {
3041
            ENSURE_( alsa_snd_pcm_drop( stream->capture.pcm ), paUnanticipatedHostError );
3042
        }
3043

    
3044
        PA_DEBUG(( "%s: Dropped frames\n", __FUNCTION__ ));
3045
    }
3046
    else
3047
    {
3048
        if( stream->playback.pcm )
3049
        {
3050
            ENSURE_( alsa_snd_pcm_nonblock( stream->playback.pcm, 0 ), paUnanticipatedHostError );
3051
            if( alsa_snd_pcm_drain( stream->playback.pcm ) < 0 )
3052
            {
3053
                PA_DEBUG(( "%s: Draining playback handle failed!\n", __FUNCTION__ ));
3054
            }
3055
        }
3056
        if( stream->capture.pcm && !stream->pcmsSynced )
3057
        {
3058
            /* We don't need to retrieve any remaining frames */
3059
            if( alsa_snd_pcm_drain( stream->capture.pcm ) < 0 )
3060
            {
3061
                PA_DEBUG(( "%s: Draining capture handle failed!\n", __FUNCTION__ ));
3062
            }
3063
        }
3064
    }
3065

    
3066
end:
3067
    return result;
3068
error:
3069
    goto end;
3070
}
3071

    
3072
/** Stop or abort stream.
3073
 *
3074
 * If a stream is in callback mode we will have to inspect whether the background thread has
3075
 * finished, or we will have to take it out. In either case we join the thread before
3076
 * returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish
3077
 * buffers (drain)
3078
 *
3079
 * Stream will be considered inactive (!PaAlsaStream::isActive) after a call to this function
3080
 */
3081
static PaError RealStop( PaAlsaStream *stream, int abort )
3082
{
3083
    PaError result = paNoError;
3084

    
3085
    /* First deal with the callback thread, cancelling and/or joining
3086
     * it if necessary
3087
     */
3088
    if( stream->callbackMode )
3089
    {
3090
        PaError threadRes;
3091
        stream->callbackAbort = abort;
3092

    
3093
        if( !abort )
3094
        {
3095
            PA_DEBUG(( "Stopping callback\n" ));
3096
        }
3097
        PA_ENSURE( PaUnixThread_Terminate( &stream->thread, !abort, &threadRes ) );
3098
        if( threadRes != paNoError )
3099
        {
3100
            PA_DEBUG(( "Callback thread returned: %d\n", threadRes ));
3101
        }
3102
#if 0
3103
        if( watchdogRes != paNoError )
3104
            PA_DEBUG(( "Watchdog thread returned: %d\n", watchdogRes ));
3105
#endif
3106

    
3107
        stream->callback_finished = 0;
3108
    }
3109
    else
3110
    {
3111
        PA_ENSURE( AlsaStop( stream, abort ) );
3112
    }
3113

    
3114
    stream->isActive = 0;
3115

    
3116
end:
3117
    return result;
3118

    
3119
error:
3120
    goto end;
3121
}
3122

    
3123
static PaError StopStream( PaStream *s )
3124
{
3125
    return RealStop( (PaAlsaStream *) s, 0 );
3126
}
3127

    
3128
static PaError AbortStream( PaStream *s )
3129
{
3130
    return RealStop( (PaAlsaStream * ) s, 1 );
3131
}
3132

    
3133
/** The stream is considered stopped before StartStream, or AFTER a call to Abort/StopStream (callback
3134
 * returning !paContinue is not considered)
3135
 *
3136
 */
3137
static PaError IsStreamStopped( PaStream *s )
3138
{
3139
    PaAlsaStream *stream = (PaAlsaStream *)s;
3140

    
3141
    /* callback_finished indicates we need to join callback thread (ie. in Abort/StopStream) */
3142
    return !IsStreamActive( s ) && !stream->callback_finished;
3143
}
3144

    
3145
static PaError IsStreamActive( PaStream *s )
3146
{
3147
    PaAlsaStream *stream = (PaAlsaStream*)s;
3148
    return stream->isActive;
3149
}
3150

    
3151
static PaTime GetStreamTime( PaStream *s )
3152
{
3153
    PaAlsaStream *stream = (PaAlsaStream*)s;
3154

    
3155
    snd_timestamp_t timestamp;
3156
    snd_pcm_status_t* status;
3157
    alsa_snd_pcm_status_alloca( &status );
3158

    
3159
    /* TODO: what if we have both?  does it really matter? */
3160

    
3161
    /* TODO: if running in callback mode, this will mean
3162
     * libasound routines are being called from multiple threads.
3163
     * need to verify that libasound is thread-safe. */
3164

    
3165
    if( stream->capture.pcm )
3166
    {
3167
        alsa_snd_pcm_status( stream->capture.pcm, status );
3168
    }
3169
    else if( stream->playback.pcm )
3170
    {
3171
        alsa_snd_pcm_status( stream->playback.pcm, status );
3172
    }
3173

    
3174
    alsa_snd_pcm_status_get_tstamp( status, &timestamp );
3175
    return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1e6;
3176
}
3177

    
3178
static double GetStreamCpuLoad( PaStream* s )
3179
{
3180
    PaAlsaStream *stream = (PaAlsaStream*)s;
3181

    
3182
    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
3183
}
3184

    
3185
/* Set the stream sample rate to a nominal value requested; allow only a defined tolerance range */
3186
static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate )
3187
{
3188
    PaError result = paNoError;
3189
    unsigned int reqRate, setRate, deviation;
3190

    
3191
    assert( pcm && hwParams );
3192

    
3193
    /* The Alsa sample rate is set by integer value; also the actual rate may differ */
3194
    reqRate = setRate = (unsigned int) sampleRate;
3195

    
3196
    ENSURE_( alsa_snd_pcm_hw_params_set_rate_near( pcm, hwParams, &setRate, NULL ), paUnanticipatedHostError );
3197
    /* The value actually set will be put in 'setRate' (may be way off); check the deviation as a proportion
3198
     * of the requested-rate with reference to the max-deviate-ratio (larger values allow less deviation) */
3199
    deviation = abs( setRate - reqRate );
3200
    if( deviation > 0 && deviation * RATE_MAX_DEVIATE_RATIO > reqRate )
3201
        result = paInvalidSampleRate;
3202

    
3203
end:
3204
    return result;
3205

    
3206
error:
3207
    /* Log */
3208
    {
3209
        unsigned int _min = 0, _max = 0;
3210
        int _dir = 0;
3211
        ENSURE_( alsa_snd_pcm_hw_params_get_rate_min( hwParams, &_min, &_dir ), paUnanticipatedHostError );
3212
        ENSURE_( alsa_snd_pcm_hw_params_get_rate_max( hwParams, &_max, &_dir ), paUnanticipatedHostError );
3213
        PA_DEBUG(( "%s: SR min = %u, max = %u, req = %u\n", __FUNCTION__, _min, _max, reqRate ));
3214
    }
3215
    goto end;
3216
}
3217

    
3218
/* Return exact sample rate in param sampleRate */
3219
static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate )
3220
{
3221
    unsigned int num, den = 1;
3222
    int err;
3223

    
3224
    assert( hwParams );
3225

    
3226
    err = alsa_snd_pcm_hw_params_get_rate_numden( hwParams, &num, &den );
3227
    *sampleRate = (double) num / den;
3228

    
3229
    return err;
3230
}
3231

    
3232
/* Utility functions for blocking/callback interfaces */
3233

    
3234
/* Atomic restart of stream (we don't want the intermediate state visible) */
3235
static PaError AlsaRestart( PaAlsaStream *stream )
3236
{
3237
    PaError result = paNoError;
3238

    
3239
    PA_ENSURE( PaUnixMutex_Lock( &stream->stateMtx ) );
3240
    PA_ENSURE( AlsaStop( stream, 0 ) );
3241
    PA_ENSURE( AlsaStart( stream, 0 ) );
3242

    
3243
    PA_DEBUG(( "%s: Restarted audio\n", __FUNCTION__ ));
3244

    
3245
error:
3246
    PA_ENSURE( PaUnixMutex_Unlock( &stream->stateMtx ) );
3247

    
3248
    return result;
3249
}
3250

    
3251
/** Recover from xrun state.
3252
 *
3253
 */
3254
static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self )
3255
{
3256
    PaError result = paNoError;
3257
    snd_pcm_status_t *st;
3258
    PaTime now = PaUtil_GetTime();
3259
    snd_timestamp_t t;
3260
    int restartAlsa = 0; /* do not restart Alsa by default */
3261

    
3262
    alsa_snd_pcm_status_alloca( &st );
3263

    
3264
    if( self->playback.pcm )
3265
    {
3266
        alsa_snd_pcm_status( self->playback.pcm, st );
3267
        if( alsa_snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
3268
        {
3269
            alsa_snd_pcm_status_get_trigger_tstamp( st, &t );
3270
            self->underrun = now * 1000 - ( (PaTime)t.tv_sec * 1000 + (PaTime)t.tv_usec / 1000 );
3271

    
3272
            if( !self->playback.canMmap )
3273
            {
3274
                if( alsa_snd_pcm_recover( self->playback.pcm, -EPIPE, 0 ) < 0 )
3275
                {
3276
                    PA_DEBUG(( "%s: [playback] non-MMAP-PCM failed recovering from XRUN, will restart Alsa\n", __FUNCTION__ ));
3277
                    ++ restartAlsa; /* did not manage to recover */
3278
                }
3279
            }
3280
            else
3281
                ++ restartAlsa; /* always restart MMAPed device */
3282
        }
3283
    }
3284
    if( self->capture.pcm )
3285
    {
3286
        alsa_snd_pcm_status( self->capture.pcm, st );
3287
        if( alsa_snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
3288
        {
3289
            alsa_snd_pcm_status_get_trigger_tstamp( st, &t );
3290
            self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
3291

    
3292
            if (!self->capture.canMmap)
3293
            {
3294
                if (alsa_snd_pcm_recover( self->capture.pcm, -EPIPE, 0 ) < 0)
3295
                {
3296
                    PA_DEBUG(( "%s: [capture] non-MMAP-PCM failed recovering from XRUN, will restart Alsa\n", __FUNCTION__ ));
3297
                    ++ restartAlsa; /* did not manage to recover */
3298
                }
3299
            }
3300
            else
3301
                ++ restartAlsa; /* always restart MMAPed device */
3302
        }
3303
    }
3304

    
3305
    if( restartAlsa )
3306
    {
3307
        PA_DEBUG(( "%s: restarting Alsa to recover from XRUN\n", __FUNCTION__ ));
3308
        PA_ENSURE( AlsaRestart( self ) );
3309
    }
3310

    
3311
end:
3312
    return result;
3313
error:
3314
    goto end;
3315
}
3316

    
3317
/** Decide if we should continue polling for specified direction, eventually adjust the poll timeout.
3318
 *
3319
 */
3320
static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamDir, int *pollTimeout, int *continuePoll )
3321
{
3322
    PaError result = paNoError;
3323
    snd_pcm_sframes_t delay, margin;
3324
    int err;
3325
    const PaAlsaStreamComponent *component = NULL, *otherComponent = NULL;
3326

    
3327
    *continuePoll = 1;
3328

    
3329
    if( StreamDirection_In == streamDir )
3330
    {
3331
        component = &stream->capture;
3332
        otherComponent = &stream->playback;
3333
    }
3334
    else
3335
    {
3336
        component = &stream->playback;
3337
        otherComponent = &stream->capture;
3338
    }
3339

    
3340
    /* ALSA docs say that negative delay should indicate xrun, but in my experience alsa_snd_pcm_delay returns -EPIPE */
3341
    if( ( err = alsa_snd_pcm_delay( otherComponent->pcm, &delay ) ) < 0 )
3342
    {
3343
        if( err == -EPIPE )
3344
        {
3345
            /* Xrun */
3346
            *continuePoll = 0;
3347
            goto error;
3348
        }
3349

    
3350
        ENSURE_( err, paUnanticipatedHostError );
3351
    }
3352

    
3353
    if( StreamDirection_Out == streamDir )
3354
    {
3355
        /* Number of eligible frames before capture overrun */
3356
        delay = otherComponent->alsaBufferSize - delay;
3357
    }
3358
    margin = delay - otherComponent->framesPerPeriod / 2;
3359

    
3360
    if( margin < 0 )
3361
    {
3362
        PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" ));
3363
        *continuePoll = 0;
3364
    }
3365
    else if( margin < otherComponent->framesPerPeriod )
3366
    {
3367
        *pollTimeout = CalculatePollTimeout( stream, margin );
3368
        PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n",
3369
                    __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback", *pollTimeout ));
3370
    }
3371

    
3372
error:
3373
    return result;
3374
}
3375

    
3376
/* Callback interface */
3377

    
3378
static void OnExit( void *data )
3379
{
3380
    PaAlsaStream *stream = (PaAlsaStream *) data;
3381

    
3382
    assert( data );
3383

    
3384
    PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
3385

    
3386
    stream->callback_finished = 1;  /* Let the outside world know stream was stopped in callback */
3387
    PA_DEBUG(( "%s: Stopping ALSA handles\n", __FUNCTION__ ));
3388
    AlsaStop( stream, stream->callbackAbort );
3389

    
3390
    PA_DEBUG(( "%s: Stoppage\n", __FUNCTION__ ));
3391

    
3392
    /* Eventually notify user all buffers have played */
3393
    if( stream->streamRepresentation.streamFinishedCallback )
3394
    {
3395
        stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
3396
    }
3397
    stream->isActive = 0;
3398
}
3399

    
3400
static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *timeInfo )
3401
{
3402
    snd_pcm_status_t *capture_status, *playback_status;
3403
    snd_timestamp_t capture_timestamp, playback_timestamp;
3404
    PaTime capture_time = 0., playback_time = 0.;
3405

    
3406
    alsa_snd_pcm_status_alloca( &capture_status );
3407
    alsa_snd_pcm_status_alloca( &playback_status );
3408

    
3409
    if( stream->capture.pcm )
3410
    {
3411
        snd_pcm_sframes_t capture_delay;
3412

    
3413
        alsa_snd_pcm_status( stream->capture.pcm, capture_status );
3414
        alsa_snd_pcm_status_get_tstamp( capture_status, &capture_timestamp );
3415

    
3416
        capture_time = capture_timestamp.tv_sec +
3417
            ( (PaTime)capture_timestamp.tv_usec / 1000000.0 );
3418
        timeInfo->currentTime = capture_time;
3419

    
3420
        capture_delay = alsa_snd_pcm_status_get_delay( capture_status );
3421
        timeInfo->inputBufferAdcTime = timeInfo->currentTime -
3422
            (PaTime)capture_delay / stream->streamRepresentation.streamInfo.sampleRate;
3423
    }
3424
    if( stream->playback.pcm )
3425
    {
3426
        snd_pcm_sframes_t playback_delay;
3427

    
3428
        alsa_snd_pcm_status( stream->playback.pcm, playback_status );
3429
        alsa_snd_pcm_status_get_tstamp( playback_status, &playback_timestamp );
3430

    
3431
        playback_time = playback_timestamp.tv_sec +
3432
            ((PaTime)playback_timestamp.tv_usec / 1000000.0);
3433

    
3434
        if( stream->capture.pcm ) /* Full duplex */
3435
        {
3436
            /* Hmm, we have both a playback and a capture timestamp.
3437
             * Hopefully they are the same... */
3438
            if( fabs( capture_time - playback_time ) > 0.01 )
3439
                PA_DEBUG(( "Capture time and playback time differ by %f\n", fabs( capture_time-playback_time ) ));
3440
        }
3441
        else
3442
            timeInfo->currentTime = playback_time;
3443

    
3444
        playback_delay = alsa_snd_pcm_status_get_delay( playback_status );
3445
        timeInfo->outputBufferDacTime = timeInfo->currentTime +
3446
            (PaTime)playback_delay / stream->streamRepresentation.streamInfo.sampleRate;
3447
    }
3448
}
3449

    
3450
/** Called after buffer processing is finished.
3451
 *
3452
 * A number of mmapped frames is committed, it is possible that an xrun has occurred in the meantime.
3453
 *
3454
 * @param numFrames The number of frames that has been processed
3455
 * @param xrun Return whether an xrun has occurred
3456
 */
3457
static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun )
3458
{
3459
    PaError result = paNoError;
3460
    int res = 0;
3461

    
3462
    /* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed
3463
     * afterwards
3464
     */
3465
    if( !self->ready )
3466
        goto end;
3467

    
3468
    if( !self->canMmap && StreamDirection_Out == self->streamDir )
3469
    {
3470
        /* Play sound */
3471
        if( self->hostInterleaved )
3472
            res = alsa_snd_pcm_writei( self->pcm, self->nonMmapBuffer, numFrames );
3473
        else
3474
        {
3475
            void *bufs[self->numHostChannels];
3476
            int bufsize = alsa_snd_pcm_format_size( self->nativeFormat, self->framesPerPeriod + 1 );
3477
            unsigned char *buffer = self->nonMmapBuffer;
3478
            int i;
3479
            for( i = 0; i < self->numHostChannels; ++i )
3480
            {
3481
                bufs[i] = buffer;
3482
                buffer += bufsize;
3483
            }
3484
            res = alsa_snd_pcm_writen( self->pcm, bufs, numFrames );
3485
        }
3486
    }
3487

    
3488
    if( self->canMmap )
3489
        res = alsa_snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
3490

    
3491
    if( res == -EPIPE || res == -ESTRPIPE )
3492
    {
3493
        *xrun = 1;
3494
    }
3495
    else
3496
    {
3497
        ENSURE_( res, paUnanticipatedHostError );
3498
    }
3499

    
3500
end:
3501
error:
3502
    return result;
3503
}
3504

    
3505
/* Extract buffer from channel area */
3506
static unsigned char *ExtractAddress( const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset )
3507
{
3508
    return (unsigned char *) area->addr + ( area->first + offset * area->step ) / 8;
3509
}
3510

    
3511
/** Do necessary adaption between user and host channels.
3512
 *
3513
    @concern ChannelAdaption Adapting between user and host channels can involve silencing unused channels and
3514
    duplicating mono information if host outputs come in pairs.
3515
 */
3516
static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp, int numFrames )
3517
{
3518
    PaError result = paNoError;
3519
    unsigned char *p;
3520
    int i;
3521
    int unusedChans = self->numHostChannels - self->numUserChannels;
3522
    unsigned char *src, *dst;
3523
    int convertMono = ( self->numHostChannels % 2 ) == 0 && ( self->numUserChannels % 2 ) != 0;
3524

    
3525
    assert( StreamDirection_Out == self->streamDir );
3526

    
3527
    if( self->hostInterleaved )
3528
    {
3529
        int swidth = alsa_snd_pcm_format_size( self->nativeFormat, 1 );
3530
        unsigned char *buffer = self->canMmap ? ExtractAddress( self->channelAreas, self->offset ) : self->nonMmapBuffer;
3531

    
3532
        /* Start after the last user channel */
3533
        p = buffer + self->numUserChannels * swidth;
3534

    
3535
        if( convertMono )
3536
        {
3537
            /* Convert the last user channel into stereo pair */
3538
            src = buffer + ( self->numUserChannels - 1 ) * swidth;
3539
            for( i = 0; i < numFrames; ++i )
3540
            {
3541
                dst = src + swidth;
3542
                memcpy( dst, src, swidth );
3543
                src += self->numHostChannels * swidth;
3544
            }
3545

    
3546
            /* Don't touch the channel we just wrote to */
3547
            p += swidth;
3548
            --unusedChans;
3549
        }
3550

    
3551
        if( unusedChans > 0 )
3552
        {
3553
            /* Silence unused output channels */
3554
            for( i = 0; i < numFrames; ++i )
3555
            {
3556
                memset( p, 0, swidth * unusedChans );
3557
                p += self->numHostChannels * swidth;
3558
            }
3559
        }
3560
    }
3561
    else
3562
    {
3563
        /* We extract the last user channel */
3564
        if( convertMono )
3565
        {
3566
            ENSURE_( alsa_snd_pcm_area_copy( self->channelAreas + self->numUserChannels, self->offset, self->channelAreas +
3567
                    ( self->numUserChannels - 1 ), self->offset, numFrames, self->nativeFormat ), paUnanticipatedHostError );
3568
            --unusedChans;
3569
        }
3570
        if( unusedChans > 0 )
3571
        {
3572
            alsa_snd_pcm_areas_silence( self->channelAreas + ( self->numHostChannels - unusedChans ), self->offset, unusedChans, numFrames,
3573
                    self->nativeFormat );
3574
        }
3575
    }
3576

    
3577
error:
3578
    return result;
3579
}
3580

    
3581
static PaError PaAlsaStream_EndProcessing( PaAlsaStream *self, unsigned long numFrames, int *xrunOccurred )
3582
{
3583
    PaError result = paNoError;
3584
    int xrun = 0;
3585

    
3586
    if( self->capture.pcm )
3587
    {
3588
        PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->capture, numFrames, &xrun ) );
3589
    }
3590
    if( self->playback.pcm )
3591
    {
3592
        if( self->playback.numHostChannels > self->playback.numUserChannels )
3593
        {
3594
            PA_ENSURE( PaAlsaStreamComponent_DoChannelAdaption( &self->playback, &self->bufferProcessor, numFrames ) );
3595
        }
3596
        PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->playback, numFrames, &xrun ) );
3597
    }
3598

    
3599
error:
3600
    *xrunOccurred = xrun;
3601
    return result;
3602
}
3603

    
3604
/** Update the number of available frames.
3605
 *
3606
 */
3607
static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent *self, unsigned long *numFrames, int *xrunOccurred )
3608
{
3609
    PaError result = paNoError;
3610
    snd_pcm_sframes_t framesAvail = alsa_snd_pcm_avail_update( self->pcm );
3611
    *xrunOccurred = 0;
3612

    
3613
    if( -EPIPE == framesAvail )
3614
    {
3615
        *xrunOccurred = 1;
3616
        framesAvail = 0;
3617
    }
3618
    else
3619
    {
3620
        ENSURE_( framesAvail, paUnanticipatedHostError );
3621
    }
3622

    
3623
    *numFrames = framesAvail;
3624

    
3625
error:
3626
    return result;
3627
}
3628

    
3629
/** Fill in pollfd objects.
3630
 */
3631
static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent* self, struct pollfd* pfds )
3632
{
3633
    PaError result = paNoError;
3634
    int ret = alsa_snd_pcm_poll_descriptors( self->pcm, pfds, self->nfds );
3635
    (void)ret;  /* Prevent unused variable warning if asserts are turned off */
3636
    assert( ret == self->nfds );
3637

    
3638
    self->ready = 0;
3639

    
3640
    return result;
3641
}
3642

    
3643
/** Examine results from poll().
3644
 *
3645
 * @param pfds pollfds to inspect
3646
 * @param shouldPoll Should we continue to poll
3647
 * @param xrun Has an xrun occurred
3648
 */
3649
static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent* self, struct pollfd* pfds, int* shouldPoll, int* xrun )
3650
{
3651
    PaError result = paNoError;
3652
    unsigned short revents;
3653

    
3654
    ENSURE_( alsa_snd_pcm_poll_descriptors_revents( self->pcm, pfds, self->nfds, &revents ), paUnanticipatedHostError );
3655
    if( revents != 0 )
3656
    {
3657
        if( revents & POLLERR )
3658
        {
3659
            *xrun = 1;
3660
        }
3661
        else if( revents & POLLHUP )
3662
        {
3663
            *xrun = 1;
3664
            PA_DEBUG(( "%s: revents has POLLHUP, processing as XRUN\n", __FUNCTION__ ));
3665
        }
3666
        else
3667
            self->ready = 1;
3668

    
3669
        *shouldPoll = 0;
3670
    }
3671
    else /* (A zero revent occurred) */
3672
        /* Work around an issue with Alsa older than 1.0.16 using some plugins (eg default with plug + dmix) where
3673
         * POLLIN or POLLOUT are zeroed by Alsa-lib if _mmap_avail() is a few frames short of avail_min at period
3674
         * boundary, possibly due to erratic dma interrupts at period boundary?  Treat as a valid event.
3675
         */
3676
        if( self->useReventFix )
3677
        {
3678
            self->ready = 1;
3679
            *shouldPoll = 0;
3680
        }
3681

    
3682
error:
3683
    return result;
3684
}
3685

    
3686
/** Return the number of available frames for this stream.
3687
 *
3688
 * @concern FullDuplex The minimum available for the two directions is calculated, it might be desirable to ignore
3689
 * one direction however (not marked ready from poll), so this is controlled by queryCapture and queryPlayback.
3690
 *
3691
 * @param queryCapture Check available for capture
3692
 * @param queryPlayback Check available for playback
3693
 * @param available The returned number of frames
3694
 * @param xrunOccurred Return whether an xrun has occurred
3695
 */
3696
static PaError PaAlsaStream_GetAvailableFrames( PaAlsaStream *self, int queryCapture, int queryPlayback, unsigned long
3697
        *available, int *xrunOccurred )
3698
{
3699
    PaError result = paNoError;
3700
    unsigned long captureFrames, playbackFrames;
3701
    *xrunOccurred = 0;
3702

    
3703
    assert( queryCapture || queryPlayback );
3704

    
3705
    if( queryCapture )
3706
    {
3707
        assert( self->capture.pcm );
3708
        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->capture, &captureFrames, xrunOccurred ) );
3709
        if( *xrunOccurred )
3710
        {
3711
            goto end;
3712
        }
3713
    }
3714
    if( queryPlayback )
3715
    {
3716
        assert( self->playback.pcm );
3717
        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->playback, &playbackFrames, xrunOccurred ) );
3718
        if( *xrunOccurred )
3719
        {
3720
            goto end;
3721
        }
3722
    }
3723

    
3724
    if( queryCapture && queryPlayback )
3725
    {
3726
        *available = PA_MIN( captureFrames, playbackFrames );
3727
        /*PA_DEBUG(("capture: %lu, playback: %lu, combined: %lu\n", captureFrames, playbackFrames, *available));*/
3728
    }
3729
    else if( queryCapture )
3730
    {
3731
        *available = captureFrames;
3732
    }
3733
    else
3734
    {
3735
        *available = playbackFrames;
3736
    }
3737

    
3738
end:
3739
error:
3740
    return result;
3741
}
3742

    
3743
/** Wait for and report available buffer space from ALSA.
3744
 *
3745
 * Unless ALSA reports a minimum of frames available for I/O, we poll the ALSA filedescriptors for more.
3746
 * Both of these operations can uncover xrun conditions.
3747
 *
3748
 * @concern Xruns Both polling and querying available frames can report an xrun condition.
3749
 *
3750
 * @param framesAvail Return the number of available frames
3751
 * @param xrunOccurred Return whether an xrun has occurred
3752
 */
3753
static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *framesAvail, int *xrunOccurred )
3754
{
3755
    PaError result = paNoError;
3756
    int pollPlayback = self->playback.pcm != NULL, pollCapture = self->capture.pcm != NULL;
3757
    int pollTimeout = self->pollTimeout;
3758
    int xrun = 0, timeouts = 0;
3759
    int pollResults;
3760

    
3761
    assert( self );
3762
    assert( framesAvail );
3763

    
3764
    if( !self->callbackMode )
3765
    {
3766
        /* In blocking mode we will only wait if necessary */
3767
        PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, self->capture.pcm != NULL, self->playback.pcm != NULL,
3768
                    framesAvail, &xrun ) );
3769
        if( xrun )
3770
        {
3771
            goto end;
3772
        }
3773

    
3774
        if( *framesAvail > 0 )
3775
        {
3776
            /* Mark pcms ready from poll */
3777
            if( self->capture.pcm )
3778
                self->capture.ready = 1;
3779
            if( self->playback.pcm )
3780
                self->playback.ready = 1;
3781

    
3782
            goto end;
3783
        }
3784
    }
3785

    
3786
    while( pollPlayback || pollCapture )
3787
    {
3788
        int totalFds = 0;
3789
        struct pollfd *capturePfds = NULL, *playbackPfds = NULL;
3790

    
3791
#ifdef PTHREAD_CANCELED
3792
        pthread_testcancel();
3793
#endif
3794
        if( pollCapture )
3795
        {
3796
            capturePfds = self->pfds;
3797
            PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->capture, capturePfds ) );
3798
            totalFds += self->capture.nfds;
3799
        }
3800
        if( pollPlayback )
3801
        {
3802
            /* self->pfds is in effect an array of fds; if necessary, index past the capture fds */
3803
            playbackPfds = self->pfds + (pollCapture ? self->capture.nfds : 0);
3804
            PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) );
3805
            totalFds += self->playback.nfds;
3806
        }
3807

    
3808
#ifdef PTHREAD_CANCELED
3809
        if( self->callbackMode )
3810
        {
3811
            /* To allow 'Abort' to terminate the callback thread, enable cancelability just for poll() (& disable after) */
3812
            pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL );
3813
        }
3814
#endif
3815

    
3816
        pollResults = poll( self->pfds, totalFds, pollTimeout );
3817

    
3818
#ifdef PTHREAD_CANCELED
3819
        if( self->callbackMode )
3820
        {
3821
            pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL );
3822
        }
3823
#endif
3824

    
3825
        if( pollResults < 0 )
3826
        {
3827
            /*  XXX: Depend on preprocessor condition? */
3828
            if( errno == EINTR )
3829
            {
3830
                /* gdb */
3831
                Pa_Sleep( 1 ); /* avoid hot loop */
3832
                continue;
3833
            }
3834

    
3835
            /* TODO: Add macro for checking system calls */
3836
            PA_ENSURE( paInternalError );
3837
        }
3838
        else if( pollResults == 0 )
3839
        {
3840
           /* Suspended, paused or failed device can provide 0 poll results. To avoid deadloop in such situation
3841
            * we simply run counter 'timeouts' which detects 0 poll result and accumulates. As soon as 2048 timouts (around 2 seconds)
3842
            * are achieved we simply fail function with paTimedOut to notify waiting methods that device is not capable
3843
            * of providing audio data anymore and needs some corresponding recovery action.
3844
            * Note that 'timeouts' is reset to 0 if poll() managed to return non 0 results.
3845
            */
3846

    
3847
            /*PA_DEBUG(( "%s: poll == 0 results, timed out, %d times left\n", __FUNCTION__, 2048 - timeouts ));*/
3848
            ++ timeouts;
3849
            if( timeouts > 1 ) /* sometimes device times out, but normally once, so we do not sleep any time */
3850
            {
3851
                Pa_Sleep( 1 ); /* avoid hot loop */
3852
            }
3853
            /* not else ! */
3854
            if( timeouts >= 2048 ) /* audio device not working, shall return error to notify waiters */
3855
            {
3856
                *framesAvail = 0; /* no frames available for processing */
3857
                xrun = 1; /* try recovering device */
3858

    
3859
                PA_DEBUG(( "%s: poll timed out\n", __FUNCTION__, timeouts ));
3860
                goto end;/*PA_ENSURE( paTimedOut );*/
3861
            }
3862
        }
3863
        else if( pollResults > 0 )
3864
        {
3865
            /* reset timouts counter */
3866
            timeouts = 0;
3867

    
3868
            /* check the return status of our pfds */
3869
            if( pollCapture )
3870
            {
3871
                PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->capture, capturePfds, &pollCapture, &xrun ) );
3872
            }
3873
            if( pollPlayback )
3874
            {
3875
                PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->playback, playbackPfds, &pollPlayback, &xrun ) );
3876
            }
3877
            if( xrun )
3878
            {
3879
                break;
3880
            }
3881
        }
3882

    
3883
        /* @concern FullDuplex If only one of two pcms is ready we may want to compromise between the two.
3884
         * If there is less than half a period's worth of samples left of frames in the other pcm's buffer we will
3885
         * stop polling.
3886
         */
3887
        if( self->capture.pcm && self->playback.pcm )
3888
        {
3889
            if( pollCapture && !pollPlayback )
3890
            {
3891
                PA_ENSURE( ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture ) );
3892
            }
3893
            else if( pollPlayback && !pollCapture )
3894
            {
3895
                PA_ENSURE( ContinuePoll( self, StreamDirection_Out, &pollTimeout, &pollPlayback ) );
3896
            }
3897
        }
3898
    }
3899

    
3900
    if( !xrun )
3901
    {
3902
        /* Get the number of available frames for the pcms that are marked ready.
3903
         * @concern FullDuplex If only one direction is marked ready (from poll), the number of frames available for
3904
         * the other direction is returned. Output is normally preferred over capture however, so capture frames may be
3905
         * discarded to avoid overrun unless paNeverDropInput is specified.
3906
         */
3907
        int captureReady = self->capture.pcm ? self->capture.ready : 0,
3908
            playbackReady = self->playback.pcm ? self->playback.ready : 0;
3909
        PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, captureReady, playbackReady, framesAvail, &xrun ) );
3910

    
3911
        if( self->capture.pcm && self->playback.pcm )
3912
        {
3913
            if( !self->playback.ready && !self->neverDropInput )
3914
            {
3915
                /* Drop input, a period's worth */
3916
                assert( self->capture.ready );
3917
                PaAlsaStreamComponent_EndProcessing( &self->capture, PA_MIN( self->capture.framesPerPeriod,
3918
                            *framesAvail ), &xrun );
3919
                *framesAvail = 0;
3920
                self->capture.ready = 0;
3921
            }
3922
        }
3923
        else if( self->capture.pcm )
3924
            assert( self->capture.ready );
3925
        else
3926
            assert( self->playback.ready );
3927
    }
3928

    
3929
end:
3930
error:
3931
    if( xrun )
3932
    {
3933
        /* Recover from the xrun state */
3934
        PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
3935
        *framesAvail = 0;
3936
    }
3937
    else
3938
    {
3939
        if( 0 != *framesAvail )
3940
        {
3941
            /* If we're reporting frames eligible for processing, one of the handles better be ready */
3942
            PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError );
3943
        }
3944
    }
3945
    *xrunOccurred = xrun;
3946

    
3947
    return result;
3948
}
3949

    
3950
/** Register per-channel ALSA buffer information with buffer processor.
3951
 *
3952
 * Mmapped buffer space is acquired from ALSA, and registered with the buffer processor. Differences between the
3953
 * number of host and user channels is taken into account.
3954
 *
3955
 * @param numFrames On entrance the number of requested frames, on exit the number of contiguously accessible frames.
3956
 */
3957
static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* self, PaUtilBufferProcessor* bp,
3958
        unsigned long* numFrames, int* xrun )
3959
{
3960
    PaError result = paNoError;
3961
    const snd_pcm_channel_area_t *areas, *area;
3962
    void (*setChannel)(PaUtilBufferProcessor *, unsigned int, void *, unsigned int) =
3963
        StreamDirection_In == self->streamDir ? PaUtil_SetInputChannel : PaUtil_SetOutputChannel;
3964
    unsigned char *buffer, *p;
3965
    int i;
3966
    unsigned long framesAvail;
3967

    
3968
    /* This _must_ be called before mmap_begin */
3969
    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( self, &framesAvail, xrun ) );
3970
    if( *xrun )
3971
    {
3972
        *numFrames = 0;
3973
        goto end;
3974
    }
3975

    
3976
    if( self->canMmap )
3977
    {
3978
        ENSURE_( alsa_snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError );
3979
        /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */
3980
        self->channelAreas = (snd_pcm_channel_area_t *)areas;
3981
    }
3982
    else
3983
    {
3984
        unsigned int bufferSize = self->numHostChannels * alsa_snd_pcm_format_size( self->nativeFormat, *numFrames );
3985
        if( bufferSize > self->nonMmapBufferSize )
3986
        {
3987
            self->nonMmapBuffer = realloc( self->nonMmapBuffer, ( self->nonMmapBufferSize = bufferSize ) );
3988
            if( !self->nonMmapBuffer )
3989
            {
3990
                result = paInsufficientMemory;
3991
                goto error;
3992
            }
3993
        }
3994
    }
3995

    
3996
    if( self->hostInterleaved )
3997
    {
3998
        int swidth = alsa_snd_pcm_format_size( self->nativeFormat, 1 );
3999

    
4000
        p = buffer = self->canMmap ? ExtractAddress( areas, self->offset ) : self->nonMmapBuffer;
4001
        for( i = 0; i < self->numUserChannels; ++i )
4002
        {
4003
            /* We're setting the channels up to userChannels, but the stride will be hostChannels samples */
4004
            setChannel( bp, i, p, self->numHostChannels );
4005
            p += swidth;
4006
        }
4007
    }
4008
    else
4009
    {
4010
        if( self->canMmap )
4011
        {
4012
            for( i = 0; i < self->numUserChannels; ++i )
4013
            {
4014
                area = areas + i;
4015
                buffer = ExtractAddress( area, self->offset );
4016
                setChannel( bp, i, buffer, 1 );
4017
            }
4018
        }
4019
        else
4020
        {
4021
            unsigned int buf_per_ch_size = self->nonMmapBufferSize / self->numHostChannels;
4022
            buffer = self->nonMmapBuffer;
4023
            for( i = 0; i < self->numUserChannels; ++i )
4024
            {
4025
                setChannel( bp, i, buffer, 1 );
4026
                buffer += buf_per_ch_size;
4027
            }
4028
        }
4029
    }
4030

    
4031
    if( !self->canMmap && StreamDirection_In == self->streamDir )
4032
    {
4033
        /* Read sound */
4034
        int res;
4035
        if( self->hostInterleaved )
4036
            res = alsa_snd_pcm_readi( self->pcm, self->nonMmapBuffer, *numFrames );
4037
        else
4038
        {
4039
            void *bufs[self->numHostChannels];
4040
            unsigned int buf_per_ch_size = self->nonMmapBufferSize / self->numHostChannels;
4041
            unsigned char *buffer = self->nonMmapBuffer;
4042
            int i;
4043
            for( i = 0; i < self->numHostChannels; ++i )
4044
            {
4045
                bufs[i] = buffer;
4046
                buffer += buf_per_ch_size;
4047
            }
4048
            res = alsa_snd_pcm_readn( self->pcm, bufs, *numFrames );
4049
        }
4050
        if( res == -EPIPE || res == -ESTRPIPE )
4051
        {
4052
            *xrun = 1;
4053
            *numFrames = 0;
4054
        }
4055
    }
4056

    
4057
end:
4058
error:
4059
    return result;
4060
}
4061

    
4062
/** Initiate buffer processing.
4063
 *
4064
 * ALSA buffers are registered with the PA buffer processor and the buffer size (in frames) set.
4065
 *
4066
 * @concern FullDuplex If both directions are being processed, the minimum amount of frames for the two directions is
4067
 * calculated.
4068
 *
4069
 * @param numFrames On entrance the number of available frames, on exit the number of received frames
4070
 * @param xrunOccurred Return whether an xrun has occurred
4071
 */
4072
static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream* self, unsigned long* numFrames, int* xrunOccurred )
4073
{
4074
    PaError result = paNoError;
4075
    unsigned long captureFrames = ULONG_MAX, playbackFrames = ULONG_MAX, commonFrames = 0;
4076
    int xrun = 0;
4077

    
4078
    if( *xrunOccurred )
4079
    {
4080
        *numFrames = 0;
4081
        return result;
4082
    }
4083
    /* If we got here at least one of the pcm's should be marked ready */
4084
    PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError );
4085

    
4086
    /* Extract per-channel ALSA buffer pointers and register them with the buffer processor.
4087
     * It is possible that a direction is not marked ready however, because it is out of sync with the other.
4088
     */
4089
    if( self->capture.pcm && self->capture.ready )
4090
    {
4091
        captureFrames = *numFrames;
4092
        PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->capture, &self->bufferProcessor, &captureFrames,
4093
                    &xrun ) );
4094
    }
4095
    if( self->playback.pcm && self->playback.ready )
4096
    {
4097
        playbackFrames = *numFrames;
4098
        PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->playback, &self->bufferProcessor, &playbackFrames,
4099
                    &xrun ) );
4100
    }
4101
    if( xrun )
4102
    {
4103
        /* Nothing more to do */
4104
        assert( 0 == commonFrames );
4105
        goto end;
4106
    }
4107

    
4108
    commonFrames = PA_MIN( captureFrames, playbackFrames );
4109
    /* assert( commonFrames <= *numFrames ); */
4110
    if( commonFrames > *numFrames )
4111
    {
4112
        /* Hmmm ... how come there are more frames available than we requested!? Blah. */
4113
        PA_DEBUG(( "%s: Common available frames are reported to be more than number requested: %lu, %lu, callbackMode: %d\n", __FUNCTION__,
4114
                    commonFrames, *numFrames, self->callbackMode ));
4115
        if( self->capture.pcm )
4116
        {
4117
            PA_DEBUG(( "%s: captureFrames: %lu, capture.ready: %d\n", __FUNCTION__, captureFrames, self->capture.ready ));
4118
        }
4119
        if( self->playback.pcm )
4120
        {
4121
            PA_DEBUG(( "%s: playbackFrames: %lu, playback.ready: %d\n", __FUNCTION__, playbackFrames, self->playback.ready ));
4122
        }
4123

    
4124
        commonFrames = 0;
4125
        goto end;
4126
    }
4127

    
4128
    /* Inform PortAudio of the number of frames we got.
4129
     * @concern FullDuplex We might be experiencing underflow in either end; if its an input underflow, we go on
4130
     * with output. If its output underflow however, depending on the paNeverDropInput flag, we may want to simply
4131
     * discard the excess input or call the callback with paOutputOverflow flagged.
4132
     */
4133
    if( self->capture.pcm )
4134
    {
4135
        if( self->capture.ready )
4136
        {
4137
            PaUtil_SetInputFrameCount( &self->bufferProcessor, commonFrames );
4138
        }
4139
        else
4140
        {
4141
            /* We have input underflow */
4142
            PaUtil_SetNoInput( &self->bufferProcessor );
4143
        }
4144
    }
4145
    if( self->playback.pcm )
4146
    {
4147
        if( self->playback.ready )
4148
        {
4149
            PaUtil_SetOutputFrameCount( &self->bufferProcessor, commonFrames );
4150
        }
4151
        else
4152
        {
4153
            /* We have output underflow, but keeping input data (paNeverDropInput) */
4154
            assert( self->neverDropInput );
4155
            assert( self->capture.pcm != NULL );
4156
            PA_DEBUG(( "%s: Setting output buffers to NULL\n", __FUNCTION__ ));
4157
            PaUtil_SetNoOutput( &self->bufferProcessor );
4158
        }
4159
    }
4160

    
4161
end:
4162
    *numFrames = commonFrames;
4163
error:
4164
    if( xrun )
4165
    {
4166
        PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
4167
        *numFrames = 0;
4168
    }
4169
    *xrunOccurred = xrun;
4170

    
4171
    return result;
4172
}
4173

    
4174
/** Callback thread's function.
4175
 *
4176
 * Roughly, the workflow can be described in the following way: The number of available frames that can be processed
4177
 * directly is obtained from ALSA, we then request as much directly accessible memory as possible within this amount
4178
 * from ALSA. The buffer memory is registered with the PA buffer processor and processing is carried out with
4179
 * PaUtil_EndBufferProcessing. Finally, the number of processed frames is reported to ALSA. The processing can
4180
 * happen in several iterations untill we have consumed the known number of available frames (or an xrun is detected).
4181
 */
4182
static void *CallbackThreadFunc( void *userData )
4183
{
4184
    PaError result = paNoError;
4185
    PaAlsaStream *stream = (PaAlsaStream*) userData;
4186
    PaStreamCallbackTimeInfo timeInfo = {0, 0, 0};
4187
    snd_pcm_sframes_t startThreshold = 0;
4188
    int callbackResult = paContinue;
4189
    PaStreamCallbackFlags cbFlags = 0;  /* We might want to keep state across iterations */
4190
    int streamStarted = 0;
4191

    
4192
    assert( stream );
4193
    /* Not implemented */
4194
    assert( !stream->primeBuffers );
4195

    
4196
    /* Execute OnExit when exiting */
4197
    pthread_cleanup_push( &OnExit, stream );
4198
#ifdef PTHREAD_CANCELED
4199
    /* 'Abort' will use thread cancellation to terminate the callback thread, but the Alsa-lib functions
4200
     * are NOT cancel-safe, (and can end up in an inconsistent state).  So, disable cancelability for
4201
     * the thread here, and just re-enable it for the poll() in PaAlsaStream_WaitForFrames(). */
4202
    pthread_testcancel();
4203
    pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL );
4204
#endif
4205

    
4206
    /* @concern StreamStart If the output is being primed the output pcm needs to be prepared, otherwise the
4207
     * stream is started immediately. The latter involves signaling the waiting main thread.
4208
     */
4209
    if( stream->primeBuffers )
4210
    {
4211
        snd_pcm_sframes_t avail;
4212

    
4213
        if( stream->playback.pcm )
4214
            ENSURE_( alsa_snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
4215
        if( stream->capture.pcm && !stream->pcmsSynced )
4216
            ENSURE_( alsa_snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );
4217

    
4218
        /* We can't be certain that the whole ring buffer is available for priming, but there should be
4219
         * at least one period */
4220
        avail = alsa_snd_pcm_avail_update( stream->playback.pcm );
4221
        startThreshold = avail - (avail % stream->playback.framesPerPeriod);
4222
        assert( startThreshold >= stream->playback.framesPerPeriod );
4223
    }
4224
    else
4225
    {
4226
        PA_ENSURE( PaUnixThread_PrepareNotify( &stream->thread ) );
4227
        /* Buffer will be zeroed */
4228
        PA_ENSURE( AlsaStart( stream, 0 ) );
4229
        PA_ENSURE( PaUnixThread_NotifyParent( &stream->thread ) );
4230

    
4231
        streamStarted = 1;
4232
    }
4233

    
4234
    while( 1 )
4235
    {
4236
        unsigned long framesAvail, framesGot;
4237
        int xrun = 0;
4238

    
4239
#ifdef PTHREAD_CANCELED
4240
        pthread_testcancel();
4241
#endif
4242

    
4243
        /* @concern StreamStop if the main thread has requested a stop and the stream has not been effectively
4244
         * stopped we signal this condition by modifying callbackResult (we'll want to flush buffered output).
4245
         */
4246
        if( PaUnixThread_StopRequested( &stream->thread ) && paContinue == callbackResult )
4247
        {
4248
            PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
4249
            callbackResult = paComplete;
4250
        }
4251

    
4252
        if( paContinue != callbackResult )
4253
        {
4254
            stream->callbackAbort = ( paAbort == callbackResult );
4255
            if( stream->callbackAbort ||
4256
                    /** @concern BlockAdaption: Go on if adaption buffers are empty */
4257
                    PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )
4258
            {
4259
                goto end;
4260
            }
4261

    
4262
            PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ ));
4263
            /* There is still buffered output that needs to be processed */
4264
        }
4265

    
4266
        /* Wait for data to become available, this comes down to polling the ALSA file descriptors untill we have
4267
         * a number of available frames.
4268
         */
4269
        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
4270
        if( xrun )
4271
        {
4272
            assert( 0 == framesAvail );
4273
            continue;
4274

    
4275
            /* XXX: Report xruns to the user? A situation is conceivable where the callback is never invoked due
4276
             * to constant xruns, it might be desirable to notify the user of this.
4277
             */
4278
        }
4279

    
4280
        /* Consume buffer space. Once we have a number of frames available for consumption we must retrieve the
4281
         * mmapped buffers from ALSA, this is contiguously accessible memory however, so we may receive smaller
4282
         * portions at a time than is available as a whole. Therefore we should be prepared to process several
4283
         * chunks successively. The buffers are passed to the PA buffer processor.
4284
         */
4285
        while( framesAvail > 0 )
4286
        {
4287
            xrun = 0;
4288

    
4289
            /** @concern Xruns Under/overflows are to be reported to the callback */
4290
            if( stream->underrun > 0.0 )
4291
            {
4292
                cbFlags |= paOutputUnderflow;
4293
                stream->underrun = 0.0;
4294
            }
4295
            if( stream->overrun > 0.0 )
4296
            {
4297
                cbFlags |= paInputOverflow;
4298
                stream->overrun = 0.0;
4299
            }
4300
            if( stream->capture.pcm && stream->playback.pcm )
4301
            {
4302
                /** @concern FullDuplex It's possible that only one direction is being processed to avoid an
4303
                 * under- or overflow, this should be reported correspondingly */
4304
                if( !stream->capture.ready )
4305
                {
4306
                    cbFlags |= paInputUnderflow;
4307
                    PA_DEBUG(( "%s: Input underflow\n", __FUNCTION__ ));
4308
                }
4309
                else if( !stream->playback.ready )
4310
                {
4311
                    cbFlags |= paOutputOverflow;
4312
                    PA_DEBUG(( "%s: Output overflow\n", __FUNCTION__ ));
4313
                }
4314
            }
4315

    
4316
#if 0
4317
            CallbackUpdate( &stream->threading );
4318
#endif
4319

    
4320
            CalculateTimeInfo( stream, &timeInfo );
4321
            PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags );
4322
            cbFlags = 0;
4323

    
4324
            /* CPU load measurement should include processing activity external to the stream callback */
4325
            PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
4326

    
4327
            framesGot = framesAvail;
4328
            if( paUtilFixedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode )
4329
            {
4330
                /* We've committed to a fixed host buffer size, stick to that */
4331
                framesGot = framesGot >= stream->maxFramesPerHostBuffer ? stream->maxFramesPerHostBuffer : 0;
4332
            }
4333
            else
4334
            {
4335
                /* We've committed to an upper bound on the size of host buffers */
4336
                assert( paUtilBoundedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode );
4337
                framesGot = PA_MIN( framesGot, stream->maxFramesPerHostBuffer );
4338
            }
4339
            PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
4340
            /* Check the host buffer size against the buffer processor configuration */
4341
            framesAvail -= framesGot;
4342

    
4343
            if( framesGot > 0 )
4344
            {
4345
                assert( !xrun );
4346
                PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
4347
                PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
4348
            }
4349
            PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot );
4350

    
4351
            if( 0 == framesGot )
4352
            {
4353
                /* Go back to polling for more frames */
4354
                break;
4355
            }
4356

    
4357
            if( paContinue != callbackResult )
4358
                break;
4359
        }
4360
    }
4361

    
4362
end:
4363
    ; /* Hack to fix "label at end of compound statement" error caused by pthread_cleanup_pop(1) macro. */
4364
    /* Match pthread_cleanup_push */
4365
    pthread_cleanup_pop( 1 );
4366

    
4367
    PA_DEBUG(( "%s: Thread %d exiting\n ", __FUNCTION__, pthread_self() ));
4368
    PaUnixThreading_EXIT( result );
4369

    
4370
error:
4371
    PA_DEBUG(( "%s: Thread %d is canceled due to error %d\n ", __FUNCTION__, pthread_self(), result ));
4372
    goto end;
4373
}
4374

    
4375
/* Blocking interface */
4376

    
4377
static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames )
4378
{
4379
    PaError result = paNoError;
4380
    PaAlsaStream *stream = (PaAlsaStream*)s;
4381
    unsigned long framesGot, framesAvail;
4382
    void *userBuffer;
4383
    snd_pcm_t *save = stream->playback.pcm;
4384

    
4385
    assert( stream );
4386

    
4387
    PA_UNLESS( stream->capture.pcm, paCanNotReadFromAnOutputOnlyStream );
4388

    
4389
    /* Disregard playback */
4390
    stream->playback.pcm = NULL;
4391

    
4392
    if( stream->overrun > 0. )
4393
    {
4394
        result = paInputOverflowed;
4395
        stream->overrun = 0.0;
4396
    }
4397

    
4398
    if( stream->capture.userInterleaved )
4399
    {
4400
        userBuffer = buffer;
4401
    }
4402
    else
4403
    {
4404
        /* Copy channels into local array */
4405
        userBuffer = stream->capture.userBuffers;
4406
        memcpy( userBuffer, buffer, sizeof (void *) * stream->capture.numUserChannels );
4407
    }
4408

    
4409
    /* Start stream if in prepared state */
4410
    if( alsa_snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED )
4411
    {
4412
        ENSURE_( alsa_snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );
4413
    }
4414

    
4415
    while( frames > 0 )
4416
    {
4417
        int xrun = 0;
4418
        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
4419
        framesGot = PA_MIN( framesAvail, frames );
4420

    
4421
        PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
4422
        if( framesGot > 0 )
4423
        {
4424
            framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot );
4425
            PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
4426
            frames -= framesGot;
4427
        }
4428
    }
4429

    
4430
end:
4431
    stream->playback.pcm = save;
4432
    return result;
4433
error:
4434
    goto end;
4435
}
4436

    
4437
static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames )
4438
{
4439
    PaError result = paNoError;
4440
    signed long err;
4441
    PaAlsaStream *stream = (PaAlsaStream*)s;
4442
    snd_pcm_uframes_t framesGot, framesAvail;
4443
    const void *userBuffer;
4444
    snd_pcm_t *save = stream->capture.pcm;
4445

    
4446
    assert( stream );
4447

    
4448
    PA_UNLESS( stream->playback.pcm, paCanNotWriteToAnInputOnlyStream );
4449

    
4450
    /* Disregard capture */
4451
    stream->capture.pcm = NULL;
4452

    
4453
    if( stream->underrun > 0. )
4454
    {
4455
        result = paOutputUnderflowed;
4456
        stream->underrun = 0.0;
4457
    }
4458

    
4459
    if( stream->playback.userInterleaved )
4460
        userBuffer = buffer;
4461
    else /* Copy channels into local array */
4462
    {
4463
        userBuffer = stream->playback.userBuffers;
4464
        memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback.numUserChannels );
4465
    }
4466

    
4467
    while( frames > 0 )
4468
    {
4469
        int xrun = 0;
4470
        snd_pcm_uframes_t hwAvail;
4471

    
4472
        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
4473
        framesGot = PA_MIN( framesAvail, frames );
4474

    
4475
        PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
4476
        if( framesGot > 0 )
4477
        {
4478
            framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot );
4479
            PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
4480
            frames -= framesGot;
4481
        }
4482

    
4483
        /* Start stream after one period of samples worth */
4484

    
4485
        /* Frames residing in buffer */
4486
        PA_ENSURE( err = GetStreamWriteAvailable( stream ) );
4487
        framesAvail = err;
4488
        hwAvail = stream->playback.alsaBufferSize - framesAvail;
4489

    
4490
        if( alsa_snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED &&
4491
                hwAvail >= stream->playback.framesPerPeriod )
4492
        {
4493
            ENSURE_( alsa_snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
4494
        }
4495
    }
4496

    
4497
end:
4498
    stream->capture.pcm = save;
4499
    return result;
4500
error:
4501
    goto end;
4502
}
4503

    
4504
/* Return frames available for reading. In the event of an overflow, the capture pcm will be restarted */
4505
static signed long GetStreamReadAvailable( PaStream* s )
4506
{
4507
    PaError result = paNoError;
4508
    PaAlsaStream *stream = (PaAlsaStream*)s;
4509
    unsigned long avail;
4510
    int xrun;
4511

    
4512
    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );
4513
    if( xrun )
4514
    {
4515
        PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );
4516
        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );
4517
        if( xrun )
4518
            PA_ENSURE( paInputOverflowed );
4519
    }
4520

    
4521
    return (signed long)avail;
4522

    
4523
error:
4524
    return result;
4525
}
4526

    
4527
static signed long GetStreamWriteAvailable( PaStream* s )
4528
{
4529
    PaError result = paNoError;
4530
    PaAlsaStream *stream = (PaAlsaStream*)s;
4531
    unsigned long avail;
4532
    int xrun;
4533

    
4534
    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->playback, &avail, &xrun ) );
4535
    if( xrun )
4536
    {
4537
        snd_pcm_sframes_t savail;
4538

    
4539
        PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );
4540
        savail = alsa_snd_pcm_avail_update( stream->playback.pcm );
4541

    
4542
        /* savail should not contain -EPIPE now, since PaAlsaStream_HandleXrun will only prepare the pcm */
4543
        ENSURE_( savail, paUnanticipatedHostError );
4544

    
4545
        avail = (unsigned long) savail;
4546
    }
4547

    
4548
    return (signed long)avail;
4549

    
4550
error:
4551
    return result;
4552
}
4553

    
4554
/* Extensions */
4555

    
4556
void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info )
4557
{
4558
    info->size = sizeof (PaAlsaStreamInfo);
4559
    info->hostApiType = paALSA;
4560
    info->version = 1;
4561
    info->deviceString = NULL;
4562
}
4563

    
4564
void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable )
4565
{
4566
    PaAlsaStream *stream = (PaAlsaStream *) s;
4567
    stream->rtSched = enable;
4568
}
4569

    
4570
#if 0
4571
void PaAlsa_EnableWatchdog( PaStream *s, int enable )
4572
{
4573
    PaAlsaStream *stream = (PaAlsaStream *) s;
4574
    stream->thread.useWatchdog = enable;
4575
}
4576
#endif
4577

    
4578
static PaError GetAlsaStreamPointer( PaStream* s, PaAlsaStream** stream )
4579
{
4580
    PaError result = paNoError;
4581
    PaUtilHostApiRepresentation* hostApi;
4582
    PaAlsaHostApiRepresentation* alsaHostApi;
4583

    
4584
    PA_ENSURE( PaUtil_ValidateStreamPointer( s ) );
4585
    PA_ENSURE( PaUtil_GetHostApiRepresentation( &hostApi, paALSA ) );
4586
    alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
4587

    
4588
    PA_UNLESS( PA_STREAM_REP( s )->streamInterface == &alsaHostApi->callbackStreamInterface
4589
            || PA_STREAM_REP( s )->streamInterface == &alsaHostApi->blockingStreamInterface,
4590
        paIncompatibleStreamHostApi );
4591

    
4592
    *stream = (PaAlsaStream*)s;
4593
error:
4594
    return paNoError;
4595
}
4596

    
4597
PaError PaAlsa_GetStreamInputCard( PaStream* s, int* card )
4598
{
4599
    PaAlsaStream *stream;
4600
    PaError result = paNoError;
4601
    snd_pcm_info_t* pcmInfo;
4602

    
4603
    PA_ENSURE( GetAlsaStreamPointer( s, &stream ) );
4604

    
4605
    /* XXX: More descriptive error? */
4606
    PA_UNLESS( stream->capture.pcm, paDeviceUnavailable );
4607

    
4608
    alsa_snd_pcm_info_alloca( &pcmInfo );
4609
    PA_ENSURE( alsa_snd_pcm_info( stream->capture.pcm, pcmInfo ) );
4610
    *card = alsa_snd_pcm_info_get_card( pcmInfo );
4611

    
4612
error:
4613
    return result;
4614
}
4615

    
4616
PaError PaAlsa_GetStreamOutputCard( PaStream* s, int* card )
4617
{
4618
    PaAlsaStream *stream;
4619
    PaError result = paNoError;
4620
    snd_pcm_info_t* pcmInfo;
4621

    
4622
    PA_ENSURE( GetAlsaStreamPointer( s, &stream ) );
4623

    
4624
    /* XXX: More descriptive error? */
4625
    PA_UNLESS( stream->playback.pcm, paDeviceUnavailable );
4626

    
4627
    alsa_snd_pcm_info_alloca( &pcmInfo );
4628
    PA_ENSURE( alsa_snd_pcm_info( stream->playback.pcm, pcmInfo ) );
4629
    *card = alsa_snd_pcm_info_get_card( pcmInfo );
4630

    
4631
error:
4632
    return result;
4633
}
4634

    
4635
PaError PaAlsa_SetRetriesBusy( int retries )
4636
{
4637
    busyRetries_ = retries;
4638
    return paNoError;
4639
}