/[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 1345 - (show annotations)
Thu Dec 7 11:54:29 2006 UTC (17 years, 6 months ago) by ossman_
File MIME type: text/plain
File size: 6681 byte(s)
Restructure driver registration structures a bit so it is easier to add
new fields (and also reduce some memory usage/leaks).

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

  ViewVC Help
Powered by ViewVC 1.1.26