/[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

Annotation of /sourceforge.net/trunk/rdesktop/rdpsnd_oss.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1365 - (hide annotations)
Thu Jan 4 05:39:39 2007 UTC (17 years, 5 months ago) by jsorg71
File MIME type: text/plain
File size: 9257 byte(s)
copyright year update

1 astrand 963 /* -*- c-basic-offset: 8 -*-
2 matthewc 475 rdesktop: A Remote Desktop Protocol client.
3     Sound Channel Process Functions - Open Sound System
4 jsorg71 1365 Copyright (C) Matthew Chapman 2003-2007
5 matthewc 475 Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6 jsorg71 1365 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 matthewc 475
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 astrand 1227 /*
24     This is a workaround for Esound bug 312665.
25     FIXME: Remove this when Esound is fixed.
26     */
27     #ifdef _FILE_OFFSET_BITS
28     #undef _FILE_OFFSET_BITS
29     #endif
30    
31 matthewc 475 #include "rdesktop.h"
32 stargo 1254 #include "rdpsnd.h"
33 stargo 1269 #include "rdpsnd_dsp.h"
34 matthewc 475 #include <unistd.h>
35     #include <fcntl.h>
36     #include <errno.h>
37 ossman_ 1302 #include <unistd.h>
38 stargo 510 #include <sys/time.h>
39 matthewc 475 #include <sys/ioctl.h>
40     #include <sys/soundcard.h>
41 ossman_ 1302 #include <sys/types.h>
42     #include <sys/stat.h>
43 matthewc 475
44 stargo 1254 #define DEFAULTDEVICE "/dev/dsp"
45 stargo 1247 #define MAX_LEN 512
46 matthewc 475
47 ossman_ 1346 static int dsp_fd = -1;
48 ossman_ 1361 static int dsp_mode;
49     static int dsp_refs;
50 ossman_ 1346
51 ossman_ 1361 static BOOL dsp_configured;
52    
53     static BOOL dsp_out;
54     static BOOL dsp_in;
55    
56     static int stereo;
57     static int format;
58 stargo 1247 static int snd_rate;
59     static short samplewidth;
60 stargo 1255 static char *dsp_dev;
61 ossman_ 1302 static BOOL in_esddsp;
62 matthewc 475
63 ossman_ 1345 /* This is a just a forward declaration */
64     static struct audio_driver oss_driver;
65    
66 ossman_ 1346 void oss_play(void);
67 ossman_ 1361 void oss_record(void);
68 ossman_ 1346
69     void
70     oss_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
71     {
72     if (dsp_fd == -1)
73     return;
74    
75 ossman_ 1361 if (dsp_out && !rdpsnd_queue_empty())
76     FD_SET(dsp_fd, wfds);
77     if (dsp_in)
78     FD_SET(dsp_fd, rfds);
79 ossman_ 1346 if (dsp_fd > *n)
80     *n = dsp_fd;
81     }
82    
83     void
84     oss_check_fds(fd_set * rfds, fd_set * wfds)
85     {
86     if (FD_ISSET(dsp_fd, wfds))
87     oss_play();
88 ossman_ 1361 if (FD_ISSET(dsp_fd, rfds))
89     oss_record();
90 ossman_ 1346 }
91    
92 ossman_ 1302 static BOOL
93     detect_esddsp(void)
94     {
95     struct stat s;
96     char *preload;
97    
98 ossman_ 1346 if (fstat(dsp_fd, &s) == -1)
99 ossman_ 1302 return False;
100    
101     if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
102     return False;
103    
104     preload = getenv("LD_PRELOAD");
105     if (preload == NULL)
106     return False;
107    
108     if (strstr(preload, "esddsp") == NULL)
109     return False;
110    
111     return True;
112     }
113    
114 matthewc 475 BOOL
115 ossman_ 1361 oss_open(int fallback)
116 matthewc 475 {
117 ossman_ 1361 int caps;
118    
119     if (dsp_fd != -1)
120 matthewc 475 {
121 ossman_ 1361 dsp_refs++;
122    
123     if (dsp_mode == O_RDWR)
124     return True;
125    
126     if (dsp_mode == fallback)
127     return True;
128    
129     dsp_refs--;
130 matthewc 475 return False;
131     }
132    
133 ossman_ 1361 dsp_configured = False;
134    
135     dsp_mode = O_RDWR;
136     dsp_fd = open(dsp_dev, O_RDWR | O_NONBLOCK);
137     if (dsp_fd != -1)
138     {
139     ioctl(dsp_fd, SNDCTL_DSP_SETDUPLEX, 0);
140    
141     if ((ioctl(dsp_fd, SNDCTL_DSP_GETCAPS, &caps) < 0) || !(caps & DSP_CAP_DUPLEX))
142     {
143     close(dsp_fd);
144     dsp_fd = -1;
145     }
146     }
147    
148     if (dsp_fd == -1)
149     {
150     dsp_mode = fallback;
151    
152     dsp_fd = open(dsp_dev, dsp_mode | O_NONBLOCK);
153     if (dsp_fd == -1)
154     {
155     perror(dsp_dev);
156     return False;
157     }
158     }
159    
160     dsp_refs++;
161    
162 ossman_ 1302 in_esddsp = detect_esddsp();
163    
164 matthewc 475 return True;
165     }
166    
167     void
168 stargo 1255 oss_close(void)
169 matthewc 475 {
170 ossman_ 1361 dsp_refs--;
171    
172     if (dsp_refs != 0)
173     return;
174    
175 ossman_ 1346 close(dsp_fd);
176     dsp_fd = -1;
177 matthewc 475 }
178    
179     BOOL
180 ossman_ 1361 oss_open_out(void)
181     {
182     if (!oss_open(O_WRONLY))
183     return False;
184    
185     dsp_out = True;
186    
187     return True;
188     }
189    
190     void
191     oss_close_out(void)
192     {
193     oss_close();
194    
195     /* Ack all remaining packets */
196     while (!rdpsnd_queue_empty())
197     rdpsnd_queue_next(0);
198    
199     dsp_out = False;
200     }
201    
202     BOOL
203     oss_open_in(void)
204     {
205     if (!oss_open(O_RDONLY))
206     return False;
207    
208     dsp_in = True;
209    
210     return True;
211     }
212    
213     void
214     oss_close_in(void)
215     {
216     oss_close();
217    
218     dsp_in = False;
219     }
220    
221     BOOL
222 jsorg71 1364 oss_format_supported(RD_WAVEFORMATEX * pwfx)
223 matthewc 475 {
224     if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
225     return False;
226     if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
227     return False;
228     if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
229     return False;
230    
231     return True;
232     }
233    
234     BOOL
235 jsorg71 1364 oss_set_format(RD_WAVEFORMATEX * pwfx)
236 matthewc 475 {
237 ossman_ 1361 int fragments;
238 stargo 1247 static BOOL driver_broken = False;
239 matthewc 475
240 ossman_ 1361 if (dsp_configured)
241     {
242     if ((pwfx->wBitsPerSample == 8) && (format != AFMT_U8))
243     return False;
244     if ((pwfx->wBitsPerSample == 16) && (format != AFMT_S16_LE))
245     return False;
246    
247     if ((pwfx->nChannels == 2) != !!stereo)
248     return False;
249    
250     if (pwfx->nSamplesPerSec != snd_rate)
251     return False;
252    
253     return True;
254     }
255    
256 ossman_ 1346 ioctl(dsp_fd, SNDCTL_DSP_RESET, NULL);
257     ioctl(dsp_fd, SNDCTL_DSP_SYNC, NULL);
258 matthewc 475
259     if (pwfx->wBitsPerSample == 8)
260     format = AFMT_U8;
261     else if (pwfx->wBitsPerSample == 16)
262     format = AFMT_S16_LE;
263    
264 stargo 1247 samplewidth = pwfx->wBitsPerSample / 8;
265 stargo 510
266 ossman_ 1346 if (ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
267 matthewc 475 {
268     perror("SNDCTL_DSP_SETFMT");
269 astrand 1318 oss_close();
270 matthewc 475 return False;
271     }
272    
273 stargo 760 if (pwfx->nChannels == 2)
274 matthewc 475 {
275 stargo 760 stereo = 1;
276 stargo 1247 samplewidth *= 2;
277 stargo 760 }
278     else
279     {
280     stereo = 0;
281     }
282    
283 ossman_ 1346 if (ioctl(dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
284 stargo 760 {
285 matthewc 475 perror("SNDCTL_DSP_CHANNELS");
286 astrand 1318 oss_close();
287 matthewc 475 return False;
288     }
289    
290 stargo 1286 oss_driver.need_resampling = 0;
291 stargo 1247 snd_rate = pwfx->nSamplesPerSec;
292 ossman_ 1346 if (ioctl(dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
293 stargo 510 {
294 stargo 1286 int rates[] = { 44100, 48000, 0 };
295     int *prates = rates;
296    
297     while (*prates != 0)
298     {
299     if ((pwfx->nSamplesPerSec != *prates)
300 ossman_ 1346 && (ioctl(dsp_fd, SNDCTL_DSP_SPEED, prates) != -1))
301 stargo 1286 {
302     oss_driver.need_resampling = 1;
303     snd_rate = *prates;
304     if (rdpsnd_dsp_resample_set
305     (snd_rate, pwfx->wBitsPerSample, pwfx->nChannels) == False)
306     {
307     error("rdpsnd_dsp_resample_set failed");
308 astrand 1318 oss_close();
309 stargo 1286 return False;
310     }
311    
312     break;
313     }
314     prates++;
315     }
316    
317     if (*prates == 0)
318     {
319     perror("SNDCTL_DSP_SPEED");
320 astrand 1318 oss_close();
321 stargo 1286 return False;
322     }
323 matthewc 475 }
324    
325 stargo 1247 /* try to get 12 fragments of 2^12 bytes size */
326     fragments = (12 << 16) + 12;
327 ossman_ 1346 ioctl(dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
328 stargo 761
329 stargo 1247 if (!driver_broken)
330 stargo 761 {
331     audio_buf_info info;
332    
333 astrand 801 memset(&info, 0, sizeof(info));
334 ossman_ 1346 if (ioctl(dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
335 stargo 761 {
336     perror("SNDCTL_DSP_GETOSPACE");
337 astrand 1318 oss_close();
338 stargo 761 return False;
339     }
340    
341     if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
342     {
343     fprintf(stderr,
344     "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
345     info.fragments, info.fragstotal, info.fragsize);
346 stargo 1247 driver_broken = True;
347 stargo 761 }
348     }
349    
350 ossman_ 1361 dsp_configured = True;
351    
352 matthewc 475 return True;
353     }
354    
355     void
356 stargo 1255 oss_volume(uint16 left, uint16 right)
357 stargo 491 {
358     uint32 volume;
359    
360 astrand 499 volume = left / (65536 / 100);
361     volume |= right / (65536 / 100) << 8;
362 stargo 509
363 ossman_ 1346 if (ioctl(dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
364 stargo 491 {
365 stargo 1275 warning("hardware volume control unavailable, falling back to software volume control!\n");
366 stargo 1269 oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
367 stargo 1275 rdpsnd_dsp_softvol_set(left, right);
368 stargo 491 return;
369     }
370     }
371    
372     void
373 stargo 1255 oss_play(void)
374 matthewc 475 {
375     struct audio_packet *packet;
376     ssize_t len;
377     STREAM out;
378    
379 ossman_ 1346 /* We shouldn't be called if the queue is empty, but still */
380 stargo 1254 if (rdpsnd_queue_empty())
381 stargo 1247 return;
382 matthewc 475
383 stargo 1254 packet = rdpsnd_queue_current_packet();
384 stargo 1247 out = &packet->s;
385 matthewc 475
386 stargo 1247 len = out->end - out->p;
387 stargo 761
388 ossman_ 1346 len = write(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
389 stargo 1247 if (len == -1)
390     {
391     if (errno != EWOULDBLOCK)
392     perror("write audio");
393     return;
394     }
395 stargo 761
396 stargo 1247 out->p += len;
397 ossman_ 1302
398 stargo 1247 if (out->p == out->end)
399     {
400 ossman_ 1302 int delay_bytes;
401     unsigned long delay_us;
402     audio_buf_info info;
403 stargo 761
404 ossman_ 1302 if (in_esddsp)
405 matthewc 475 {
406 ossman_ 1302 /* EsounD has no way of querying buffer status, so we have to
407     * go with a fixed size. */
408     delay_bytes = out->size;
409 stargo 1247 }
410     else
411     {
412 ossman_ 1302 #ifdef SNDCTL_DSP_GETODELAY
413     delay_bytes = 0;
414 ossman_ 1346 if (ioctl(dsp_fd, SNDCTL_DSP_GETODELAY, &delay_bytes) == -1)
415 ossman_ 1302 delay_bytes = -1;
416     #else
417     delay_bytes = -1;
418     #endif
419    
420     if (delay_bytes == -1)
421     {
422 ossman_ 1346 if (ioctl(dsp_fd, SNDCTL_DSP_GETOSPACE, &info) != -1)
423 ossman_ 1302 delay_bytes = info.fragstotal * info.fragsize - info.bytes;
424     else
425     delay_bytes = out->size;
426     }
427 matthewc 475 }
428 ossman_ 1302
429     delay_us = delay_bytes * (1000000 / (samplewidth * snd_rate));
430     rdpsnd_queue_next(delay_us);
431 matthewc 475 }
432     }
433 stargo 1255
434 ossman_ 1361 void
435     oss_record(void)
436     {
437     char buffer[32768];
438     int len;
439    
440     len = read(dsp_fd, buffer, sizeof(buffer));
441     if (len == -1)
442     {
443     if (errno != EWOULDBLOCK)
444     perror("read audio");
445     return;
446     }
447    
448     rdpsnd_record(buffer, len);
449     }
450    
451 stargo 1351 struct audio_driver *
452     oss_register(char *options)
453     {
454 ossman_ 1356 memset(&oss_driver, 0, sizeof(oss_driver));
455    
456     oss_driver.name = "oss";
457 stargo 1351 oss_driver.description =
458 ossman_ 1356 "OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV";
459 ossman_ 1345
460 stargo 1351 oss_driver.add_fds = oss_add_fds;
461     oss_driver.check_fds = oss_check_fds;
462 ossman_ 1346
463 ossman_ 1361 oss_driver.wave_out_open = oss_open_out;
464     oss_driver.wave_out_close = oss_close_out;
465 stargo 1351 oss_driver.wave_out_format_supported = oss_format_supported;
466     oss_driver.wave_out_set_format = oss_set_format;
467     oss_driver.wave_out_volume = oss_volume;
468 ossman_ 1345
469 ossman_ 1361 oss_driver.wave_in_open = oss_open_in;
470     oss_driver.wave_in_close = oss_close_in;
471     oss_driver.wave_in_format_supported = oss_format_supported;
472     oss_driver.wave_in_set_format = oss_set_format;
473     oss_driver.wave_in_volume = NULL; /* FIXME */
474    
475 stargo 1351 oss_driver.need_byteswap_on_be = 0;
476     oss_driver.need_resampling = 0;
477 ossman_ 1345
478 stargo 1255 if (options)
479     {
480     dsp_dev = xstrdup(options);
481     }
482     else
483     {
484     dsp_dev = getenv("AUDIODEV");
485    
486     if (dsp_dev == NULL)
487     {
488 ossman_ 1356 dsp_dev = DEFAULTDEVICE;
489 stargo 1255 }
490     }
491    
492     return &oss_driver;
493     }

  ViewVC Help
Powered by ViewVC 1.1.26