/[rdesktop]/sourceforge.net/trunk/rdesktop/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

Contents of /sourceforge.net/trunk/rdesktop/rdpsnd_alsa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1253 - (show annotations)
Sun Sep 17 10:00:55 2006 UTC (17 years, 8 months ago) by stargo
File MIME type: text/plain
File size: 7608 byte(s)
add alsa-driver

1 /* -*- 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