/[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 1318 - (show annotations)
Thu Nov 2 11:55:59 2006 UTC (17 years, 8 months ago) by astrand
File MIME type: text/plain
File size: 6735 byte(s)
After closing g_dsp_fd, set g_dsp_busy to false. This prevents errors of type: ERROR: select: Bad file descriptor

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 g_dsp_busy = 0;
93 }
94
95 BOOL
96 oss_format_supported(WAVEFORMATEX * pwfx)
97 {
98 if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
99 return False;
100 if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
101 return False;
102 if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
103 return False;
104
105 return True;
106 }
107
108 BOOL
109 oss_set_format(WAVEFORMATEX * pwfx)
110 {
111 int stereo, format, fragments;
112 static BOOL driver_broken = False;
113
114 ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);
115 ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL);
116
117 if (pwfx->wBitsPerSample == 8)
118 format = AFMT_U8;
119 else if (pwfx->wBitsPerSample == 16)
120 format = AFMT_S16_LE;
121
122 samplewidth = pwfx->wBitsPerSample / 8;
123
124 if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
125 {
126 perror("SNDCTL_DSP_SETFMT");
127 oss_close();
128 return False;
129 }
130
131 if (pwfx->nChannels == 2)
132 {
133 stereo = 1;
134 samplewidth *= 2;
135 }
136 else
137 {
138 stereo = 0;
139 }
140
141 if (ioctl(g_dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
142 {
143 perror("SNDCTL_DSP_CHANNELS");
144 oss_close();
145 return False;
146 }
147
148 oss_driver.need_resampling = 0;
149 snd_rate = pwfx->nSamplesPerSec;
150 if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
151 {
152 int rates[] = { 44100, 48000, 0 };
153 int *prates = rates;
154
155 while (*prates != 0)
156 {
157 if ((pwfx->nSamplesPerSec != *prates)
158 && (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, prates) != -1))
159 {
160 oss_driver.need_resampling = 1;
161 snd_rate = *prates;
162 if (rdpsnd_dsp_resample_set
163 (snd_rate, pwfx->wBitsPerSample, pwfx->nChannels) == False)
164 {
165 error("rdpsnd_dsp_resample_set failed");
166 oss_close();
167 return False;
168 }
169
170 break;
171 }
172 prates++;
173 }
174
175 if (*prates == 0)
176 {
177 perror("SNDCTL_DSP_SPEED");
178 oss_close();
179 return False;
180 }
181 }
182
183 /* try to get 12 fragments of 2^12 bytes size */
184 fragments = (12 << 16) + 12;
185 ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
186
187 if (!driver_broken)
188 {
189 audio_buf_info info;
190
191 memset(&info, 0, sizeof(info));
192 if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
193 {
194 perror("SNDCTL_DSP_GETOSPACE");
195 oss_close();
196 return False;
197 }
198
199 if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
200 {
201 fprintf(stderr,
202 "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
203 info.fragments, info.fragstotal, info.fragsize);
204 driver_broken = True;
205 }
206 }
207
208 return True;
209 }
210
211 void
212 oss_volume(uint16 left, uint16 right)
213 {
214 uint32 volume;
215
216 volume = left / (65536 / 100);
217 volume |= right / (65536 / 100) << 8;
218
219 if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
220 {
221 warning("hardware volume control unavailable, falling back to software volume control!\n");
222 oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
223 rdpsnd_dsp_softvol_set(left, right);
224 return;
225 }
226 }
227
228 void
229 oss_play(void)
230 {
231 struct audio_packet *packet;
232 ssize_t len;
233 STREAM out;
234
235 if (rdpsnd_queue_empty())
236 {
237 g_dsp_busy = 0;
238 return;
239 }
240
241 packet = rdpsnd_queue_current_packet();
242 out = &packet->s;
243
244 len = out->end - out->p;
245
246 len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
247 if (len == -1)
248 {
249 if (errno != EWOULDBLOCK)
250 perror("write audio");
251 g_dsp_busy = 1;
252 return;
253 }
254
255 out->p += len;
256
257 if (out->p == out->end)
258 {
259 int delay_bytes;
260 unsigned long delay_us;
261 audio_buf_info info;
262
263 if (in_esddsp)
264 {
265 /* EsounD has no way of querying buffer status, so we have to
266 * go with a fixed size. */
267 delay_bytes = out->size;
268 }
269 else
270 {
271 #ifdef SNDCTL_DSP_GETODELAY
272 delay_bytes = 0;
273 if (ioctl(g_dsp_fd, SNDCTL_DSP_GETODELAY, &delay_bytes) == -1)
274 delay_bytes = -1;
275 #else
276 delay_bytes = -1;
277 #endif
278
279 if (delay_bytes == -1)
280 {
281 if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) != -1)
282 delay_bytes = info.fragstotal * info.fragsize - info.bytes;
283 else
284 delay_bytes = out->size;
285 }
286 }
287
288 delay_us = delay_bytes * (1000000 / (samplewidth * snd_rate));
289 rdpsnd_queue_next(delay_us);
290 }
291 else
292 {
293 g_dsp_busy = 1;
294 }
295
296 return;
297 }
298
299 struct audio_driver *
300 oss_register(char *options)
301 {
302 oss_driver.wave_out_open = oss_open;
303 oss_driver.wave_out_close = oss_close;
304 oss_driver.wave_out_format_supported = oss_format_supported;
305 oss_driver.wave_out_set_format = oss_set_format;
306 oss_driver.wave_out_volume = oss_volume;
307 oss_driver.wave_out_play = oss_play;
308 oss_driver.name = xstrdup("oss");
309 oss_driver.description =
310 xstrdup("OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV");
311 oss_driver.need_byteswap_on_be = 0;
312 oss_driver.need_resampling = 0;
313 oss_driver.next = NULL;
314
315 if (options)
316 {
317 dsp_dev = xstrdup(options);
318 }
319 else
320 {
321 dsp_dev = getenv("AUDIODEV");
322
323 if (dsp_dev == NULL)
324 {
325 dsp_dev = xstrdup(DEFAULTDEVICE);
326 }
327 }
328
329 return &oss_driver;
330 }

  ViewVC Help
Powered by ViewVC 1.1.26