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 void *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 if (!pcm_play_dma_complete_callback(PCM_DMAST_OK
, &pcm_data
,
232 copy_n
= MIN((ssize_t
)pcm_size
, frames_left
*4);
233 memcpy(&frames
[2*(period_size
-frames_left
)], pcm_data
, copy_n
);
237 frames_left
-= copy_n
/4;
242 pcm_play_dma_status_callback(PCM_DMAST_STARTED
);
248 #ifdef USE_ASYNC_CALLBACK
249 static void async_callback(snd_async_handler_t
*ahandler
)
251 snd_pcm_t
*handle
= snd_async_handler_get_pcm(ahandler
);
253 if (pthread_mutex_trylock(&pcm_mtx
) != 0)
256 static void pcm_tick(void)
258 if (snd_pcm_state(handle
) != SND_PCM_STATE_RUNNING
)
262 while (snd_pcm_avail_update(handle
) >= period_size
)
266 int err
= snd_pcm_writei(handle
, frames
, period_size
);
267 if (err
< 0 && err
!= period_size
&& err
!= -EAGAIN
)
269 printf("Write error: written %i expected %li\n", err
, period_size
);
275 DEBUGF("%s: No Data.\n", __func__
);
279 #ifdef USE_ASYNC_CALLBACK
280 pthread_mutex_unlock(&pcm_mtx
);
284 static int async_rw(snd_pcm_t
*handle
)
287 snd_pcm_sframes_t sample_size
;
290 #ifdef USE_ASYNC_CALLBACK
291 /* assign alternative stack for the signal handlers */
293 .ss_sp
= signal_stack
,
294 .ss_size
= sizeof(signal_stack
),
299 err
= sigaltstack(&ss
, NULL
);
302 DEBUGF("Unable to install alternative signal stack: %s", strerror(err
));
306 err
= snd_async_add_pcm_handler(&ahandler
, handle
, async_callback
, NULL
);
309 DEBUGF("Unable to register async handler: %s\n", snd_strerror(err
));
313 /* only modify the stack the handler runs on */
314 sigaction(SIGIO
, NULL
, &sa
);
315 sa
.sa_flags
|= SA_ONSTACK
;
316 err
= sigaction(SIGIO
, &sa
, NULL
);
319 DEBUGF("Unable to install alternative signal stack: %s", strerror(err
));
324 /* fill buffer with silence to initiate playback without noisy click */
325 sample_size
= buffer_size
;
326 samples
= malloc(sample_size
* channels
* sizeof(short));
328 snd_pcm_format_set_silence(format
, samples
, sample_size
);
329 err
= snd_pcm_writei(handle
, samples
, sample_size
);
334 DEBUGF("Initial write error: %s\n", snd_strerror(err
));
337 if (err
!= (ssize_t
)sample_size
)
339 DEBUGF("Initial write error: written %i expected %li\n", err
, sample_size
);
342 if (snd_pcm_state(handle
) == SND_PCM_STATE_PREPARED
)
344 err
= snd_pcm_start(handle
);
347 DEBUGF("Start error: %s\n", snd_strerror(err
));
359 snd_pcm_close(handle
);
363 void pcm_play_dma_init(void)
368 if ((err
= snd_pcm_open(&handle
, device
, SND_PCM_STREAM_PLAYBACK
, 0)) < 0)
370 printf("%s(): Cannot open device %s: %s\n", __func__
, device
, snd_strerror(err
));
375 if ((err
= snd_pcm_nonblock(handle
, 1)))
376 printf("Could not set non-block mode: %s\n", snd_strerror(err
));
378 if ((err
= set_hwparams(handle
, rate
)) < 0)
380 printf("Setting of hwparams failed: %s\n", snd_strerror(err
));
383 if ((err
= set_swparams(handle
)) < 0)
385 printf("Setting of swparams failed: %s\n", snd_strerror(err
));
389 pcm_dma_apply_settings();
391 #ifdef USE_ASYNC_CALLBACK
392 pthread_mutexattr_t attr
;
393 pthread_mutexattr_init(&attr
);
394 pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE
);
395 pthread_mutex_init(&pcm_mtx
, &attr
);
397 tick_add_task(pcm_tick
);
405 void pcm_play_lock(void)
407 #ifdef USE_ASYNC_CALLBACK
408 pthread_mutex_lock(&pcm_mtx
);
410 if (recursion
++ == 0)
411 tick_remove_task(pcm_tick
);
415 void pcm_play_unlock(void)
417 #ifdef USE_ASYNC_CALLBACK
418 pthread_mutex_unlock(&pcm_mtx
);
420 if (--recursion
== 0)
421 tick_add_task(pcm_tick
);
425 static void pcm_dma_apply_settings_nolock(void)
427 snd_pcm_drop(handle
);
428 set_hwparams(handle
, pcm_sampr
);
431 void pcm_dma_apply_settings(void)
434 pcm_dma_apply_settings_nolock();
439 void pcm_play_dma_pause(bool pause
)
441 snd_pcm_pause(handle
, pause
);
445 void pcm_play_dma_stop(void)
447 snd_pcm_drain(handle
);
450 void pcm_play_dma_start(const void *addr
, size_t size
)
452 pcm_dma_apply_settings_nolock();
459 snd_pcm_state_t state
= snd_pcm_state(handle
);
462 case SND_PCM_STATE_RUNNING
:
464 case SND_PCM_STATE_XRUN
:
466 DEBUGF("Trying to recover from error\n");
467 int err
= snd_pcm_recover(handle
, -EPIPE
, 0);
469 DEBUGF("Recovery failed: %s\n", snd_strerror(err
));
472 case SND_PCM_STATE_SETUP
:
474 int err
= snd_pcm_prepare(handle
);
476 printf("Prepare error: %s\n", snd_strerror(err
));
479 case SND_PCM_STATE_PREPARED
:
480 { /* prepared state, we need to fill the buffer with silence before
482 int err
= async_rw(handle
);
484 printf("Start error: %s\n", snd_strerror(err
));
487 case SND_PCM_STATE_PAUSED
:
488 { /* paused, simply resume */
489 pcm_play_dma_pause(0);
492 case SND_PCM_STATE_DRAINING
:
493 /* run until drained */
496 DEBUGF("Unhandled state: %s\n", snd_pcm_state_name(state
));
502 size_t pcm_get_bytes_waiting(void)
507 const void * pcm_play_dma_get_peak_buffer(int *count
)
509 uintptr_t addr
= (uintptr_t)pcm_data
;
510 *count
= pcm_size
/ 4;
511 return (void *)((addr
+ 3) & ~3);
514 void pcm_play_dma_postinit(void)
520 void pcm_set_mixer_volume(int volume
)
524 #ifdef HAVE_RECORDING
525 void pcm_rec_lock(void)
529 void pcm_rec_unlock(void)
533 void pcm_rec_dma_init(void)
537 void pcm_rec_dma_close(void)
541 void pcm_rec_dma_start(void *start
, size_t size
)
547 void pcm_rec_dma_stop(void)
551 const void * pcm_rec_dma_get_peak_buffer(void)
556 void audiohw_set_recvol(int left
, int right
, int type
)
563 #endif /* HAVE_RECORDING */