1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2010 Thomas Martitz
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
24 * Based, but heavily modified, on the example given at
25 * http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_8c-example.html
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.
30 * 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.
35 * TODO: Rewrite this to do it properly with multithreading
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.
41 * device works which doesnt break with other apps running.
49 #include <alsa/asoundlib.h>
55 #include "pcm-internal.h"
56 #include "pcm_mixer.h"
57 #include "pcm_sampr.h"
63 #define USE_ASYNC_CALLBACK
64 /* plughw:0,0 works with both, however "default" is recommended.
65 * default doesnt seem to work with async callback but doesn't break
66 * with multple applications running */
67 static char device
[] = "plughw:0,0"; /* playback device */
68 static const snd_pcm_access_t access_
= SND_PCM_ACCESS_RW_INTERLEAVED
; /* access mode */
69 static const snd_pcm_format_t format
= SND_PCM_FORMAT_S16
; /* sample format */
70 static const int channels
= 2; /* count of channels */
71 static unsigned int rate
= 44100; /* stream rate */
73 static snd_pcm_t
*handle
;
74 static snd_pcm_sframes_t buffer_size
= MIX_FRAME_SAMPLES
* 32; /* ~16k */
75 static snd_pcm_sframes_t period_size
= MIX_FRAME_SAMPLES
* 4; /* ~4k */
78 static const char *pcm_data
= 0;
79 static size_t pcm_size
= 0;
81 #ifdef USE_ASYNC_CALLBACK
82 static snd_async_handler_t
*ahandler
;
83 static pthread_mutex_t pcm_mtx
;
84 static char signal_stack
[SIGSTKSZ
];
89 static int set_hwparams(snd_pcm_t
*handle
, unsigned sample_rate
)
93 snd_pcm_hw_params_t
*params
;
94 snd_pcm_hw_params_malloc(¶ms
);
97 /* choose all parameters */
98 err
= snd_pcm_hw_params_any(handle
, params
);
101 printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err
));
104 /* set the interleaved read/write format */
105 err
= snd_pcm_hw_params_set_access(handle
, params
, access_
);
108 printf("Access type not available for playback: %s\n", snd_strerror(err
));
111 /* set the sample format */
112 err
= snd_pcm_hw_params_set_format(handle
, params
, format
);
115 printf("Sample format not available for playback: %s\n", snd_strerror(err
));
118 /* set the count of channels */
119 err
= snd_pcm_hw_params_set_channels(handle
, params
, channels
);
122 printf("Channels count (%i) not available for playbacks: %s\n", channels
, snd_strerror(err
));
125 /* set the stream rate */
127 err
= snd_pcm_hw_params_set_rate_near(handle
, params
, &rrate
, 0);
130 printf("Rate %iHz not available for playback: %s\n", rate
, snd_strerror(err
));
133 if (rrate
!= sample_rate
)
135 printf("Rate doesn't match (requested %iHz, get %iHz)\n", sample_rate
, err
);
140 /* set the buffer size */
141 err
= snd_pcm_hw_params_set_buffer_size_near(handle
, params
, &buffer_size
);
144 printf("Unable to set buffer size %ld for playback: %s\n", buffer_size
, snd_strerror(err
));
148 /* set the period size */
149 err
= snd_pcm_hw_params_set_period_size_near (handle
, params
, &period_size
, NULL
);
152 printf("Unable to set period size %ld for playback: %s\n", period_size
, snd_strerror(err
));
156 frames
= malloc(period_size
* channels
* sizeof(short));
158 /* write the parameters to device */
159 err
= snd_pcm_hw_params(handle
, params
);
162 printf("Unable to set hw params for playback: %s\n", snd_strerror(err
));
166 err
= 0; /* success */
168 snd_pcm_hw_params_free(params
);
172 /* Set sw params: playback start threshold and low buffer watermark */
173 static int set_swparams(snd_pcm_t
*handle
)
177 snd_pcm_sw_params_t
*swparams
;
178 snd_pcm_sw_params_malloc(&swparams
);
180 /* get the current swparams */
181 err
= snd_pcm_sw_params_current(handle
, swparams
);
184 printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err
));
187 /* start the transfer when the buffer is haalmost full */
188 err
= snd_pcm_sw_params_set_start_threshold(handle
, swparams
, buffer_size
/ 2);
191 printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err
));
194 /* allow the transfer when at least period_size samples can be processed */
195 err
= snd_pcm_sw_params_set_avail_min(handle
, swparams
, period_size
);
198 printf("Unable to set avail min for playback: %s\n", snd_strerror(err
));
201 /* write the parameters to the playback device */
202 err
= snd_pcm_sw_params(handle
, swparams
);
205 printf("Unable to set sw params for playback: %s\n", snd_strerror(err
));
209 err
= 0; /* success */
211 snd_pcm_sw_params_free(swparams
);
215 /* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */
216 static bool fill_frames(void)
218 ssize_t copy_n
, frames_left
= period_size
;
219 bool new_buffer
= false;
221 while (frames_left
> 0)
226 pcm_play_get_more_callback((void **)&pcm_data
, &pcm_size
);
227 if (!pcm_size
|| !pcm_data
)
230 copy_n
= MIN((ssize_t
)pcm_size
, frames_left
*4);
231 memcpy(&frames
[2*(period_size
-frames_left
)], pcm_data
, copy_n
);
235 frames_left
-= copy_n
/4;
240 pcm_play_dma_started_callback();
246 #ifdef USE_ASYNC_CALLBACK
247 static void async_callback(snd_async_handler_t
*ahandler
)
249 snd_pcm_t
*handle
= snd_async_handler_get_pcm(ahandler
);
251 if (pthread_mutex_trylock(&pcm_mtx
) != 0)
254 static void pcm_tick(void)
256 if (snd_pcm_state(handle
) != SND_PCM_STATE_RUNNING
)
260 while (snd_pcm_avail_update(handle
) >= period_size
)
264 int err
= snd_pcm_writei(handle
, frames
, period_size
);
265 if (err
< 0 && err
!= period_size
&& err
!= -EAGAIN
)
267 printf("Write error: written %i expected %li\n", err
, period_size
);
273 DEBUGF("%s: No Data.\n", __func__
);
277 #ifdef USE_ASYNC_CALLBACK
278 pthread_mutex_unlock(&pcm_mtx
);
282 static int async_rw(snd_pcm_t
*handle
)
285 snd_pcm_sframes_t sample_size
;
288 #ifdef USE_ASYNC_CALLBACK
289 /* assign alternative stack for the signal handlers */
291 .ss_sp
= signal_stack
,
292 .ss_size
= sizeof(signal_stack
),
297 err
= sigaltstack(&ss
, NULL
);
300 DEBUGF("Unable to install alternative signal stack: %s", strerror(err
));
304 err
= snd_async_add_pcm_handler(&ahandler
, handle
, async_callback
, NULL
);
307 DEBUGF("Unable to register async handler: %s\n", snd_strerror(err
));
311 /* only modify the stack the handler runs on */
312 sigaction(SIGIO
, NULL
, &sa
);
313 sa
.sa_flags
|= SA_ONSTACK
;
314 err
= sigaction(SIGIO
, &sa
, NULL
);
317 DEBUGF("Unable to install alternative signal stack: %s", strerror(err
));
322 /* fill buffer with silence to initiate playback without noisy click */
323 sample_size
= buffer_size
;
324 samples
= malloc(sample_size
* channels
* sizeof(short));
326 snd_pcm_format_set_silence(format
, samples
, sample_size
);
327 err
= snd_pcm_writei(handle
, samples
, sample_size
);
332 DEBUGF("Initial write error: %s\n", snd_strerror(err
));
335 if (err
!= (ssize_t
)sample_size
)
337 DEBUGF("Initial write error: written %i expected %li\n", err
, sample_size
);
340 if (snd_pcm_state(handle
) == SND_PCM_STATE_PREPARED
)
342 err
= snd_pcm_start(handle
);
345 DEBUGF("Start error: %s\n", snd_strerror(err
));
357 snd_pcm_close(handle
);
361 void pcm_play_dma_init(void)
366 if ((err
= snd_pcm_open(&handle
, device
, SND_PCM_STREAM_PLAYBACK
, 0)) < 0)
368 printf("%s(): Cannot open device %s: %s\n", __func__
, device
, snd_strerror(err
));
373 if ((err
= snd_pcm_nonblock(handle
, 1)))
374 printf("Could not set non-block mode: %s\n", snd_strerror(err
));
376 if ((err
= set_hwparams(handle
, rate
)) < 0)
378 printf("Setting of hwparams failed: %s\n", snd_strerror(err
));
381 if ((err
= set_swparams(handle
)) < 0)
383 printf("Setting of swparams failed: %s\n", snd_strerror(err
));
387 pcm_dma_apply_settings();
389 #ifdef USE_ASYNC_CALLBACK
390 pthread_mutexattr_t attr
;
391 pthread_mutexattr_init(&attr
);
392 pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE
);
393 pthread_mutex_init(&pcm_mtx
, &attr
);
395 tick_add_task(pcm_tick
);
403 void pcm_play_lock(void)
405 #ifdef USE_ASYNC_CALLBACK
406 pthread_mutex_lock(&pcm_mtx
);
408 if (recursion
++ == 0)
409 tick_remove_task(pcm_tick
);
413 void pcm_play_unlock(void)
415 #ifdef USE_ASYNC_CALLBACK
416 pthread_mutex_unlock(&pcm_mtx
);
418 if (--recursion
== 0)
419 tick_add_task(pcm_tick
);
423 static void pcm_dma_apply_settings_nolock(void)
425 snd_pcm_drop(handle
);
426 set_hwparams(handle
, pcm_sampr
);
429 void pcm_dma_apply_settings(void)
432 pcm_dma_apply_settings_nolock();
437 void pcm_play_dma_pause(bool pause
)
439 snd_pcm_pause(handle
, pause
);
443 void pcm_play_dma_stop(void)
445 snd_pcm_drain(handle
);
448 void pcm_play_dma_start(const void *addr
, size_t size
)
450 pcm_dma_apply_settings_nolock();
457 snd_pcm_state_t state
= snd_pcm_state(handle
);
460 case SND_PCM_STATE_RUNNING
:
462 case SND_PCM_STATE_XRUN
:
464 DEBUGF("Trying to recover from error\n");
465 int err
= snd_pcm_recover(handle
, -EPIPE
, 0);
467 DEBUGF("Recovery failed: %s\n", snd_strerror(err
));
470 case SND_PCM_STATE_SETUP
:
472 int err
= snd_pcm_prepare(handle
);
474 printf("Prepare error: %s\n", snd_strerror(err
));
477 case SND_PCM_STATE_PREPARED
:
478 { /* prepared state, we need to fill the buffer with silence before
480 int err
= async_rw(handle
);
482 printf("Start error: %s\n", snd_strerror(err
));
485 case SND_PCM_STATE_PAUSED
:
486 { /* paused, simply resume */
487 pcm_play_dma_pause(0);
490 case SND_PCM_STATE_DRAINING
:
491 /* run until drained */
494 DEBUGF("Unhandled state: %s\n", snd_pcm_state_name(state
));
500 size_t pcm_get_bytes_waiting(void)
505 const void * pcm_play_dma_get_peak_buffer(int *count
)
507 uintptr_t addr
= (uintptr_t)pcm_data
;
508 *count
= pcm_size
/ 4;
509 return (void *)((addr
+ 3) & ~3);
512 void pcm_play_dma_postinit(void)
518 void pcm_set_mixer_volume(int volume
)
522 #ifdef HAVE_RECORDING
523 void pcm_rec_lock(void)
527 void pcm_rec_unlock(void)
531 void pcm_rec_dma_init(void)
535 void pcm_rec_dma_close(void)
539 void pcm_rec_dma_start(void *start
, size_t size
)
545 void pcm_rec_dma_stop(void)
549 const void * pcm_rec_dma_get_peak_buffer(void)
554 void audiohw_set_recvol(int left
, int right
, int type
)
561 #endif /* HAVE_RECORDING */