src: rename file from *-* to *_*
[transsip-mirror.git] / src / alsa.c
blob00bf6d153d85de6e2a89f5522a9ffee1d696f139
1 /*
2 * transsip - the telephony toolkit
3 * By Daniel Borkmann <daniel@transsip.org>
4 * Copyright 2011-2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Swiss federal institute of technology (ETH Zurich)
6 * Copyright 2004-2006 Jean-Marc Valin
7 * Copyright 2006 Commonwealth Scientific and Industrial Research
8 * Organisation (CSIRO) Australia (2-clause BSD)
9 * Subject to the GPL, version 2.
12 #include <stdlib.h>
13 #include <sys/poll.h>
14 #include <alsa/asoundlib.h>
16 #include "built_in.h"
17 #include "die.h"
18 #include "alsa.h"
19 #include "xmalloc.h"
21 #define PERIODS 3
23 struct alsa_dev {
24 char *name;
25 int channels;
26 int period;
27 snd_pcm_t *capture_handle;
28 snd_pcm_t *playback_handle;
29 unsigned int read_fds;
30 struct pollfd *read_fd;
31 unsigned int write_fds;
32 struct pollfd *write_fd;
35 static void alsa_set_hw_params(struct alsa_dev *dev, snd_pcm_t *handle,
36 unsigned int rate, int channels, int period)
38 int dir, ret;
39 snd_pcm_uframes_t period_size;
40 snd_pcm_uframes_t buffer_size;
41 snd_pcm_hw_params_t *hw_params;
43 ret = snd_pcm_hw_params_malloc(&hw_params);
44 if (ret < 0)
45 panic("Cannot allocate hardware parameters: %s\n",
46 snd_strerror(ret));
48 ret = snd_pcm_hw_params_any(handle, hw_params);
49 if (ret < 0)
50 panic("Cannot initialize hardware parameters: %s\n",
51 snd_strerror(ret));
53 ret = snd_pcm_hw_params_set_access(handle, hw_params,
54 SND_PCM_ACCESS_RW_INTERLEAVED);
55 if (ret < 0)
56 panic("Cannot set access type: %s\n",
57 snd_strerror(ret));
59 ret = snd_pcm_hw_params_set_format(handle, hw_params,
60 SND_PCM_FORMAT_S16_LE);
61 if (ret < 0)
62 panic("Cannot set sample format: %s\n",
63 snd_strerror(ret));
65 ret = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rate, 0);
66 if (ret < 0)
67 panic("Cannot set sample rate: %s\n",
68 snd_strerror(ret));
70 ret = snd_pcm_hw_params_set_channels(handle, hw_params, channels);
71 if (ret < 0)
72 panic("Cannot set channel number: %s\n",
73 snd_strerror(ret));
75 period_size = period;
76 dir = 0;
77 ret = snd_pcm_hw_params_set_period_size_near(handle, hw_params,
78 &period_size, &dir);
79 if (ret < 0)
80 panic("Cannot set period size: %s\n",
81 snd_strerror(ret));
83 ret = snd_pcm_hw_params_set_periods(handle, hw_params, PERIODS, 0);
84 if (ret < 0)
85 panic("Cannot set period number: %s\n",
86 snd_strerror(ret));
88 buffer_size = period_size * PERIODS;
89 dir = 0;
90 ret = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params,
91 &buffer_size);
92 if (ret < 0)
93 panic("Cannot set buffer size: %s\n",
94 snd_strerror(ret));
96 ret = snd_pcm_hw_params(handle, hw_params);
97 if (ret < 0)
98 panic("Cannot set capture parameters: %s\n",
99 snd_strerror(ret));
101 snd_pcm_hw_params_free(hw_params);
104 static void alsa_set_sw_params(struct alsa_dev *dev, snd_pcm_t *handle,
105 int period, int thres)
107 int ret;
108 snd_pcm_sw_params_t *sw_params;
110 ret = snd_pcm_sw_params_malloc(&sw_params);
111 if (ret < 0)
112 panic("Cannot allocate software parameters: %s\n",
113 snd_strerror(ret));
115 ret = snd_pcm_sw_params_current(handle, sw_params);
116 if (ret < 0)
117 panic("Cannot initialize software parameters: %s\n",
118 snd_strerror(ret));
120 ret = snd_pcm_sw_params_set_avail_min(handle, sw_params, period);
121 if (ret < 0)
122 panic("Cannot set minimum available count: %s\n",
123 snd_strerror(ret));
125 if (thres) {
126 ret = snd_pcm_sw_params_set_start_threshold(handle, sw_params,
127 period);
128 if (ret < 0)
129 panic("Cannot set start mode: %s\n",
130 snd_strerror(ret));
134 ret = snd_pcm_sw_params(handle, sw_params);
135 if (ret < 0)
136 panic("Cannot set software parameters: %s\n",
137 snd_strerror(ret));
139 snd_pcm_sw_params_free(sw_params);
142 struct alsa_dev *alsa_open(char *devname, unsigned int rate,
143 int channels, int period)
145 int ret;
146 struct alsa_dev *dev;
148 if (!devname)
149 devname = "plughw:0,0";
151 dev = xzmalloc(sizeof(*dev));
152 dev->name = xstrdup(devname);
153 dev->channels = channels;
154 dev->period = period;
156 ret = snd_pcm_open(&dev->capture_handle, dev->name,
157 SND_PCM_STREAM_CAPTURE, 0);
158 if (ret < 0)
159 panic("Cannot open audio capture device %s: %s\n",
160 dev->name, snd_strerror(ret));
162 alsa_set_hw_params(dev, dev->capture_handle, rate, channels, period);
163 alsa_set_sw_params(dev, dev->capture_handle, period, 0);
165 ret = snd_pcm_open(&dev->playback_handle, dev->name,
166 SND_PCM_STREAM_PLAYBACK, 0);
167 if (ret < 0)
168 panic("Cannot open audio playback device %s: %s\n",
169 dev->name, snd_strerror(ret));
171 alsa_set_hw_params(dev, dev->playback_handle, rate, channels, period);
172 alsa_set_sw_params(dev, dev->playback_handle, period, 1);
174 snd_pcm_link(dev->capture_handle, dev->playback_handle);
176 ret = snd_pcm_prepare(dev->capture_handle);
177 if (ret < 0)
178 panic("Cannot prepare audio interface: %s\n",
179 snd_strerror(ret));
181 ret = snd_pcm_prepare(dev->playback_handle);
182 if (ret < 0)
183 panic("Cannot prepare audio interface: %s\n",
184 snd_strerror(ret));
186 dev->read_fds = snd_pcm_poll_descriptors_count(dev->capture_handle);
187 dev->write_fds = snd_pcm_poll_descriptors_count(dev->playback_handle);
188 dev->read_fd = xzmalloc(dev->read_fds * sizeof(*dev->read_fd));
190 ret = snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd,
191 dev->read_fds);
192 if (ret != dev->read_fds)
193 panic("Cannot obtain capture file descriptors: %s\n",
194 snd_strerror(ret));
196 dev->write_fd = xzmalloc(dev->write_fds * sizeof(*dev->write_fd));
198 ret = snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd,
199 dev->write_fds);
200 if (ret != dev->write_fds)
201 panic("Cannot obtain playback file descriptors: %s\n",
202 snd_strerror(ret));
204 return dev;
207 void alsa_close(struct alsa_dev *dev)
209 snd_pcm_close(dev->capture_handle);
210 snd_pcm_close(dev->playback_handle);
212 xfree(dev->name);
213 xfree(dev->read_fd);
214 xfree(dev->write_fd);
215 xfree(dev);
218 ssize_t alsa_read(struct alsa_dev *dev, short *pcm, size_t len)
220 ssize_t ret = snd_pcm_readi(dev->capture_handle, pcm, len);
221 if (unlikely(ret != len)) {
222 if (ret < 0) {
223 ret = snd_pcm_prepare(dev->capture_handle);
224 if (unlikely(ret < 0))
225 printf("Error preparing interface: %s\n",
226 snd_strerror(ret));
228 ret = snd_pcm_start(dev->capture_handle);
229 if (unlikely(ret < 0))
230 printf("Error preparing interface: %s\n",
231 snd_strerror(ret));
233 return 1;
235 return 0;
238 ssize_t alsa_write(struct alsa_dev *dev, const short *pcm, size_t len)
240 ssize_t ret = snd_pcm_writei(dev->playback_handle, pcm, len);
241 if (unlikely(ret != len)) {
242 if (ret < 0) {
243 ret = snd_pcm_prepare(dev->playback_handle);
244 if (unlikely(ret < 0))
245 printf("Error preparing interface: %s\n",
246 snd_strerror(ret));
248 return 1;
250 return 0;
253 int alsa_cap_ready(struct alsa_dev *dev, struct pollfd *pfds,
254 unsigned int nfds)
256 int ret;
257 unsigned short revents = 0;
259 ret = snd_pcm_poll_descriptors_revents(dev->capture_handle, pfds,
260 dev->read_fds, &revents);
261 if (ret < 0) {
262 whine("Error in alsa_cap_ready: %s\n", snd_strerror(ret));
263 return pfds[0].revents & POLLIN;
266 return revents & POLLIN;
269 int alsa_play_ready(struct alsa_dev *dev, struct pollfd *pfds,
270 unsigned int nfds)
272 int ret;
273 unsigned short revents = 0;
275 ret = snd_pcm_poll_descriptors_revents(dev->playback_handle,
276 pfds + dev->read_fds,
277 dev->write_fds, &revents);
278 if (ret < 0) {
279 whine("Error in alsa_play_ready: %s\n", snd_strerror(ret));
280 return pfds[1].revents & POLLOUT;
283 return revents & POLLOUT;
286 void alsa_start(struct alsa_dev *dev)
288 short *pcm;
289 size_t len = dev->period * dev->channels;
291 pcm = xzmalloc(len * sizeof(*pcm));
293 alsa_write(dev, pcm, dev->period);
294 alsa_write(dev, pcm, dev->period);
296 xfree(pcm);
298 snd_pcm_start(dev->capture_handle);
299 snd_pcm_start(dev->playback_handle);
302 void alsa_stop(struct alsa_dev *dev)
306 inline unsigned int alsa_nfds(struct alsa_dev *dev)
308 return dev->read_fds + dev->write_fds;
311 void alsa_getfds(struct alsa_dev *dev, struct pollfd *pfds,
312 unsigned int nfds)
314 int i;
316 for (i = 0; i < dev->read_fds; ++i)
317 pfds[i] = dev->read_fd[i];
319 for (i = 0; i < dev->write_fds; ++i)
320 pfds[i + dev->read_fds] = dev->write_fd[i];