/[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 1433 - (show annotations)
Fri Feb 8 10:40:56 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: 9073 byte(s)
Properly store the current device settings for full duplex operation.

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 format = AUDIO_ENCODING_LINEAR8;
311 else if (pwfx->wBitsPerSample == 16)
312 format = AUDIO_ENCODING_LINEAR;
313
314 samplewidth = pwfx->wBitsPerSample / 8;
315
316 if (pwfx->nChannels == 1)
317 {
318 info.play.channels = 1;
319 stereo = 0;
320 }
321 else if (pwfx->nChannels == 2)
322 {
323 info.play.channels = 2;
324 stereo = 1;
325 samplewidth *= 2;
326 }
327
328 snd_rate = pwfx->nSamplesPerSec;
329
330 info.play.sample_rate = pwfx->nSamplesPerSec;
331 info.play.precision = pwfx->wBitsPerSample;
332 info.play.encoding = format;
333 info.play.samples = 0;
334 info.play.eof = 0;
335 info.play.error = 0;
336
337 info.record.sample_rate = info.play.sample_rate;
338 info.record.channels = info.play.channels;
339 info.record.precision = info.play.precision;
340 info.record.encoding = info.play.encoding;
341 info.record.samples = 0;
342 info.record.error = 0;
343
344 if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
345 {
346 perror("AUDIO_SETINFO");
347 sun_close();
348 return False;
349 }
350
351 dsp_configured = True;
352
353 if (dsp_in)
354 sun_resume();
355
356 return True;
357 }
358
359 void
360 sun_volume(uint16 left, uint16 right)
361 {
362 audio_info_t info;
363 uint balance;
364 uint volume;
365
366 AUDIO_INITINFO(&info);
367
368 volume = (left > right) ? left : right;
369
370 if (volume / AUDIO_MID_BALANCE != 0)
371 {
372 balance =
373 AUDIO_MID_BALANCE - (left / (volume / AUDIO_MID_BALANCE)) +
374 (right / (volume / AUDIO_MID_BALANCE));
375 }
376 else
377 {
378 balance = AUDIO_MID_BALANCE;
379 }
380
381 info.play.gain = volume / (65536 / AUDIO_MAX_GAIN);
382 info.play.balance = balance;
383
384 if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
385 {
386 perror("AUDIO_SETINFO");
387 return;
388 }
389 }
390
391 void
392 sun_play(void)
393 {
394 struct audio_packet *packet;
395 ssize_t len;
396 STREAM out;
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 written_samples += len / (samplewidth * (stereo ? 2 : 1));
421
422 dsp_broken = False;
423
424 out->p += len;
425
426 if (out->p == out->end)
427 {
428 audio_info_t info;
429 uint_t delay_samples;
430 unsigned long delay_us;
431
432 if (ioctl(dsp_fd, AUDIO_GETINFO, &info) != -1)
433 delay_samples = written_samples - info.play.samples;
434 else
435 delay_samples = out->size / (samplewidth * (stereo ? 2 : 1));
436
437 delay_us = delay_samples * (1000000 / snd_rate);
438 rdpsnd_queue_next(delay_us);
439 }
440 }
441
442 void
443 sun_record(void)
444 {
445 char buffer[32768];
446 int len;
447
448 len = read(dsp_fd, buffer, sizeof(buffer));
449 if (len == -1)
450 {
451 if (errno != EWOULDBLOCK)
452 perror("read audio");
453 return;
454 }
455
456 rdpsnd_record(buffer, len);
457 }
458
459 struct audio_driver *
460 sun_register(char *options)
461 {
462 static struct audio_driver sun_driver;
463
464 memset(&sun_driver, 0, sizeof(sun_driver));
465
466 sun_driver.name = "sun";
467 sun_driver.description =
468 "SUN/BSD output driver, default device: " DEFAULTDEVICE " or $AUDIODEV";
469
470 sun_driver.add_fds = sun_add_fds;
471 sun_driver.check_fds = sun_check_fds;
472
473 sun_driver.wave_out_open = sun_open_out;
474 sun_driver.wave_out_close = sun_close_out;
475 sun_driver.wave_out_format_supported = sun_format_supported;
476 sun_driver.wave_out_set_format = sun_set_format;
477 sun_driver.wave_out_volume = sun_volume;
478
479 sun_driver.wave_in_open = sun_open_in;
480 sun_driver.wave_in_close = sun_close_in;
481 sun_driver.wave_in_format_supported = sun_format_supported;
482 sun_driver.wave_in_set_format = sun_set_format;
483 sun_driver.wave_in_volume = NULL; /* FIXME */
484
485 sun_driver.need_byteswap_on_be = 1;
486 sun_driver.need_resampling = 0;
487
488 if (options)
489 {
490 dsp_dev = xstrdup(options);
491 }
492 else
493 {
494 dsp_dev = getenv("AUDIODEV");
495
496 if (dsp_dev == NULL)
497 {
498 dsp_dev = DEFAULTDEVICE;
499 }
500 }
501
502 return &sun_driver;
503 }

  ViewVC Help
Powered by ViewVC 1.1.26