Removed files, reorganized code i.e. renamed write_or_die.c to xutils.c
[transsip.git] / src / alsa.c
blob8ff0d86cd3d1551f755f472efb88782e9672ebe0
1 /*
2 * transsip - the telephony network
3 * By Daniel Borkmann <daniel@transsip.org>
4 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Swiss federal institute of technology (ETH Zurich)
6 * Subject to the GPL, version 2.
7 */
9 /*
10 * Copyright (C) 2011 Daniel Borkmann (major cleanups, improvements, fixed bugs)
11 * Copyright (C) 2004-2006 Jean-Marc Valin
12 * Copyright (C) 2006 Commonwealth Scientific and Industrial Research
13 * Organisation (CSIRO) Australia
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions are
17 * met:
19 * 1. Redistributions of source code must retain the above copyright notice,
20 * this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
39 #include "compiler.h"
40 #include "die.h"
41 #include "alsa.h"
42 #include "xmalloc.h"
43 #include "xutils.h"
45 #define PERIODS 3
47 struct alsa_dev {
48 char *name;
49 int channels;
50 int period;
51 snd_pcm_t *capture_handle;
52 snd_pcm_t *playback_handle;
53 unsigned int read_fds;
54 struct pollfd *read_fd;
55 unsigned int write_fds;
56 struct pollfd *write_fd;
59 static void alsa_set_hw_params(struct alsa_dev *dev, snd_pcm_t *handle,
60 unsigned int rate, int channels, int period)
62 int dir, ret;
63 snd_pcm_uframes_t period_size;
64 snd_pcm_uframes_t buffer_size;
65 snd_pcm_hw_params_t *hw_params;
67 ret = snd_pcm_hw_params_malloc(&hw_params);
68 if (ret < 0)
69 panic("Cannot allocate hardware parameters: %s\n",
70 snd_strerror(ret));
71 ret = snd_pcm_hw_params_any(handle, hw_params);
72 if (ret < 0)
73 panic("Cannot initialize hardware parameters: %s\n",
74 snd_strerror(ret));
75 ret = snd_pcm_hw_params_set_access(handle, hw_params,
76 SND_PCM_ACCESS_RW_INTERLEAVED);
77 if (ret < 0)
78 panic("Cannot set access type: %s\n",
79 snd_strerror(ret));
80 ret = snd_pcm_hw_params_set_format(handle, hw_params,
81 SND_PCM_FORMAT_S16_LE);
82 if (ret < 0)
83 panic("Cannot set sample format: %s\n",
84 snd_strerror(ret));
85 ret = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rate, 0);
86 if (ret < 0)
87 panic("Cannot set sample rate: %s\n",
88 snd_strerror(ret));
89 ret = snd_pcm_hw_params_set_channels(handle, hw_params, channels);
90 if (ret < 0)
91 panic("Cannot set channel number: %s\n",
92 snd_strerror(ret));
93 period_size = period;
94 dir = 0;
95 ret = snd_pcm_hw_params_set_period_size_near(handle, hw_params,
96 &period_size, &dir);
97 if (ret < 0)
98 panic("Cannot set period size: %s\n",
99 snd_strerror(ret));
100 ret = snd_pcm_hw_params_set_periods(handle, hw_params, PERIODS, 0);
101 if (ret < 0)
102 panic("Cannot set period number: %s\n",
103 snd_strerror(ret));
104 buffer_size = period_size * PERIODS;
105 dir = 0;
106 ret = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params,
107 &buffer_size);
108 if (ret < 0)
109 panic("Cannot set buffer size: %s\n",
110 snd_strerror(ret));
111 ret = snd_pcm_hw_params(handle, hw_params);
112 if (ret < 0)
113 panic("Cannot set capture parameters: %s\n",
114 snd_strerror(ret));
115 snd_pcm_hw_params_free(hw_params);
118 static void alsa_set_sw_params(struct alsa_dev *dev, snd_pcm_t *handle,
119 int period, int thres)
121 int ret;
122 snd_pcm_sw_params_t *sw_params;
124 ret = snd_pcm_sw_params_malloc(&sw_params);
125 if (ret < 0)
126 panic("Cannot allocate software parameters: %s\n",
127 snd_strerror(ret));
128 ret = snd_pcm_sw_params_current(handle, sw_params);
129 if (ret < 0)
130 panic("Cannot initialize software parameters: %s\n",
131 snd_strerror(ret));
132 ret = snd_pcm_sw_params_set_avail_min(handle, sw_params, period);
133 if (ret < 0)
134 panic("Cannot set minimum available count: %s\n",
135 snd_strerror(ret));
136 if (thres) {
137 ret = snd_pcm_sw_params_set_start_threshold(handle, sw_params,
138 period);
139 if (ret < 0)
140 panic("Cannot set start mode: %s\n",
141 snd_strerror(ret));
144 ret = snd_pcm_sw_params(handle, sw_params);
145 if (ret < 0)
146 panic("Cannot set software parameters: %s\n",
147 snd_strerror(ret));
148 snd_pcm_sw_params_free(sw_params);
151 struct alsa_dev *alsa_open(char *devname, unsigned int rate,
152 int channels, int period)
154 int ret;
155 struct alsa_dev *dev;
157 if (!devname)
158 devname = "plughw:0,0";
160 dev = xzmalloc(sizeof(*dev));
161 dev->name = xstrdup(devname);
162 dev->channels = channels;
163 dev->period = period;
165 ret = snd_pcm_open(&dev->capture_handle, dev->name,
166 SND_PCM_STREAM_CAPTURE, 0);
167 if (ret < 0)
168 panic("Cannot open audio capture device %s: %s\n",
169 dev->name, snd_strerror(ret));
170 alsa_set_hw_params(dev, dev->capture_handle, rate, channels, period);
171 alsa_set_sw_params(dev, dev->capture_handle, period, 0);
173 ret = snd_pcm_open(&dev->playback_handle, dev->name,
174 SND_PCM_STREAM_PLAYBACK, 0);
175 if (ret < 0)
176 panic("Cannot open audio playback device %s: %s\n",
177 dev->name, snd_strerror(ret));
178 alsa_set_hw_params(dev, dev->playback_handle, rate, channels, period);
179 alsa_set_sw_params(dev, dev->playback_handle, period, 1);
181 snd_pcm_link(dev->capture_handle, dev->playback_handle);
183 ret = snd_pcm_prepare(dev->capture_handle);
184 if (ret < 0)
185 panic("Cannot prepare audio interface: %s\n",
186 snd_strerror(ret));
188 ret = snd_pcm_prepare(dev->playback_handle);
189 if (ret < 0)
190 panic("Cannot prepare audio interface: %s\n",
191 snd_strerror(ret));
193 dev->read_fds = snd_pcm_poll_descriptors_count(dev->capture_handle);
194 dev->write_fds = snd_pcm_poll_descriptors_count(dev->playback_handle);
196 dev->read_fd = xzmalloc(dev->read_fds * sizeof(*dev->read_fd));
197 ret = snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd,
198 dev->read_fds);
199 if (ret != dev->read_fds)
200 panic("Cannot obtain capture file descriptors: %s\n",
201 snd_strerror(ret));
203 dev->write_fd = xzmalloc(dev->write_fds * sizeof(*dev->write_fd));
204 ret = snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd,
205 dev->write_fds);
206 if (ret != dev->write_fds)
207 panic("Cannot obtain playback file descriptors: %s\n",
208 snd_strerror(ret));
210 return dev;
213 void alsa_close(struct alsa_dev *dev)
215 snd_pcm_close(dev->capture_handle);
216 snd_pcm_close(dev->playback_handle);
218 xfree(dev->name);
219 xfree(dev->read_fd);
220 xfree(dev->write_fd);
221 xfree(dev);
224 ssize_t alsa_read(struct alsa_dev *dev, short *pcm, size_t len)
226 ssize_t ret;
227 ret = snd_pcm_readi(dev->capture_handle, pcm, len);
228 if (unlikely(ret != len)) {
229 if (ret < 0) {
230 if (ret == -EPIPE) {
231 info("An overrun has occured, "
232 "reseting capture!\n");
233 } else {
234 info("Read from audio interface "
235 "failed: %s\n", snd_strerror(ret));
238 ret = snd_pcm_prepare(dev->capture_handle);
239 if (unlikely(ret < 0))
240 info("Error preparing interface: %s\n",
241 snd_strerror(ret));
243 ret = snd_pcm_start(dev->capture_handle);
244 if (unlikely(ret < 0))
245 info("Error preparing interface: %s\n",
246 snd_strerror(ret));
250 return ret;
253 ssize_t alsa_write(struct alsa_dev *dev, const short *pcm, size_t len)
255 ssize_t ret;
256 ret = snd_pcm_writei(dev->playback_handle, pcm, len);
257 if (unlikely(ret != len)) {
258 if (ret < 0) {
259 if (ret == -EPIPE) {
260 info("An underrun has occured, "
261 "reseting playback!\n");
262 } else {
263 info("Write to audio interface "
264 "failed: %s\n", snd_strerror(ret));
267 ret = snd_pcm_prepare(dev->playback_handle);
268 if (unlikely(ret < 0))
269 info("Error preparing interface: %s\n",
270 snd_strerror(ret));
274 return ret;
277 int alsa_cap_ready(struct alsa_dev *dev, struct pollfd *pfds,
278 unsigned int nfds)
280 int ret;
281 unsigned short revents = 0;
283 ret = snd_pcm_poll_descriptors_revents(dev->capture_handle, pfds,
284 dev->read_fds, &revents);
285 if (ret < 0) {
286 whine("Error in alsa_cap_ready: %s\n", snd_strerror(ret));
287 return pfds[0].revents & POLLIN;
290 return revents & POLLIN;
293 int alsa_play_ready(struct alsa_dev *dev, struct pollfd *pfds,
294 unsigned int nfds)
296 int ret;
297 unsigned short revents = 0;
298 ret = snd_pcm_poll_descriptors_revents(dev->playback_handle,
299 pfds + dev->read_fds,
300 dev->write_fds, &revents);
301 if (ret < 0) {
302 whine("Error in alsa_play_ready: %s\n", snd_strerror(ret));
303 return pfds[1].revents & POLLOUT;
306 return revents & POLLOUT;
309 void alsa_start(struct alsa_dev *dev)
311 short *pcm;
312 size_t len = dev->period * dev->channels;
314 pcm = xzmalloc(len * sizeof(*pcm));
315 alsa_write(dev, pcm, dev->period);
316 alsa_write(dev, pcm, dev->period);
317 xfree(pcm);
319 snd_pcm_start(dev->capture_handle);
320 snd_pcm_start(dev->playback_handle);
323 inline unsigned int alsa_nfds(struct alsa_dev *dev)
325 return dev->read_fds + dev->write_fds;
328 void alsa_getfds(struct alsa_dev *dev, struct pollfd *pfds,
329 unsigned int nfds)
331 int i;
333 BUG_ON(nfds < alsa_nfds(dev), "%s\n", __func__);
335 for (i = 0; i < dev->read_fds; ++i)
336 pfds[i] = dev->read_fd[i];
337 for (i = 0; i < dev->write_fds; ++i)
338 pfds[i + dev->read_fds] = dev->write_fd[i];