2 * This file is part of DisOrder.
3 * Copyright (C) 2008 Richard Kettlewell
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * @brief Background-thread interface to ALSA
26 #if HAVE_ALSA_ASOUNDLIB_H
29 #include <alsa/asoundlib.h>
35 /** @brief Output handle */
36 static snd_pcm_t
*pcm
;
38 /** @brief Called to get audio data */
39 static alsa_bg_supply
*supplyfn
;
41 static pthread_t alsa_bg_collect_tid
, alsa_bg_play_tid
;
43 /** @brief Set to shut down the background threads */
44 static int alsa_bg_shutdown
= 0;
46 /** @brief Number of channels (samples per frame) */
49 /** @brief Number of bytes per samples */
50 #define BYTES_PER_SAMPLE 2
52 /** @brief Number of bytes per frame */
53 #define BYTES_PER_FRAME (CHANNELS * BYTES_PER_SAMPLE)
55 /** @brief Buffer size in bytes */
56 #define BUFFER_BYTES 65536
58 /** @brief Buffer size in frames */
59 #define BUFFER_FRAMES (BUFFER_BYTES / BYTES_PER_FRAME)
61 /** @brief Buffer size in samples */
62 #define BUFFER_SAMPLES (BUFFER_BYTES / BYTES_PER_SAMPLE)
64 /** @brief Audio buffer */
65 static uint8_t alsa_bg_buffer
[BUFFER_BYTES
];
67 /** @brief First playable byte in audio buffer */
68 static unsigned alsa_bg_start
;
70 /** @brief Number of playable bytes in audio buffer */
71 static unsigned alsa_bg_count
;
73 /** @brief Current enable status */
74 static int alsa_bg_enabled
;
76 /** @brief Lock protecting audio buffer pointers */
77 static pthread_mutex_t alsa_bg_lock
= PTHREAD_MUTEX_INITIALIZER
;
79 /** @brief Signaled when buffer contents changes */
80 static pthread_cond_t alsa_bg_cond
= PTHREAD_COND_INITIALIZER
;
82 /** @brief Call a pthread_ function and fatal() on exit */
87 fatal(prc, "%s", #x); \
90 /** @brief Data collection thread
92 * This thread collects audio data to play and stores it in the ring
95 static void *alsa_bg_collect(void attribute((unused
)) *arg
) {
96 unsigned avail_start
, avail_count
;
99 ep(pthread_mutex_lock(&alsa_bg_lock
));
101 /* If we're shutting down, quit straight away */
104 /* While we're disabled or the buffer is full, just wait */
105 if(!alsa_bg_enabled
|| alsa_bg_count
== BUFFER_BYTES
) {
106 ep(pthread_cond_wait(&alsa_bg_cond
, &alsa_bg_lock
));
109 /* Figure out where and how big the gap we can write into is */
110 avail_start
= alsa_bg_start
+ alsa_bg_count
;
111 if(avail_start
< BUFFER_BYTES
)
112 avail_count
= BUFFER_BYTES
- avail_start
;
114 avail_start
%= BUFFER_BYTES
;
115 avail_count
= alsa_bg_start
- avail_start
;
117 assert(avail_start
< BUFFER_BYTES
);
118 assert(avail_count
<= BUFFER_BYTES
);
119 assert(avail_count
+ alsa_bg_count
<= BUFFER_BYTES
);
120 ep(pthread_mutex_unlock(&alsa_bg_lock
));
121 count
= supplyfn(alsa_bg_buffer
+ avail_start
,
122 avail_count
/ BYTES_PER_SAMPLE
);
123 ep(pthread_mutex_lock(&alsa_bg_lock
));
124 alsa_bg_count
+= count
* BYTES_PER_SAMPLE
;
125 assert(alsa_bg_start
< BUFFER_BYTES
);
126 assert(alsa_bg_count
<= BUFFER_BYTES
);
127 ep(pthread_cond_signal(&alsa_bg_cond
));
129 ep(pthread_mutex_unlock(&alsa_bg_lock
));
133 /** @brief Playback thread
135 * This thread reads audio data out of the ring buffer and plays it back
137 static void *alsa_bg_play(void attribute((unused
)) *arg
) {
138 int prepared
= 1, err
;
139 int start
, nbytes
, nframes
, rframes
;
141 ep(pthread_mutex_lock(&alsa_bg_lock
));
143 /* If we're shutting down, quit straight away */
146 /* Wait for some data to be available. (If we are marked disabled
147 * we keep on playing what we've got.) */
148 if(alsa_bg_count
== 0) {
150 if((err
= snd_pcm_drain(pcm
)))
151 fatal(0, "snd_pcm_drain: %d", err
);
154 ep(pthread_cond_wait(&alsa_bg_cond
, &alsa_bg_lock
));
157 /* Calculate how much we can play */
158 start
= alsa_bg_start
;
159 if(start
+ alsa_bg_count
<= BUFFER_BYTES
)
160 nbytes
= alsa_bg_count
;
162 nbytes
= BUFFER_BYTES
- start
;
163 /* Limit how much of the buffer we play. The effect is that we return from
164 * _writei earlier, and therefore free up more buffer space to read fresh
165 * data into. /2 works fine, /4 is just conservative. /1 (i.e. abolishing
166 * the heuristic) produces noticably noisy output. */
167 if(nbytes
> BUFFER_BYTES
/ 4)
168 nbytes
= BUFFER_BYTES
/ 4;
169 assert((unsigned)nbytes
<= alsa_bg_count
);
170 nframes
= nbytes
/ BYTES_PER_FRAME
;
171 ep(pthread_mutex_unlock(&alsa_bg_lock
));
172 /* Make sure the PCM is prepared */
174 if((err
= snd_pcm_prepare(pcm
)))
175 fatal(0, "snd_pcm_prepare: %d", err
);
178 /* Play what we can */
179 rframes
= snd_pcm_writei(pcm
, alsa_bg_buffer
+ start
, nframes
);
180 ep(pthread_mutex_lock(&alsa_bg_lock
));
184 error(0, "underrun detected");
185 if((err
= snd_pcm_prepare(pcm
)))
186 fatal(0, "snd_pcm_prepare: %d", err
);
189 fatal(0, "snd_pcm_writei: %d", rframes
);
192 const int rbytes
= rframes
* BYTES_PER_FRAME
;
193 /*fprintf(stderr, "%5d -> %5d\n", nbytes, rbytes);*/
194 /* Update the buffer pointers */
195 alsa_bg_count
-= rbytes
;
196 alsa_bg_start
+= rbytes
;
197 if(alsa_bg_start
>= BUFFER_BYTES
)
198 alsa_bg_start
-= BUFFER_BYTES
;
199 assert(alsa_bg_start
< BUFFER_BYTES
);
200 assert(alsa_bg_count
<= BUFFER_BYTES
);
201 /* Let the collector know we've opened up some space */
202 ep(pthread_cond_signal(&alsa_bg_cond
));
205 ep(pthread_mutex_unlock(&alsa_bg_lock
));
209 /** @brief Enable ALSA play */
210 void alsa_bg_enable(void) {
211 ep(pthread_mutex_lock(&alsa_bg_lock
));
213 ep(pthread_cond_broadcast(&alsa_bg_cond
));
214 ep(pthread_mutex_unlock(&alsa_bg_lock
));
217 /** @brief Disable ALSA play */
218 void alsa_bg_disable(void) {
219 ep(pthread_mutex_lock(&alsa_bg_lock
));
221 ep(pthread_cond_broadcast(&alsa_bg_cond
));
222 ep(pthread_mutex_unlock(&alsa_bg_lock
));
225 /** @brief Initialize background ALSA playback
226 * @param device Target device or NULL to use default
227 * @param supply Function to call to get audio data to play
229 * Playback is not initially enabled; see alsa_bg_enable(). When playback is
230 * enabled, @p supply will be called in a background thread to request audio
231 * data. It should return in a timely manner, but playback happens from a
232 * further thread and delays in @p supply will not delay transfer of data to
233 * the sound device (provided it doesn't actually run out).
235 void alsa_bg_init(const char *device
,
236 alsa_bg_supply
*supply
) {
237 snd_pcm_hw_params_t
*hwparams
;
238 /* Only support one format for now */
239 const int sample_format
= SND_PCM_FORMAT_S16_BE
;
240 unsigned rate
= 44100;
243 if((err
= snd_pcm_open(&pcm
,
244 device ? device
: "default",
245 SND_PCM_STREAM_PLAYBACK
,
247 fatal(0, "error from snd_pcm_open: %d", err
);
248 /* Set up 'hardware' parameters */
249 snd_pcm_hw_params_alloca(&hwparams
);
250 if((err
= snd_pcm_hw_params_any(pcm
, hwparams
)) < 0)
251 fatal(0, "error from snd_pcm_hw_params_any: %d", err
);
252 if((err
= snd_pcm_hw_params_set_access(pcm
, hwparams
,
253 SND_PCM_ACCESS_RW_INTERLEAVED
)) < 0)
254 fatal(0, "error from snd_pcm_hw_params_set_access: %d", err
);
255 if((err
= snd_pcm_hw_params_set_format(pcm
, hwparams
,
258 fatal(0, "error from snd_pcm_hw_params_set_format (%d): %d",
260 if((err
= snd_pcm_hw_params_set_rate_near(pcm
, hwparams
, &rate
, 0)) < 0)
261 fatal(0, "error from snd_pcm_hw_params_set_rate (%d): %d",
263 if((err
= snd_pcm_hw_params_set_channels(pcm
, hwparams
,
265 fatal(0, "error from snd_pcm_hw_params_set_channels (%d): %d",
267 if((err
= snd_pcm_hw_params(pcm
, hwparams
)) < 0)
268 fatal(0, "error calling snd_pcm_hw_params: %d", err
);
270 /* Record the audio supply function */
273 /* Create the audio output thread */
274 alsa_bg_shutdown
= 0;
276 ep(pthread_create(&alsa_bg_collect_tid
, 0, alsa_bg_collect
, 0));
277 ep(pthread_create(&alsa_bg_play_tid
, 0, alsa_bg_play
, 0));
280 void alsa_bg_close(void) {
283 /* Notify background threads that we're shutting down */
284 ep(pthread_mutex_lock(&alsa_bg_lock
));
286 alsa_bg_shutdown
= 1;
287 ep(pthread_cond_signal(&alsa_bg_cond
));
288 ep(pthread_mutex_unlock(&alsa_bg_lock
));
289 /* Join background threads when they're done */
290 ep(pthread_join(alsa_bg_collect_tid
, &r
));
291 ep(pthread_join(alsa_bg_play_tid
, &r
));
292 /* Close audio device */