/[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 1346 - (show annotations)
Thu Dec 7 15:23:45 2006 UTC (17 years, 5 months ago) by ossman_
File MIME type: text/plain
File size: 7045 byte(s)
Abstract select() handling in rdpsnd so that backends can do their thing
more correctly.

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 dsp_fd = -1;
47 static BOOL dsp_busy;
48
49 static int snd_rate;
50 static short samplewidth;
51 static char *dsp_dev;
52 static BOOL in_esddsp;
53
54 /* This is a just a forward declaration */
55 static struct audio_driver oss_driver;
56
57 void oss_play(void);
58
59 void
60 oss_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
61 {
62 if (dsp_fd == -1)
63 return;
64
65 if (rdpsnd_queue_empty())
66 return;
67
68 FD_SET(dsp_fd, wfds);
69 if (dsp_fd > *n)
70 *n = dsp_fd;
71 }
72
73 void
74 oss_check_fds(fd_set * rfds, fd_set * wfds)
75 {
76 if (FD_ISSET(dsp_fd, wfds))
77 oss_play();
78 }
79
80 static BOOL
81 detect_esddsp(void)
82 {
83 struct stat s;
84 char *preload;
85
86 if (fstat(dsp_fd, &s) == -1)
87 return False;
88
89 if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
90 return False;
91
92 preload = getenv("LD_PRELOAD");
93 if (preload == NULL)
94 return False;
95
96 if (strstr(preload, "esddsp") == NULL)
97 return False;
98
99 return True;
100 }
101
102 BOOL
103 oss_open(void)
104 {
105 if ((dsp_fd = open(dsp_dev, O_WRONLY)) == -1)
106 {
107 perror(dsp_dev);
108 return False;
109 }
110
111 in_esddsp = detect_esddsp();
112
113 return True;
114 }
115
116 void
117 oss_close(void)
118 {
119 close(dsp_fd);
120 dsp_fd = -1;
121 dsp_busy = False;
122 }
123
124 BOOL
125 oss_format_supported(WAVEFORMATEX * pwfx)
126 {
127 if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
128 return False;
129 if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
130 return False;
131 if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
132 return False;
133
134 return True;
135 }
136
137 BOOL
138 oss_set_format(WAVEFORMATEX * pwfx)
139 {
140 int stereo, format, fragments;
141 static BOOL driver_broken = False;
142
143 ioctl(dsp_fd, SNDCTL_DSP_RESET, NULL);
144 ioctl(dsp_fd, SNDCTL_DSP_SYNC, NULL);
145
146 if (pwfx->wBitsPerSample == 8)
147 format = AFMT_U8;
148 else if (pwfx->wBitsPerSample == 16)
149 format = AFMT_S16_LE;
150
151 samplewidth = pwfx->wBitsPerSample / 8;
152
153 if (ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
154 {
155 perror("SNDCTL_DSP_SETFMT");
156 oss_close();
157 return False;
158 }
159
160 if (pwfx->nChannels == 2)
161 {
162 stereo = 1;
163 samplewidth *= 2;
164 }
165 else
166 {
167 stereo = 0;
168 }
169
170 if (ioctl(dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
171 {
172 perror("SNDCTL_DSP_CHANNELS");
173 oss_close();
174 return False;
175 }
176
177 oss_driver.need_resampling = 0;
178 snd_rate = pwfx->nSamplesPerSec;
179 if (ioctl(dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
180 {
181 int rates[] = { 44100, 48000, 0 };
182 int *prates = rates;
183
184 while (*prates != 0)
185 {
186 if ((pwfx->nSamplesPerSec != *prates)
187 && (ioctl(dsp_fd, SNDCTL_DSP_SPEED, prates) != -1))
188 {
189 oss_driver.need_resampling = 1;
190 snd_rate = *prates;
191 if (rdpsnd_dsp_resample_set
192 (snd_rate, pwfx->wBitsPerSample, pwfx->nChannels) == False)
193 {
194 error("rdpsnd_dsp_resample_set failed");
195 oss_close();
196 return False;
197 }
198
199 break;
200 }
201 prates++;
202 }
203
204 if (*prates == 0)
205 {
206 perror("SNDCTL_DSP_SPEED");
207 oss_close();
208 return False;
209 }
210 }
211
212 /* try to get 12 fragments of 2^12 bytes size */
213 fragments = (12 << 16) + 12;
214 ioctl(dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
215
216 if (!driver_broken)
217 {
218 audio_buf_info info;
219
220 memset(&info, 0, sizeof(info));
221 if (ioctl(dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
222 {
223 perror("SNDCTL_DSP_GETOSPACE");
224 oss_close();
225 return False;
226 }
227
228 if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
229 {
230 fprintf(stderr,
231 "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
232 info.fragments, info.fragstotal, info.fragsize);
233 driver_broken = True;
234 }
235 }
236
237 return True;
238 }
239
240 void
241 oss_volume(uint16 left, uint16 right)
242 {
243 uint32 volume;
244
245 volume = left / (65536 / 100);
246 volume |= right / (65536 / 100) << 8;
247
248 if (ioctl(dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
249 {
250 warning("hardware volume control unavailable, falling back to software volume control!\n");
251 oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
252 rdpsnd_dsp_softvol_set(left, right);
253 return;
254 }
255 }
256
257 void
258 oss_play(void)
259 {
260 struct audio_packet *packet;
261 ssize_t len;
262 STREAM out;
263
264 /* We shouldn't be called if the queue is empty, but still */
265 if (rdpsnd_queue_empty())
266 return;
267
268 packet = rdpsnd_queue_current_packet();
269 out = &packet->s;
270
271 len = out->end - out->p;
272
273 len = write(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
274 if (len == -1)
275 {
276 if (errno != EWOULDBLOCK)
277 perror("write audio");
278 return;
279 }
280
281 out->p += len;
282
283 if (out->p == out->end)
284 {
285 int delay_bytes;
286 unsigned long delay_us;
287 audio_buf_info info;
288
289 if (in_esddsp)
290 {
291 /* EsounD has no way of querying buffer status, so we have to
292 * go with a fixed size. */
293 delay_bytes = out->size;
294 }
295 else
296 {
297 #ifdef SNDCTL_DSP_GETODELAY
298 delay_bytes = 0;
299 if (ioctl(dsp_fd, SNDCTL_DSP_GETODELAY, &delay_bytes) == -1)
300 delay_bytes = -1;
301 #else
302 delay_bytes = -1;
303 #endif
304
305 if (delay_bytes == -1)
306 {
307 if (ioctl(dsp_fd, SNDCTL_DSP_GETOSPACE, &info) != -1)
308 delay_bytes = info.fragstotal * info.fragsize - info.bytes;
309 else
310 delay_bytes = out->size;
311 }
312 }
313
314 delay_us = delay_bytes * (1000000 / (samplewidth * snd_rate));
315 rdpsnd_queue_next(delay_us);
316 }
317 }
318
319 static struct audio_driver oss_driver = {
320 .name = "oss",
321 .description = "OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV",
322
323 .add_fds = oss_add_fds,
324 .check_fds = oss_check_fds,
325
326 .wave_out_open = oss_open,
327 .wave_out_close = oss_close,
328 .wave_out_format_supported = oss_format_supported,
329 .wave_out_set_format = oss_set_format,
330 .wave_out_volume = oss_volume,
331
332 .need_byteswap_on_be = 0,
333 .need_resampling = 0,
334 };
335
336 struct audio_driver *
337 oss_register(char *options)
338 {
339 if (options)
340 {
341 dsp_dev = xstrdup(options);
342 }
343 else
344 {
345 dsp_dev = getenv("AUDIODEV");
346
347 if (dsp_dev == NULL)
348 {
349 dsp_dev = xstrdup(DEFAULTDEVICE);
350 }
351 }
352
353 return &oss_driver;
354 }

  ViewVC Help
Powered by ViewVC 1.1.26