reenabled stun probe
[transsip.git] / src / alsa.c
blob6da3a8a60e3b3bf59c7fcfe2b99bf57103f71182
1 /*
2 * transsip - the telephony network
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;
42 ret = snd_pcm_hw_params_malloc(&hw_params);
43 if (ret < 0)
44 panic("Cannot allocate hardware parameters: %s\n",
45 snd_strerror(ret));
46 ret = snd_pcm_hw_params_any(handle, hw_params);
47 if (ret < 0)
48 panic("Cannot initialize hardware parameters: %s\n",
49 snd_strerror(ret));
50 ret = snd_pcm_hw_params_set_access(handle, hw_params,
51 SND_PCM_ACCESS_RW_INTERLEAVED);
52 if (ret < 0)
53 panic("Cannot set access type: %s\n",
54 snd_strerror(ret));
55 ret = snd_pcm_hw_params_set_format(handle, hw_params,
56 SND_PCM_FORMAT_S16_LE);
57 if (ret < 0)
58 panic("Cannot set sample format: %s\n",
59 snd_strerror(ret));
60 ret = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rate, 0);
61 if (ret < 0)
62 panic("Cannot set sample rate: %s\n",
63 snd_strerror(ret));
64 ret = snd_pcm_hw_params_set_channels(handle, hw_params, channels);
65 if (ret < 0)
66 panic("Cannot set channel number: %s\n",
67 snd_strerror(ret));
68 period_size = period;
69 dir = 0;
70 ret = snd_pcm_hw_params_set_period_size_near(handle, hw_params,
71 &period_size, &dir);
72 if (ret < 0)
73 panic("Cannot set period size: %s\n",
74 snd_strerror(ret));
75 ret = snd_pcm_hw_params_set_periods(handle, hw_params, PERIODS, 0);
76 if (ret < 0)
77 panic("Cannot set period number: %s\n",
78 snd_strerror(ret));
79 buffer_size = period_size * PERIODS;
80 dir = 0;
81 ret = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params,
82 &buffer_size);
83 if (ret < 0)
84 panic("Cannot set buffer size: %s\n",
85 snd_strerror(ret));
86 ret = snd_pcm_hw_params(handle, hw_params);
87 if (ret < 0)
88 panic("Cannot set capture parameters: %s\n",
89 snd_strerror(ret));
90 snd_pcm_hw_params_free(hw_params);
93 static void alsa_set_sw_params(struct alsa_dev *dev, snd_pcm_t *handle,
94 int period, int thres)
96 int ret;
97 snd_pcm_sw_params_t *sw_params;
98 ret = snd_pcm_sw_params_malloc(&sw_params);
99 if (ret < 0)
100 panic("Cannot allocate software parameters: %s\n",
101 snd_strerror(ret));
102 ret = snd_pcm_sw_params_current(handle, sw_params);
103 if (ret < 0)
104 panic("Cannot initialize software parameters: %s\n",
105 snd_strerror(ret));
106 ret = snd_pcm_sw_params_set_avail_min(handle, sw_params, period);
107 if (ret < 0)
108 panic("Cannot set minimum available count: %s\n",
109 snd_strerror(ret));
110 if (thres) {
111 ret = snd_pcm_sw_params_set_start_threshold(handle, sw_params,
112 period);
113 if (ret < 0)
114 panic("Cannot set start mode: %s\n",
115 snd_strerror(ret));
118 ret = snd_pcm_sw_params(handle, sw_params);
119 if (ret < 0)
120 panic("Cannot set software parameters: %s\n",
121 snd_strerror(ret));
122 snd_pcm_sw_params_free(sw_params);
125 struct alsa_dev *alsa_open(char *devname, unsigned int rate,
126 int channels, int period)
128 int ret;
129 struct alsa_dev *dev;
130 if (!devname)
131 devname = "plughw:0,0";
132 dev = xzmalloc(sizeof(*dev));
133 dev->name = xstrdup(devname);
134 dev->channels = channels;
135 dev->period = period;
136 ret = snd_pcm_open(&dev->capture_handle, dev->name,
137 SND_PCM_STREAM_CAPTURE, 0);
138 if (ret < 0)
139 panic("Cannot open audio capture device %s: %s\n",
140 dev->name, snd_strerror(ret));
141 alsa_set_hw_params(dev, dev->capture_handle, rate, channels, period);
142 alsa_set_sw_params(dev, dev->capture_handle, period, 0);
143 ret = snd_pcm_open(&dev->playback_handle, dev->name,
144 SND_PCM_STREAM_PLAYBACK, 0);
145 if (ret < 0)
146 panic("Cannot open audio playback device %s: %s\n",
147 dev->name, snd_strerror(ret));
148 alsa_set_hw_params(dev, dev->playback_handle, rate, channels, period);
149 alsa_set_sw_params(dev, dev->playback_handle, period, 1);
150 snd_pcm_link(dev->capture_handle, dev->playback_handle);
151 ret = snd_pcm_prepare(dev->capture_handle);
152 if (ret < 0)
153 panic("Cannot prepare audio interface: %s\n",
154 snd_strerror(ret));
155 ret = snd_pcm_prepare(dev->playback_handle);
156 if (ret < 0)
157 panic("Cannot prepare audio interface: %s\n",
158 snd_strerror(ret));
159 dev->read_fds = snd_pcm_poll_descriptors_count(dev->capture_handle);
160 dev->write_fds = snd_pcm_poll_descriptors_count(dev->playback_handle);
161 dev->read_fd = xzmalloc(dev->read_fds * sizeof(*dev->read_fd));
162 ret = snd_pcm_poll_descriptors(dev->capture_handle, dev->read_fd,
163 dev->read_fds);
164 if (ret != dev->read_fds)
165 panic("Cannot obtain capture file descriptors: %s\n",
166 snd_strerror(ret));
167 dev->write_fd = xzmalloc(dev->write_fds * sizeof(*dev->write_fd));
168 ret = snd_pcm_poll_descriptors(dev->playback_handle, dev->write_fd,
169 dev->write_fds);
170 if (ret != dev->write_fds)
171 panic("Cannot obtain playback file descriptors: %s\n",
172 snd_strerror(ret));
173 return dev;
176 void alsa_close(struct alsa_dev *dev)
178 snd_pcm_close(dev->capture_handle);
179 snd_pcm_close(dev->playback_handle);
180 xfree(dev->name);
181 xfree(dev->read_fd);
182 xfree(dev->write_fd);
183 xfree(dev);
186 ssize_t alsa_read(struct alsa_dev *dev, short *pcm, size_t len)
188 ssize_t ret;
189 ret = snd_pcm_readi(dev->capture_handle, pcm, len);
190 if (unlikely(ret != len)) {
191 if (ret < 0) {
192 if (ret == -EPIPE) {
193 printf("An overrun has occured, "
194 "reseting capture!\n");
195 } else {
196 printf("Read from audio interface "
197 "failed: %s\n", snd_strerror(ret));
199 ret = snd_pcm_prepare(dev->capture_handle);
200 if (unlikely(ret < 0))
201 printf("Error preparing interface: %s\n",
202 snd_strerror(ret));
203 ret = snd_pcm_start(dev->capture_handle);
204 if (unlikely(ret < 0))
205 printf("Error preparing interface: %s\n",
206 snd_strerror(ret));
209 return ret;
212 ssize_t alsa_write(struct alsa_dev *dev, const short *pcm, size_t len)
214 ssize_t ret;
215 ret = snd_pcm_writei(dev->playback_handle, pcm, len);
216 if (unlikely(ret != len)) {
217 if (ret < 0) {
218 if (ret == -EPIPE) {
219 printf("An underrun has occured, "
220 "reseting playback!\n");
221 } else {
222 printf("Write to audio interface "
223 "failed: %s\n", snd_strerror(ret));
225 ret = snd_pcm_prepare(dev->playback_handle);
226 if (unlikely(ret < 0))
227 printf("Error preparing interface: %s\n",
228 snd_strerror(ret));
231 return ret;
234 int alsa_cap_ready(struct alsa_dev *dev, struct pollfd *pfds,
235 unsigned int nfds)
237 int ret;
238 unsigned short revents = 0;
239 ret = snd_pcm_poll_descriptors_revents(dev->capture_handle, pfds,
240 dev->read_fds, &revents);
241 if (ret < 0) {
242 whine("Error in alsa_cap_ready: %s\n", snd_strerror(ret));
243 return pfds[0].revents & POLLIN;
245 return revents & POLLIN;
248 int alsa_play_ready(struct alsa_dev *dev, struct pollfd *pfds,
249 unsigned int nfds)
251 int ret;
252 unsigned short revents = 0;
253 ret = snd_pcm_poll_descriptors_revents(dev->playback_handle,
254 pfds + dev->read_fds,
255 dev->write_fds, &revents);
256 if (ret < 0) {
257 whine("Error in alsa_play_ready: %s\n", snd_strerror(ret));
258 return pfds[1].revents & POLLOUT;
260 return revents & POLLOUT;
263 void alsa_start(struct alsa_dev *dev)
265 short *pcm;
266 size_t len = dev->period * dev->channels;
267 pcm = xzmalloc(len * sizeof(*pcm));
268 alsa_write(dev, pcm, dev->period);
269 alsa_write(dev, pcm, dev->period);
270 xfree(pcm);
271 snd_pcm_start(dev->capture_handle);
272 snd_pcm_start(dev->playback_handle);
275 void alsa_stop(struct alsa_dev *dev)
279 inline unsigned int alsa_nfds(struct alsa_dev *dev)
281 return dev->read_fds + dev->write_fds;
284 void alsa_getfds(struct alsa_dev *dev, struct pollfd *pfds,
285 unsigned int nfds)
287 int i;
288 for (i = 0; i < dev->read_fds; ++i)
289 pfds[i] = dev->read_fd[i];
290 for (i = 0; i < dev->write_fds; ++i)
291 pfds[i + dev->read_fds] = dev->write_fd[i];