/[rdesktop]/sourceforge.net/tags/RDESKTOP-1-6-0/rdesktop/rdpsnd_oss.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 /sourceforge.net/tags/RDESKTOP-1-6-0/rdesktop/rdpsnd_oss.c

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

revision 476 by matthewc, Sat Oct 4 00:03:24 2003 UTC revision 1345 by ossman_, Thu Dec 7 11:54:29 2006 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 - Open Sound System     Sound Channel Process Functions - Open Sound System
4     Copyright (C) Matthew Chapman 2003     Copyright (C) Matthew Chapman 2003
# Line 19  Line 19 
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */  */
21    
22    /*
23       This is a workaround for Esound bug 312665.
24       FIXME: Remove this when Esound is fixed.
25    */
26    #ifdef _FILE_OFFSET_BITS
27    #undef _FILE_OFFSET_BITS
28    #endif
29    
30  #include "rdesktop.h"  #include "rdesktop.h"
31    #include "rdpsnd.h"
32    #include "rdpsnd_dsp.h"
33  #include <unistd.h>  #include <unistd.h>
34  #include <fcntl.h>  #include <fcntl.h>
35  #include <errno.h>  #include <errno.h>
36    #include <unistd.h>
37    #include <sys/time.h>
38  #include <sys/ioctl.h>  #include <sys/ioctl.h>
39  #include <sys/soundcard.h>  #include <sys/soundcard.h>
40    #include <sys/types.h>
41    #include <sys/stat.h>
42    
43  #define MAX_QUEUE       10  #define DEFAULTDEVICE   "/dev/dsp"
44    #define MAX_LEN         512
45    
46  int g_dsp_fd;  static int snd_rate;
47  BOOL g_dsp_busy;  static short samplewidth;
48    static char *dsp_dev;
49    static BOOL in_esddsp;
50    
51  static struct audio_packet {  /* This is a just a forward declaration */
52          struct stream s;  static struct audio_driver oss_driver;
         uint16 tick;  
         uint8 index;  
 } packet_queue[MAX_QUEUE];  
 static unsigned int queue_hi, queue_lo;  
53    
54  BOOL  static BOOL
55  wave_out_open(void)  detect_esddsp(void)
56  {  {
57          char *dsp_dev = "/dev/dsp";          struct stat s;
58            char *preload;
59    
60            if (fstat(g_dsp_fd, &s) == -1)
61                    return False;
62    
63            if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
64                    return False;
65    
66            preload = getenv("LD_PRELOAD");
67            if (preload == NULL)
68                    return False;
69    
70            if (strstr(preload, "esddsp") == NULL)
71                    return False;
72    
73            return True;
74    }
75    
76    BOOL
77    oss_open(void)
78    {
79          if ((g_dsp_fd = open(dsp_dev, O_WRONLY)) == -1)          if ((g_dsp_fd = open(dsp_dev, O_WRONLY)) == -1)
80          {          {
81                  perror(dsp_dev);                  perror(dsp_dev);
82                  return False;                  return False;
83          }          }
84    
85          /* Non-blocking so that user interface is responsive */          in_esddsp = detect_esddsp();
86          fcntl(g_dsp_fd, F_SETFL, fcntl(g_dsp_fd, F_GETFL)|O_NONBLOCK);  
87          return True;          return True;
88  }  }
89    
90  void  void
91  wave_out_close(void)  oss_close(void)
92  {  {
93          close(g_dsp_fd);          close(g_dsp_fd);
94            g_dsp_busy = 0;
95  }  }
96    
97  BOOL  BOOL
98  wave_out_format_supported(WAVEFORMATEX *pwfx)  oss_format_supported(WAVEFORMATEX * pwfx)
99  {  {
100          if (pwfx->wFormatTag != WAVE_FORMAT_PCM)          if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
101                  return False;                  return False;
# Line 74  wave_out_format_supported(WAVEFORMATEX * Line 108  wave_out_format_supported(WAVEFORMATEX *
108  }  }
109    
110  BOOL  BOOL
111  wave_out_set_format(WAVEFORMATEX *pwfx)  oss_set_format(WAVEFORMATEX * pwfx)
112  {  {
113          int speed, channels, format;          int stereo, format, fragments;
114            static BOOL driver_broken = False;
115    
116          ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);          ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);
117          ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL);          ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL);
# Line 86  wave_out_set_format(WAVEFORMATEX *pwfx) Line 121  wave_out_set_format(WAVEFORMATEX *pwfx)
121          else if (pwfx->wBitsPerSample == 16)          else if (pwfx->wBitsPerSample == 16)
122                  format = AFMT_S16_LE;                  format = AFMT_S16_LE;
123    
124            samplewidth = pwfx->wBitsPerSample / 8;
125    
126          if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)          if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
127          {          {
128                  perror("SNDCTL_DSP_SETFMT");                  perror("SNDCTL_DSP_SETFMT");
129                  close(g_dsp_fd);                  oss_close();
130                  return False;                  return False;
131          }          }
132    
133          channels = pwfx->nChannels;          if (pwfx->nChannels == 2)
134          if (ioctl(g_dsp_fd, SNDCTL_DSP_CHANNELS, &channels) == -1)          {
135                    stereo = 1;
136                    samplewidth *= 2;
137            }
138            else
139            {
140                    stereo = 0;
141            }
142    
143            if (ioctl(g_dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
144          {          {
145                  perror("SNDCTL_DSP_CHANNELS");                  perror("SNDCTL_DSP_CHANNELS");
146                  close(g_dsp_fd);                  oss_close();
147                  return False;                  return False;
148          }          }
149    
150          speed = pwfx->nSamplesPerSec;          oss_driver.need_resampling = 0;
151          if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &speed) == -1)          snd_rate = pwfx->nSamplesPerSec;
152            if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
153          {          {
154                  perror("SNDCTL_DSP_SPEED");                  int rates[] = { 44100, 48000, 0 };
155                  close(g_dsp_fd);                  int *prates = rates;
156                  return False;  
157                    while (*prates != 0)
158                    {
159                            if ((pwfx->nSamplesPerSec != *prates)
160                                && (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, prates) != -1))
161                            {
162                                    oss_driver.need_resampling = 1;
163                                    snd_rate = *prates;
164                                    if (rdpsnd_dsp_resample_set
165                                        (snd_rate, pwfx->wBitsPerSample, pwfx->nChannels) == False)
166                                    {
167                                            error("rdpsnd_dsp_resample_set failed");
168                                            oss_close();
169                                            return False;
170                                    }
171    
172                                    break;
173                            }
174                            prates++;
175                    }
176    
177                    if (*prates == 0)
178                    {
179                            perror("SNDCTL_DSP_SPEED");
180                            oss_close();
181                            return False;
182                    }
183            }
184    
185            /* try to get 12 fragments of 2^12 bytes size */
186            fragments = (12 << 16) + 12;
187            ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
188    
189            if (!driver_broken)
190            {
191                    audio_buf_info info;
192    
193                    memset(&info, 0, sizeof(info));
194                    if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
195                    {
196                            perror("SNDCTL_DSP_GETOSPACE");
197                            oss_close();
198                            return False;
199                    }
200    
201                    if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
202                    {
203                            fprintf(stderr,
204                                    "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
205                                    info.fragments, info.fragstotal, info.fragsize);
206                            driver_broken = True;
207                    }
208          }          }
209    
210          return True;          return True;
211  }  }
212    
213  void  void
214  wave_out_write(STREAM s, uint16 tick, uint8 index)  oss_volume(uint16 left, uint16 right)
215  {  {
216          struct audio_packet *packet = &packet_queue[queue_hi];          uint32 volume;
217          unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;  
218            volume = left / (65536 / 100);
219            volume |= right / (65536 / 100) << 8;
220    
221          if (next_hi == queue_lo)          if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
222          {          {
223                  error("No space to queue audio packet\n");                  warning("hardware volume control unavailable, falling back to software volume control!\n");
224                    oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
225                    rdpsnd_dsp_softvol_set(left, right);
226                  return;                  return;
227          }          }
   
         queue_hi = next_hi;  
   
         packet->s = *s;  
         packet->tick = tick;  
         packet->index = index;  
   
         /* we steal the data buffer from s, give it a new one */  
         s->data = malloc(s->size);  
   
         if (!g_dsp_busy)  
                 wave_out_play();  
228  }  }
229    
230  void  void
231  wave_out_play(void)  oss_play(void)
232  {  {
233          struct audio_packet *packet;          struct audio_packet *packet;
234          ssize_t len;          ssize_t len;
235          STREAM out;          STREAM out;
236    
237          while (1)          if (rdpsnd_queue_empty())
238          {          {
239                  if (queue_lo == queue_hi)                  g_dsp_busy = 0;
240                  {                  return;
241                          g_dsp_busy = 0;          }
                         return;  
                 }  
242    
243                  packet = &packet_queue[queue_lo];          packet = rdpsnd_queue_current_packet();
244                  out = &packet->s;          out = &packet->s;
245    
246                  len = write(g_dsp_fd, out->p, out->end-out->p);          len = out->end - out->p;
247                  if (len == -1)  
248            len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
249            if (len == -1)
250            {
251                    if (errno != EWOULDBLOCK)
252                            perror("write audio");
253                    g_dsp_busy = 1;
254                    return;
255            }
256    
257            out->p += len;
258    
259            if (out->p == out->end)
260            {
261                    int delay_bytes;
262                    unsigned long delay_us;
263                    audio_buf_info info;
264    
265                    if (in_esddsp)
266                  {                  {
267                          if (errno != EWOULDBLOCK)                          /* EsounD has no way of querying buffer status, so we have to
268                                  perror("write audio");                           * go with a fixed size. */
269                          g_dsp_busy = 1;                          delay_bytes = out->size;
                         return;  
270                  }                  }
271                    else
272                    {
273    #ifdef SNDCTL_DSP_GETODELAY
274                            delay_bytes = 0;
275                            if (ioctl(g_dsp_fd, SNDCTL_DSP_GETODELAY, &delay_bytes) == -1)
276                                    delay_bytes = -1;
277    #else
278                            delay_bytes = -1;
279    #endif
280    
281                            if (delay_bytes == -1)
282                            {
283                                    if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) != -1)
284                                            delay_bytes = info.fragstotal * info.fragsize - info.bytes;
285                                    else
286                                            delay_bytes = out->size;
287                            }
288                    }
289    
290                    delay_us = delay_bytes * (1000000 / (samplewidth * snd_rate));
291                    rdpsnd_queue_next(delay_us);
292            }
293            else
294            {
295                    g_dsp_busy = 1;
296            }
297    
298            return;
299    }
300    
301    static struct audio_driver oss_driver = {
302            .name = "oss",
303            .description = "OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV",
304    
305            .wave_out_open = oss_open,
306            .wave_out_close = oss_close,
307            .wave_out_format_supported = oss_format_supported,
308            .wave_out_set_format = oss_set_format,
309            .wave_out_volume = oss_volume,
310            .wave_out_play = oss_play,
311    
312            .need_byteswap_on_be = 0,
313            .need_resampling = 0,
314    };
315    
316    struct audio_driver *
317    oss_register(char *options)
318    {
319            if (options)
320            {
321                    dsp_dev = xstrdup(options);
322            }
323            else
324            {
325                    dsp_dev = getenv("AUDIODEV");
326    
327                  out->p += len;                  if (dsp_dev == NULL)
                 if (out->p == out->end)  
328                  {                  {
329                          rdpsnd_send_completion(packet->tick, packet->index);                          dsp_dev = xstrdup(DEFAULTDEVICE);
                         free(out->data);  
                         queue_lo = (queue_lo + 1) % MAX_QUEUE;  
330                  }                  }
331          }          }
332    
333            return &oss_driver;
334  }  }

Legend:
Removed from v.476  
changed lines
  Added in v.1345

  ViewVC Help
Powered by ViewVC 1.1.26