VirtualBox

source: vbox/trunk/src/VBox/RDP/client/rdpsnd_sun.c@ 9902

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

Added rdesktop 1.6.0.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 9.6 KB
 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Sound Channel Process Functions - Sun
4 Copyright (C) Matthew Chapman 2003-2007
5 Copyright (C) GuoJunBo [email protected] 2003
6 Copyright (C) Michael Gernoth [email protected] 2003-2007
7 Copyright 2007 Pierre Ossman <[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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#include "rdesktop.h"
25#include "rdpsnd.h"
26#include <unistd.h>
27#include <fcntl.h>
28#include <errno.h>
29#include <sys/ioctl.h>
30#include <sys/audioio.h>
31#include <string.h>
32
33#if (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
34#include <stropts.h>
35#endif
36
37#define DEFAULTDEVICE "/dev/audio"
38#define MAX_LEN 512
39
40static int dsp_fd = -1;
41static int dsp_mode;
42static int dsp_refs;
43
44static RD_BOOL dsp_configured;
45static RD_BOOL dsp_broken;
46static RD_BOOL broken_2_channel_record = False;
47
48static RD_BOOL dsp_out;
49static RD_BOOL dsp_in;
50
51static int stereo;
52static int format;
53static uint32 snd_rate;
54static short samplewidth;
55static char *dsp_dev;
56
57static uint_t written_samples;
58
59void sun_play(void);
60void sun_record(void);
61
62static int
63sun_pause(void)
64{
65 audio_info_t info;
66
67 AUDIO_INITINFO(&info);
68
69 info.record.pause = 1;
70
71 if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
72 return -1;
73
74#if defined I_FLUSH && defined FLUSHR
75 if (ioctl(dsp_fd, I_FLUSH, FLUSHR) == -1)
76 return -1;
77#endif
78
79 return 0;
80}
81
82static int
83sun_resume(void)
84{
85 audio_info_t info;
86
87 AUDIO_INITINFO(&info);
88
89 info.record.pause = 0;
90
91 if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
92 return -1;
93
94 return 0;
95}
96
97void
98sun_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
99{
100 if (dsp_fd == -1)
101 return;
102
103 if (dsp_out && !rdpsnd_queue_empty())
104 FD_SET(dsp_fd, wfds);
105 if (dsp_in)
106 FD_SET(dsp_fd, rfds);
107 if (dsp_fd > *n)
108 *n = dsp_fd;
109}
110
111void
112sun_check_fds(fd_set * rfds, fd_set * wfds)
113{
114 if (FD_ISSET(dsp_fd, wfds))
115 sun_play();
116 if (FD_ISSET(dsp_fd, rfds))
117 sun_record();
118}
119
120RD_BOOL
121sun_open(int mode)
122{
123 audio_info_t info;
124
125 if (dsp_fd != -1)
126 {
127 dsp_refs++;
128
129 if (dsp_mode == O_RDWR)
130 return True;
131
132 if (dsp_mode == mode)
133 return True;
134
135 dsp_refs--;
136 return False;
137 }
138
139 dsp_configured = False;
140 dsp_broken = False;
141
142 written_samples = 0;
143
144 dsp_mode = O_RDWR;
145 dsp_fd = open(dsp_dev, O_RDWR | O_NONBLOCK);
146 if (dsp_fd != -1)
147 {
148 AUDIO_INITINFO(&info);
149
150 if ((ioctl(dsp_fd, AUDIO_GETINFO, &info) == -1)
151 || !(info.hw_features & AUDIO_HWFEATURE_DUPLEX))
152 {
153 close(dsp_fd);
154 dsp_fd = -1;
155 }
156 }
157
158 if (dsp_fd == -1)
159 {
160 dsp_mode = mode;
161
162 dsp_fd = open(dsp_dev, dsp_mode | O_NONBLOCK);
163 if (dsp_fd == -1)
164 {
165 perror(dsp_dev);
166 return False;
167 }
168 }
169
170 /*
171 * Pause recording until we actually start using it.
172 */
173 if (dsp_mode != O_WRONLY)
174 {
175 if (sun_pause() == -1)
176 {
177 close(dsp_fd);
178 dsp_fd = -1;
179 return False;
180 }
181 }
182
183 dsp_refs++;
184
185 return True;
186}
187
188void
189sun_close(void)
190{
191 dsp_refs--;
192
193 if (dsp_refs != 0)
194 return;
195
196 close(dsp_fd);
197 dsp_fd = -1;
198}
199
200RD_BOOL
201sun_open_out(void)
202{
203 if (!sun_open(O_WRONLY))
204 return False;
205
206 dsp_out = True;
207
208 return True;
209}
210
211void
212sun_close_out(void)
213{
214#if defined I_FLUSH && defined FLUSHW
215 /* Flush the audiobuffer */
216 ioctl(dsp_fd, I_FLUSH, FLUSHW);
217#endif
218#if defined AUDIO_FLUSH
219 ioctl(dsp_fd, AUDIO_FLUSH, NULL);
220#endif
221
222 sun_close();
223
224 /* Ack all remaining packets */
225 while (!rdpsnd_queue_empty())
226 rdpsnd_queue_next(0);
227
228 dsp_out = False;
229}
230
231RD_BOOL
232sun_open_in(void)
233{
234#if ! (defined I_FLUSH && defined FLUSHR)
235 /*
236 * It is not possible to reliably use the recording without
237 * flush operations.
238 */
239 return False;
240#endif
241
242 if (!sun_open(O_RDONLY))
243 return False;
244
245 /* 2 channel recording is known to be broken on Solaris x86
246 Sun Ray systems */
247#ifdef L_ENDIAN
248 if (strstr(dsp_dev, "/utaudio/"))
249 broken_2_channel_record = True;
250#endif
251
252 /*
253 * Unpause the stream now that we have someone using it.
254 */
255 if (sun_resume() == -1)
256 {
257 sun_close();
258 return False;
259 }
260
261 dsp_in = True;
262
263 return True;
264}
265
266void
267sun_close_in(void)
268{
269 /*
270 * Repause the stream when the user goes away.
271 */
272 sun_pause();
273
274 sun_close();
275
276 dsp_in = False;
277}
278
279RD_BOOL
280sun_format_supported(RD_WAVEFORMATEX * pwfx)
281{
282 if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
283 return False;
284 if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
285 return False;
286 if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
287 return False;
288
289 return True;
290}
291
292RD_BOOL
293sun_set_format(RD_WAVEFORMATEX * pwfx)
294{
295 audio_info_t info;
296
297 ioctl(dsp_fd, AUDIO_DRAIN, 0);
298 AUDIO_INITINFO(&info);
299
300 if (dsp_configured)
301 {
302 if ((pwfx->wBitsPerSample == 8) && (format != AUDIO_ENCODING_LINEAR8))
303 return False;
304 if ((pwfx->wBitsPerSample == 16) && (format != AUDIO_ENCODING_LINEAR))
305 return False;
306
307 if ((pwfx->nChannels == 2) != !!stereo)
308 return False;
309
310 if (pwfx->nSamplesPerSec != snd_rate)
311 return False;
312
313 return True;
314 }
315
316 sun_pause();
317
318 if (pwfx->wBitsPerSample == 8)
319 format = AUDIO_ENCODING_LINEAR8;
320 else if (pwfx->wBitsPerSample == 16)
321 format = AUDIO_ENCODING_LINEAR;
322
323 samplewidth = pwfx->wBitsPerSample / 8;
324
325 info.play.channels = pwfx->nChannels;
326 info.record.channels = info.play.channels;
327
328 if (pwfx->nChannels == 1)
329 {
330 stereo = 0;
331 }
332 else if (pwfx->nChannels == 2)
333 {
334 stereo = 1;
335 samplewidth *= 2;
336
337 if (broken_2_channel_record)
338 {
339 info.record.channels = 1;
340 }
341 }
342
343 snd_rate = pwfx->nSamplesPerSec;
344
345 info.play.sample_rate = pwfx->nSamplesPerSec;
346 info.play.precision = pwfx->wBitsPerSample;
347 info.play.encoding = format;
348 info.play.samples = 0;
349 info.play.eof = 0;
350 info.play.error = 0;
351
352 info.record.sample_rate = info.play.sample_rate;
353 info.record.precision = info.play.precision;
354 info.record.encoding = info.play.encoding;
355 info.record.samples = 0;
356 info.record.error = 0;
357
358 if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
359 {
360 perror("AUDIO_SETINFO");
361 sun_close();
362 return False;
363 }
364
365 dsp_configured = True;
366
367 if (dsp_in)
368 sun_resume();
369
370 return True;
371}
372
373void
374sun_volume(uint16 left, uint16 right)
375{
376 audio_info_t info;
377 uint balance;
378 uint volume;
379
380 AUDIO_INITINFO(&info);
381
382 volume = (left > right) ? left : right;
383
384 if (volume / AUDIO_MID_BALANCE != 0)
385 {
386 balance =
387 AUDIO_MID_BALANCE - (left / (volume / AUDIO_MID_BALANCE)) +
388 (right / (volume / AUDIO_MID_BALANCE));
389 }
390 else
391 {
392 balance = AUDIO_MID_BALANCE;
393 }
394
395 info.play.gain = volume / (65536 / AUDIO_MAX_GAIN);
396 info.play.balance = balance;
397
398 if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
399 {
400 perror("AUDIO_SETINFO");
401 return;
402 }
403}
404
405void
406sun_play(void)
407{
408 struct audio_packet *packet;
409 ssize_t len;
410 STREAM out;
411
412 /* We shouldn't be called if the queue is empty, but still */
413 if (rdpsnd_queue_empty())
414 return;
415
416 packet = rdpsnd_queue_current_packet();
417 out = &packet->s;
418
419 len = out->end - out->p;
420
421 len = write(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
422 if (len == -1)
423 {
424 if (errno != EWOULDBLOCK)
425 {
426 if (!dsp_broken)
427 perror("RDPSND: write()");
428 dsp_broken = True;
429 rdpsnd_queue_next(0);
430 }
431 return;
432 }
433
434 written_samples += len / (samplewidth * (stereo ? 2 : 1));
435
436 dsp_broken = False;
437
438 out->p += len;
439
440 if (out->p == out->end)
441 {
442 audio_info_t info;
443 uint_t delay_samples;
444 unsigned long delay_us;
445
446 if (ioctl(dsp_fd, AUDIO_GETINFO, &info) != -1)
447 delay_samples = written_samples - info.play.samples;
448 else
449 delay_samples = out->size / (samplewidth * (stereo ? 2 : 1));
450
451 delay_us = delay_samples * (1000000 / snd_rate);
452 rdpsnd_queue_next(delay_us);
453 }
454}
455
456void
457sun_record(void)
458{
459 char buffer[32768];
460 int len;
461
462 len = read(dsp_fd, buffer, sizeof(buffer) / 2);
463 if (len == -1)
464 {
465 if (errno != EWOULDBLOCK)
466 perror("read audio");
467 return;
468 }
469
470 if (broken_2_channel_record)
471 {
472 unsigned int i;
473 int rec_samplewidth = samplewidth / 2;
474 /* Loop over each byte read backwards and put in place */
475 i = len - 1;
476 do
477 {
478 int samples_before = i / rec_samplewidth * 2;
479 int sample_byte = i % rec_samplewidth;
480 int ch1_offset = samples_before * rec_samplewidth + sample_byte;
481 // Channel 1
482 buffer[ch1_offset] = buffer[i];
483 // Channel 2
484 buffer[ch1_offset + rec_samplewidth] = buffer[i];
485
486 i--;
487 }
488 while (i);
489 len *= 2;
490 }
491
492 rdpsnd_record(buffer, len);
493}
494
495struct audio_driver *
496sun_register(char *options)
497{
498 static struct audio_driver sun_driver;
499
500 memset(&sun_driver, 0, sizeof(sun_driver));
501
502 sun_driver.name = "sun";
503 sun_driver.description =
504 "SUN/BSD output driver, default device: " DEFAULTDEVICE " or $AUDIODEV";
505
506 sun_driver.add_fds = sun_add_fds;
507 sun_driver.check_fds = sun_check_fds;
508
509 sun_driver.wave_out_open = sun_open_out;
510 sun_driver.wave_out_close = sun_close_out;
511 sun_driver.wave_out_format_supported = sun_format_supported;
512 sun_driver.wave_out_set_format = sun_set_format;
513 sun_driver.wave_out_volume = sun_volume;
514
515 sun_driver.wave_in_open = sun_open_in;
516 sun_driver.wave_in_close = sun_close_in;
517 sun_driver.wave_in_format_supported = sun_format_supported;
518 sun_driver.wave_in_set_format = sun_set_format;
519 sun_driver.wave_in_volume = NULL; /* FIXME */
520
521 sun_driver.need_byteswap_on_be = 1;
522 sun_driver.need_resampling = 0;
523
524 if (options)
525 {
526 dsp_dev = xstrdup(options);
527 }
528 else
529 {
530 dsp_dev = getenv("AUDIODEV");
531
532 if (dsp_dev == NULL)
533 {
534 dsp_dev = DEFAULTDEVICE;
535 }
536 }
537
538 return &sun_driver;
539}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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