/[rdesktop]/jpeg/rdesktop/trunk/rdpsnd_sun.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 /jpeg/rdesktop/trunk/rdpsnd_sun.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1432 - (show annotations)
Fri Feb 8 10:36:28 2008 UTC (16 years, 4 months ago) by ossman_
Original Path: sourceforge.net/trunk/rdesktop/rdpsnd_sun.c
File MIME type: text/plain
File size: 9051 byte(s)
Fondle the device a bit more carefully when recording to guarantee that we
properly sync up with the data stream. This is crucial to get reliable
behaviour on multi-byte frames.

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

  ViewVC Help
Powered by ViewVC 1.1.26