Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

ALSA: Further rework:

* Get rid of non-async (ie tick task) mode due to inherent brokenness
* Get rid of nonblock mode; we never write if buffers aren't sufficient
* Move driver init into pcm_open() instead of pcm_init()
* Much better underrun handling
* Better error handling in some situations
* Add in recording functionality
* Use smaller audio buffers to avoid glitching
* Don't start audio buffer with silence
* Allow device name to be overridden by target

Recording portions based on work done by Lorenzo Miori in g#633

Change-Id: I0197bdc1749c28109eb79def1e6a3e1d62d8cef3

+370 -192
+364 -192
firmware/target/hosted/pcm-alsa.c
··· 19 19 * 20 20 ****************************************************************************/ 21 21 22 - 23 22 /* 24 23 * Based, but heavily modified, on the example given at 25 24 * http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_8c-example.html 26 25 * 27 - * This driver uses the so-called unsafe async callback method and hardcoded device 28 - * names. It fails when the audio device is busy by other apps. 26 + * This driver uses the so-called unsafe async callback method. 29 27 * 30 28 * To make the async callback safer, an alternative stack is installed, since 31 - * it's run from a signal hanlder (which otherwise uses the user stack). If 32 - * tick tasks are run from a signal handler too, please install 33 - * an alternative stack for it too. 29 + * it's run from a signal hanlder (which otherwise uses the user stack). 34 30 * 35 - * TODO: Rewrite this to do it properly with multithreading 36 - * 37 - * Alternatively, a version using polling in a tick task is provided. While 38 - * supposedly safer, it appears to use more CPU (however I didn't measure it 39 - * accurately, only looked at htop). At least, in this mode the "default" 40 - * device works which doesnt break with other apps running. 31 + * TODO: Rewrite this to properly use multithreading and/or direct mmap() 41 32 */ 42 33 43 34 #include "autoconf.h" ··· 69 60 * default doesnt seem to work with async callback but doesn't break 70 61 * with multple applications running */ 71 62 #define DEFAULT_PLAYBACK_DEVICE "plughw:0,0" 72 - 73 - #define USE_ASYNC_CALLBACK 63 + #define DEFAULT_CAPTURE_DEVICE "default" 74 64 75 65 static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */ 76 66 #if defined(SONY_NWZ_LINUX) || defined(HAVE_FIIO_LINUX_CODEC) ··· 93 83 static const void *pcm_data = 0; 94 84 static size_t pcm_size = 0; 95 85 96 - #ifdef USE_ASYNC_CALLBACK 97 - static snd_async_handler_t *ahandler; 86 + static snd_async_handler_t *ahandler = NULL; 98 87 static pthread_mutex_t pcm_mtx; 99 88 static char signal_stack[SIGSTKSZ]; 100 - #else 101 - static int recursion; 89 + 90 + static const char *playback_dev = DEFAULT_PLAYBACK_DEVICE; 91 + 92 + #ifdef HAVE_RECORDING 93 + static void *pcm_data_rec = DEFAULT_CAPTURE_DEVICE; 94 + static const char *capture_dev = NULL; 95 + static snd_pcm_stream_t current_alsa_mode; /* SND_PCM_STREAM_PLAYBACK / _CAPTURE */ 96 + #endif 97 + 98 + static const char *current_alsa_device; 99 + 100 + void pcm_alsa_set_playback_device(const char *device) 101 + { 102 + playback_dev = device; 103 + } 104 + 105 + #ifdef HAVE_RECORDING 106 + void pcm_alsa_set_capture_device(const char *device) 107 + { 108 + capture_dev = device; 109 + } 102 110 #endif 103 111 104 112 static int set_hwparams(snd_pcm_t *handle) ··· 108 116 snd_pcm_hw_params_t *params; 109 117 snd_pcm_hw_params_malloc(&params); 110 118 111 - /* Size playback buffers based on sample rate */ 119 + /* Size playback buffers based on sample rate. 120 + Note these are in FRAMES, and are sized to be about 10ms 121 + for the buffer and 2.5ms for the period */ 112 122 if (pcm_sampr > SAMPR_96) { 113 - buffer_size = MIX_FRAME_SAMPLES * 32 * 4; /* ~64k */ 114 - period_size = MIX_FRAME_SAMPLES * 4 * 4; /* ~16k */ 123 + buffer_size = MIX_FRAME_SAMPLES * 16 * 4; /* 32k */ 124 + period_size = MIX_FRAME_SAMPLES * 4 * 4; /* 4k */ 115 125 } else if (pcm_sampr > SAMPR_48) { 116 - buffer_size = MIX_FRAME_SAMPLES * 32 * 2; /* ~32k */ 117 - period_size = MIX_FRAME_SAMPLES * 4 * 2; /* ~8k */ 126 + buffer_size = MIX_FRAME_SAMPLES * 16 * 2; /* 16k */ 127 + period_size = MIX_FRAME_SAMPLES * 4 * 2; /* 2k */ 118 128 } else { 119 - buffer_size = MIX_FRAME_SAMPLES * 32; /* ~16k */ 120 - period_size = MIX_FRAME_SAMPLES * 4; /* ~4k */ 129 + buffer_size = MIX_FRAME_SAMPLES * 16; /* 4k */ 130 + period_size = MIX_FRAME_SAMPLES * 4; /* 1k */ 121 131 } 122 132 123 133 /* choose all parameters */ 124 134 err = snd_pcm_hw_params_any(handle, params); 125 135 if (err < 0) 126 136 { 127 - panicf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); 137 + panicf("Broken configuration for playback: no configurations available: %s", snd_strerror(err)); 128 138 goto error; 129 139 } 130 140 /* set the interleaved read/write format */ 131 141 err = snd_pcm_hw_params_set_access(handle, params, access_); 132 142 if (err < 0) 133 143 { 134 - panicf("Access type not available for playback: %s\n", snd_strerror(err)); 144 + panicf("Access type not available for playback: %s", snd_strerror(err)); 135 145 goto error; 136 146 } 137 147 /* set the sample format */ 138 148 err = snd_pcm_hw_params_set_format(handle, params, format); 139 149 if (err < 0) 140 150 { 141 - logf("Sample format not available for playback: %s\n", snd_strerror(err)); 151 + logf("Sample format not available for playback: %s", snd_strerror(err)); 142 152 goto error; 143 153 } 144 154 /* set the count of channels */ 145 155 err = snd_pcm_hw_params_set_channels(handle, params, channels); 146 156 if (err < 0) 147 157 { 148 - logf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err)); 158 + logf("Channels count (%i) not available for playbacks: %s", channels, snd_strerror(err)); 149 159 goto error; 150 160 } 151 161 /* set the stream rate */ ··· 153 163 err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0); 154 164 if (err < 0) 155 165 { 156 - logf("Rate %iHz not available for playback: %s\n", pcm_sampr, snd_strerror(err)); 166 + logf("Rate %luHz not available for playback: %s", pcm_sampr, snd_strerror(err)); 157 167 goto error; 158 168 } 159 169 real_sample_rate = srate; 160 170 if (real_sample_rate != pcm_sampr) 161 171 { 162 - logf("Rate doesn't match (requested %iHz, get %iHz)\n", pcm_sampr, real_sample_rate); 172 + logf("Rate doesn't match (requested %luHz, get %dHz)", pcm_sampr, real_sample_rate); 163 173 err = -EINVAL; 164 174 goto error; 165 175 } ··· 168 178 err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size); 169 179 if (err < 0) 170 180 { 171 - logf("Unable to set buffer size %ld for playback: %s\n", buffer_size, snd_strerror(err)); 181 + logf("Unable to set buffer size %ld for playback: %s", buffer_size, snd_strerror(err)); 172 182 goto error; 173 183 } 174 184 ··· 176 186 err = snd_pcm_hw_params_set_period_size_near (handle, params, &period_size, NULL); 177 187 if (err < 0) 178 188 { 179 - logf("Unable to set period size %ld for playback: %s\n", period_size, snd_strerror(err)); 189 + logf("Unable to set period size %ld for playback: %s", period_size, snd_strerror(err)); 180 190 goto error; 181 191 } 182 192 ··· 187 197 err = snd_pcm_hw_params(handle, params); 188 198 if (err < 0) 189 199 { 190 - logf("Unable to set hw params for playback: %s\n", snd_strerror(err)); 200 + logf("Unable to set hw params for playback: %s", snd_strerror(err)); 191 201 goto error; 192 202 } 193 203 ··· 209 219 err = snd_pcm_sw_params_current(handle, swparams); 210 220 if (err < 0) 211 221 { 212 - logf("Unable to determine current swparams for playback: %s\n", snd_strerror(err)); 222 + logf("Unable to determine current swparams for playback: %s", snd_strerror(err)); 213 223 goto error; 214 224 } 215 225 /* start the transfer when the buffer is half full */ 216 226 err = snd_pcm_sw_params_set_start_threshold(handle, swparams, buffer_size / 2); 217 227 if (err < 0) 218 228 { 219 - logf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err)); 229 + logf("Unable to set start threshold mode for playback: %s", snd_strerror(err)); 220 230 goto error; 221 231 } 222 232 /* allow the transfer when at least period_size samples can be processed */ 223 233 err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size); 224 234 if (err < 0) 225 235 { 226 - logf("Unable to set avail min for playback: %s\n", snd_strerror(err)); 236 + logf("Unable to set avail min for playback: %s", snd_strerror(err)); 227 237 goto error; 228 238 } 229 239 /* write the parameters to the playback device */ 230 240 err = snd_pcm_sw_params(handle, swparams); 231 241 if (err < 0) 232 242 { 233 - logf("Unable to set sw params for playback: %s\n", snd_strerror(err)); 243 + logf("Unable to set sw params for playback: %s", snd_strerror(err)); 234 244 goto error; 235 245 } 236 246 ··· 273 283 dig_vol_mult_l = 1 << vol_shift_l | 1 << (vol_shift_l - 2); 274 284 else 275 285 dig_vol_mult_l = 1 << vol_shift_l | 1 << (vol_shift_l - 1); 276 - logf("l: %d dB -> factor = %d\n", vol_db_l - 48, dig_vol_mult_l); 286 + logf("l: %d dB -> factor = %d", vol_db_l - 48, dig_vol_mult_l); 277 287 if(r_r == 0) 278 288 dig_vol_mult_r = 1 << vol_shift_r; 279 289 else if(r_r == 1) 280 290 dig_vol_mult_r = 1 << vol_shift_r | 1 << (vol_shift_r - 2); 281 291 else 282 292 dig_vol_mult_r = 1 << vol_shift_r | 1 << (vol_shift_r - 1); 283 - logf("r: %d dB -> factor = %d\n", vol_db_r - 48, dig_vol_mult_r); 293 + logf("r: %d dB -> factor = %d", vol_db_r - 48, dig_vol_mult_r); 284 294 } 285 295 286 296 /* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */ 287 - static bool fill_frames(void) 297 + static bool copy_frames(bool first) 288 298 { 289 - ssize_t copy_n, frames_left = period_size; 299 + ssize_t nframes, frames_left = period_size; 290 300 bool new_buffer = false; 291 301 292 302 while (frames_left > 0) ··· 294 304 if (!pcm_size) 295 305 { 296 306 new_buffer = true; 297 - if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, &pcm_data, 298 - &pcm_size)) 307 + #ifdef HAVE_RECORDING 308 + switch (current_alsa_mode) 299 309 { 300 - return false; 310 + case SND_PCM_STREAM_PLAYBACK: 311 + #endif 312 + if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, &pcm_data, &pcm_size)) 313 + { 314 + return false; 315 + } 316 + #ifdef HAVE_RECORDING 317 + break; 318 + case SND_PCM_STREAM_CAPTURE: 319 + if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, &pcm_data, &pcm_size)) 320 + { 321 + return false; 322 + } 323 + break; 324 + default: 325 + break; 301 326 } 327 + #endif 302 328 } 303 329 330 + /* Note: This assumes stereo 16-bit */ 304 331 if (pcm_size % 4) 305 332 panicf("Wrong pcm_size"); 306 333 /* the compiler will optimize this test away */ 307 - copy_n = MIN((ssize_t)pcm_size/4, frames_left); 334 + nframes = MIN((ssize_t)pcm_size/4, frames_left); 308 335 if (format == SND_PCM_FORMAT_S32_LE) 309 336 { 310 337 /* We have to convert 16-bit to 32-bit, the need to multiply the 311 338 * sample by some value so the sound is not too low */ 312 339 const short *pcm_ptr = pcm_data; 313 340 sample_t *sample_ptr = &frames[2*(period_size-frames_left)]; 314 - for (int i = 0; i < copy_n; i++) 341 + for (int i = 0; i < nframes; i++) 315 342 { 316 343 *sample_ptr++ = *pcm_ptr++ * dig_vol_mult_l; 317 344 *sample_ptr++ = *pcm_ptr++ * dig_vol_mult_r; ··· 319 346 } 320 347 else 321 348 { 322 - /* Rockbox and PCM have same format: memcopy */ 323 - memcpy(&frames[2*(period_size-frames_left)], pcm_data, copy_n * 4); 349 + #ifdef HAVE_RECORDING 350 + switch (current_alsa_mode) 351 + { 352 + case SND_PCM_STREAM_PLAYBACK: 353 + #endif 354 + /* Rockbox and PCM have same format: memcopy */ 355 + memcpy(&frames[2*(period_size-frames_left)], pcm_data, nframes * 4); 356 + #ifdef HAVE_RECORDING 357 + break; 358 + case SND_PCM_STREAM_CAPTURE: 359 + memcpy(pcm_data_rec, &frames[2*(period_size-frames_left)], nframes * 4); 360 + break; 361 + default: 362 + break; 363 + } 364 + #endif 324 365 } 325 - pcm_data += copy_n*4; 326 - pcm_size -= copy_n*4; 327 - frames_left -= copy_n; 366 + pcm_data += nframes*4; 367 + pcm_size -= nframes*4; 368 + frames_left -= nframes; 328 369 329 - if (new_buffer) 370 + if (new_buffer && !first) 330 371 { 331 372 new_buffer = false; 332 - pcm_play_dma_status_callback(PCM_DMAST_STARTED); 373 + #ifdef HAVE_RECORDING 374 + switch (current_alsa_mode) 375 + { 376 + case SND_PCM_STREAM_PLAYBACK: 377 + #endif 378 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 379 + #ifdef HAVE_RECORDING 380 + break; 381 + case SND_PCM_STREAM_CAPTURE: 382 + pcm_rec_dma_status_callback(PCM_DMAST_STARTED); 383 + break; 384 + default: 385 + break; 386 + } 387 + #endif 333 388 } 334 389 } 335 390 336 391 return true; 337 392 } 338 393 339 - #ifdef USE_ASYNC_CALLBACK 340 394 static void async_callback(snd_async_handler_t *ahandler) 341 395 { 396 + int err; 397 + 398 + if (!ahandler) return; 399 + 342 400 snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler); 401 + 402 + if (!handle) return; 343 403 344 404 if (pthread_mutex_trylock(&pcm_mtx) != 0) 345 405 return; 346 - #else 347 - static void pcm_tick(void) 348 - { 349 - if (snd_pcm_state(handle) != SND_PCM_STATE_RUNNING) 350 - return; 406 + 407 + snd_pcm_state_t state = snd_pcm_state(handle); 408 + 409 + if (state == SND_PCM_STATE_XRUN) 410 + { 411 + logf("underrun!"); 412 + err = snd_pcm_recover(handle, -EPIPE, 0); 413 + if (err < 0) { 414 + logf("XRUN Recovery error: %s", snd_strerror(err)); 415 + goto abort; 416 + } 417 + } 418 + else if (state == SND_PCM_STATE_DRAINING) 419 + { 420 + logf("draining..."); 421 + goto abort; 422 + } 423 + else if (state == SND_PCM_STATE_SETUP) 424 + { 425 + goto abort; 426 + } 427 + 428 + #ifdef HAVE_RECORDING 429 + if (current_alsa_mode == SND_PCM_STREAM_PLAYBACK) 430 + { 351 431 #endif 352 - 353 - while (snd_pcm_avail_update(handle) >= period_size) 432 + while (snd_pcm_avail_update(handle) >= period_size) 433 + { 434 + if (copy_frames(false)) 435 + { 436 + err = snd_pcm_writei(handle, frames, period_size); 437 + if (err < 0 && err != period_size && err != -EAGAIN) 438 + { 439 + logf("Write error: written %i expected %li", err, period_size); 440 + break; 441 + } 442 + } 443 + else 444 + { 445 + logf("%s: No Data (%d).", __func__, state); 446 + break; 447 + } 448 + } 449 + #ifdef HAVE_RECORDING 450 + } 451 + else if (current_alsa_mode == SND_PCM_STREAM_CAPTURE) 354 452 { 355 - if (fill_frames()) 453 + while (snd_pcm_avail_update(handle) >= period_size) 356 454 { 357 - int err = snd_pcm_writei(handle, frames, period_size); 455 + int err = snd_pcm_readi(handle, frames, period_size); 358 456 if (err < 0 && err != period_size && err != -EAGAIN) 359 457 { 360 - logf("Write error: written %i expected %li\n", err, period_size); 458 + logf("Read error: read %i expected %li", err, period_size); 459 + break; 460 + } 461 + 462 + /* start the fake DMA transfer */ 463 + if (!copy_frames(false)) 464 + { 465 + /* do not spam logf */ 466 + /* logf("%s: No Data.", __func__); */ 361 467 break; 362 468 } 363 469 } 364 - else 365 - { 366 - logf("%s: No Data.\n", __func__); 367 - break; 470 + } 471 + #endif 472 + 473 + if (snd_pcm_state(handle) == SND_PCM_STATE_PREPARED) 474 + { 475 + err = snd_pcm_start(handle); 476 + if (err < 0) { 477 + logf("cb start error: %s", snd_strerror(err)); 478 + goto abort; 368 479 } 369 480 } 370 - #ifdef USE_ASYNC_CALLBACK 481 + 482 + abort: 371 483 pthread_mutex_unlock(&pcm_mtx); 484 + } 485 + 486 + static void close_hwdev(void) 487 + { 488 + logf("closedev (%p)", handle); 489 + 490 + if (handle) { 491 + snd_pcm_drain(handle); 492 + #ifdef AUDIOHW_MUTE_ON_PAUSE 493 + audiohw_mute(true); 494 + #endif 495 + if (ahandler) { 496 + snd_async_del_handler(ahandler); 497 + ahandler = NULL; 498 + } 499 + snd_pcm_close(handle); 500 + 501 + handle = NULL; 502 + } 503 + current_alsa_device = NULL; 504 + 505 + #ifdef HAVE_RECORDING 506 + pcm_data_rec = NULL; 372 507 #endif 373 508 } 374 509 375 - static int async_rw(snd_pcm_t *handle) 510 + static void alsadev_cleanup(void) 511 + { 512 + free(frames); 513 + frames = NULL; 514 + close_hwdev(); 515 + } 516 + 517 + static void open_hwdev(const char *device, snd_pcm_stream_t mode) 376 518 { 377 519 int err; 378 - snd_pcm_sframes_t sample_size; 379 - sample_t *samples; 520 + 521 + logf("opendev %s (%p)", device, handle); 522 + 523 + if (handle && device == current_alsa_device 524 + #ifdef HAVE_RECORDING 525 + && current_alsa_mode == mode 526 + #endif 527 + ) 528 + { 529 + return; 530 + } 531 + 532 + /* Close old handle */ 533 + close_hwdev(); 534 + 535 + if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) 536 + { 537 + panicf("%s(): Cannot open device %s: %s", __func__, device, snd_strerror(err)); 538 + } 539 + last_sample_rate = 0; 540 + 541 + pthread_mutexattr_t attr; 542 + pthread_mutexattr_init(&attr); 543 + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 544 + pthread_mutex_init(&pcm_mtx, &attr); 380 545 381 - #ifdef USE_ASYNC_CALLBACK 382 546 /* assign alternative stack for the signal handlers */ 383 547 stack_t ss = { 384 548 .ss_sp = signal_stack, ··· 390 554 err = sigaltstack(&ss, NULL); 391 555 if (err < 0) 392 556 { 393 - logf("Unable to install alternative signal stack: %s", strerror(err)); 394 - return err; 557 + panicf("Unable to install alternative signal stack: %s", strerror(err)); 395 558 } 396 559 397 560 err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, NULL); 398 561 if (err < 0) 399 562 { 400 - logf("Unable to register async handler: %s\n", snd_strerror(err)); 401 - return err; 563 + panicf("Unable to register async handler: %s", snd_strerror(err)); 402 564 } 403 565 404 566 /* only modify the stack the handler runs on */ ··· 407 569 err = sigaction(SIGIO, &sa, NULL); 408 570 if (err < 0) 409 571 { 410 - logf("Unable to install alternative signal stack: %s", strerror(err)); 411 - return err; 572 + panicf("Unable to install alternative signal stack: %s", strerror(err)); 412 573 } 574 + 575 + #ifdef HAVE_RECORDING 576 + current_alsa_mode = mode; 577 + #else 578 + (void)mode; 413 579 #endif 580 + current_alsa_device = device; 414 581 415 - /* fill buffer with silence to initiate playback without noisy click */ 416 - sample_size = buffer_size; 417 - samples = calloc(1, sample_size * channels * sizeof(sample_t)); 418 - 419 - snd_pcm_format_set_silence(format, samples, sample_size); 420 - err = snd_pcm_writei(handle, samples, sample_size); 421 - free(samples); 422 - 423 - if (err < 0) 424 - { 425 - logf("Initial write error: %s\n", snd_strerror(err)); 426 - return err; 427 - } 428 - if (err != (ssize_t)sample_size) 429 - { 430 - logf("Initial write error: written %i expected %li\n", err, sample_size); 431 - return err; 432 - } 433 - 434 - snd_pcm_state_t state = snd_pcm_state(handle); 435 - logf("PCM RW State %d", state); 436 - if (state == SND_PCM_STATE_PREPARED) 437 - { 438 - err = snd_pcm_start(handle); 439 - if (err < 0) 440 - { 441 - logf("Start error: %s\n", snd_strerror(err)); 442 - return err; 443 - } 444 - } else { 445 - return state; 446 - } 447 - 448 - return 0; 449 - } 450 - 451 - void cleanup(void) 452 - { 453 - free(frames); 454 - frames = NULL; 455 - snd_pcm_close(handle); 456 - handle = NULL; 457 - } 458 - 459 - static void open_hwdev(const char *device) 460 - { 461 - int err; 462 - 463 - logf("opendev %s (%p)", device, handle); 464 - 465 - /* Close old handle first, if needed */ 466 - if (handle) { 467 - pcm_play_dma_stop(); 468 - snd_pcm_close(handle); 469 - handle = NULL; 470 - } 471 - 472 - if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) 473 - { 474 - panicf("%s(): Cannot open device %s: %s\n", __func__, device, snd_strerror(err)); 475 - } 476 - if ((err = snd_pcm_nonblock(handle, 1))) 477 - panicf("Could not set non-block mode: %s\n", snd_strerror(err)); 478 - 479 - last_sample_rate = 0; 582 + atexit(alsadev_cleanup); 480 583 } 481 584 482 585 void pcm_play_dma_init(void) ··· 485 588 486 589 audiohw_preinit(); 487 590 488 - open_hwdev(DEFAULT_PLAYBACK_DEVICE); 489 - 490 - #ifdef USE_ASYNC_CALLBACK 491 - pthread_mutexattr_t attr; 492 - pthread_mutexattr_init(&attr); 493 - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 494 - pthread_mutex_init(&pcm_mtx, &attr); 495 - #else 496 - tick_add_task(pcm_tick); 497 - #endif 591 + open_hwdev(playback_dev, SND_PCM_STREAM_PLAYBACK); 498 592 499 - atexit(cleanup); 500 593 return; 501 594 } 502 595 503 596 void pcm_play_lock(void) 504 597 { 505 - #ifdef USE_ASYNC_CALLBACK 506 598 pthread_mutex_lock(&pcm_mtx); 507 - #else 508 - if (recursion++ == 0) 509 - tick_remove_task(pcm_tick); 510 - #endif 511 599 } 512 600 513 601 void pcm_play_unlock(void) 514 602 { 515 - #ifdef USE_ASYNC_CALLBACK 516 603 pthread_mutex_unlock(&pcm_mtx); 517 - #else 518 - if (--recursion == 0) 519 - tick_add_task(pcm_tick); 520 - #endif 521 604 } 522 605 523 606 static void pcm_dma_apply_settings_nolock(void) 524 607 { 525 - logf("PCM DMA Settings %d %d", last_sample_rate, pcm_sampr); 608 + logf("PCM DMA Settings %d %lu", last_sample_rate, pcm_sampr); 526 609 527 610 if (last_sample_rate != pcm_sampr) 528 611 { 529 - last_sample_rate = pcm_sampr; 612 + last_sample_rate = pcm_sampr; 530 613 531 614 #ifdef AUDIOHW_MUTE_ON_SRATE_CHANGE 532 - // XXX AK4450 (xDuoo X3ii) needs to be muted when switching rates. 533 615 audiohw_mute(true); 534 616 #endif 535 617 snd_pcm_drop(handle); ··· 555 637 void pcm_play_dma_pause(bool pause) 556 638 { 557 639 logf("PCM DMA pause %d", pause); 640 + if (!handle) return; 641 + 558 642 #ifdef AUDIOHW_MUTE_ON_PAUSE 559 643 if (pause) audiohw_mute(true); 560 644 #endif ··· 566 650 567 651 void pcm_play_dma_stop(void) 568 652 { 569 - snd_pcm_nonblock(handle, 0); 570 - snd_pcm_drain(handle); 571 - snd_pcm_nonblock(handle, 1); 572 - // last_sample_rate = 0; 653 + logf("PCM DMA stop (%d)", snd_pcm_state(handle)); 654 + 655 + int err = snd_pcm_drain(handle); 656 + if (err < 0) 657 + if (err < 0) 658 + logf("Drain failed: %s", snd_strerror(err)); 573 659 #ifdef AUDIOHW_MUTE_ON_PAUSE 574 660 audiohw_mute(true); 575 661 #endif 576 - logf("PCM DMA stopped"); 577 662 } 578 663 579 664 void pcm_play_dma_start(const void *addr, size_t size) ··· 591 676 while (1) 592 677 { 593 678 snd_pcm_state_t state = snd_pcm_state(handle); 594 - logf("PCM State %d", state); 679 + logf("PCM State %d", state); 595 680 596 681 switch (state) 597 682 { 598 683 case SND_PCM_STATE_RUNNING: 684 + #if defined(AUDIOHW_MUTE_ON_PAUSE) 685 + audiohw_mute(false); 686 + #endif 599 687 return; 600 688 case SND_PCM_STATE_XRUN: 601 689 { 602 - logf("Trying to recover from error\n"); 690 + logf("Trying to recover from error"); 603 691 int err = snd_pcm_recover(handle, -EPIPE, 0); 604 692 if (err < 0) 605 - logf("Recovery failed: %s\n", snd_strerror(err)); 693 + logf("Recovery failed: %s", snd_strerror(err)); 606 694 continue; 607 695 } 608 696 case SND_PCM_STATE_SETUP: 609 697 { 610 698 int err = snd_pcm_prepare(handle); 611 699 if (err < 0) 612 - logf("Prepare error: %s\n", snd_strerror(err)); 700 + logf("Prepare error: %s", snd_strerror(err)); 701 + } 613 702 /* fall through */ 614 - } 615 703 case SND_PCM_STATE_PREPARED: 616 - { /* prepared state, we need to fill the buffer with silence before 617 - * starting */ 618 - int err = async_rw(handle); 619 - if (err < 0) { 620 - logf("Start error: %s\n", snd_strerror(err)); 704 + { 705 + int err; 706 + #if 0 707 + /* fill buffer with silence to initiate playback without noisy click */ 708 + snd_pcm_sframes_t sample_size = buffer_size; 709 + sample_t *samples = calloc(1, sample_size * channels * sizeof(sample_t)); 710 + 711 + snd_pcm_format_set_silence(format, samples, sample_size); 712 + err = snd_pcm_writei(handle, samples, sample_size); 713 + free(samples); 714 + 715 + if (err != (ssize_t)sample_size) 716 + { 717 + logf("Initial write error: written %i expected %li", err, sample_size); 621 718 return; 622 719 } 623 - #if defined(AUDIOHW_MUTE_ON_PAUSE) 624 - audiohw_mute(false); 720 + #else 721 + /* Fill buffer with proper sample data */ 722 + while (snd_pcm_avail_update(handle) >= period_size) 723 + { 724 + if (copy_frames(true)) 725 + { 726 + err = snd_pcm_writei(handle, frames, period_size); 727 + if (err < 0 && err != period_size && err != -EAGAIN) 728 + { 729 + logf("Write error: written %i expected %li", err, period_size); 730 + break; 731 + } 732 + } 733 + } 625 734 #endif 626 - if (err == 0) 627 - return; 735 + err = snd_pcm_start(handle); 736 + if (err < 0) { 737 + logf("start error: %s", snd_strerror(err)); 738 + } 739 + 628 740 break; 629 741 } 630 742 case SND_PCM_STATE_PAUSED: ··· 636 748 /* run until drained */ 637 749 continue; 638 750 default: 639 - logf("Unhandled state: %s\n", snd_pcm_state_name(state)); 751 + logf("Unhandled state: %s", snd_pcm_state_name(state)); 640 752 return; 641 753 } 642 754 } ··· 676 788 #ifdef HAVE_RECORDING 677 789 void pcm_rec_lock(void) 678 790 { 791 + pcm_play_lock(); 679 792 } 680 793 681 794 void pcm_rec_unlock(void) 682 795 { 796 + pcm_play_unlock(); 683 797 } 684 798 685 799 void pcm_rec_dma_init(void) 686 800 { 801 + logf("PCM REC DMA Init"); 802 + 803 + open_hwdev(capture_dev, SND_PCM_STREAM_CAPTURE); 687 804 } 688 805 689 806 void pcm_rec_dma_close(void) 690 807 { 808 + logf("Rec DMA Close"); 809 + close_hwdev(); 691 810 } 692 811 693 812 void pcm_rec_dma_start(void *start, size_t size) 694 813 { 695 - (void)start; 696 - (void)size; 814 + logf("PCM REC DMA start (%p %d)", start, size); 815 + pcm_dma_apply_settings_nolock(); 816 + pcm_data_rec = start; 817 + pcm_size = size; 818 + 819 + if (!handle) return; 820 + 821 + while (1) 822 + { 823 + snd_pcm_state_t state = snd_pcm_state(handle); 824 + 825 + switch (state) 826 + { 827 + case SND_PCM_STATE_RUNNING: 828 + return; 829 + case SND_PCM_STATE_XRUN: 830 + { 831 + logf("Trying to recover from error"); 832 + int err = snd_pcm_recover(handle, -EPIPE, 0); 833 + if (err < 0) 834 + panicf("Recovery failed: %s", snd_strerror(err)); 835 + continue; 836 + } 837 + case SND_PCM_STATE_SETUP: 838 + { 839 + int err = snd_pcm_prepare(handle); 840 + if (err < 0) 841 + panicf("Prepare error: %s", snd_strerror(err)); 842 + } 843 + /* fall through */ 844 + case SND_PCM_STATE_PREPARED: 845 + { 846 + int err = snd_pcm_start(handle); 847 + if (err < 0) 848 + panicf("Start error: %s", snd_strerror(err)); 849 + return; 850 + } 851 + case SND_PCM_STATE_PAUSED: 852 + { /* paused, simply resume */ 853 + pcm_play_dma_pause(0); 854 + return; 855 + } 856 + case SND_PCM_STATE_DRAINING: 857 + /* run until drained */ 858 + continue; 859 + default: 860 + logf("Unhandled state: %s", snd_pcm_state_name(state)); 861 + return; 862 + } 863 + } 697 864 } 698 865 699 866 void pcm_rec_dma_stop(void) 700 867 { 868 + logf("Rec DMA Stop"); 869 + close_hwdev(); 701 870 } 702 871 703 872 const void * pcm_rec_dma_get_peak_buffer(void) 704 873 { 705 - return NULL; 874 + uintptr_t addr = (uintptr_t)pcm_data_rec; 875 + return (void*)((addr + 3) & ~3); 706 876 } 707 877 878 + #ifdef SIMULATOR 708 879 void audiohw_set_recvol(int left, int right, int type) 709 880 { 710 881 (void)left; 711 882 (void)right; 712 883 (void)type; 713 884 } 885 + #endif 714 886 715 887 #endif /* HAVE_RECORDING */
+6
firmware/target/hosted/pcm-alsa.h
··· 28 28 void pcm_alsa_set_digital_volume(int vol_db_l, int vol_db_r); 29 29 #endif 30 30 31 + /* These two should be invoked in your audiohw_preinit() call! */ 32 + void pcm_alsa_set_playback_device(const char *device); 33 + #if defined(HAVE_RECORDING) 34 + void pcm_alsa_set_capture_device(const char *device); 35 + #endif 36 + 31 37 int pcm_alsa_get_rate(void); 32 38 33 39 #endif /* __PCM_ALSA_RB_H__ */