2 * Lightweight Autonomic Network Architecture
3 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
4 * Swiss federal institute of technology (ETH Zurich)
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
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.
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
)
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
);
68 panic("Cannot allocate hardware parameters: %s\n",
70 ret
= snd_pcm_hw_params_any(handle
, hw_params
);
72 panic("Cannot initialize hardware parameters: %s\n",
74 ret
= snd_pcm_hw_params_set_access(handle
, hw_params
,
75 SND_PCM_ACCESS_RW_INTERLEAVED
);
77 panic("Cannot set access type: %s\n",
79 ret
= snd_pcm_hw_params_set_format(handle
, hw_params
,
80 SND_PCM_FORMAT_S16_LE
);
82 panic("Cannot set sample format: %s\n",
84 ret
= snd_pcm_hw_params_set_rate_near(handle
, hw_params
, &rate
, 0);
86 panic("Cannot set sample rate: %s\n",
88 ret
= snd_pcm_hw_params_set_channels(handle
, hw_params
, channels
);
90 panic("Cannot set channel number: %s\n",
94 ret
= snd_pcm_hw_params_set_period_size_near(handle
, hw_params
,
97 panic("Cannot set period size: %s\n",
99 ret
= snd_pcm_hw_params_set_periods(handle
, hw_params
, PERIODS
, 0);
101 panic("Cannot set period number: %s\n",
103 buffer_size
= period_size
* PERIODS
;
105 ret
= snd_pcm_hw_params_set_buffer_size_near(handle
, hw_params
,
108 panic("Cannot set buffer size: %s\n",
110 ret
= snd_pcm_hw_params(handle
, hw_params
);
112 panic("Cannot set capture parameters: %s\n",
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
)
121 snd_pcm_sw_params_t
*sw_params
;
123 ret
= snd_pcm_sw_params_malloc(&sw_params
);
125 panic("Cannot allocate software parameters: %s\n",
127 ret
= snd_pcm_sw_params_current(handle
, sw_params
);
129 panic("Cannot initialize software parameters: %s\n",
131 ret
= snd_pcm_sw_params_set_avail_min(handle
, sw_params
, period
);
133 panic("Cannot set minimum available count: %s\n",
136 ret
= snd_pcm_sw_params_set_start_threshold(handle
, sw_params
,
139 panic("Cannot set start mode: %s\n",
143 ret
= snd_pcm_sw_params(handle
, sw_params
);
145 panic("Cannot set software parameters: %s\n",
147 snd_pcm_sw_params_free(sw_params
);
150 struct alsa_dev
*alsa_open(char *devname
, unsigned int rate
,
151 int channels
, int period
)
154 struct alsa_dev
*dev
;
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);
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);
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
);
184 panic("Cannot prepare audio interface: %s\n",
187 ret
= snd_pcm_prepare(dev
->playback_handle
);
189 panic("Cannot prepare audio interface: %s\n",
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
,
198 if (ret
!= dev
->read_fds
)
199 panic("Cannot obtain capture file descriptors: %s\n",
202 dev
->write_fd
= xzmalloc(dev
->write_fds
* sizeof(*dev
->write_fd
));
203 ret
= snd_pcm_poll_descriptors(dev
->playback_handle
, dev
->write_fd
,
205 if (ret
!= dev
->write_fds
)
206 panic("Cannot obtain playback file descriptors: %s\n",
212 void alsa_close(struct alsa_dev
*dev
)
214 snd_pcm_close(dev
->capture_handle
);
215 snd_pcm_close(dev
->playback_handle
);
219 xfree(dev
->write_fd
);
223 ssize_t
alsa_read(struct alsa_dev
*dev
, short *pcm
, size_t len
)
226 ret
= snd_pcm_readi(dev
->capture_handle
, pcm
, len
);
227 if (unlikely(ret
!= len
)) {
230 info("An overrun has occured, "
231 "reseting capture!\n");
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",
242 ret
= snd_pcm_start(dev
->capture_handle
);
243 if (unlikely(ret
< 0))
244 info("Error preparing interface: %s\n",
252 ssize_t
alsa_write(struct alsa_dev
*dev
, const short *pcm
, size_t len
)
255 ret
= snd_pcm_writei(dev
->playback_handle
, pcm
, len
);
256 if (unlikely(ret
!= len
)) {
259 info("An underrun has occured, "
260 "reseting playback!\n");
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",
276 int alsa_cap_ready(struct alsa_dev
*dev
, struct pollfd
*pfds
,
280 unsigned short revents
= 0;
282 ret
= snd_pcm_poll_descriptors_revents(dev
->capture_handle
, pfds
,
283 dev
->read_fds
, &revents
);
285 whine("error in alsa_cap_ready: %s\n",
287 return pfds
[0].revents
& POLLIN
;
290 return revents
& POLLIN
;
293 int alsa_play_ready(struct alsa_dev
*dev
, struct pollfd
*pfds
,
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
);
302 whine("error in alsa_play_ready: %s\n",
304 return pfds
[1].revents
& POLLOUT
;
307 return revents
& POLLOUT
;
310 void alsa_start(struct alsa_dev
*dev
)
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
);
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
,
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
];