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.
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
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.
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
)
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
);
69 panic("Cannot allocate hardware parameters: %s\n",
71 ret
= snd_pcm_hw_params_any(handle
, hw_params
);
73 panic("Cannot initialize hardware parameters: %s\n",
75 ret
= snd_pcm_hw_params_set_access(handle
, hw_params
,
76 SND_PCM_ACCESS_RW_INTERLEAVED
);
78 panic("Cannot set access type: %s\n",
80 ret
= snd_pcm_hw_params_set_format(handle
, hw_params
,
81 SND_PCM_FORMAT_S16_LE
);
83 panic("Cannot set sample format: %s\n",
85 ret
= snd_pcm_hw_params_set_rate_near(handle
, hw_params
, &rate
, 0);
87 panic("Cannot set sample rate: %s\n",
89 ret
= snd_pcm_hw_params_set_channels(handle
, hw_params
, channels
);
91 panic("Cannot set channel number: %s\n",
95 ret
= snd_pcm_hw_params_set_period_size_near(handle
, hw_params
,
98 panic("Cannot set period size: %s\n",
100 ret
= snd_pcm_hw_params_set_periods(handle
, hw_params
, PERIODS
, 0);
102 panic("Cannot set period number: %s\n",
104 buffer_size
= period_size
* PERIODS
;
106 ret
= snd_pcm_hw_params_set_buffer_size_near(handle
, hw_params
,
109 panic("Cannot set buffer size: %s\n",
111 ret
= snd_pcm_hw_params(handle
, hw_params
);
113 panic("Cannot set capture parameters: %s\n",
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
)
122 snd_pcm_sw_params_t
*sw_params
;
124 ret
= snd_pcm_sw_params_malloc(&sw_params
);
126 panic("Cannot allocate software parameters: %s\n",
128 ret
= snd_pcm_sw_params_current(handle
, sw_params
);
130 panic("Cannot initialize software parameters: %s\n",
132 ret
= snd_pcm_sw_params_set_avail_min(handle
, sw_params
, period
);
134 panic("Cannot set minimum available count: %s\n",
137 ret
= snd_pcm_sw_params_set_start_threshold(handle
, sw_params
,
140 panic("Cannot set start mode: %s\n",
144 ret
= snd_pcm_sw_params(handle
, sw_params
);
146 panic("Cannot set software parameters: %s\n",
148 snd_pcm_sw_params_free(sw_params
);
151 struct alsa_dev
*alsa_open(char *devname
, unsigned int rate
,
152 int channels
, int period
)
155 struct alsa_dev
*dev
;
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);
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);
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
);
185 panic("Cannot prepare audio interface: %s\n",
188 ret
= snd_pcm_prepare(dev
->playback_handle
);
190 panic("Cannot prepare audio interface: %s\n",
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
,
199 if (ret
!= dev
->read_fds
)
200 panic("Cannot obtain capture file descriptors: %s\n",
203 dev
->write_fd
= xzmalloc(dev
->write_fds
* sizeof(*dev
->write_fd
));
204 ret
= snd_pcm_poll_descriptors(dev
->playback_handle
, dev
->write_fd
,
206 if (ret
!= dev
->write_fds
)
207 panic("Cannot obtain playback file descriptors: %s\n",
213 void alsa_close(struct alsa_dev
*dev
)
215 snd_pcm_close(dev
->capture_handle
);
216 snd_pcm_close(dev
->playback_handle
);
220 xfree(dev
->write_fd
);
224 ssize_t
alsa_read(struct alsa_dev
*dev
, short *pcm
, size_t len
)
227 ret
= snd_pcm_readi(dev
->capture_handle
, pcm
, len
);
228 if (unlikely(ret
!= len
)) {
231 info("An overrun has occured, "
232 "reseting capture!\n");
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",
243 ret
= snd_pcm_start(dev
->capture_handle
);
244 if (unlikely(ret
< 0))
245 info("Error preparing interface: %s\n",
253 ssize_t
alsa_write(struct alsa_dev
*dev
, const short *pcm
, size_t len
)
256 ret
= snd_pcm_writei(dev
->playback_handle
, pcm
, len
);
257 if (unlikely(ret
!= len
)) {
260 info("An underrun has occured, "
261 "reseting playback!\n");
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",
277 int alsa_cap_ready(struct alsa_dev
*dev
, struct pollfd
*pfds
,
281 unsigned short revents
= 0;
283 ret
= snd_pcm_poll_descriptors_revents(dev
->capture_handle
, pfds
,
284 dev
->read_fds
, &revents
);
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
,
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", snd_strerror(ret
));
303 return pfds
[1].revents
& POLLOUT
;
306 return revents
& POLLOUT
;
309 void alsa_start(struct alsa_dev
*dev
)
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
);
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
,
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
];