/[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

Annotation of /jpeg/rdesktop/trunk/rdpsnd_sun.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1507 - (hide annotations)
Mon Jul 20 16:45:11 2009 UTC (14 years, 10 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 astrand 963 /* -*- c-basic-offset: 8 -*-
2 matthewc 476 rdesktop: A Remote Desktop Protocol client.
3     Sound Channel Process Functions - Sun
4 jsorg71 1475 Copyright (C) Matthew Chapman 2003-2008
5 matthewc 476 Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6 jsorg71 1475 Copyright (C) Michael Gernoth mike@zerfleddert.de 2003-2008
7     Copyright 2007-2008 Pierre Ossman <ossman@cendio.se> for Cendio AB
8 matthewc 476
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 stargo 1254 #include "rdpsnd.h"
26 matthewc 476 #include <unistd.h>
27     #include <fcntl.h>
28     #include <errno.h>
29     #include <sys/ioctl.h>
30 matthewc 477 #include <sys/audioio.h>
31 astrand 1470 #include <string.h>
32 matthewc 476
33 stargo 560 #if (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
34     #include <stropts.h>
35     #endif
36    
37 stargo 1254 #define DEFAULTDEVICE "/dev/audio"
38 ossman_ 1428 #define MAX_LEN 512
39 matthewc 476
40 ossman_ 1346 static int dsp_fd = -1;
41 ossman_ 1428 static int dsp_mode;
42     static int dsp_refs;
43 ossman_ 1346
44 ossman_ 1428 static RD_BOOL dsp_configured;
45     static RD_BOOL dsp_broken;
46 astrand 1470 static RD_BOOL broken_2_channel_record = False;
47 ossman_ 1428
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 stargo 1255 static char *dsp_dev;
56 matthewc 476
57 ossman_ 1428 static uint_t written_samples;
58    
59 stargo 1347 void sun_play(void);
60 ossman_ 1428 void sun_record(void);
61 ossman_ 1346
62 ossman_ 1432 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 ossman_ 1346 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 ossman_ 1428 if (dsp_out && !rdpsnd_queue_empty())
104     FD_SET(dsp_fd, wfds);
105     if (dsp_in)
106     FD_SET(dsp_fd, rfds);
107 ossman_ 1346 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 ossman_ 1428 if (FD_ISSET(dsp_fd, rfds))
117     sun_record();
118 ossman_ 1346 }
119    
120 jsorg71 1372 RD_BOOL
121 ossman_ 1428 sun_open(int mode)
122 matthewc 476 {
123 ossman_ 1428 audio_info_t info;
124    
125     if (dsp_fd != -1)
126 matthewc 476 {
127 ossman_ 1428 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 matthewc 476 return False;
137     }
138    
139 ossman_ 1428 dsp_configured = False;
140     dsp_broken = False;
141 astrand 499
142 ossman_ 1428 written_samples = 0;
143 astrand 499
144 ossman_ 1428 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 ossman_ 1432 /*
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 ossman_ 1428 dsp_refs++;
184    
185 matthewc 476 return True;
186     }
187    
188     void
189 stargo 1255 sun_close(void)
190 matthewc 476 {
191 ossman_ 1428 dsp_refs--;
192 matthewc 477
193 ossman_ 1428 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 stargo 538 #if defined I_FLUSH && defined FLUSHW
215 matthewc 477 /* Flush the audiobuffer */
216 ossman_ 1346 ioctl(dsp_fd, I_FLUSH, FLUSHW);
217 stargo 538 #endif
218 stargo 561 #if defined AUDIO_FLUSH
219 ossman_ 1346 ioctl(dsp_fd, AUDIO_FLUSH, NULL);
220 stargo 561 #endif
221 ossman_ 1428
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 matthewc 476 }
230    
231 jsorg71 1372 RD_BOOL
232 ossman_ 1428 sun_open_in(void)
233     {
234 ossman_ 1432 #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 ossman_ 1428 if (!sun_open(O_RDONLY))
243     return False;
244    
245 astrand 1470 /* 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 ossman_ 1432 /*
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 ossman_ 1428 dsp_in = True;
262    
263     return True;
264     }
265    
266     void
267     sun_close_in(void)
268     {
269 ossman_ 1432 /*
270     * Repause the stream when the user goes away.
271     */
272     sun_pause();
273    
274 ossman_ 1428 sun_close();
275    
276     dsp_in = False;
277     }
278    
279     RD_BOOL
280 jsorg71 1364 sun_format_supported(RD_WAVEFORMATEX * pwfx)
281 matthewc 476 {
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 jsorg71 1372 RD_BOOL
293 jsorg71 1364 sun_set_format(RD_WAVEFORMATEX * pwfx)
294 matthewc 476 {
295     audio_info_t info;
296    
297 ossman_ 1346 ioctl(dsp_fd, AUDIO_DRAIN, 0);
298 matthewc 476 AUDIO_INITINFO(&info);
299    
300 ossman_ 1428 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 matthewc 476
307 ossman_ 1428 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 ossman_ 1432 sun_pause();
317    
318 matthewc 476 if (pwfx->wBitsPerSample == 8)
319 ossman_ 1433 format = AUDIO_ENCODING_LINEAR8;
320 matthewc 476 else if (pwfx->wBitsPerSample == 16)
321 ossman_ 1433 format = AUDIO_ENCODING_LINEAR;
322 matthewc 476
323 ossman_ 1428 samplewidth = pwfx->wBitsPerSample / 8;
324 stargo 491
325 astrand 1470 info.play.channels = pwfx->nChannels;
326     info.record.channels = info.play.channels;
327    
328 astrand 499 if (pwfx->nChannels == 1)
329     {
330 ossman_ 1433 stereo = 0;
331 matthewc 476 }
332 astrand 499 else if (pwfx->nChannels == 2)
333 matthewc 476 {
334 ossman_ 1433 stereo = 1;
335 ossman_ 1428 samplewidth *= 2;
336 astrand 1470
337     if (broken_2_channel_record)
338     {
339     info.record.channels = 1;
340     }
341 matthewc 476 }
342    
343 ossman_ 1428 snd_rate = pwfx->nSamplesPerSec;
344    
345 matthewc 476 info.play.sample_rate = pwfx->nSamplesPerSec;
346     info.play.precision = pwfx->wBitsPerSample;
347 ossman_ 1433 info.play.encoding = format;
348 matthewc 476 info.play.samples = 0;
349     info.play.eof = 0;
350     info.play.error = 0;
351    
352 ossman_ 1428 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 ossman_ 1346 if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
359 matthewc 476 {
360     perror("AUDIO_SETINFO");
361 ossman_ 1346 sun_close();
362 matthewc 476 return False;
363     }
364    
365 ossman_ 1428 dsp_configured = True;
366    
367 ossman_ 1432 if (dsp_in)
368     sun_resume();
369    
370 matthewc 476 return True;
371     }
372    
373     void
374 stargo 1255 sun_volume(uint16 left, uint16 right)
375 stargo 491 {
376     audio_info_t info;
377     uint balance;
378     uint volume;
379    
380 stargo 772 AUDIO_INITINFO(&info);
381 stargo 491
382     volume = (left > right) ? left : right;
383    
384 astrand 499 if (volume / AUDIO_MID_BALANCE != 0)
385 stargo 491 {
386 astrand 499 balance =
387     AUDIO_MID_BALANCE - (left / (volume / AUDIO_MID_BALANCE)) +
388     (right / (volume / AUDIO_MID_BALANCE));
389 stargo 491 }
390     else
391     {
392     balance = AUDIO_MID_BALANCE;
393     }
394    
395 astrand 499 info.play.gain = volume / (65536 / AUDIO_MAX_GAIN);
396 stargo 491 info.play.balance = balance;
397    
398 ossman_ 1346 if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
399 stargo 491 {
400     perror("AUDIO_SETINFO");
401     return;
402     }
403     }
404    
405     void
406 stargo 1255 sun_play(void)
407 matthewc 476 {
408     struct audio_packet *packet;
409     ssize_t len;
410     STREAM out;
411    
412 ossman_ 1428 /* 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 matthewc 476 {
424 ossman_ 1428 if (errno != EWOULDBLOCK)
425 matthewc 477 {
426 ossman_ 1428 if (!dsp_broken)
427     perror("RDPSND: write()");
428     dsp_broken = True;
429     rdpsnd_queue_next(0);
430 matthewc 477 }
431 ossman_ 1428 return;
432     }
433 matthewc 477
434 ossman_ 1428 written_samples += len / (samplewidth * (stereo ? 2 : 1));
435 matthewc 476
436 ossman_ 1428 dsp_broken = False;
437 matthewc 476
438 ossman_ 1428 out->p += len;
439 matthewc 476
440 ossman_ 1428 if (out->p == out->end)
441     {
442     audio_info_t info;
443     uint_t delay_samples;
444     unsigned long delay_us;
445 matthewc 476
446 ossman_ 1428 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 matthewc 476
451 ossman_ 1428 delay_us = delay_samples * (1000000 / snd_rate);
452     rdpsnd_queue_next(delay_us);
453     }
454     }
455 matthewc 477
456 ossman_ 1428 void
457     sun_record(void)
458     {
459     char buffer[32768];
460     int len;
461    
462 astrand 1470 len = read(dsp_fd, buffer, sizeof(buffer) / 2);
463 ossman_ 1428 if (len == -1)
464     {
465     if (errno != EWOULDBLOCK)
466     perror("read audio");
467     return;
468 matthewc 476 }
469 ossman_ 1428
470 astrand 1470 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 ossman_ 1428 rdpsnd_record(buffer, len);
493 matthewc 476 }
494 stargo 1255
495 stargo 1351 struct audio_driver *
496     sun_register(char *options)
497     {
498     static struct audio_driver sun_driver;
499 ossman_ 1345
500 ossman_ 1356 memset(&sun_driver, 0, sizeof(sun_driver));
501    
502     sun_driver.name = "sun";
503 stargo 1351 sun_driver.description =
504 ossman_ 1356 "SUN/BSD output driver, default device: " DEFAULTDEVICE " or $AUDIODEV";
505 ossman_ 1346
506 stargo 1351 sun_driver.add_fds = sun_add_fds;
507     sun_driver.check_fds = sun_check_fds;
508 ossman_ 1345
509 ossman_ 1428 sun_driver.wave_out_open = sun_open_out;
510     sun_driver.wave_out_close = sun_close_out;
511 stargo 1351 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 ossman_ 1345
515 ossman_ 1428 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 stargo 1351 sun_driver.need_byteswap_on_be = 1;
522     sun_driver.need_resampling = 0;
523    
524 stargo 1255 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 ossman_ 1356 dsp_dev = DEFAULTDEVICE;
535 stargo 1255 }
536     }
537    
538     return &sun_driver;
539     }

  ViewVC Help
Powered by ViewVC 1.1.26