/[rdesktop]/jpeg/rdesktop/trunk/rdpsnd_alsa.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /jpeg/rdesktop/trunk/rdpsnd_alsa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1351 - (hide annotations)
Sun Dec 24 13:53:23 2006 UTC (17 years, 5 months ago) by stargo
Original Path: sourceforge.net/trunk/rdesktop/rdpsnd_alsa.c
File MIME type: text/plain
File size: 8377 byte(s)
Make code compile with C89 compilers again

1 stargo 1253 /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.
3     Sound Channel Process Functions - alsa-driver
4     Copyright (C) Matthew Chapman 2003
5     Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6     Copyright (C) Michael Gernoth mike@zerfleddert.de 2006
7    
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12    
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     GNU General Public License for more details.
17    
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     */
22    
23     #include "rdesktop.h"
24 stargo 1254 #include "rdpsnd.h"
25 stargo 1261 #include "rdpsnd_dsp.h"
26 stargo 1253 #include <unistd.h>
27     #include <fcntl.h>
28     #include <errno.h>
29     #include <alsa/asoundlib.h>
30     #include <sys/time.h>
31    
32     #define DEFAULTDEVICE "default"
33     #define MAX_FRAMES 32
34    
35 ossman_ 1346 static struct pollfd pfds[32];
36     static int num_fds;
37    
38 stargo 1253 static snd_pcm_t *pcm_handle = NULL;
39     static snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
40     static BOOL reopened;
41     static short samplewidth;
42     static int audiochannels;
43 ossman_ 1302 static unsigned int rate;
44 stargo 1255 static char *pcm_name;
45 stargo 1253
46 ossman_ 1346 void alsa_play(void);
47    
48     void
49     alsa_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
50     {
51     int err;
52     struct pollfd *f;
53    
54     if (!pcm_handle)
55     return;
56    
57     if (rdpsnd_queue_empty())
58     return;
59    
60     num_fds = snd_pcm_poll_descriptors_count(pcm_handle);
61    
62     if (num_fds > sizeof(pfds) / sizeof(*pfds))
63     return;
64    
65     err = snd_pcm_poll_descriptors(pcm_handle, pfds, num_fds);
66     if (err < 0)
67     return;
68    
69     for (f = pfds; f < &pfds[num_fds]; f++)
70     {
71     if (f->events & POLLIN)
72     FD_SET(f->fd, rfds);
73     if (f->events & POLLOUT)
74     FD_SET(f->fd, wfds);
75     if (f->fd > *n && (f->events & (POLLIN | POLLOUT)))
76     *n = f->fd;
77     }
78     }
79    
80     void
81     alsa_check_fds(fd_set * rfds, fd_set * wfds)
82     {
83     struct pollfd *f;
84     int err;
85     unsigned short revents;
86    
87     if (!pcm_handle)
88     return;
89    
90     for (f = pfds; f < &pfds[num_fds]; f++)
91     {
92     f->revents = 0;
93     if (f->fd != -1)
94     {
95     /* Fixme: This doesn't properly deal with things like POLLHUP */
96     if (FD_ISSET(f->fd, rfds))
97     f->revents |= POLLIN;
98     if (FD_ISSET(f->fd, wfds))
99     f->revents |= POLLOUT;
100     }
101     }
102    
103     err = snd_pcm_poll_descriptors_revents(pcm_handle, pfds, num_fds, &revents);
104     if (err < 0)
105     return;
106    
107     if (revents & POLLOUT)
108     alsa_play();
109     }
110    
111 stargo 1253 BOOL
112 stargo 1255 alsa_open(void)
113 stargo 1253 {
114     int err;
115    
116     if ((err = snd_pcm_open(&pcm_handle, pcm_name, stream, 0)) < 0)
117     {
118     error("snd_pcm_open: %s\n", snd_strerror(err));
119     return False;
120     }
121    
122     reopened = True;
123    
124     return True;
125     }
126    
127     void
128 stargo 1255 alsa_close(void)
129 stargo 1253 {
130     /* Ack all remaining packets */
131 stargo 1254 while (!rdpsnd_queue_empty())
132 ossman_ 1302 rdpsnd_queue_next(0);
133 stargo 1253
134     if (pcm_handle)
135     {
136     snd_pcm_close(pcm_handle);
137 stargo 1325 pcm_handle = NULL;
138 stargo 1253 }
139     }
140    
141     BOOL
142 stargo 1255 alsa_format_supported(WAVEFORMATEX * pwfx)
143 stargo 1253 {
144     #if 0
145     int err;
146     snd_pcm_hw_params_t *hwparams = NULL;
147    
148     if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
149     {
150     error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
151     return False;
152     }
153    
154     if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
155     {
156     error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
157     return False;
158     }
159     snd_pcm_hw_params_free(hwparams);
160     #endif
161    
162     if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
163     return False;
164     if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
165     return False;
166     if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
167     return False;
168     if ((pwfx->nSamplesPerSec != 44100) && (pwfx->nSamplesPerSec != 22050))
169     return False;
170    
171     return True;
172     }
173    
174     BOOL
175 stargo 1255 alsa_set_format(WAVEFORMATEX * pwfx)
176 stargo 1253 {
177     snd_pcm_hw_params_t *hwparams = NULL;
178     int err;
179     unsigned int buffertime;
180    
181     samplewidth = pwfx->wBitsPerSample / 8;
182    
183     if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
184     {
185     error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
186     return False;
187     }
188    
189     if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
190     {
191     error("snd_pcm_hw_params_any: %s\n", snd_strerror(err));
192     return False;
193     }
194    
195     if ((err =
196     snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
197     {
198     error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err));
199     return False;
200     }
201    
202     if (pwfx->wBitsPerSample == 16)
203     {
204     if ((err =
205     snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
206     {
207     error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
208     return False;
209     }
210     }
211     else
212     {
213     if ((err =
214     snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S8)) < 0)
215     {
216     error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
217     return False;
218     }
219     }
220    
221     #if 0
222     if ((err = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 1)) < 0)
223     {
224     error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err));
225     return False;
226     }
227     #endif
228    
229 ossman_ 1302 rate = pwfx->nSamplesPerSec;
230     if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, 0)) < 0)
231 stargo 1253 {
232     error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err));
233     return False;
234     }
235    
236     audiochannels = pwfx->nChannels;
237     if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, pwfx->nChannels)) < 0)
238     {
239     error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err));
240     return False;
241     }
242    
243    
244     buffertime = 500000; /* microseconds */
245     if ((err =
246     snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &buffertime, 0)) < 0)
247     {
248     error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err));
249     return False;
250     }
251    
252     if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
253     {
254     error("snd_pcm_hw_params: %s\n", snd_strerror(err));
255     return False;
256     }
257    
258     snd_pcm_hw_params_free(hwparams);
259    
260     if ((err = snd_pcm_prepare(pcm_handle)) < 0)
261     {
262     error("snd_pcm_prepare: %s\n", snd_strerror(err));
263     return False;
264     }
265    
266     reopened = True;
267    
268     return True;
269     }
270    
271     void
272 stargo 1255 alsa_play(void)
273 stargo 1253 {
274     struct audio_packet *packet;
275     STREAM out;
276     int len;
277     static long prev_s, prev_us;
278     unsigned int duration;
279     struct timeval tv;
280     int next_tick;
281    
282     if (reopened)
283     {
284     reopened = False;
285     gettimeofday(&tv, NULL);
286     prev_s = tv.tv_sec;
287     prev_us = tv.tv_usec;
288     }
289    
290 ossman_ 1346 /* We shouldn't be called if the queue is empty, but still */
291 stargo 1254 if (rdpsnd_queue_empty())
292 stargo 1253 return;
293    
294 stargo 1254 packet = rdpsnd_queue_current_packet();
295 stargo 1253 out = &packet->s;
296    
297 stargo 1254 next_tick = rdpsnd_queue_next_tick();
298 stargo 1253
299     len = (out->end - out->p) / (samplewidth * audiochannels);
300     if ((len = snd_pcm_writei(pcm_handle, out->p, ((MAX_FRAMES < len) ? MAX_FRAMES : len))) < 0)
301     {
302     snd_pcm_prepare(pcm_handle);
303     len = 0;
304     }
305     out->p += (len * samplewidth * audiochannels);
306    
307     gettimeofday(&tv, NULL);
308    
309     duration = ((tv.tv_sec - prev_s) * 1000000 + (tv.tv_usec - prev_us)) / 1000;
310    
311     if (packet->tick > next_tick)
312     next_tick += 65536;
313    
314     if ((out->p == out->end) || duration > next_tick - packet->tick + 500)
315     {
316 ossman_ 1302 snd_pcm_sframes_t delay_frames;
317     unsigned long delay_us;
318    
319 stargo 1253 prev_s = tv.tv_sec;
320     prev_us = tv.tv_usec;
321    
322     if (abs((next_tick - packet->tick) - duration) > 20)
323     {
324     DEBUG(("duration: %d, calc: %d, ", duration, next_tick - packet->tick));
325     DEBUG(("last: %d, is: %d, should: %d\n", packet->tick,
326     (packet->tick + duration) % 65536, next_tick % 65536));
327     }
328    
329 ossman_ 1302 if (snd_pcm_delay(pcm_handle, &delay_frames) < 0)
330     delay_frames = out->size / (samplewidth * audiochannels);
331     if (delay_frames < 0)
332     delay_frames = 0;
333    
334     delay_us = delay_frames * (1000000 / rate);
335    
336     rdpsnd_queue_next(delay_us);
337 stargo 1253 }
338     }
339 stargo 1255
340 stargo 1351 struct audio_driver *
341     alsa_register(char *options)
342     {
343     static struct audio_driver alsa_driver;
344 ossman_ 1345
345 stargo 1351 alsa_driver.name = xstrdup("alsa");
346     alsa_driver.description = xstrdup("ALSA output driver, default device: " DEFAULTDEVICE);
347 ossman_ 1346
348 stargo 1351 alsa_driver.add_fds = alsa_add_fds;
349     alsa_driver.check_fds = alsa_check_fds;
350 ossman_ 1345
351 stargo 1351 alsa_driver.wave_out_open = alsa_open;
352     alsa_driver.wave_out_close = alsa_close;
353     alsa_driver.wave_out_format_supported = alsa_format_supported;
354     alsa_driver.wave_out_set_format = alsa_set_format;
355     alsa_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
356 ossman_ 1345
357 stargo 1351 alsa_driver.need_byteswap_on_be = 0;
358     alsa_driver.need_resampling = 0;
359    
360 stargo 1255 if (options)
361     {
362     pcm_name = xstrdup(options);
363     }
364     else
365     {
366     pcm_name = xstrdup(DEFAULTDEVICE);
367     }
368    
369     return &alsa_driver;
370     }

  ViewVC Help
Powered by ViewVC 1.1.26