/[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 1260 - (show annotations)
Sun Sep 17 15:25:10 2006 UTC (17 years, 8 months ago) by stargo
File MIME type: text/plain
File size: 7279 byte(s)
unify audio-byteswapping as a dsp-function

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

  ViewVC Help
Powered by ViewVC 1.1.26