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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 561 by stargo, Thu Dec 11 15:07:04 2003 UTC revision 1433 by ossman_, Fri Feb 8 10:40:56 2008 UTC
# Line 1  Line 1 
1  /*  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     Sound Channel Process Functions - Sun     Sound Channel Process Functions - Sun
4     Copyright (C) Matthew Chapman 2003     Copyright (C) Matthew Chapman 2003-2007
5     Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003     Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6     Copyright (C) Michael Gernoth mike@zerfleddert.de 2003     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     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     it under the terms of the GNU General Public License as published by
# Line 21  Line 22 
22  */  */
23    
24  #include "rdesktop.h"  #include "rdesktop.h"
25    #include "rdpsnd.h"
26  #include <unistd.h>  #include <unistd.h>
27  #include <fcntl.h>  #include <fcntl.h>
28  #include <errno.h>  #include <errno.h>
# Line 31  Line 33 
33  #include <stropts.h>  #include <stropts.h>
34  #endif  #endif
35    
36  #define MAX_QUEUE       10  #define DEFAULTDEVICE   "/dev/audio"
37    #define MAX_LEN         512
38    
39  int g_dsp_fd;  static int dsp_fd = -1;
40  BOOL g_dsp_busy = False;  static int dsp_mode;
41  static BOOL g_reopened;  static int dsp_refs;
 static BOOL g_swapaudio;  
 static short g_samplewidth;  
42    
43  static struct audio_packet  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          struct stream s;          if (dsp_fd == -1)
99          uint16 tick;                  return;
100          uint8 index;  
101  } packet_queue[MAX_QUEUE];          if (dsp_out && !rdpsnd_queue_empty())
102  static unsigned int queue_hi, queue_lo;                  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  BOOL  void
110  wave_out_open(void)  sun_check_fds(fd_set * rfds, fd_set * wfds)
111  {  {
112          char *dsp_dev = getenv("AUDIODEV");          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_dev == NULL)          if (dsp_fd != -1)
124          {          {
125                  dsp_dev = "/dev/audio";                  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          if ((g_dsp_fd = open(dsp_dev, O_WRONLY | O_NONBLOCK)) == -1)          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                  perror(dsp_dev);                  AUDIO_INITINFO(&info);
147                  return False;  
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          /* Non-blocking so that user interface is responsive */          if (dsp_fd == -1)
157          fcntl(g_dsp_fd, F_SETFL, fcntl(g_dsp_fd, F_GETFL) | O_NONBLOCK);          {
158                    dsp_mode = mode;
159    
160          queue_lo = queue_hi = 0;                  dsp_fd = open(dsp_dev, dsp_mode | O_NONBLOCK);
161          g_reopened = True;                  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;          return True;
184  }  }
185    
186  void  void
187  wave_out_close(void)  sun_close(void)
188  {  {
189          /* Ack all remaining packets */          dsp_refs--;
         while (queue_lo != queue_hi)  
         {  
                 rdpsnd_send_completion(packet_queue[queue_lo].tick, packet_queue[queue_lo].index);  
                 free(packet_queue[queue_lo].s.data);  
                 queue_lo = (queue_lo + 1) % MAX_QUEUE;  
         }  
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  #if defined I_FLUSH && defined FLUSHW
213          /* Flush the audiobuffer */          /* Flush the audiobuffer */
214          ioctl(g_dsp_fd, I_FLUSH, FLUSHW);          ioctl(dsp_fd, I_FLUSH, FLUSHW);
215  #endif  #endif
216  #if defined AUDIO_FLUSH  #if defined AUDIO_FLUSH
217          ioctl(g_dsp_fd, AUDIO_FLUSH, NULL);          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  #endif
239          close(g_dsp_fd);  
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  BOOL  void
258  wave_out_format_supported(WAVEFORMATEX * pwfx)  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)          if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
274                  return False;                  return False;
# Line 106  wave_out_format_supported(WAVEFORMATEX * Line 280  wave_out_format_supported(WAVEFORMATEX *
280          return True;          return True;
281  }  }
282    
283  BOOL  RD_BOOL
284  wave_out_set_format(WAVEFORMATEX * pwfx)  sun_set_format(RD_WAVEFORMATEX * pwfx)
285  {  {
286          audio_info_t info;          audio_info_t info;
         int test = 1;  
287    
288          ioctl(g_dsp_fd, AUDIO_DRAIN, 0);          ioctl(dsp_fd, AUDIO_DRAIN, 0);
         g_swapaudio = False;  
289          AUDIO_INITINFO(&info);          AUDIO_INITINFO(&info);
290    
291            if (dsp_configured)
         if (pwfx->wBitsPerSample == 8)  
292          {          {
293                  info.play.encoding = AUDIO_ENCODING_LINEAR8;                  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)          else if (pwfx->wBitsPerSample == 16)
312          {                  format = AUDIO_ENCODING_LINEAR;
                 info.play.encoding = AUDIO_ENCODING_LINEAR;  
                 /* Do we need to swap the 16bit values? (Are we BigEndian) */  
                 g_swapaudio = !(*(uint8 *) (&test));  
         }  
313    
314          g_samplewidth = pwfx->wBitsPerSample / 8;          samplewidth = pwfx->wBitsPerSample / 8;
315    
316          if (pwfx->nChannels == 1)          if (pwfx->nChannels == 1)
317          {          {
318                  info.play.channels = 1;                  info.play.channels = 1;
319                    stereo = 0;
320          }          }
321          else if (pwfx->nChannels == 2)          else if (pwfx->nChannels == 2)
322          {          {
323                  info.play.channels = 2;                  info.play.channels = 2;
324                  g_samplewidth *= 2;                  stereo = 1;
325                    samplewidth *= 2;
326          }          }
327    
328            snd_rate = pwfx->nSamplesPerSec;
329    
330          info.play.sample_rate = pwfx->nSamplesPerSec;          info.play.sample_rate = pwfx->nSamplesPerSec;
331          info.play.precision = pwfx->wBitsPerSample;          info.play.precision = pwfx->wBitsPerSample;
332            info.play.encoding = format;
333          info.play.samples = 0;          info.play.samples = 0;
334          info.play.eof = 0;          info.play.eof = 0;
335          info.play.error = 0;          info.play.error = 0;
         g_reopened = True;  
336    
337          if (ioctl(g_dsp_fd, AUDIO_SETINFO, &info) == -1)          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");                  perror("AUDIO_SETINFO");
347                  close(g_dsp_fd);                  sun_close();
348                  return False;                  return False;
349          }          }
350    
351            dsp_configured = True;
352    
353            if (dsp_in)
354                    sun_resume();
355    
356          return True;          return True;
357  }  }
358    
359  void  void
360  wave_out_volume(uint16 left, uint16 right)  sun_volume(uint16 left, uint16 right)
361  {  {
362          audio_info_t info;          audio_info_t info;
363          uint balance;          uint balance;
364          uint volume;          uint volume;
365    
366          if (ioctl(g_dsp_fd, AUDIO_GETINFO, &info) == -1)          AUDIO_INITINFO(&info);
         {  
                 perror("AUDIO_GETINFO");  
                 return;  
         }  
367    
368          volume = (left > right) ? left : right;          volume = (left > right) ? left : right;
369    
# Line 186  wave_out_volume(uint16 left, uint16 righ Line 381  wave_out_volume(uint16 left, uint16 righ
381          info.play.gain = volume / (65536 / AUDIO_MAX_GAIN);          info.play.gain = volume / (65536 / AUDIO_MAX_GAIN);
382          info.play.balance = balance;          info.play.balance = balance;
383    
384          if (ioctl(g_dsp_fd, AUDIO_SETINFO, &info) == -1)          if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
385          {          {
386                  perror("AUDIO_SETINFO");                  perror("AUDIO_SETINFO");
387                  return;                  return;
# Line 194  wave_out_volume(uint16 left, uint16 righ Line 389  wave_out_volume(uint16 left, uint16 righ
389  }  }
390    
391  void  void
392  wave_out_write(STREAM s, uint16 tick, uint8 index)  sun_play(void)
393  {  {
394          struct audio_packet *packet = &packet_queue[queue_hi];          struct audio_packet *packet;
395          unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;          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          if (next_hi == queue_lo)          len = write(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
408            if (len == -1)
409          {          {
410                  error("No space to queue audio packet\n");                  if (errno != EWOULDBLOCK)
411                    {
412                            if (!dsp_broken)
413                                    perror("RDPSND: write()");
414                            dsp_broken = True;
415                            rdpsnd_queue_next(0);
416                    }
417                  return;                  return;
418          }          }
419    
420          queue_hi = next_hi;          written_samples += len / (samplewidth * (stereo ? 2 : 1));
421    
422            dsp_broken = False;
423    
424          packet->s = *s;          out->p += len;
425          packet->tick = tick;  
426          packet->index = index;          if (out->p == out->end)
427          packet->s.p += 4;          {
428                    audio_info_t info;
429                    uint_t delay_samples;
430                    unsigned long delay_us;
431    
432          /* we steal the data buffer from s, give it a new one */                  if (ioctl(dsp_fd, AUDIO_GETINFO, &info) != -1)
433          s->data = malloc(s->size);                          delay_samples = written_samples - info.play.samples;
434                    else
435                            delay_samples = out->size / (samplewidth * (stereo ? 2 : 1));
436    
437          if (!g_dsp_busy)                  delay_us = delay_samples * (1000000 / snd_rate);
438                  wave_out_play();                  rdpsnd_queue_next(delay_us);
439            }
440  }  }
441    
442  void  void
443  wave_out_play(void)  sun_record(void)
444  {  {
445          struct audio_packet *packet;          char buffer[32768];
446          audio_info_t info;          int len;
         ssize_t len;  
         unsigned int i;  
         uint8 swap;  
         STREAM out;  
         static BOOL swapped = False;  
         static BOOL sentcompletion = True;  
         static uint32 samplecnt = 0;  
         static uint32 numsamples;  
447    
448          while (1)          len = read(dsp_fd, buffer, sizeof(buffer));
449            if (len == -1)
450          {          {
451                  if (g_reopened)                  if (errno != EWOULDBLOCK)
452                  {                          perror("read audio");
453                          /* Device was just (re)openend */                  return;
454                          samplecnt = 0;          }
                         swapped = False;  
                         sentcompletion = True;  
                         g_reopened = False;  
                 }  
455    
456                  if (queue_lo == queue_hi)          rdpsnd_record(buffer, len);
457                  {  }
                         g_dsp_busy = 0;  
                         return;  
                 }  
458    
459                  packet = &packet_queue[queue_lo];  struct audio_driver *
460                  out = &packet->s;  sun_register(char *options)
461    {
462            static struct audio_driver sun_driver;
463    
464                  /* Swap the current packet, but only once */          memset(&sun_driver, 0, sizeof(sun_driver));
                 if (g_swapaudio && !swapped)  
                 {  
                         for (i = 0; i < out->end - out->p; i += 2)  
                         {  
                                 swap = *(out->p + i);  
                                 *(out->p + i) = *(out->p + i + 1);  
                                 *(out->p + i + 1) = swap;  
                         }  
                         swapped = True;  
                 }  
465    
466                  if (sentcompletion)          sun_driver.name = "sun";
467                  {          sun_driver.description =
468                          sentcompletion = False;                  "SUN/BSD output driver, default device: " DEFAULTDEVICE " or $AUDIODEV";
                         numsamples = (out->end - out->p) / g_samplewidth;  
                 }  
469    
470                  len = 0;          sun_driver.add_fds = sun_add_fds;
471            sun_driver.check_fds = sun_check_fds;
472    
473                  if (out->end != out->p)          sun_driver.wave_out_open = sun_open_out;
474                  {          sun_driver.wave_out_close = sun_close_out;
475                          len = write(g_dsp_fd, out->p, out->end - out->p);          sun_driver.wave_out_format_supported = sun_format_supported;
476                          if (len == -1)          sun_driver.wave_out_set_format = sun_set_format;
477                          {          sun_driver.wave_out_volume = sun_volume;
478                                  if (errno != EWOULDBLOCK)  
479                                          perror("write audio");          sun_driver.wave_in_open = sun_open_in;
480                                  g_dsp_busy = 1;          sun_driver.wave_in_close = sun_close_in;
481                                  return;          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                  out->p += len;          if (options)
489                  if (out->p == out->end)          {
490                    dsp_dev = xstrdup(options);
491            }
492            else
493            {
494                    dsp_dev = getenv("AUDIODEV");
495    
496                    if (dsp_dev == NULL)
497                  {                  {
498                          if (ioctl(g_dsp_fd, AUDIO_GETINFO, &info) == -1)                          dsp_dev = DEFAULTDEVICE;
                         {  
                                 perror("AUDIO_GETINFO");  
                                 return;  
                         }  
   
                         /* Ack the packet, if we have played at least 70% */  
                         if (info.play.samples >= samplecnt + ((numsamples * 7) / 10))  
                         {  
                                 samplecnt += numsamples;  
                                 rdpsnd_send_completion(packet->tick, packet->index);  
                                 free(out->data);  
                                 queue_lo = (queue_lo + 1) % MAX_QUEUE;  
                                 swapped = False;  
                                 sentcompletion = True;  
                         }  
                         else  
                         {  
                                 g_dsp_busy = 1;  
                                 return;  
                         }  
499                  }                  }
500          }          }
501    
502            return &sun_driver;
503  }  }

Legend:
Removed from v.561  
changed lines
  Added in v.1433

  ViewVC Help
Powered by ViewVC 1.1.26