Make track_db public
[cmus.git] / alsa.c
blob64e12f730db5c916c3715379628bc6f12b22bb15
1 /*
2 * Copyright 2004-2005 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
21 * snd_pcm_state_t:
23 * Open
24 * SND_PCM_STATE_OPEN = 0,
26 * Setup installed
27 * SND_PCM_STATE_SETUP = 1,
29 * Ready to start
30 * SND_PCM_STATE_PREPARED = 2,
32 * Running
33 * SND_PCM_STATE_RUNNING = 3,
35 * Stopped: underrun (playback) or overrun (capture) detected
36 * SND_PCM_STATE_XRUN = 4,
38 * Draining: running (playback) or stopped (capture)
39 * SND_PCM_STATE_DRAINING = 5,
41 * Paused
42 * SND_PCM_STATE_PAUSED = 6,
44 * Hardware is suspended
45 * SND_PCM_STATE_SUSPENDED = 7,
47 * Hardware is disconnected
48 * SND_PCM_STATE_DISCONNECTED = 8,
51 #include "op.h"
52 #include "utils.h"
53 #include "xmalloc.h"
54 #include "sf.h"
55 #include "debug.h"
57 #define ALSA_PCM_NEW_HW_PARAMS_API
58 #define ALSA_PCM_NEW_SW_PARAMS_API
60 #include <alsa/asoundlib.h>
62 /* without one of these play-back won't start */
63 #define SET_BUFFER_TIME
64 #define SET_PERIOD_TIME
66 #define SET_AVAIL_MIN
68 /* with this alsa hangs sometimes (ogg, not enough data with first write?) */
69 /* #define SET_START_THRESHOLD */
71 static sample_format_t alsa_sf;
72 static snd_pcm_t *alsa_handle;
73 static snd_pcm_format_t alsa_fmt;
74 static int alsa_can_pause;
75 static snd_pcm_status_t *status;
77 /* bytes (bits * channels / 8) */
78 static int alsa_frame_size;
80 /* configuration */
81 static char *alsa_dsp_device = NULL;
83 #ifdef SET_START_THRESHOLD
84 static int alsa_buffer_size;
85 #endif
87 #ifdef SET_AVAIL_MIN
88 static int alsa_period_size;
89 #endif
91 #if 0
92 #define debug_ret(func, ret) \
93 d_print("%s returned %d %s\n", func, ret, ret < 0 ? snd_strerror(ret) : "")
94 #else
95 #define debug_ret(func, ret) do { } while (0)
96 #endif
98 static int alsa_error_to_op_error(int err)
100 err = -err;
101 if (err < SND_ERROR_BEGIN) {
102 errno = err;
103 return -OP_ERROR_ERRNO;
105 return -OP_ERROR_INTERNAL;
108 /* we don't want error messages to stderr */
109 static void error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...)
113 static int op_alsa_init(void)
115 int rc;
117 snd_lib_error_set_handler(error_handler);
119 if (alsa_dsp_device == NULL)
120 alsa_dsp_device = xstrdup("default");
121 rc = snd_pcm_status_malloc(&status);
122 if (rc < 0) {
123 free(alsa_dsp_device);
124 alsa_dsp_device = NULL;
125 errno = ENOMEM;
126 return -OP_ERROR_ERRNO;
128 return 0;
131 static int op_alsa_exit(void)
133 snd_pcm_status_free(status);
134 free(alsa_dsp_device);
135 alsa_dsp_device = NULL;
136 return 0;
139 /* randomize hw params */
140 static int alsa_set_hw_params(void)
142 snd_pcm_hw_params_t *hwparams;
143 const char *cmd;
144 unsigned int rate;
145 int rc, dir;
146 #if defined(SET_AVAIL_MIN) || defined(SET_START_THRESHOLD)
147 snd_pcm_uframes_t frames;
148 #endif
149 #ifdef SET_BUFFER_TIME
150 unsigned int alsa_buffer_time = 500e3;
151 #endif
152 #ifdef SET_PERIOD_TIME
153 unsigned int alsa_period_time = 50e3;
154 #endif
156 snd_pcm_hw_params_alloca(&hwparams);
158 cmd = "snd_pcm_hw_params_any";
159 rc = snd_pcm_hw_params_any(alsa_handle, hwparams);
160 if (rc < 0)
161 goto error;
163 alsa_can_pause = snd_pcm_hw_params_can_pause(hwparams);
164 d_print("can pause = %d\n", alsa_can_pause);
166 cmd = "snd_pcm_hw_params_set_access";
167 rc = snd_pcm_hw_params_set_access(alsa_handle, hwparams,
168 SND_PCM_ACCESS_RW_INTERLEAVED);
169 if (rc < 0)
170 goto error;
172 alsa_fmt = snd_pcm_build_linear_format(sf_get_bits(alsa_sf), sf_get_bits(alsa_sf),
173 sf_get_signed(alsa_sf) ? 0 : 1,
174 sf_get_bigendian(alsa_sf));
175 cmd = "snd_pcm_hw_params_set_format";
176 rc = snd_pcm_hw_params_set_format(alsa_handle, hwparams, alsa_fmt);
177 if (rc < 0)
178 goto error;
180 cmd = "snd_pcm_hw_params_set_channels";
181 rc = snd_pcm_hw_params_set_channels(alsa_handle, hwparams, sf_get_channels(alsa_sf));
182 if (rc < 0)
183 goto error;
185 cmd = "snd_pcm_hw_params_set_rate";
186 rate = sf_get_rate(alsa_sf);
187 dir = 0;
188 rc = snd_pcm_hw_params_set_rate_near(alsa_handle, hwparams, &rate, &dir);
189 if (rc < 0)
190 goto error;
191 d_print("rate=%d\n", rate);
193 #ifdef SET_BUFFER_TIME
194 cmd = "snd_pcm_hw_params_set_buffer_time_near";
195 dir = 0;
196 rc = snd_pcm_hw_params_set_buffer_time_near(alsa_handle, hwparams, &alsa_buffer_time, &dir);
197 if (rc < 0)
198 goto error;
199 #endif
201 #ifdef SET_PERIOD_TIME
202 cmd = "snd_pcm_hw_params_set_period_time_near";
203 dir = 0;
204 rc = snd_pcm_hw_params_set_period_time_near(alsa_handle, hwparams, &alsa_period_time, &dir);
205 if (rc < 0)
206 goto error;
207 #endif
209 #ifdef SET_AVAIL_MIN
210 rc = snd_pcm_hw_params_get_period_size(hwparams, &frames, &dir);
211 if (rc < 0) {
212 alsa_period_size = -1;
213 } else {
214 alsa_period_size = frames * alsa_frame_size;
216 d_print("period_size = %d (dir = %d)\n", alsa_period_size, dir);
217 #endif
219 #ifdef SET_START_THRESHOLD
220 rc = snd_pcm_hw_params_get_buffer_size(hwparams, &frames);
221 if (rc < 0) {
222 alsa_buffer_size = -1;
223 } else {
224 alsa_buffer_size = frames * alsa_frame_size;
226 d_print("buffer_size = %d\n", alsa_buffer_size);
227 #endif
229 cmd = "snd_pcm_hw_params";
230 rc = snd_pcm_hw_params(alsa_handle, hwparams);
231 if (rc < 0)
232 goto error;
233 return 0;
234 error:
235 d_print("%s: error: %s\n", cmd, snd_strerror(rc));
236 return rc;
239 /* randomize sw params */
240 static int alsa_set_sw_params(void)
242 #if defined(SET_START_THRESHOLD) || defined(SET_AVAIL_MIN)
243 snd_pcm_sw_params_t *swparams;
244 const char *cmd;
245 int rc;
247 /* allocate the software parameter structure */
248 snd_pcm_sw_params_alloca(&swparams);
250 /* fetch the current software parameters */
251 cmd = "snd_pcm_sw_params_current";
252 rc = snd_pcm_sw_params_current(alsa_handle, swparams);
253 if (rc < 0)
254 goto error;
256 #ifdef SET_START_THRESHOLD
257 if (alsa_buffer_size > 0) {
258 /* start the transfer when N frames available */
259 cmd = "snd_pcm_sw_params_set_start_threshold";
260 /* start playing when hardware buffer is full (64 kB, 372 ms) */
261 rc = snd_pcm_sw_params_set_start_threshold(alsa_handle, swparams, alsa_buffer_size / alsa_frame_size);
262 if (rc < 0)
263 goto error;
265 #endif
267 #ifdef SET_AVAIL_MIN
268 if (alsa_period_size > 0) {
269 snd_pcm_uframes_t frames = alsa_period_size / alsa_frame_size;
271 /* minimum avail frames to consider pcm ready. must be power of 2 */
272 cmd = "snd_pcm_sw_params_set_avail_min";
273 /* underrun when available is <8192 B or 46.5 ms */
274 rc = snd_pcm_sw_params_set_avail_min(alsa_handle, swparams, frames);
275 if (rc < 0)
276 goto error;
278 cmd = "snd_pcm_sw_params_set_silence_threshold";
279 rc = snd_pcm_sw_params_set_silence_threshold(alsa_handle, swparams, frames);
280 if (rc < 0)
281 goto error;
283 #endif
285 /* commit the params structure to ALSA */
286 cmd = "snd_pcm_sw_params";
287 rc = snd_pcm_sw_params(alsa_handle, swparams);
288 if (rc < 0)
289 goto error;
290 return 0;
291 error:
292 d_print("%s: error: %s\n", cmd, snd_strerror(rc));
293 return rc;
294 #else
295 return 0;
296 #endif
299 static int op_alsa_open(sample_format_t sf)
301 int rc;
303 alsa_sf = sf;
304 alsa_frame_size = sf_get_frame_size(alsa_sf);
306 rc = snd_pcm_open(&alsa_handle, alsa_dsp_device, SND_PCM_STREAM_PLAYBACK, 0);
307 if (rc < 0)
308 goto error;
310 rc = alsa_set_hw_params();
311 if (rc)
312 goto close_error;
313 rc = alsa_set_sw_params();
314 if (rc)
315 goto close_error;
317 rc = snd_pcm_prepare(alsa_handle);
318 if (rc < 0)
319 goto close_error;
320 return 0;
321 close_error:
322 snd_pcm_close(alsa_handle);
323 error:
324 return alsa_error_to_op_error(rc);
327 static unsigned int period_fill = 0;
329 static int op_alsa_write(const char *buffer, int count);
331 static int op_alsa_close(void)
333 int rc;
335 /* it is impossible to calculate period_fill if period_size is -1 */
336 if (alsa_period_size > 0 && period_fill) {
337 char buf[8192];
338 int silence_bytes = alsa_period_size - period_fill;
340 if (silence_bytes > sizeof(buf)) {
341 d_print("silence buf not big enough %d\n", silence_bytes);
342 silence_bytes = sizeof(buf);
344 d_print("silencing %d bytes\n", silence_bytes);
345 snd_pcm_format_set_silence(alsa_fmt, buf, silence_bytes / sf_get_sample_size(alsa_sf));
346 op_alsa_write(buf, silence_bytes);
347 period_fill = 0;
350 rc = snd_pcm_drain(alsa_handle);
351 debug_ret("snd_pcm_drain", rc);
353 rc = snd_pcm_close(alsa_handle);
354 debug_ret("snd_pcm_close", rc);
355 return 0;
358 static int op_alsa_drop(void)
360 int rc;
362 period_fill = 0;
364 /* infinite timeout */
365 rc = snd_pcm_wait(alsa_handle, -1);
366 debug_ret("snd_pcm_wait", rc);
368 rc = snd_pcm_drop(alsa_handle);
369 debug_ret("snd_pcm_drop", rc);
371 rc = snd_pcm_prepare(alsa_handle);
372 debug_ret("snd_pcm_prepare", rc);
374 /* drop set state to SETUP
375 * prepare set state to PREPARED
377 * so if old state was PAUSED we can't UNPAUSE (see op_alsa_unpause)
379 return 0;
382 static int op_alsa_write(const char *buffer, int count)
384 int rc, len;
385 int recovered = 0;
387 len = count / alsa_frame_size;
388 again:
389 rc = snd_pcm_writei(alsa_handle, buffer, len);
390 if (rc < 0) {
391 // rc _should_ be either -EBADFD, -EPIPE or -ESTRPIPE
392 if (!recovered && (rc == -EINTR || rc == -EPIPE || rc == -ESTRPIPE)) {
393 d_print("snd_pcm_writei failed: %s, trying to recover\n",
394 snd_strerror(rc));
395 recovered++;
396 // this handles -EINTR, -EPIPE and -ESTRPIPE
397 // for other errors it just returns the error code
398 rc = snd_pcm_recover(alsa_handle, rc, 1);
399 if (!rc)
400 goto again;
403 /* this handles EAGAIN too which is not critical error */
404 return alsa_error_to_op_error(rc);
407 rc *= alsa_frame_size;
408 period_fill += rc;
409 period_fill %= alsa_period_size;
410 return rc;
413 static int op_alsa_buffer_space(void)
415 int rc;
416 snd_pcm_uframes_t f;
418 rc = snd_pcm_status(alsa_handle, status);
419 if (rc < 0) {
420 debug_ret("snd_pcm_status", rc);
421 return alsa_error_to_op_error(rc);
424 f = snd_pcm_status_get_avail(status);
425 if (f > 1e6) {
426 d_print("snd_pcm_status_get_avail returned huge number: %lu\n", f);
427 f = 1024;
429 return f * alsa_frame_size;
432 static int op_alsa_pause(void)
434 if (alsa_can_pause) {
435 snd_pcm_state_t state;
436 int rc;
438 state = snd_pcm_state(alsa_handle);
439 if (state == SND_PCM_STATE_PREPARED) {
440 // state is PREPARED -> no need to pause
441 } else if (state == SND_PCM_STATE_RUNNING) {
442 // state is RUNNING - > pause
444 // infinite timeout
445 rc = snd_pcm_wait(alsa_handle, -1);
446 debug_ret("snd_pcm_wait", rc);
448 rc = snd_pcm_pause(alsa_handle, 1);
449 debug_ret("snd_pcm_pause", rc);
450 } else {
451 d_print("error: state is not RUNNING or PREPARED\n");
454 return 0;
457 static int op_alsa_unpause(void)
459 if (alsa_can_pause) {
460 snd_pcm_state_t state;
461 int rc;
463 state = snd_pcm_state(alsa_handle);
464 if (state == SND_PCM_STATE_PREPARED) {
465 // state is PREPARED -> no need to unpause
466 } else if (state == SND_PCM_STATE_PAUSED) {
467 // state is PAUSED -> unpause
469 // infinite timeout
470 rc = snd_pcm_wait(alsa_handle, -1);
471 debug_ret("snd_pcm_wait", rc);
473 rc = snd_pcm_pause(alsa_handle, 0);
474 debug_ret("snd_pcm_pause", rc);
475 } else {
476 d_print("error: state is not PAUSED nor PREPARED\n");
479 return 0;
482 static int op_alsa_set_option(int key, const char *val)
484 switch (key) {
485 case 0:
486 free(alsa_dsp_device);
487 alsa_dsp_device = xstrdup(val);
488 break;
489 default:
490 return -OP_ERROR_NOT_OPTION;
492 return 0;
495 static int op_alsa_get_option(int key, char **val)
497 switch (key) {
498 case 0:
499 if (alsa_dsp_device)
500 *val = xstrdup(alsa_dsp_device);
501 break;
502 default:
503 return -OP_ERROR_NOT_OPTION;
505 return 0;
508 const struct output_plugin_ops op_pcm_ops = {
509 .init = op_alsa_init,
510 .exit = op_alsa_exit,
511 .open = op_alsa_open,
512 .close = op_alsa_close,
513 .drop = op_alsa_drop,
514 .write = op_alsa_write,
515 .buffer_space = op_alsa_buffer_space,
516 .pause = op_alsa_pause,
517 .unpause = op_alsa_unpause,
518 .set_option = op_alsa_set_option,
519 .get_option = op_alsa_get_option
522 const char * const op_pcm_options[] = {
523 "device",
524 NULL
527 const int op_priority = 0;