/[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 1253 - (hide annotations)
Sun Sep 17 10:00:55 2006 UTC (17 years, 9 months ago) by stargo
Original Path: sourceforge.net/trunk/rdesktop/rdpsnd_alsa.c
File MIME type: text/plain
File size: 7608 byte(s)
add alsa-driver

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     #include <unistd.h>
25     #include <fcntl.h>
26     #include <errno.h>
27     #include <alsa/asoundlib.h>
28     #include <sys/time.h>
29    
30     #define DEFAULTDEVICE "default"
31     #define MAX_QUEUE 10
32     #define MAX_FRAMES 32
33    
34     int g_dsp_fd;
35     BOOL g_dsp_busy = False;
36     static snd_pcm_t *pcm_handle = NULL;
37     static snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
38     static BOOL reopened;
39     static short samplewidth;
40     static int audiochannels;
41    
42     static struct audio_packet
43     {
44     struct stream s;
45     uint16 tick;
46     uint8 index;
47     } packet_queue[MAX_QUEUE];
48     static unsigned int queue_hi, queue_lo;
49    
50     BOOL
51     wave_out_open(void)
52     {
53     char *pcm_name;
54     int err;
55    
56     pcm_name = xstrdup(DEFAULTDEVICE);
57    
58     if ((err = snd_pcm_open(&pcm_handle, pcm_name, stream, 0)) < 0)
59     {
60     error("snd_pcm_open: %s\n", snd_strerror(err));
61     return False;
62     }
63    
64     g_dsp_fd = 0;
65     queue_lo = queue_hi = 0;
66    
67     reopened = True;
68    
69     return True;
70     }
71    
72     void
73     wave_out_close(void)
74     {
75     /* Ack all remaining packets */
76     while (queue_lo != queue_hi)
77     {
78     rdpsnd_send_completion(packet_queue[queue_lo].tick, packet_queue[queue_lo].index);
79     free(packet_queue[queue_lo].s.data);
80     queue_lo = (queue_lo + 1) % MAX_QUEUE;
81     }
82    
83     if (pcm_handle)
84     {
85     snd_pcm_drop(pcm_handle);
86     snd_pcm_close(pcm_handle);
87     }
88     }
89    
90     BOOL
91     wave_out_format_supported(WAVEFORMATEX * pwfx)
92     {
93     #if 0
94     int err;
95     snd_pcm_hw_params_t *hwparams = NULL;
96    
97     if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
98     {
99     error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
100     return False;
101     }
102    
103     if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
104     {
105     error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
106     return False;
107     }
108     snd_pcm_hw_params_free(hwparams);
109     #endif
110    
111     if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
112     return False;
113     if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
114     return False;
115     if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
116     return False;
117     if ((pwfx->nSamplesPerSec != 44100) && (pwfx->nSamplesPerSec != 22050))
118     return False;
119    
120     return True;
121     }
122    
123     BOOL
124     wave_out_set_format(WAVEFORMATEX * pwfx)
125     {
126     snd_pcm_hw_params_t *hwparams = NULL;
127     unsigned int rate, exact_rate;
128     int err;
129     unsigned int buffertime;
130    
131     samplewidth = pwfx->wBitsPerSample / 8;
132    
133     if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
134     {
135     error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
136     return False;
137     }
138    
139     if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
140     {
141     error("snd_pcm_hw_params_any: %s\n", snd_strerror(err));
142     return False;
143     }
144    
145     if ((err =
146     snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
147     {
148     error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err));
149     return False;
150     }
151    
152     if (pwfx->wBitsPerSample == 16)
153     {
154     if ((err =
155     snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
156     {
157     error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
158     return False;
159     }
160     }
161     else
162     {
163     if ((err =
164     snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S8)) < 0)
165     {
166     error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
167     return False;
168     }
169     }
170    
171     #if 0
172     if ((err = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 1)) < 0)
173     {
174     error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err));
175     return False;
176     }
177     #endif
178    
179     exact_rate = rate = pwfx->nSamplesPerSec;
180     if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0)) < 0)
181     {
182     error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err));
183     return False;
184     }
185    
186     audiochannels = pwfx->nChannels;
187     if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, pwfx->nChannels)) < 0)
188     {
189     error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err));
190     return False;
191     }
192    
193    
194     buffertime = 500000; /* microseconds */
195     if ((err =
196     snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &buffertime, 0)) < 0)
197     {
198     error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err));
199     return False;
200     }
201    
202     if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
203     {
204     error("snd_pcm_hw_params: %s\n", snd_strerror(err));
205     return False;
206     }
207    
208     snd_pcm_hw_params_free(hwparams);
209    
210     if ((err = snd_pcm_prepare(pcm_handle)) < 0)
211     {
212     error("snd_pcm_prepare: %s\n", snd_strerror(err));
213     return False;
214     }
215    
216     reopened = True;
217    
218     return True;
219     }
220    
221     void
222     wave_out_volume(uint16 left, uint16 right)
223     {
224     static int warned = 0;
225    
226     if (!warned)
227     {
228     warning("volume changes currently not supported with experimental alsa-output\n");
229     warned = 1;
230     }
231     }
232    
233     void
234     wave_out_write(STREAM s, uint16 tick, uint8 index)
235     {
236     struct audio_packet *packet = &packet_queue[queue_hi];
237     unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;
238    
239     if (next_hi == queue_lo)
240     {
241     error("No space to queue audio packet\n");
242     return;
243     }
244    
245     queue_hi = next_hi;
246    
247     packet->s = *s;
248     packet->tick = tick;
249     packet->index = index;
250     packet->s.p += 4;
251    
252     /* we steal the data buffer from s, give it a new one */
253     s->data = (uint8 *) malloc(s->size);
254    
255     if (!g_dsp_busy)
256     wave_out_play();
257     }
258    
259     void
260     wave_out_play(void)
261     {
262     struct audio_packet *packet;
263     STREAM out;
264     int len;
265     static long prev_s, prev_us;
266     unsigned int duration;
267     struct timeval tv;
268     int next_tick;
269    
270     if (reopened)
271     {
272     reopened = False;
273     gettimeofday(&tv, NULL);
274     prev_s = tv.tv_sec;
275     prev_us = tv.tv_usec;
276     }
277    
278     if (queue_lo == queue_hi)
279     {
280     g_dsp_busy = 0;
281     return;
282     }
283    
284     packet = &packet_queue[queue_lo];
285     out = &packet->s;
286    
287     if (((queue_lo + 1) % MAX_QUEUE) != queue_hi)
288     {
289     next_tick = packet_queue[(queue_lo + 1) % MAX_QUEUE].tick;
290     }
291     else
292     {
293     next_tick = (packet->tick + 65535) % 65536;
294     }
295    
296     len = (out->end - out->p) / (samplewidth * audiochannels);
297     if ((len = snd_pcm_writei(pcm_handle, out->p, ((MAX_FRAMES < len) ? MAX_FRAMES : len))) < 0)
298     {
299     snd_pcm_prepare(pcm_handle);
300     len = 0;
301     }
302     out->p += (len * samplewidth * audiochannels);
303    
304     gettimeofday(&tv, NULL);
305    
306     duration = ((tv.tv_sec - prev_s) * 1000000 + (tv.tv_usec - prev_us)) / 1000;
307    
308     if (packet->tick > next_tick)
309     next_tick += 65536;
310    
311     if ((out->p == out->end) || duration > next_tick - packet->tick + 500)
312     {
313     prev_s = tv.tv_sec;
314     prev_us = tv.tv_usec;
315    
316     if (abs((next_tick - packet->tick) - duration) > 20)
317     {
318     DEBUG(("duration: %d, calc: %d, ", duration, next_tick - packet->tick));
319     DEBUG(("last: %d, is: %d, should: %d\n", packet->tick,
320     (packet->tick + duration) % 65536, next_tick % 65536));
321     }
322    
323     /* Until all drivers are using the windows sound-ticks, we need to
324     substract the 50 ticks added later by rdpsnd.c */
325     rdpsnd_send_completion(((packet->tick + duration) % 65536) - 50, packet->index);
326     free(out->data);
327     queue_lo = (queue_lo + 1) % MAX_QUEUE;
328     }
329    
330     g_dsp_busy = 1;
331     return;
332     }

  ViewVC Help
Powered by ViewVC 1.1.26