/[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 1507 - (show annotations)
Mon Jul 20 16:45:11 2009 UTC (14 years, 9 months ago) by dpavlin
File MIME type: text/plain
File size: 9881 byte(s)
branch for integration of Daniel Jarboe <daniel.jarboe(at)gmail.com>
patches for jpeg
1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Sound Channel Process Functions - Sun
4 Copyright (C) Matthew Chapman 2003-2008
5 Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6 Copyright (C) Michael Gernoth mike@zerfleddert.de 2003-2008
7 Copyright 2007-2008 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 #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
40 static int dsp_fd = -1;
41 static int dsp_mode;
42 static int dsp_refs;
43
44 static RD_BOOL dsp_configured;
45 static RD_BOOL dsp_broken;
46 static RD_BOOL broken_2_channel_record = False;
47
48 static RD_BOOL dsp_out;
49 static RD_BOOL dsp_in;
50
51 static int stereo;
52 static int format;
53 static uint32 snd_rate;
54 static short samplewidth;
55 static char *dsp_dev;
56
57 static uint_t written_samples;
58
59 void sun_play(void);
60 void sun_record(void);
61
62 static int
63 sun_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
82 static int
83 sun_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
97 void
98 sun_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
111 void
112 sun_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
120 RD_BOOL
121 sun_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
188 void
189 sun_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
200 RD_BOOL
201 sun_open_out(void)
202 {
203 if (!sun_open(O_WRONLY))
204 return False;
205
206 dsp_out = True;
207
208 return True;
209 }
210
211 void
212 sun_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
231 RD_BOOL
232 sun_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
266 void
267 sun_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
279 RD_BOOL
280 sun_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
292 RD_BOOL
293 sun_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
373 void
374 sun_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
405 void
406 sun_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
456 void
457 sun_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
495 struct audio_driver *
496 sun_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 }

  ViewVC Help
Powered by ViewVC 1.1.26