/[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 772 by stargo, Sat Sep 11 19:17:48 2004 UTC revision 1470 by astrand, Thu Apr 24 15:11:17 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>
29  #include <sys/ioctl.h>  #include <sys/ioctl.h>
30  #include <sys/audioio.h>  #include <sys/audioio.h>
31    #include <string.h>
32    
33  #if (defined(sun) && (defined(__svr4__) || defined(__SVR4)))  #if (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
34  #include <stropts.h>  #include <stropts.h>
35  #endif  #endif
36    
37  #define MAX_QUEUE       10  #define DEFAULTDEVICE   "/dev/audio"
38    #define MAX_LEN         512
39    
40  int g_dsp_fd;  static int dsp_fd = -1;
41  BOOL g_dsp_busy = False;  static int dsp_mode;
42  static BOOL g_reopened;  static int dsp_refs;
 static BOOL g_swapaudio;  
 static short g_samplewidth;  
43    
44  static struct audio_packet  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          struct stream s;          if (dsp_fd == -1)
101          uint16 tick;                  return;
         uint8 index;  
 } packet_queue[MAX_QUEUE];  
 static unsigned int queue_hi, queue_lo;  
102    
103  BOOL          if (dsp_out && !rdpsnd_queue_empty())
104  wave_out_open(void)                  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          char *dsp_dev = getenv("AUDIODEV");          if (FD_ISSET(dsp_fd, wfds))
115                    sun_play();
116            if (FD_ISSET(dsp_fd, rfds))
117                    sun_record();
118    }
119    
120          if (dsp_dev == NULL)  RD_BOOL
121    sun_open(int mode)
122    {
123            audio_info_t info;
124    
125            if (dsp_fd != -1)
126          {          {
127                  dsp_dev = "/dev/audio";                  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          if ((g_dsp_fd = open(dsp_dev, O_WRONLY | O_NONBLOCK)) == -1)          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                  perror(dsp_dev);                  AUDIO_INITINFO(&info);
149                  return False;  
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          /* Non-blocking so that user interface is responsive */          if (dsp_fd == -1)
159          fcntl(g_dsp_fd, F_SETFL, fcntl(g_dsp_fd, F_GETFL) | O_NONBLOCK);          {
160                    dsp_mode = mode;
161    
162          queue_lo = queue_hi = 0;                  dsp_fd = open(dsp_dev, dsp_mode | O_NONBLOCK);
163          g_reopened = True;                  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;          return True;
186  }  }
187    
188  void  void
189  wave_out_close(void)  sun_close(void)
190  {  {
191          /* Ack all remaining packets */          dsp_refs--;
192          while (queue_lo != queue_hi)  
193          {          if (dsp_refs != 0)
194                  rdpsnd_send_completion(packet_queue[queue_lo].tick, packet_queue[queue_lo].index);                  return;
195                  free(packet_queue[queue_lo].s.data);  
196                  queue_lo = (queue_lo + 1) % MAX_QUEUE;          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  #if defined I_FLUSH && defined FLUSHW
215          /* Flush the audiobuffer */          /* Flush the audiobuffer */
216          ioctl(g_dsp_fd, I_FLUSH, FLUSHW);          ioctl(dsp_fd, I_FLUSH, FLUSHW);
217  #endif  #endif
218  #if defined AUDIO_FLUSH  #if defined AUDIO_FLUSH
219          ioctl(g_dsp_fd, AUDIO_FLUSH, NULL);          ioctl(dsp_fd, AUDIO_FLUSH, NULL);
220  #endif  #endif
221          close(g_dsp_fd);  
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  BOOL  RD_BOOL
280  wave_out_format_supported(WAVEFORMATEX * pwfx)  sun_format_supported(RD_WAVEFORMATEX * pwfx)
281  {  {
282          if (pwfx->wFormatTag != WAVE_FORMAT_PCM)          if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
283                  return False;                  return False;
# Line 106  wave_out_format_supported(WAVEFORMATEX * Line 289  wave_out_format_supported(WAVEFORMATEX *
289          return True;          return True;
290  }  }
291    
292  BOOL  RD_BOOL
293  wave_out_set_format(WAVEFORMATEX * pwfx)  sun_set_format(RD_WAVEFORMATEX * pwfx)
294  {  {
295          audio_info_t info;          audio_info_t info;
296    
297          ioctl(g_dsp_fd, AUDIO_DRAIN, 0);          ioctl(dsp_fd, AUDIO_DRAIN, 0);
         g_swapaudio = False;  
298          AUDIO_INITINFO(&info);          AUDIO_INITINFO(&info);
299    
300            if (dsp_configured)
         if (pwfx->wBitsPerSample == 8)  
301          {          {
302                  info.play.encoding = AUDIO_ENCODING_LINEAR8;                  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)          else if (pwfx->wBitsPerSample == 16)
321          {                  format = AUDIO_ENCODING_LINEAR;
322                  info.play.encoding = AUDIO_ENCODING_LINEAR;  
323                  /* Do we need to swap the 16bit values? (Are we BigEndian) */          samplewidth = pwfx->wBitsPerSample / 8;
 #ifdef B_ENDIAN  
                 g_swapaudio = 1;  
 #else  
                 g_swapaudio = 0;  
 #endif  
         }  
324    
325          g_samplewidth = pwfx->wBitsPerSample / 8;          info.play.channels = pwfx->nChannels;
326            info.record.channels = info.play.channels;
327    
328          if (pwfx->nChannels == 1)          if (pwfx->nChannels == 1)
329          {          {
330                  info.play.channels = 1;                  stereo = 0;
331          }          }
332          else if (pwfx->nChannels == 2)          else if (pwfx->nChannels == 2)
333          {          {
334                  info.play.channels = 2;                  stereo = 1;
335                  g_samplewidth *= 2;                  samplewidth *= 2;
336    
337                    if (broken_2_channel_record)
338                    {
339                            info.record.channels = 1;
340                            if (rdpsnd_dsp_resample_set(pwfx->nSamplesPerSec, pwfx->wBitsPerSample, 2)
341                                == False)
342                            {
343                                    return False;
344                            }
345                    }
346          }          }
347    
348            snd_rate = pwfx->nSamplesPerSec;
349    
350          info.play.sample_rate = pwfx->nSamplesPerSec;          info.play.sample_rate = pwfx->nSamplesPerSec;
351          info.play.precision = pwfx->wBitsPerSample;          info.play.precision = pwfx->wBitsPerSample;
352            info.play.encoding = format;
353          info.play.samples = 0;          info.play.samples = 0;
354          info.play.eof = 0;          info.play.eof = 0;
355          info.play.error = 0;          info.play.error = 0;
         g_reopened = True;  
356    
357          if (ioctl(g_dsp_fd, AUDIO_SETINFO, &info) == -1)          info.record.sample_rate = info.play.sample_rate;
358            info.record.precision = info.play.precision;
359            info.record.encoding = info.play.encoding;
360            info.record.samples = 0;
361            info.record.error = 0;
362    
363            if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
364          {          {
365                  perror("AUDIO_SETINFO");                  perror("AUDIO_SETINFO");
366                  close(g_dsp_fd);                  sun_close();
367                  return False;                  return False;
368          }          }
369    
370            dsp_configured = True;
371    
372            if (dsp_in)
373                    sun_resume();
374    
375          return True;          return True;
376  }  }
377    
378  void  void
379  wave_out_volume(uint16 left, uint16 right)  sun_volume(uint16 left, uint16 right)
380  {  {
381          audio_info_t info;          audio_info_t info;
382          uint balance;          uint balance;
# Line 185  wave_out_volume(uint16 left, uint16 righ Line 400  wave_out_volume(uint16 left, uint16 righ
400          info.play.gain = volume / (65536 / AUDIO_MAX_GAIN);          info.play.gain = volume / (65536 / AUDIO_MAX_GAIN);
401          info.play.balance = balance;          info.play.balance = balance;
402    
403          if (ioctl(g_dsp_fd, AUDIO_SETINFO, &info) == -1)          if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
404          {          {
405                  perror("AUDIO_SETINFO");                  perror("AUDIO_SETINFO");
406                  return;                  return;
# Line 193  wave_out_volume(uint16 left, uint16 righ Line 408  wave_out_volume(uint16 left, uint16 righ
408  }  }
409    
410  void  void
411  wave_out_write(STREAM s, uint16 tick, uint8 index)  sun_play(void)
412  {  {
413          struct audio_packet *packet = &packet_queue[queue_hi];          struct audio_packet *packet;
414          unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;          ssize_t len;
415            STREAM out;
416    
417            /* We shouldn't be called if the queue is empty, but still */
418            if (rdpsnd_queue_empty())
419                    return;
420    
421          if (next_hi == queue_lo)          packet = rdpsnd_queue_current_packet();
422            out = &packet->s;
423    
424            len = out->end - out->p;
425    
426            len = write(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
427            if (len == -1)
428          {          {
429                  error("No space to queue audio packet\n");                  if (errno != EWOULDBLOCK)
430                    {
431                            if (!dsp_broken)
432                                    perror("RDPSND: write()");
433                            dsp_broken = True;
434                            rdpsnd_queue_next(0);
435                    }
436                  return;                  return;
437          }          }
438    
439          queue_hi = next_hi;          written_samples += len / (samplewidth * (stereo ? 2 : 1));
440    
441            dsp_broken = False;
442    
443          packet->s = *s;          out->p += len;
         packet->tick = tick;  
         packet->index = index;  
         packet->s.p += 4;  
444    
445          /* we steal the data buffer from s, give it a new one */          if (out->p == out->end)
446          s->data = malloc(s->size);          {
447                    audio_info_t info;
448                    uint_t delay_samples;
449                    unsigned long delay_us;
450    
451                    if (ioctl(dsp_fd, AUDIO_GETINFO, &info) != -1)
452                            delay_samples = written_samples - info.play.samples;
453                    else
454                            delay_samples = out->size / (samplewidth * (stereo ? 2 : 1));
455    
456          if (!g_dsp_busy)                  delay_us = delay_samples * (1000000 / snd_rate);
457                  wave_out_play();                  rdpsnd_queue_next(delay_us);
458            }
459  }  }
460    
461  void  void
462  wave_out_play(void)  sun_record(void)
463  {  {
464          struct audio_packet *packet;          char buffer[32768];
465          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;  
466    
467          while (1)          len = read(dsp_fd, buffer, sizeof(buffer) / 2);
468            if (len == -1)
469          {          {
470                  if (g_reopened)                  if (errno != EWOULDBLOCK)
471                  {                          perror("read audio");
472                          /* Device was just (re)openend */                  return;
473                          samplecnt = 0;          }
                         swapped = False;  
                         sentcompletion = True;  
                         g_reopened = False;  
                 }  
474    
475                  if (queue_lo == queue_hi)          if (broken_2_channel_record)
476            {
477                    unsigned int i;
478                    int rec_samplewidth = samplewidth / 2;
479                    /* Loop over each byte read backwards and put in place */
480                    i = len - 1;
481                    do
482                  {                  {
483                          g_dsp_busy = 0;                          int samples_before = i / rec_samplewidth * 2;
484                          return;                          int sample_byte = i % rec_samplewidth;
485                            int ch1_offset = samples_before * rec_samplewidth + sample_byte;
486                            // Channel 1
487                            buffer[ch1_offset] = buffer[i];
488                            // Channel 2
489                            buffer[ch1_offset + rec_samplewidth] = buffer[i];
490    
491                            i--;
492                  }                  }
493                    while (i);
494                    len *= 2;
495            }
496    
497                  packet = &packet_queue[queue_lo];          rdpsnd_record(buffer, len);
498                  out = &packet->s;  }
499    
500                  /* Swap the current packet, but only once */  struct audio_driver *
501                  if (g_swapaudio && !swapped)  sun_register(char *options)
502                  {  {
503                          for (i = 0; i < out->end - out->p; i += 2)          static struct audio_driver sun_driver;
                         {  
                                 swap = *(out->p + i);  
                                 *(out->p + i) = *(out->p + i + 1);  
                                 *(out->p + i + 1) = swap;  
                         }  
                         swapped = True;  
                 }  
504    
505                  if (sentcompletion)          memset(&sun_driver, 0, sizeof(sun_driver));
                 {  
                         sentcompletion = False;  
                         numsamples = (out->end - out->p) / g_samplewidth;  
                 }  
506    
507                  len = 0;          sun_driver.name = "sun";
508            sun_driver.description =
509                    "SUN/BSD output driver, default device: " DEFAULTDEVICE " or $AUDIODEV";
510    
511                  if (out->end != out->p)          sun_driver.add_fds = sun_add_fds;
512                  {          sun_driver.check_fds = sun_check_fds;
                         len = write(g_dsp_fd, out->p, out->end - out->p);  
                         if (len == -1)  
                         {  
                                 if (errno != EWOULDBLOCK)  
                                         perror("write audio");  
                                 g_dsp_busy = 1;  
                                 return;  
                         }  
                 }  
513    
514                  out->p += len;          sun_driver.wave_out_open = sun_open_out;
515                  if (out->p == out->end)          sun_driver.wave_out_close = sun_close_out;
516                  {          sun_driver.wave_out_format_supported = sun_format_supported;
517                          if (ioctl(g_dsp_fd, AUDIO_GETINFO, &info) == -1)          sun_driver.wave_out_set_format = sun_set_format;
518                          {          sun_driver.wave_out_volume = sun_volume;
                                 perror("AUDIO_GETINFO");  
                                 return;  
                         }  
519    
520                          /* Ack the packet, if we have played at least 70% */          sun_driver.wave_in_open = sun_open_in;
521                          if (info.play.samples >= samplecnt + ((numsamples * 7) / 10))          sun_driver.wave_in_close = sun_close_in;
522                          {          sun_driver.wave_in_format_supported = sun_format_supported;
523                                  samplecnt += numsamples;          sun_driver.wave_in_set_format = sun_set_format;
524                                  rdpsnd_send_completion(packet->tick, packet->index);          sun_driver.wave_in_volume = NULL;       /* FIXME */
525                                  free(out->data);  
526                                  queue_lo = (queue_lo + 1) % MAX_QUEUE;          sun_driver.need_byteswap_on_be = 1;
527                                  swapped = False;          sun_driver.need_resampling = 0;
528                                  sentcompletion = True;  
529                          }          if (options)
530                          else          {
531                          {                  dsp_dev = xstrdup(options);
532                                  g_dsp_busy = 1;          }
533                                  return;          else
534                          }          {
535                    dsp_dev = getenv("AUDIODEV");
536    
537                    if (dsp_dev == NULL)
538                    {
539                            dsp_dev = DEFAULTDEVICE;
540                  }                  }
541          }          }
542    
543            return &sun_driver;
544  }  }

Legend:
Removed from v.772  
changed lines
  Added in v.1470

  ViewVC Help
Powered by ViewVC 1.1.26