ethernetgmii: make design files compile (warning: takes longer than 1 hour)
[ana-net.git] / app / alsa.c
bloba1e41ef603ccc5db00430b160fdaf48542898988
1 /*
2 * Lightweight Autonomic Network Architecture
3 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
4 * Swiss federal institute of technology (ETH Zurich)
5 * Subject to the GPL.
6 */
8 /*
9 * Copyright (C) 2011 Daniel Borkmann (major cleanups, improvements, fixed bugs)
10 * Copyright (C) 2004-2006 Jean-Marc Valin
11 * Copyright (C) 2006 Commonwealth Scientific and Industrial Research
12 * Organisation (CSIRO) Australia
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met:
18 * 1. Redistributions of source code must retain the above copyright notice,
19 * this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
38 #include "compiler.h"
39 #include "die.h"
40 #include "alsa.h"
41 #include "xmalloc.h"
42 #include "strlcpy.h"
44 #define PERIODS 3
46 struct alsa_dev {
47 char *name;
48 int channels;
49 int period;
50 snd_pcm_t *capture_handle;
51 snd_pcm_t *playback_handle;
52 unsigned int read_fds;
53 struct pollfd *read_fd;
54 unsigned int write_fds;
55 struct pollfd *write_fd;
58 static void alsa_set_hw_params(struct alsa_dev *dev, snd_pcm_t *handle,
59 unsigned int rate, int channels, int period)
61 int dir, ret;
62 snd_pcm_uframes_t period_size;
63 snd_pcm_uframes_t buffer_size;
64 snd_pcm_hw_params_t *hw_params;
66 ret = snd_pcm_hw_params_malloc(&hw_params);
67 if (ret < 0)
68 panic("Cannot allocate hardware parameters: %s\n",
69 snd_strerror(ret));
70 ret = snd_pcm_hw_params_any(handle, hw_params);
71 if (ret < 0)
72 panic("Cannot initialize hardware parameters: %s\n",
73 snd_strerror(ret));
74 ret = snd_pcm_hw_params_set_access(handle, hw_params,
75 SND_PCM_ACCESS_RW_INTERLEAVED);
76 if (ret < 0)
77 panic("Cannot set access type: %s\n",
78 snd_strerror(ret));
79 ret = snd_pcm_hw_params_set_format(handle, hw_params,
80 SND_PCM_FORMAT_S16_LE);
81 if (ret < 0)
82 panic("Cannot set sample format: %s\n",
83 snd_strerror(ret));
84 ret = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rate, 0);
85 if (ret < 0)
86 panic("Cannot set sample rate: %s\n",
87 snd_strerror(ret));
88 ret = snd_pcm_hw_params_set_channels(handle, hw_params, channels);
89 if (ret < 0)
90 panic("Cannot set channel number: %s\n",
91 snd_strerror(ret));
92 period_size = period;
93 dir = 0;
94 ret = snd_pcm_hw_params_set_period_size_near(handle, hw_params,
95 &period_size, &dir);
96 if (ret < 0)
97 panic("Cannot set period size: %s\n",
98 snd_strerror(ret));
99 ret = snd_pcm_hw_params_set_periods(handle, hw_params, PERIODS, 0);
100 if (ret < 0)
101 panic("Cannot set period number: %s\n",
102 snd_strerror(ret));
103 buffer_size = period_size * PERIODS;
104 dir = 0;
105 ret = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params,
106 &buffer_size);
107 if (ret < 0)
108 panic("Cannot set buffer size: %s\n",
109 snd_strerror(ret));
110 ret = snd_pcm_hw_params(handle, hw_params);
111 if (ret < 0)
112 panic("Cannot set capture parameters: %s\n",
113 snd_strerror(ret));
114 snd_pcm_hw_params_free(hw_params);
117 static void alsa_set_sw_params(struct alsa_dev *dev, snd_pcm_t *handle,
118 int period, int thres)
120 int ret;
121 snd_pcm_sw_params_t *sw_params;
123 ret = snd_pcm_sw_params_malloc(&sw_params);
124 if (ret < 0)
125 panic("Cannot allocate software parameters: %s\n",
126 snd_strerror(ret));
127 ret = snd_pcm_sw_params_current(handle, sw_params);
128 if (ret < 0)
129 panic("Cannot initialize software parameters: %s\n",
130 snd_strerror(ret));
131 ret = snd_pcm_sw_params_set_avail_min(handle, sw_params, period);
132 if (ret < 0)
133 panic("Cannot set minimum available count: %s\n",
134 snd_strerror(ret));
135 if (thres) {
136 ret = snd_pcm_sw_params_set_start_threshold(handle, sw_params,
137 period);
138 if (ret < 0)
139 panic("Cannot set start mode: %s\n",
140 snd_strerror(ret));
143 ret = snd_pcm_sw_params(handle, sw_params);
144 if (ret < 0)
145 panic("Cannot set software parameters: %s\n",
146 snd_strerror(ret));
147 snd_pcm_sw_params_free(sw_params);
150 struct alsa_dev *alsa_open(char *devname, unsigned int rate,
151 int channels, int period)
153 int ret;
154 struct alsa_dev *dev;
156 if (!devname)
157 devname = "plughw:0,0";
159 dev = xzmalloc(sizeof(*dev));
160 dev->name = xstrdup(devname);
161 dev->channels = channels;
162 dev->period = period;
164 ret = snd_pcm_open(&dev->capture_handle, dev->name,
165 SND_PCM_STREAM_CAPTURE, 0);
166 if (ret < 0)
167 panic("Cannot open audio capture device %s: %s\n",
168 dev->name, snd_strerror(ret));
169 alsa_set_hw_params(dev, dev->capture_handle, rate, channels, period);
170 alsa_set_sw_params(dev, dev->capture_handle, period, 0);
172 ret = snd_pcm_open(&dev->playback_handle, dev->name,
173 SND_PCM_STREAM_PLAYBACK, 0);
174 if (ret < 0)
175 panic("Cannot open audio playback device %s: %s\n",
176 dev->name, snd_strerror(ret));
177 alsa_set_hw_params(dev, dev->playback_handle, rate, channels, period);
178 alsa_set_sw_params(dev, dev->playback_handle, period, 1);
180 snd_pcm_link(dev->capture_handle, dev->playback_handle);
182 ret = snd_pcm_prepare(dev->capture_handle);
183 if (ret < 0)
184 panic("Cannot prepare audio interface: %s\n",
185 snd_strerror(ret));
187 ret = snd_pcm_prepare(dev->playback_handle);
188 if (ret < 0)
189 panic("Cannot prepare audio interface: %s\n",
190 snd_strerror(ret));
192 dev->read_fds = snd_pcm_poll_descriptors_count(dev->capture_handle);
193 dev->write_fds = snd_pcm_poll_descriptors_count(dev->playback_handle);
195 dev->read_fd = xzmalloc(dev->read_fds * sizeof(*dev->read_fd));
196 ret = snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd,
197 dev->read_fds);
198 if (ret != dev->read_fds)
199 panic("Cannot obtain capture file descriptors: %s\n",
200 snd_strerror(ret));
202 dev->write_fd = xzmalloc(dev->write_fds * sizeof(*dev->write_fd));
203 ret = snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd,
204 dev->write_fds);
205 if (ret != dev->write_fds)
206 panic("Cannot obtain playback file descriptors: %s\n",
207 snd_strerror(ret));
209 return dev;
212 void alsa_close(struct alsa_dev *dev)
214 snd_pcm_close(dev->capture_handle);
215 snd_pcm_close(dev->playback_handle);
217 xfree(dev->name);
218 xfree(dev->read_fd);
219 xfree(dev->write_fd);
220 xfree(dev);
223 ssize_t alsa_read(struct alsa_dev *dev, short *pcm, size_t len)
225 ssize_t ret;
226 ret = snd_pcm_readi(dev->capture_handle, pcm, len);
227 if (unlikely(ret != len)) {
228 if (ret < 0) {
229 if (ret == -EPIPE) {
230 info("An overrun has occured, "
231 "reseting capture!\n");
232 } else {
233 info("Read from audio interface "
234 "failed: %s\n", snd_strerror(ret));
237 ret = snd_pcm_prepare(dev->capture_handle);
238 if (unlikely(ret < 0))
239 info("Error preparing interface: %s\n",
240 snd_strerror(ret));
242 ret = snd_pcm_start(dev->capture_handle);
243 if (unlikely(ret < 0))
244 info("Error preparing interface: %s\n",
245 snd_strerror(ret));
249 return ret;
252 ssize_t alsa_write(struct alsa_dev *dev, const short *pcm, size_t len)
254 ssize_t ret;
255 ret = snd_pcm_writei(dev->playback_handle, pcm, len);
256 if (unlikely(ret != len)) {
257 if (ret < 0) {
258 if (ret == -EPIPE) {
259 info("An underrun has occured, "
260 "reseting playback!\n");
261 } else {
262 info("Write to audio interface "
263 "failed: %s\n", snd_strerror(ret));
266 ret = snd_pcm_prepare(dev->playback_handle);
267 if (unlikely(ret < 0))
268 info("Error preparing interface: %s\n",
269 snd_strerror(ret));
273 return ret;
276 int alsa_cap_ready(struct alsa_dev *dev, struct pollfd *pfds,
277 unsigned int nfds)
279 int ret;
280 unsigned short revents = 0;
282 ret = snd_pcm_poll_descriptors_revents(dev->capture_handle, pfds,
283 dev->read_fds, &revents);
284 if (ret < 0) {
285 whine("error in alsa_cap_ready: %s\n",
286 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",
303 snd_strerror(ret));
304 return pfds[1].revents & POLLOUT;
307 return revents & POLLOUT;
310 void alsa_start(struct alsa_dev *dev)
312 short *pcm;
313 size_t len = dev->period * dev->channels;
315 pcm = xzmalloc(len * sizeof(*pcm));
316 alsa_write(dev, pcm, dev->period);
317 alsa_write(dev, pcm, dev->period);
318 xfree(pcm);
320 snd_pcm_start(dev->capture_handle);
321 snd_pcm_start(dev->playback_handle);
324 inline unsigned int alsa_nfds(struct alsa_dev *dev)
326 return dev->read_fds + dev->write_fds;
329 void alsa_getfds(struct alsa_dev *dev, struct pollfd *pfds,
330 unsigned int nfds)
332 int i;
334 BUG_ON(nfds < alsa_nfds(dev), "%s\n", __func__);
336 for (i = 0; i < dev->read_fds; ++i)
337 pfds[i] = dev->read_fd[i];
338 for (i = 0; i < dev->write_fds; ++i)
339 pfds[i + dev->read_fds] = dev->write_fd[i];