pa_linux_alsa.c (173649B)
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, ×tamp ); 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 }