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

  ViewVC Help
Powered by ViewVC 1.1.26