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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1302 - (show annotations)
Thu Oct 26 09:47:17 2006 UTC (17 years, 7 months ago) by ossman_
File MIME type: text/plain
File size: 6738 byte(s)
Rewrite the queue management a bit so that blocks are not completed until
they have finished playing. This also makes the queue system mandatory for
all backends.

1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Sound Channel Process Functions - Open Sound System
4 Copyright (C) Matthew Chapman 2003
5 Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /*
23 This is a workaround for Esound bug 312665.
24 FIXME: Remove this when Esound is fixed.
25 */
26 #ifdef _FILE_OFFSET_BITS
27 #undef _FILE_OFFSET_BITS
28 #endif
29
30 #include "rdesktop.h"
31 #include "rdpsnd.h"
32 #include "rdpsnd_dsp.h"
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <sys/time.h>
38 #include <sys/ioctl.h>
39 #include <sys/soundcard.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42
43 #define DEFAULTDEVICE "/dev/dsp"
44 #define MAX_LEN 512
45
46 static int snd_rate;
47 static short samplewidth;
48 static char *dsp_dev;
49 static struct audio_driver oss_driver;
50 static BOOL in_esddsp;
51
52 static BOOL
53 detect_esddsp(void)
54 {
55 struct stat s;
56 char *preload;
57
58 if (fstat(g_dsp_fd, &s) == -1)
59 return False;
60
61 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
62 return False;
63
64 preload = getenv("LD_PRELOAD");
65 if (preload == NULL)
66 return False;
67
68 if (strstr(preload, "esddsp") == NULL)
69 return False;
70
71 return True;
72 }
73
74 BOOL
75 oss_open(void)
76 {
77 if ((g_dsp_fd = open(dsp_dev, O_WRONLY)) == -1)
78 {
79 perror(dsp_dev);
80 return False;
81 }
82
83 in_esddsp = detect_esddsp();
84
85 return True;
86 }
87
88 void
89 oss_close(void)
90 {
91 close(g_dsp_fd);
92 }
93
94 BOOL
95 oss_format_supported(WAVEFORMATEX * pwfx)
96 {
97 if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
98 return False;
99 if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
100 return False;
101 if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
102 return False;
103
104 return True;
105 }
106
107 BOOL
108 oss_set_format(WAVEFORMATEX * pwfx)
109 {
110 int stereo, format, fragments;
111 static BOOL driver_broken = False;
112
113 ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);
114 ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL);
115
116 if (pwfx->wBitsPerSample == 8)
117 format = AFMT_U8;
118 else if (pwfx->wBitsPerSample == 16)
119 format = AFMT_S16_LE;
120
121 samplewidth = pwfx->wBitsPerSample / 8;
122
123 if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
124 {
125 perror("SNDCTL_DSP_SETFMT");
126 close(g_dsp_fd);
127 return False;
128 }
129
130 if (pwfx->nChannels == 2)
131 {
132 stereo = 1;
133 samplewidth *= 2;
134 }
135 else
136 {
137 stereo = 0;
138 }
139
140 if (ioctl(g_dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
141 {
142 perror("SNDCTL_DSP_CHANNELS");
143 close(g_dsp_fd);
144 return False;
145 }
146
147 oss_driver.need_resampling = 0;
148 snd_rate = pwfx->nSamplesPerSec;
149 if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
150 {
151 int rates[] = { 44100, 48000, 0 };
152 int *prates = rates;
153
154 while (*prates != 0)
155 {
156 if ((pwfx->nSamplesPerSec != *prates)
157 && (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, prates) != -1))
158 {
159 oss_driver.need_resampling = 1;
160 snd_rate = *prates;
161 if (rdpsnd_dsp_resample_set
162 (snd_rate, pwfx->wBitsPerSample, pwfx->nChannels) == False)
163 {
164 error("rdpsnd_dsp_resample_set failed");
165 close(g_dsp_fd);
166 return False;
167 }
168
169 break;
170 }
171 prates++;
172 }
173
174 if (*prates == 0)
175 {
176 perror("SNDCTL_DSP_SPEED");
177 close(g_dsp_fd);
178 return False;
179 }
180 }
181
182 /* try to get 12 fragments of 2^12 bytes size */
183 fragments = (12 << 16) + 12;
184 ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
185
186 if (!driver_broken)
187 {
188 audio_buf_info info;
189
190 memset(&info, 0, sizeof(info));
191 if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
192 {
193 perror("SNDCTL_DSP_GETOSPACE");
194 close(g_dsp_fd);
195 return False;
196 }
197
198 if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
199 {
200 fprintf(stderr,
201 "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
202 info.fragments, info.fragstotal, info.fragsize);
203 driver_broken = True;
204 }
205 }
206
207 return True;
208 }
209
210 void
211 oss_volume(uint16 left, uint16 right)
212 {
213 uint32 volume;
214
215 volume = left / (65536 / 100);
216 volume |= right / (65536 / 100) << 8;
217
218 if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
219 {
220 warning("hardware volume control unavailable, falling back to software volume control!\n");
221 oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
222 rdpsnd_dsp_softvol_set(left, right);
223 return;
224 }
225 }
226
227 void
228 oss_play(void)
229 {
230 struct audio_packet *packet;
231 ssize_t len;
232 STREAM out;
233
234 if (rdpsnd_queue_empty())
235 {
236 g_dsp_busy = 0;
237 return;
238 }
239
240 packet = rdpsnd_queue_current_packet();
241 out = &packet->s;
242
243 len = out->end - out->p;
244
245 len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
246 if (len == -1)
247 {
248 if (errno != EWOULDBLOCK)
249 perror("write audio");
250 g_dsp_busy = 1;
251 return;
252 }
253
254 out->p += len;
255
256 if (out->p == out->end)
257 {
258 int delay_bytes;
259 unsigned long delay_us;
260 audio_buf_info info;
261
262 if (in_esddsp)
263 {
264 /* EsounD has no way of querying buffer status, so we have to
265 * go with a fixed size. */
266 delay_bytes = out->size;
267 }
268 else
269 {
270 #ifdef SNDCTL_DSP_GETODELAY
271 delay_bytes = 0;
272 if (ioctl(g_dsp_fd, SNDCTL_DSP_GETODELAY, &delay_bytes) == -1)
273 delay_bytes = -1;
274 #else
275 delay_bytes = -1;
276 #endif
277
278 if (delay_bytes == -1)
279 {
280 if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) != -1)
281 delay_bytes = info.fragstotal * info.fragsize - info.bytes;
282 else
283 delay_bytes = out->size;
284 }
285 }
286
287 delay_us = delay_bytes * (1000000 / (samplewidth * snd_rate));
288 rdpsnd_queue_next(delay_us);
289 }
290 else
291 {
292 g_dsp_busy = 1;
293 }
294
295 return;
296 }
297
298 struct audio_driver *
299 oss_register(char *options)
300 {
301 oss_driver.wave_out_open = oss_open;
302 oss_driver.wave_out_close = oss_close;
303 oss_driver.wave_out_format_supported = oss_format_supported;
304 oss_driver.wave_out_set_format = oss_set_format;
305 oss_driver.wave_out_volume = oss_volume;
306 oss_driver.wave_out_play = oss_play;
307 oss_driver.name = xstrdup("oss");
308 oss_driver.description =
309 xstrdup("OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV");
310 oss_driver.need_byteswap_on_be = 0;
311 oss_driver.need_resampling = 0;
312 oss_driver.next = NULL;
313
314 if (options)
315 {
316 dsp_dev = xstrdup(options);
317 }
318 else
319 {
320 dsp_dev = getenv("AUDIODEV");
321
322 if (dsp_dev == NULL)
323 {
324 dsp_dev = xstrdup(DEFAULTDEVICE);
325 }
326 }
327
328 return &oss_driver;
329 }

  ViewVC Help
Powered by ViewVC 1.1.26