VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.3/rdpsnd_oss.c@ 55121

最後變更 在這個檔案從55121是 55121,由 vboxsync 提交於 10 年 前

rdesktop 1.8.3 unmodified

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 10.1 KB
 
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 <matthewc.unsw.edu.au> 2003-2008
5 Copyright (C) GuoJunBo <[email protected]> 2003
6 Copyright 2006-2008 Pierre Ossman <[email protected]> for Cendio AB
7 Copyright 2005-2011 Peter Astrand <[email protected]> for Cendio AB
8
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23/*
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#include <assert.h>
32
33#include "rdesktop.h"
34#include "rdpsnd.h"
35#include "rdpsnd_dsp.h"
36#include <unistd.h>
37#include <fcntl.h>
38#include <errno.h>
39#include <unistd.h>
40#include <sys/time.h>
41#include <sys/ioctl.h>
42#include <sys/soundcard.h>
43#include <sys/types.h>
44#include <sys/stat.h>
45
46#define DEFAULTDEVICE "/dev/dsp"
47#define MAX_LEN 512
48
49static int dsp_fd = -1;
50static int dsp_mode;
51
52static RD_BOOL dsp_configured;
53static RD_BOOL dsp_broken;
54
55static int stereo;
56static int format;
57static uint32 snd_rate;
58static short samplewidth;
59static char *dsp_dev;
60static RD_BOOL in_esddsp;
61
62/* This is a just a forward declaration */
63static struct audio_driver oss_driver;
64
65static void oss_play(void);
66static void oss_record(void);
67static RD_BOOL oss_set_format(RD_WAVEFORMATEX * pwfx);
68
69static void
70oss_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
71{
72 if (dsp_fd == -1)
73 return;
74
75 if ((dsp_mode == O_WRONLY || dsp_mode == O_RDWR) && !rdpsnd_queue_empty())
76 FD_SET(dsp_fd, wfds);
77 if (dsp_mode == O_RDONLY || dsp_mode == O_RDWR)
78 FD_SET(dsp_fd, rfds);
79 if (dsp_fd > *n)
80 *n = dsp_fd;
81}
82
83static void
84oss_check_fds(fd_set * rfds, fd_set * wfds)
85{
86 if (FD_ISSET(dsp_fd, wfds))
87 oss_play();
88 if (FD_ISSET(dsp_fd, rfds))
89 oss_record();
90}
91
92static RD_BOOL
93detect_esddsp(void)
94{
95 struct stat s;
96 char *preload;
97
98 if (fstat(dsp_fd, &s) == -1)
99 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
115static void
116oss_restore_format()
117{
118 RD_WAVEFORMATEX wfx;
119 memset(&wfx, 0, sizeof(RD_WAVEFORMATEX));
120 switch (format)
121 {
122 case AFMT_U8:
123 wfx.wBitsPerSample = 8;
124 break;
125 case AFMT_S16_LE:
126 wfx.wBitsPerSample = 16;
127 break;
128 default:
129 wfx.wBitsPerSample = 0;
130 }
131 wfx.nChannels = stereo ? 2 : 1;
132 wfx.nSamplesPerSec = snd_rate;
133 oss_set_format(&wfx);
134}
135
136
137static RD_BOOL
138oss_open(int wanted)
139{
140 if (dsp_fd != -1)
141 {
142 if (wanted == dsp_mode)
143 {
144 /* should probably not happen */
145 return True;
146 }
147 else
148 {
149 /* device open but not our mode. Before
150 reopening O_RDWR, verify that the device is
151 duplex capable */
152 int caps;
153 ioctl(dsp_fd, SNDCTL_DSP_SETDUPLEX, 0);
154 if ((ioctl(dsp_fd, SNDCTL_DSP_GETCAPS, &caps) < 0)
155 || !(caps & DSP_CAP_DUPLEX))
156 {
157 warning("This device is not capable of full duplex operation.\n");
158 return False;
159 }
160 close(dsp_fd);
161 dsp_mode = O_RDWR;
162 }
163 }
164 else
165 {
166 dsp_mode = wanted;
167 }
168
169 dsp_configured = False;
170 dsp_broken = False;
171
172 dsp_fd = open(dsp_dev, dsp_mode | O_NONBLOCK);
173
174 if (dsp_fd == -1)
175 {
176 perror(dsp_dev);
177 return False;
178 }
179
180 in_esddsp = detect_esddsp();
181
182 return True;
183}
184
185static void
186oss_close(void)
187{
188 close(dsp_fd);
189 dsp_fd = -1;
190}
191
192static RD_BOOL
193oss_open_out(void)
194{
195 if (!oss_open(O_WRONLY))
196 return False;
197
198 return True;
199}
200
201static void
202oss_close_out(void)
203{
204 oss_close();
205 if (dsp_mode == O_RDWR)
206 {
207 if (oss_open(O_RDONLY))
208 oss_restore_format();
209 }
210
211 /* Ack all remaining packets */
212 while (!rdpsnd_queue_empty())
213 rdpsnd_queue_next(0);
214}
215
216static RD_BOOL
217oss_open_in(void)
218{
219 if (!oss_open(O_RDONLY))
220 return False;
221
222 return True;
223}
224
225static void
226oss_close_in(void)
227{
228 oss_close();
229 if (dsp_mode == O_RDWR)
230 {
231 if (oss_open(O_WRONLY))
232 oss_restore_format();
233 }
234}
235
236static RD_BOOL
237oss_format_supported(RD_WAVEFORMATEX * pwfx)
238{
239 if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
240 return False;
241 if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
242 return False;
243 if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
244 return False;
245
246 return True;
247}
248
249static RD_BOOL
250oss_set_format(RD_WAVEFORMATEX * pwfx)
251{
252 int fragments;
253 static RD_BOOL driver_broken = False;
254
255 assert(dsp_fd != -1);
256
257 if (dsp_configured)
258 {
259 if ((pwfx->wBitsPerSample == 8) && (format != AFMT_U8))
260 return False;
261 if ((pwfx->wBitsPerSample == 16) && (format != AFMT_S16_LE))
262 return False;
263
264 if ((pwfx->nChannels == 2) != ! !stereo)
265 return False;
266
267 if (pwfx->nSamplesPerSec != snd_rate)
268 return False;
269
270 return True;
271 }
272
273 ioctl(dsp_fd, SNDCTL_DSP_RESET, NULL);
274 ioctl(dsp_fd, SNDCTL_DSP_SYNC, NULL);
275
276 if (pwfx->wBitsPerSample == 8)
277 format = AFMT_U8;
278 else if (pwfx->wBitsPerSample == 16)
279 format = AFMT_S16_LE;
280
281 samplewidth = pwfx->wBitsPerSample / 8;
282
283 if (ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
284 {
285 perror("SNDCTL_DSP_SETFMT");
286 oss_close();
287 return False;
288 }
289
290 if (pwfx->nChannels == 2)
291 {
292 stereo = 1;
293 samplewidth *= 2;
294 }
295 else
296 {
297 stereo = 0;
298 }
299
300 if (ioctl(dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
301 {
302 perror("SNDCTL_DSP_CHANNELS");
303 oss_close();
304 return False;
305 }
306
307 oss_driver.need_resampling = 0;
308 snd_rate = pwfx->nSamplesPerSec;
309 if (ioctl(dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
310 {
311 uint32 rates[] = { 44100, 48000, 0 };
312 uint32 *prates = rates;
313
314 while (*prates != 0)
315 {
316 if ((pwfx->nSamplesPerSec != *prates)
317 && (ioctl(dsp_fd, SNDCTL_DSP_SPEED, prates) != -1))
318 {
319 oss_driver.need_resampling = 1;
320 snd_rate = *prates;
321 if (rdpsnd_dsp_resample_set
322 (snd_rate, pwfx->wBitsPerSample, pwfx->nChannels) == False)
323 {
324 error("rdpsnd_dsp_resample_set failed");
325 oss_close();
326 return False;
327 }
328
329 break;
330 }
331 prates++;
332 }
333
334 if (*prates == 0)
335 {
336 perror("SNDCTL_DSP_SPEED");
337 oss_close();
338 return False;
339 }
340 }
341
342 /* try to get 12 fragments of 2^12 bytes size */
343 fragments = (12 << 16) + 12;
344 ioctl(dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
345
346 if (!driver_broken)
347 {
348 audio_buf_info info;
349
350 memset(&info, 0, sizeof(info));
351 if (ioctl(dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
352 {
353 perror("SNDCTL_DSP_GETOSPACE");
354 oss_close();
355 return False;
356 }
357
358 if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
359 {
360 fprintf(stderr,
361 "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
362 info.fragments, info.fragstotal, info.fragsize);
363 driver_broken = True;
364 }
365 }
366
367 dsp_configured = True;
368
369 return True;
370}
371
372static void
373oss_volume(uint16 left, uint16 right)
374{
375 uint32 volume;
376
377 volume = left / (65536 / 100);
378 volume |= right / (65536 / 100) << 8;
379
380 if (ioctl(dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
381 {
382 warning("hardware volume control unavailable, falling back to software volume control!\n");
383 oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
384 rdpsnd_dsp_softvol_set(left, right);
385 return;
386 }
387}
388
389static void
390oss_play(void)
391{
392 struct audio_packet *packet;
393 ssize_t len;
394 STREAM out;
395
396 assert(dsp_fd != -1);
397
398 /* We shouldn't be called if the queue is empty, but still */
399 if (rdpsnd_queue_empty())
400 return;
401
402 packet = rdpsnd_queue_current_packet();
403 out = &packet->s;
404
405 len = out->end - out->p;
406
407 len = write(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
408 if (len == -1)
409 {
410 if (errno != EWOULDBLOCK)
411 {
412 if (!dsp_broken)
413 perror("RDPSND: write()");
414 dsp_broken = True;
415 rdpsnd_queue_next(0);
416 }
417 return;
418 }
419
420 dsp_broken = False;
421
422 out->p += len;
423
424 if (out->p == out->end)
425 {
426 int delay_bytes;
427 unsigned long delay_us;
428 audio_buf_info info;
429
430 if (in_esddsp)
431 {
432 /* EsounD has no way of querying buffer status, so we have to
433 * go with a fixed size. */
434 delay_bytes = out->size;
435 }
436 else
437 {
438#ifdef SNDCTL_DSP_GETODELAY
439 delay_bytes = 0;
440 if (ioctl(dsp_fd, SNDCTL_DSP_GETODELAY, &delay_bytes) == -1)
441 delay_bytes = -1;
442#else
443 delay_bytes = -1;
444#endif
445
446 if (delay_bytes == -1)
447 {
448 if (ioctl(dsp_fd, SNDCTL_DSP_GETOSPACE, &info) != -1)
449 delay_bytes = info.fragstotal * info.fragsize - info.bytes;
450 else
451 delay_bytes = out->size;
452 }
453 }
454
455 delay_us = delay_bytes * (1000000 / (samplewidth * snd_rate));
456 rdpsnd_queue_next(delay_us);
457 }
458}
459
460static void
461oss_record(void)
462{
463 char buffer[32768];
464 int len;
465
466 assert(dsp_fd != -1);
467
468 len = read(dsp_fd, buffer, sizeof(buffer));
469 if (len == -1)
470 {
471 if (errno != EWOULDBLOCK)
472 {
473 if (!dsp_broken)
474 perror("RDPSND: read()");
475 dsp_broken = True;
476 rdpsnd_queue_next(0);
477 }
478 return;
479 }
480
481 dsp_broken = False;
482
483 rdpsnd_record(buffer, len);
484}
485
486struct audio_driver *
487oss_register(char *options)
488{
489 memset(&oss_driver, 0, sizeof(oss_driver));
490
491 oss_driver.name = "oss";
492 oss_driver.description =
493 "OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV";
494
495 oss_driver.add_fds = oss_add_fds;
496 oss_driver.check_fds = oss_check_fds;
497
498 oss_driver.wave_out_open = oss_open_out;
499 oss_driver.wave_out_close = oss_close_out;
500 oss_driver.wave_out_format_supported = oss_format_supported;
501 oss_driver.wave_out_set_format = oss_set_format;
502 oss_driver.wave_out_volume = oss_volume;
503
504 oss_driver.wave_in_open = oss_open_in;
505 oss_driver.wave_in_close = oss_close_in;
506 oss_driver.wave_in_format_supported = oss_format_supported;
507 oss_driver.wave_in_set_format = oss_set_format;
508 oss_driver.wave_in_volume = NULL; /* FIXME */
509
510 oss_driver.need_byteswap_on_be = 0;
511 oss_driver.need_resampling = 0;
512
513 if (options)
514 {
515 dsp_dev = xstrdup(options);
516 }
517 else
518 {
519 dsp_dev = getenv("AUDIODEV");
520
521 if (dsp_dev == NULL)
522 {
523 dsp_dev = DEFAULTDEVICE;
524 }
525 }
526
527 return &oss_driver;
528}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette