2 * Copyright (C) 2008 Mark Hills <mark@pogo.org.uk>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * version 2, as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License version 2 for more details.
13 * You should have received a copy of the GNU General Public License
14 * version 2 along with this program; if not, write to the Free
15 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 #include <alsa/asoundlib.h>
26 #include "timecoder.h"
29 #define DEFAULT_ALSA_BUFFER 8 /* milliseconds */
30 static guint alsa_buffer
= DEFAULT_ALSA_BUFFER
;
32 /* This structure doesn't have corresponding functions to be an
33 * abstraction of the ALSA calls; it is merely a container for these
40 int pe_count
; /* number of pollfd entries */
43 snd_pcm_uframes_t period
;
48 struct alsa_pcm_t capture
, playback
;
52 static void alsa_error(const char *msg
, int r
)
54 fprintf(stderr
, "ALSA %s: %s\n", msg
, snd_strerror(r
));
58 static int pcm_open(struct alsa_pcm_t
*alsa
, const char *device_name
,
59 snd_pcm_stream_t stream
, int buffer_time
)
64 snd_pcm_hw_params_t
*hw_params
;
66 r
= snd_pcm_open(&alsa
->pcm
, device_name
, stream
, SND_PCM_NONBLOCK
);
68 alsa_error("open", r
);
72 r
= snd_pcm_hw_params_malloc(&hw_params
);
74 alsa_error("hw_params_malloc", r
);
78 r
= snd_pcm_hw_params_any(alsa
->pcm
, hw_params
);
80 alsa_error("hw_params_any", r
);
84 r
= snd_pcm_hw_params_set_access(alsa
->pcm
, hw_params
,
85 SND_PCM_ACCESS_RW_INTERLEAVED
);
87 alsa_error("hw_params_set_access", r
);
91 r
= snd_pcm_hw_params_set_format(alsa
->pcm
, hw_params
, SND_PCM_FORMAT_S16
);
93 alsa_error("hw_params_set_format", r
);
94 fprintf(stderr
, "16-bit signed format is not available. "
95 "You may need to use a 'plughw' device.\n");
99 r
= snd_pcm_hw_params_set_rate(alsa
->pcm
, hw_params
, DEVICE_RATE
, 0);
101 alsa_error("hw_params_set_rate", r
);
102 fprintf(stderr
, "%dHz sample rate not available. You may need to use "
103 "a 'plughw' device.\n", DEVICE_RATE
);
107 r
= snd_pcm_hw_params_set_channels(alsa
->pcm
, hw_params
, DEVICE_CHANNELS
);
109 alsa_error("hw_params_set_channels", r
);
110 fprintf(stderr
, "%d channel audio not available on this device.\n",
115 p
= buffer_time
* 1000; /* microseconds */
117 r
= snd_pcm_hw_params_set_buffer_time_max(alsa
->pcm
, hw_params
, &p
, &dir
);
119 alsa_error("hw_params_set_buffer_time_max", r
);
120 fprintf(stderr
, "Buffer of %dms may be too small for this hardware.\n",
125 r
= snd_pcm_hw_params(alsa
->pcm
, hw_params
);
127 alsa_error("hw_params", r
);
131 r
= snd_pcm_hw_params_get_period_size(hw_params
, &alsa
->period
, &dir
);
133 alsa_error("get_period_size", r
);
137 snd_pcm_hw_params_free(hw_params
);
139 bytes
= alsa
->period
* DEVICE_CHANNELS
* sizeof(signed short);
140 alsa
->buf
= malloc(bytes
);
146 /* snd_pcm_readi() returns uninitialised memory on first call,
147 * possibly caused by premature POLLIN. Keep valgrind happy. */
149 memset(alsa
->buf
, 0, bytes
);
155 static int pcm_close(struct alsa_pcm_t
*alsa
)
159 r
= snd_pcm_close(alsa
->pcm
);
161 alsa_error("close", r
);
170 static int pcm_pollfds(struct alsa_pcm_t
*alsa
, struct pollfd
*pe
, int n
)
174 count
= snd_pcm_poll_descriptors_count(alsa
->pcm
);
181 r
= snd_pcm_poll_descriptors(alsa
->pcm
, pe
, count
);
184 alsa_error("poll_descriptors", r
);
191 alsa
->pe_count
= count
;
196 static int pcm_revents(struct alsa_pcm_t
*alsa
, unsigned short *revents
) {
199 r
= snd_pcm_poll_descriptors_revents(alsa
->pcm
, alsa
->pe
, alsa
->pe_count
,
202 alsa_error("poll_descriptors_revents", r
);
211 /* Start the audio device capture and playback */
213 static int start(struct device_t
*dv
)
216 struct alsa_t
*alsa
= (struct alsa_t
*)dv
->local
;
218 r
= snd_pcm_start(alsa
->capture
.pcm
);
220 alsa_error("start", r
);
228 /* Register this device's interest in a set of pollfd file
231 static int pollfds(struct device_t
*dv
, struct pollfd
*pe
, int pe_size
)
234 struct alsa_t
*alsa
= (struct alsa_t
*)dv
->local
;
238 r
= pcm_pollfds(&alsa
->capture
, pe
, pe_size
);
246 r
= pcm_pollfds(&alsa
->playback
, pe
, pe_size
);
256 /* Collect audio from the player and push it into the device's buffer,
259 static int playback(struct device_t
*dv
)
262 struct alsa_t
*alsa
= (struct alsa_t
*)dv
->local
;
265 player_collect(dv
->player
, alsa
->playback
.buf
, alsa
->playback
.period
);
267 memset(alsa
->playback
.buf
, 0,
268 alsa
->playback
.period
* DEVICE_CHANNELS
* sizeof(short));
271 r
= snd_pcm_writei(alsa
->playback
.pcm
, alsa
->playback
.buf
,
272 alsa
->playback
.period
);
276 if(r
< alsa
->playback
.period
) {
277 fprintf(stderr
, "alsa: playback underrun %d/%ld.\n", r
,
278 alsa
->playback
.period
);
285 /* Pull audio from the device's buffer for capture, and pass it
286 * through to the timecoder */
288 static int capture(struct device_t
*dv
)
291 struct alsa_t
*alsa
= (struct alsa_t
*)dv
->local
;
293 r
= snd_pcm_readi(alsa
->capture
.pcm
, alsa
->capture
.buf
,
294 alsa
->capture
.period
);
298 if(r
< alsa
->capture
.period
) {
299 fprintf(stderr
, "alsa: capture underrun %d/%ld.\n",
300 r
, alsa
->capture
.period
);
304 timecoder_submit(dv
->timecoder
, alsa
->capture
.buf
, r
);
310 /* After poll() has returned, instruct a device to do all it can at
311 * the present time. Return zero if success, otherwise -1 */
313 static int handle(struct device_t
*dv
)
316 unsigned short revents
;
317 struct alsa_t
*alsa
= (struct alsa_t
*)dv
->local
;
319 /* Check input buffer for timecode capture */
321 r
= pcm_revents(&alsa
->capture
, &revents
);
325 if(revents
& POLLIN
) {
330 fputs("ALSA: capture xrun.\n", stderr
);
331 r
= snd_pcm_prepare(alsa
->capture
.pcm
);
333 alsa_error("prepare", r
);
337 r
= snd_pcm_start(alsa
->capture
.pcm
);
339 alsa_error("start", r
);
344 alsa_error("capture", r
);
350 /* Check the output buffer for playback */
352 r
= pcm_revents(&alsa
->playback
, &revents
);
356 if(revents
& POLLOUT
) {
361 fputs("ALSA: playback xrun.\n", stderr
);
363 r
= snd_pcm_prepare(alsa
->playback
.pcm
) < 0;
365 alsa_error("prepare", r
);
369 /* The device starts when data is written. POLLOUT
370 * events are generated in prepared state. */
373 alsa_error("playback", r
);
383 /* Close ALSA device and clear any allocations */
385 static int clear(struct device_t
*dv
)
387 struct alsa_t
*alsa
= (struct alsa_t
*)dv
->local
;
389 pcm_close(&alsa
->capture
);
390 pcm_close(&alsa
->playback
);
397 /* Open ALSA device. Do not operate on audio until device_start() */
399 int alsa_init(struct device_t
*dv
, const char *device_name
, int buffer_time
)
403 alsa
= malloc(sizeof(struct alsa_t
));
409 if(pcm_open(&alsa
->capture
, device_name
, SND_PCM_STREAM_CAPTURE
,
412 fputs("Failed to open device for capture.\n", stderr
);
416 if(pcm_open(&alsa
->playback
, device_name
, SND_PCM_STREAM_PLAYBACK
,
419 fputs("Failed to open device for playback.\n", stderr
);
425 dv
->pollfds
= pollfds
;
438 static gboolean
parse_alsa_device(const gchar
*option_name
, const gchar
*value
, gpointer data
, GError
**error
)
440 struct device_t
* device
= createDevice(error
);
445 return connectAudio(device
, alsa_init(device
, value
, alsa_buffer
));
448 static GOptionEntry alsaOptions
[] =
450 { "alsa_device", 'a', 0, G_OPTION_ARG_CALLBACK
, &parse_alsa_device
, "Build a deck connected to ALSA audio device", "hw:1,0"},
451 // Set size of ALSA buffer for subsequence devices
452 { "buffer_time", 'm', 0, G_OPTION_ARG_INT
, &alsa_buffer
, "Buffer size", NULL
},
456 GOptionGroup
* get_alsa_option_group()
458 GOptionGroup
* group
= g_option_group_new
461 "ALSA device options",
462 "Show ALSA help options",
467 if(alsaOptions
[1].arg_description
== NULL
)
468 alsaOptions
[1].arg_description
= g_strdup_printf("%u", DEFAULT_ALSA_BUFFER
);
470 g_option_group_add_entries(group
, alsaOptions
);