summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/hosted/pcm-alsa.c116
1 files changed, 69 insertions, 47 deletions
diff --git a/firmware/target/hosted/pcm-alsa.c b/firmware/target/hosted/pcm-alsa.c
index c7df99e23d..d42775e8ef 100644
--- a/firmware/target/hosted/pcm-alsa.c
+++ b/firmware/target/hosted/pcm-alsa.c
@@ -5,9 +5,9 @@
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$
9 * 8 *
10 * Copyright (C) 2010 Thomas Martitz 9 * Copyright (C) 2010 Thomas Martitz
10 * Copyright (c) 2020 Solomon Peachy
11 * 11 *
12 * This program is free software; you can redistribute it and/or 12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 13 * modify it under the terms of the GNU General Public License
@@ -41,12 +41,14 @@
41 * device works which doesnt break with other apps running. 41 * device works which doesnt break with other apps running.
42 */ 42 */
43 43
44
45#include "autoconf.h" 44#include "autoconf.h"
46 45
47#include <stdlib.h> 46#include <stdlib.h>
48#include <stdbool.h> 47#include <stdbool.h>
49#include <alsa/asoundlib.h> 48#include <alsa/asoundlib.h>
49
50//#define LOGF_ENABLE
51
50#include "system.h" 52#include "system.h"
51#include "debug.h" 53#include "debug.h"
52#include "kernel.h" 54#include "kernel.h"
@@ -59,6 +61,8 @@
59#include "audiohw.h" 61#include "audiohw.h"
60#include "pcm-alsa.h" 62#include "pcm-alsa.h"
61 63
64#include "logf.h"
65
62#include <pthread.h> 66#include <pthread.h>
63#include <signal.h> 67#include <signal.h>
64 68
@@ -119,28 +123,28 @@ static int set_hwparams(snd_pcm_t *handle)
119 err = snd_pcm_hw_params_any(handle, params); 123 err = snd_pcm_hw_params_any(handle, params);
120 if (err < 0) 124 if (err < 0)
121 { 125 {
122 printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); 126 panicf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
123 goto error; 127 goto error;
124 } 128 }
125 /* set the interleaved read/write format */ 129 /* set the interleaved read/write format */
126 err = snd_pcm_hw_params_set_access(handle, params, access_); 130 err = snd_pcm_hw_params_set_access(handle, params, access_);
127 if (err < 0) 131 if (err < 0)
128 { 132 {
129 printf("Access type not available for playback: %s\n", snd_strerror(err)); 133 panicf("Access type not available for playback: %s\n", snd_strerror(err));
130 goto error; 134 goto error;
131 } 135 }
132 /* set the sample format */ 136 /* set the sample format */
133 err = snd_pcm_hw_params_set_format(handle, params, format); 137 err = snd_pcm_hw_params_set_format(handle, params, format);
134 if (err < 0) 138 if (err < 0)
135 { 139 {
136 printf("Sample format not available for playback: %s\n", snd_strerror(err)); 140 logf("Sample format not available for playback: %s\n", snd_strerror(err));
137 goto error; 141 goto error;
138 } 142 }
139 /* set the count of channels */ 143 /* set the count of channels */
140 err = snd_pcm_hw_params_set_channels(handle, params, channels); 144 err = snd_pcm_hw_params_set_channels(handle, params, channels);
141 if (err < 0) 145 if (err < 0)
142 { 146 {
143 printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err)); 147 logf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err));
144 goto error; 148 goto error;
145 } 149 }
146 /* set the stream rate */ 150 /* set the stream rate */
@@ -148,13 +152,13 @@ static int set_hwparams(snd_pcm_t *handle)
148 err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0); 152 err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0);
149 if (err < 0) 153 if (err < 0)
150 { 154 {
151 printf("Rate %iHz not available for playback: %s\n", sample_rate, snd_strerror(err)); 155 logf("Rate %iHz not available for playback: %s\n", sample_rate, snd_strerror(err));
152 goto error; 156 goto error;
153 } 157 }
154 real_sample_rate = srate; 158 real_sample_rate = srate;
155 if (real_sample_rate != sample_rate) 159 if (real_sample_rate != sample_rate)
156 { 160 {
157 printf("Rate doesn't match (requested %iHz, get %iHz)\n", sample_rate, real_sample_rate); 161 logf("Rate doesn't match (requested %iHz, get %iHz)\n", sample_rate, real_sample_rate);
158 err = -EINVAL; 162 err = -EINVAL;
159 goto error; 163 goto error;
160 } 164 }
@@ -163,7 +167,7 @@ static int set_hwparams(snd_pcm_t *handle)
163 err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size); 167 err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size);
164 if (err < 0) 168 if (err < 0)
165 { 169 {
166 printf("Unable to set buffer size %ld for playback: %s\n", buffer_size, snd_strerror(err)); 170 logf("Unable to set buffer size %ld for playback: %s\n", buffer_size, snd_strerror(err));
167 goto error; 171 goto error;
168 } 172 }
169 173
@@ -171,18 +175,18 @@ static int set_hwparams(snd_pcm_t *handle)
171 err = snd_pcm_hw_params_set_period_size_near (handle, params, &period_size, NULL); 175 err = snd_pcm_hw_params_set_period_size_near (handle, params, &period_size, NULL);
172 if (err < 0) 176 if (err < 0)
173 { 177 {
174 printf("Unable to set period size %ld for playback: %s\n", period_size, snd_strerror(err)); 178 logf("Unable to set period size %ld for playback: %s\n", period_size, snd_strerror(err));
175 goto error; 179 goto error;
176 } 180 }
177 181
178 free(frames); 182 if (frames) free(frames);
179 frames = calloc(1, period_size * channels * sizeof(sample_t)); 183 frames = calloc(1, period_size * channels * sizeof(sample_t));
180 184
181 /* write the parameters to device */ 185 /* write the parameters to device */
182 err = snd_pcm_hw_params(handle, params); 186 err = snd_pcm_hw_params(handle, params);
183 if (err < 0) 187 if (err < 0)
184 { 188 {
185 printf("Unable to set hw params for playback: %s\n", snd_strerror(err)); 189 logf("Unable to set hw params for playback: %s\n", snd_strerror(err));
186 goto error; 190 goto error;
187 } 191 }
188 192
@@ -204,28 +208,28 @@ static int set_swparams(snd_pcm_t *handle)
204 err = snd_pcm_sw_params_current(handle, swparams); 208 err = snd_pcm_sw_params_current(handle, swparams);
205 if (err < 0) 209 if (err < 0)
206 { 210 {
207 printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err)); 211 logf("Unable to determine current swparams for playback: %s\n", snd_strerror(err));
208 goto error; 212 goto error;
209 } 213 }
210 /* start the transfer when the buffer is half full */ 214 /* start the transfer when the buffer is half full */
211 err = snd_pcm_sw_params_set_start_threshold(handle, swparams, buffer_size / 2); 215 err = snd_pcm_sw_params_set_start_threshold(handle, swparams, buffer_size / 2);
212 if (err < 0) 216 if (err < 0)
213 { 217 {
214 printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err)); 218 logf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err));
215 goto error; 219 goto error;
216 } 220 }
217 /* allow the transfer when at least period_size samples can be processed */ 221 /* allow the transfer when at least period_size samples can be processed */
218 err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size); 222 err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size);
219 if (err < 0) 223 if (err < 0)
220 { 224 {
221 printf("Unable to set avail min for playback: %s\n", snd_strerror(err)); 225 logf("Unable to set avail min for playback: %s\n", snd_strerror(err));
222 goto error; 226 goto error;
223 } 227 }
224 /* write the parameters to the playback device */ 228 /* write the parameters to the playback device */
225 err = snd_pcm_sw_params(handle, swparams); 229 err = snd_pcm_sw_params(handle, swparams);
226 if (err < 0) 230 if (err < 0)
227 { 231 {
228 printf("Unable to set sw params for playback: %s\n", snd_strerror(err)); 232 logf("Unable to set sw params for playback: %s\n", snd_strerror(err));
229 goto error; 233 goto error;
230 } 234 }
231 235
@@ -268,14 +272,14 @@ void pcm_alsa_set_digital_volume(int vol_db_l, int vol_db_r)
268 dig_vol_mult_l = 1 << vol_shift_l | 1 << (vol_shift_l - 2); 272 dig_vol_mult_l = 1 << vol_shift_l | 1 << (vol_shift_l - 2);
269 else 273 else
270 dig_vol_mult_l = 1 << vol_shift_l | 1 << (vol_shift_l - 1); 274 dig_vol_mult_l = 1 << vol_shift_l | 1 << (vol_shift_l - 1);
271 printf("l: %d dB -> factor = %d\n", vol_db_l - 48, dig_vol_mult_l); 275 logf("l: %d dB -> factor = %d\n", vol_db_l - 48, dig_vol_mult_l);
272 if(r_r == 0) 276 if(r_r == 0)
273 dig_vol_mult_r = 1 << vol_shift_r; 277 dig_vol_mult_r = 1 << vol_shift_r;
274 else if(r_r == 1) 278 else if(r_r == 1)
275 dig_vol_mult_r = 1 << vol_shift_r | 1 << (vol_shift_r - 2); 279 dig_vol_mult_r = 1 << vol_shift_r | 1 << (vol_shift_r - 2);
276 else 280 else
277 dig_vol_mult_r = 1 << vol_shift_r | 1 << (vol_shift_r - 1); 281 dig_vol_mult_r = 1 << vol_shift_r | 1 << (vol_shift_r - 1);
278 printf("r: %d dB -> factor = %d\n", vol_db_r - 48, dig_vol_mult_r); 282 logf("r: %d dB -> factor = %d\n", vol_db_r - 48, dig_vol_mult_r);
279} 283}
280 284
281/* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */ 285/* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */
@@ -327,6 +331,7 @@ static bool fill_frames(void)
327 pcm_play_dma_status_callback(PCM_DMAST_STARTED); 331 pcm_play_dma_status_callback(PCM_DMAST_STARTED);
328 } 332 }
329 } 333 }
334
330 return true; 335 return true;
331} 336}
332 337
@@ -351,13 +356,13 @@ static void pcm_tick(void)
351 int err = snd_pcm_writei(handle, frames, period_size); 356 int err = snd_pcm_writei(handle, frames, period_size);
352 if (err < 0 && err != period_size && err != -EAGAIN) 357 if (err < 0 && err != period_size && err != -EAGAIN)
353 { 358 {
354 printf("Write error: written %i expected %li\n", err, period_size); 359 logf("Write error: written %i expected %li\n", err, period_size);
355 break; 360 break;
356 } 361 }
357 } 362 }
358 else 363 else
359 { 364 {
360 DEBUGF("%s: No Data.\n", __func__); 365 logf("%s: No Data.\n", __func__);
361 break; 366 break;
362 } 367 }
363 } 368 }
@@ -384,14 +389,14 @@ static int async_rw(snd_pcm_t *handle)
384 err = sigaltstack(&ss, NULL); 389 err = sigaltstack(&ss, NULL);
385 if (err < 0) 390 if (err < 0)
386 { 391 {
387 DEBUGF("Unable to install alternative signal stack: %s", strerror(err)); 392 logf("Unable to install alternative signal stack: %s", strerror(err));
388 return err; 393 return err;
389 } 394 }
390 395
391 err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, NULL); 396 err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, NULL);
392 if (err < 0) 397 if (err < 0)
393 { 398 {
394 DEBUGF("Unable to register async handler: %s\n", snd_strerror(err)); 399 logf("Unable to register async handler: %s\n", snd_strerror(err));
395 return err; 400 return err;
396 } 401 }
397 402
@@ -401,7 +406,7 @@ static int async_rw(snd_pcm_t *handle)
401 err = sigaction(SIGIO, &sa, NULL); 406 err = sigaction(SIGIO, &sa, NULL);
402 if (err < 0) 407 if (err < 0)
403 { 408 {
404 DEBUGF("Unable to install alternative signal stack: %s", strerror(err)); 409 logf("Unable to install alternative signal stack: %s", strerror(err));
405 return err; 410 return err;
406 } 411 }
407#endif 412#endif
@@ -416,27 +421,31 @@ static int async_rw(snd_pcm_t *handle)
416 421
417 if (err < 0) 422 if (err < 0)
418 { 423 {
419 DEBUGF("Initial write error: %s\n", snd_strerror(err)); 424 logf("Initial write error: %s\n", snd_strerror(err));
420 return err; 425 return err;
421 } 426 }
422 if (err != (ssize_t)sample_size) 427 if (err != (ssize_t)sample_size)
423 { 428 {
424 DEBUGF("Initial write error: written %i expected %li\n", err, sample_size); 429 logf("Initial write error: written %i expected %li\n", err, sample_size);
425 return err; 430 return err;
426 } 431 }
427 if (snd_pcm_state(handle) == SND_PCM_STATE_PREPARED) 432
433 snd_pcm_state_t state = snd_pcm_state(handle);
434 logf("PCM RW State %d", state);
435 if (state == SND_PCM_STATE_PREPARED)
428 { 436 {
429 err = snd_pcm_start(handle); 437 err = snd_pcm_start(handle);
430 if (err < 0) 438 if (err < 0)
431 { 439 {
432 DEBUGF("Start error: %s\n", snd_strerror(err)); 440 logf("Start error: %s\n", snd_strerror(err));
433 return err; 441 return err;
434 } 442 }
443 } else {
444 return state;
435 } 445 }
436 return 0; 446 return 0;
437} 447}
438 448
439
440void cleanup(void) 449void cleanup(void)
441{ 450{
442 free(frames); 451 free(frames);
@@ -448,6 +457,9 @@ void cleanup(void)
448void pcm_play_dma_init(void) 457void pcm_play_dma_init(void)
449{ 458{
450 int err; 459 int err;
460
461 logf("PCM DMA Init");
462
451 audiohw_preinit(); 463 audiohw_preinit();
452 464
453 if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) 465 if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
@@ -482,7 +494,6 @@ void pcm_play_dma_init(void)
482 return; 494 return;
483} 495}
484 496
485
486void pcm_play_lock(void) 497void pcm_play_lock(void)
487{ 498{
488#ifdef USE_ASYNC_CALLBACK 499#ifdef USE_ASYNC_CALLBACK
@@ -506,12 +517,13 @@ void pcm_play_unlock(void)
506#if defined(HAVE_XDUOO_LINUX_CODEC) || defined(HAVE_FIIO_LINUX_CODEC) || defined(HAVE_ROCKER_CODEC) 517#if defined(HAVE_XDUOO_LINUX_CODEC) || defined(HAVE_FIIO_LINUX_CODEC) || defined(HAVE_ROCKER_CODEC)
507static void pcm_dma_apply_settings_nolock(void) 518static void pcm_dma_apply_settings_nolock(void)
508{ 519{
520 logf("PCM DMA Settings %d %d", sample_rate, pcm_sampr);
509 if (sample_rate != pcm_sampr) 521 if (sample_rate != pcm_sampr)
510 { 522 {
511 audiohw_mute(true); 523 audiohw_mute(true);
512 snd_pcm_drop(handle); 524 snd_pcm_drop(handle);
513 set_hwparams(handle); 525 set_hwparams(handle);
514 audiohw_mute(false); 526 audiohw_mute(false);
515 } 527 }
516} 528}
517#else 529#else
@@ -533,20 +545,24 @@ void pcm_dma_apply_settings(void)
533 pcm_play_unlock(); 545 pcm_play_unlock();
534} 546}
535 547
536
537void pcm_play_dma_pause(bool pause) 548void pcm_play_dma_pause(bool pause)
538{ 549{
550 logf("PCM DMA pause %d", pause);
539 snd_pcm_pause(handle, pause); 551 snd_pcm_pause(handle, pause);
540} 552}
541 553
542
543void pcm_play_dma_stop(void) 554void pcm_play_dma_stop(void)
544{ 555{
556 snd_pcm_nonblock(handle, 0);
545 snd_pcm_drain(handle); 557 snd_pcm_drain(handle);
558 snd_pcm_nonblock(handle, 1);
559 sample_rate = 0;
560 logf("PCM DMA stopped");
546} 561}
547 562
548void pcm_play_dma_start(const void *addr, size_t size) 563void pcm_play_dma_start(const void *addr, size_t size)
549{ 564{
565 logf("PCM DMA start (%p %d)", addr, size);
550 pcm_dma_apply_settings_nolock(); 566 pcm_dma_apply_settings_nolock();
551 567
552 pcm_data = addr; 568 pcm_data = addr;
@@ -555,32 +571,38 @@ void pcm_play_dma_start(const void *addr, size_t size)
555 while (1) 571 while (1)
556 { 572 {
557 snd_pcm_state_t state = snd_pcm_state(handle); 573 snd_pcm_state_t state = snd_pcm_state(handle);
574 logf("PCM State %d", state);
575
558 switch (state) 576 switch (state)
559 { 577 {
560 case SND_PCM_STATE_RUNNING: 578 case SND_PCM_STATE_RUNNING:
561 return; 579 return;
562 case SND_PCM_STATE_XRUN: 580 case SND_PCM_STATE_XRUN:
563 { 581 {
564 DEBUGF("Trying to recover from error\n"); 582 logf("Trying to recover from error\n");
565 int err = snd_pcm_recover(handle, -EPIPE, 0); 583 int err = snd_pcm_recover(handle, -EPIPE, 0);
566 if (err < 0) 584 if (err < 0)
567 DEBUGF("Recovery failed: %s\n", snd_strerror(err)); 585 logf("Recovery failed: %s\n", snd_strerror(err));
568 continue; 586 continue;
569 } 587 }
570 case SND_PCM_STATE_SETUP: 588 case SND_PCM_STATE_SETUP:
571 { 589 {
572 int err = snd_pcm_prepare(handle); 590 int err = snd_pcm_prepare(handle);
573 if (err < 0) 591 if (err < 0)
574 printf("Prepare error: %s\n", snd_strerror(err)); 592 logf("Prepare error: %s\n", snd_strerror(err));
575 /* fall through */ 593 /* fall through */
576 } 594 }
577 case SND_PCM_STATE_PREPARED: 595 case SND_PCM_STATE_PREPARED:
578 { /* prepared state, we need to fill the buffer with silence before 596 { /* prepared state, we need to fill the buffer with silence before
579 * starting */ 597 * starting */
580 int err = async_rw(handle); 598 int err = async_rw(handle);
581 if (err < 0) 599 if (err < 0) {
582 printf("Start error: %s\n", snd_strerror(err)); 600 logf("Start error: %s\n", snd_strerror(err));
583 return; 601 return;
602 }
603 if (err == 0)
604 return;
605 break;
584 } 606 }
585 case SND_PCM_STATE_PAUSED: 607 case SND_PCM_STATE_PAUSED:
586 { /* paused, simply resume */ 608 { /* paused, simply resume */
@@ -591,7 +613,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
591 /* run until drained */ 613 /* run until drained */
592 continue; 614 continue;
593 default: 615 default:
594 DEBUGF("Unhandled state: %s\n", snd_pcm_state_name(state)); 616 logf("Unhandled state: %s\n", snd_pcm_state_name(state));
595 return; 617 return;
596 } 618 }
597 } 619 }