2 * transsip - the telephony toolkit
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.
14 #include <alsa/asoundlib.h>
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
)
39 snd_pcm_uframes_t period_size
;
40 snd_pcm_uframes_t buffer_size
;
41 snd_pcm_hw_params_t
*hw_params
;
43 ret
= snd_pcm_hw_params_malloc(&hw_params
);
45 panic("Cannot allocate hardware parameters: %s\n",
48 ret
= snd_pcm_hw_params_any(handle
, hw_params
);
50 panic("Cannot initialize hardware parameters: %s\n",
53 ret
= snd_pcm_hw_params_set_access(handle
, hw_params
,
54 SND_PCM_ACCESS_RW_INTERLEAVED
);
56 panic("Cannot set access type: %s\n",
59 ret
= snd_pcm_hw_params_set_format(handle
, hw_params
,
60 SND_PCM_FORMAT_S16_LE
);
62 panic("Cannot set sample format: %s\n",
65 ret
= snd_pcm_hw_params_set_rate_near(handle
, hw_params
, &rate
, 0);
67 panic("Cannot set sample rate: %s\n",
70 ret
= snd_pcm_hw_params_set_channels(handle
, hw_params
, channels
);
72 panic("Cannot set channel number: %s\n",
77 ret
= snd_pcm_hw_params_set_period_size_near(handle
, hw_params
,
80 panic("Cannot set period size: %s\n",
83 ret
= snd_pcm_hw_params_set_periods(handle
, hw_params
, PERIODS
, 0);
85 panic("Cannot set period number: %s\n",
88 buffer_size
= period_size
* PERIODS
;
90 ret
= snd_pcm_hw_params_set_buffer_size_near(handle
, hw_params
,
93 panic("Cannot set buffer size: %s\n",
96 ret
= snd_pcm_hw_params(handle
, hw_params
);
98 panic("Cannot set capture parameters: %s\n",
101 snd_pcm_hw_params_free(hw_params
);
104 static void alsa_set_sw_params(struct alsa_dev
*dev
, snd_pcm_t
*handle
,
105 int period
, int thres
)
108 snd_pcm_sw_params_t
*sw_params
;
110 ret
= snd_pcm_sw_params_malloc(&sw_params
);
112 panic("Cannot allocate software parameters: %s\n",
115 ret
= snd_pcm_sw_params_current(handle
, sw_params
);
117 panic("Cannot initialize software parameters: %s\n",
120 ret
= snd_pcm_sw_params_set_avail_min(handle
, sw_params
, period
);
122 panic("Cannot set minimum available count: %s\n",
126 ret
= snd_pcm_sw_params_set_start_threshold(handle
, sw_params
,
129 panic("Cannot set start mode: %s\n",
134 ret
= snd_pcm_sw_params(handle
, sw_params
);
136 panic("Cannot set software parameters: %s\n",
139 snd_pcm_sw_params_free(sw_params
);
142 struct alsa_dev
*alsa_open(char *devname
, unsigned int rate
,
143 int channels
, int period
)
146 struct alsa_dev
*dev
;
149 devname
= "plughw:0,0";
151 dev
= xzmalloc(sizeof(*dev
));
152 dev
->name
= xstrdup(devname
);
153 dev
->channels
= channels
;
154 dev
->period
= period
;
156 ret
= snd_pcm_open(&dev
->capture_handle
, dev
->name
,
157 SND_PCM_STREAM_CAPTURE
, 0);
159 panic("Cannot open audio capture device %s: %s\n",
160 dev
->name
, snd_strerror(ret
));
162 alsa_set_hw_params(dev
, dev
->capture_handle
, rate
, channels
, period
);
163 alsa_set_sw_params(dev
, dev
->capture_handle
, period
, 0);
165 ret
= snd_pcm_open(&dev
->playback_handle
, dev
->name
,
166 SND_PCM_STREAM_PLAYBACK
, 0);
168 panic("Cannot open audio playback device %s: %s\n",
169 dev
->name
, snd_strerror(ret
));
171 alsa_set_hw_params(dev
, dev
->playback_handle
, rate
, channels
, period
);
172 alsa_set_sw_params(dev
, dev
->playback_handle
, period
, 1);
174 snd_pcm_link(dev
->capture_handle
, dev
->playback_handle
);
176 ret
= snd_pcm_prepare(dev
->capture_handle
);
178 panic("Cannot prepare audio interface: %s\n",
181 ret
= snd_pcm_prepare(dev
->playback_handle
);
183 panic("Cannot prepare audio interface: %s\n",
186 dev
->read_fds
= snd_pcm_poll_descriptors_count(dev
->capture_handle
);
187 dev
->write_fds
= snd_pcm_poll_descriptors_count(dev
->playback_handle
);
188 dev
->read_fd
= xzmalloc(dev
->read_fds
* sizeof(*dev
->read_fd
));
190 ret
= snd_pcm_poll_descriptors(dev
->capture_handle
, dev
->read_fd
,
192 if (ret
!= dev
->read_fds
)
193 panic("Cannot obtain capture file descriptors: %s\n",
196 dev
->write_fd
= xzmalloc(dev
->write_fds
* sizeof(*dev
->write_fd
));
198 ret
= snd_pcm_poll_descriptors(dev
->playback_handle
, dev
->write_fd
,
200 if (ret
!= dev
->write_fds
)
201 panic("Cannot obtain playback file descriptors: %s\n",
207 void alsa_close(struct alsa_dev
*dev
)
209 snd_pcm_close(dev
->capture_handle
);
210 snd_pcm_close(dev
->playback_handle
);
214 xfree(dev
->write_fd
);
218 ssize_t
alsa_read(struct alsa_dev
*dev
, short *pcm
, size_t len
)
220 ssize_t ret
= snd_pcm_readi(dev
->capture_handle
, pcm
, len
);
221 if (unlikely(ret
!= len
)) {
223 ret
= snd_pcm_prepare(dev
->capture_handle
);
224 if (unlikely(ret
< 0))
225 printf("Error preparing interface: %s\n",
228 ret
= snd_pcm_start(dev
->capture_handle
);
229 if (unlikely(ret
< 0))
230 printf("Error preparing interface: %s\n",
238 ssize_t
alsa_write(struct alsa_dev
*dev
, const short *pcm
, size_t len
)
240 ssize_t ret
= snd_pcm_writei(dev
->playback_handle
, pcm
, len
);
241 if (unlikely(ret
!= len
)) {
243 ret
= snd_pcm_prepare(dev
->playback_handle
);
244 if (unlikely(ret
< 0))
245 printf("Error preparing interface: %s\n",
253 int alsa_cap_ready(struct alsa_dev
*dev
, struct pollfd
*pfds
,
257 unsigned short revents
= 0;
259 ret
= snd_pcm_poll_descriptors_revents(dev
->capture_handle
, pfds
,
260 dev
->read_fds
, &revents
);
262 whine("Error in alsa_cap_ready: %s\n", snd_strerror(ret
));
263 return pfds
[0].revents
& POLLIN
;
266 return revents
& POLLIN
;
269 int alsa_play_ready(struct alsa_dev
*dev
, struct pollfd
*pfds
,
273 unsigned short revents
= 0;
275 ret
= snd_pcm_poll_descriptors_revents(dev
->playback_handle
,
276 pfds
+ dev
->read_fds
,
277 dev
->write_fds
, &revents
);
279 whine("Error in alsa_play_ready: %s\n", snd_strerror(ret
));
280 return pfds
[1].revents
& POLLOUT
;
283 return revents
& POLLOUT
;
286 void alsa_start(struct alsa_dev
*dev
)
289 size_t len
= dev
->period
* dev
->channels
;
291 pcm
= xzmalloc(len
* sizeof(*pcm
));
293 alsa_write(dev
, pcm
, dev
->period
);
294 alsa_write(dev
, pcm
, dev
->period
);
298 snd_pcm_start(dev
->capture_handle
);
299 snd_pcm_start(dev
->playback_handle
);
302 void alsa_stop(struct alsa_dev
*dev
)
306 inline unsigned int alsa_nfds(struct alsa_dev
*dev
)
308 return dev
->read_fds
+ dev
->write_fds
;
311 void alsa_getfds(struct alsa_dev
*dev
, struct pollfd
*pfds
,
316 for (i
= 0; i
< dev
->read_fds
; ++i
)
317 pfds
[i
] = dev
->read_fd
[i
];
319 for (i
= 0; i
< dev
->write_fds
; ++i
)
320 pfds
[i
+ dev
->read_fds
] = dev
->write_fd
[i
];