/[rdesktop]/sourceforge.net/trunk/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/trunk/rdesktop/rdpsnd_oss.c

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

revision 491 by stargo, Mon Oct 13 16:09:45 2003 UTC revision 1275 by stargo, Sun Oct 1 11:08:09 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 <sys/time.h>
37  #include <sys/ioctl.h>  #include <sys/ioctl.h>
38  #include <sys/soundcard.h>  #include <sys/soundcard.h>
39    
40  #define MAX_QUEUE       10  #define DEFAULTDEVICE   "/dev/dsp"
41    #define MAX_LEN         512
42    
43  int g_dsp_fd;  static int snd_rate;
44  BOOL g_dsp_busy;  static short samplewidth;
45    static char *dsp_dev;
46  static struct audio_packet {  static struct audio_driver oss_driver;
         struct stream s;  
         uint16 tick;  
         uint8 index;  
 } packet_queue[MAX_QUEUE];  
 static unsigned int queue_hi, queue_lo;  
47    
48  BOOL  BOOL
49  wave_out_open(void)  oss_open(void)
50  {  {
51          char *dsp_dev = "/dev/dsp";          if ((g_dsp_fd = open(dsp_dev, O_WRONLY)) == -1)
   
         if ((g_dsp_fd = open(dsp_dev, O_WRONLY|O_NONBLOCK)) == -1)  
52          {          {
53                  perror(dsp_dev);                  perror(dsp_dev);
54                  return False;                  return False;
55          }          }
56    
         /* Non-blocking so that user interface is responsive */  
         fcntl(g_dsp_fd, F_SETFL, fcntl(g_dsp_fd, F_GETFL)|O_NONBLOCK);  
57          return True;          return True;
58  }  }
59    
60  void  void
61  wave_out_close(void)  oss_close(void)
62  {  {
63          close(g_dsp_fd);          close(g_dsp_fd);
64  }  }
65    
66  BOOL  BOOL
67  wave_out_format_supported(WAVEFORMATEX *pwfx)  oss_format_supported(WAVEFORMATEX * pwfx)
68  {  {
69          if (pwfx->wFormatTag != WAVE_FORMAT_PCM)          if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
70                  return False;                  return False;
# Line 74  wave_out_format_supported(WAVEFORMATEX * Line 77  wave_out_format_supported(WAVEFORMATEX *
77  }  }
78    
79  BOOL  BOOL
80  wave_out_set_format(WAVEFORMATEX *pwfx)  oss_set_format(WAVEFORMATEX * pwfx)
81  {  {
82          int speed, channels, format;          int stereo, format, fragments;
83            static BOOL driver_broken = False;
84    
85          ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);          ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);
86          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 90  wave_out_set_format(WAVEFORMATEX *pwfx)
90          else if (pwfx->wBitsPerSample == 16)          else if (pwfx->wBitsPerSample == 16)
91                  format = AFMT_S16_LE;                  format = AFMT_S16_LE;
92    
93            samplewidth = pwfx->wBitsPerSample / 8;
94    
95          if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)          if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
96          {          {
97                  perror("SNDCTL_DSP_SETFMT");                  perror("SNDCTL_DSP_SETFMT");
# Line 93  wave_out_set_format(WAVEFORMATEX *pwfx) Line 99  wave_out_set_format(WAVEFORMATEX *pwfx)
99                  return False;                  return False;
100          }          }
101    
102          channels = pwfx->nChannels;          if (pwfx->nChannels == 2)
103          if (ioctl(g_dsp_fd, SNDCTL_DSP_CHANNELS, &channels) == -1)          {
104                    stereo = 1;
105                    samplewidth *= 2;
106            }
107            else
108            {
109                    stereo = 0;
110            }
111    
112            if (ioctl(g_dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
113          {          {
114                  perror("SNDCTL_DSP_CHANNELS");                  perror("SNDCTL_DSP_CHANNELS");
115                  close(g_dsp_fd);                  close(g_dsp_fd);
116                  return False;                  return False;
117          }          }
118    
119          speed = pwfx->nSamplesPerSec;          snd_rate = pwfx->nSamplesPerSec;
120          if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &speed) == -1)          if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
121          {          {
122                  perror("SNDCTL_DSP_SPEED");                  perror("SNDCTL_DSP_SPEED");
123                  close(g_dsp_fd);                  close(g_dsp_fd);
124                  return False;                  return False;
125          }          }
126    
127            /* try to get 12 fragments of 2^12 bytes size */
128            fragments = (12 << 16) + 12;
129            ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
130    
131            if (!driver_broken)
132            {
133                    audio_buf_info info;
134    
135                    memset(&info, 0, sizeof(info));
136                    if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
137                    {
138                            perror("SNDCTL_DSP_GETOSPACE");
139                            close(g_dsp_fd);
140                            return False;
141                    }
142    
143                    if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
144                    {
145                            fprintf(stderr,
146                                    "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
147                                    info.fragments, info.fragstotal, info.fragsize);
148                            driver_broken = True;
149                    }
150            }
151    
152          return True;          return True;
153  }  }
154    
155  void  void
156  wave_out_volume(uint16 left, uint16 right)  oss_volume(uint16 left, uint16 right)
157  {  {
158          uint32 volume;          uint32 volume;
159    
160          volume = left/(65536/100);          volume = left / (65536 / 100);
161          volume |= right/(65536/100) << 8;          volume |= right / (65536 / 100) << 8;
162    
163          if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)          if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
164          {          {
165                  perror("MIXER_WRITE(SOUND_MIXER_PCM)");                  warning("hardware volume control unavailable, falling back to software volume control!\n");
166                    oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
167                    rdpsnd_dsp_softvol_set(left, right);
168                  return;                  return;
169          }          }
170  }  }
171    
172  void  void
173  wave_out_write(STREAM s, uint16 tick, uint8 index)  oss_play(void)
174  {  {
175          struct audio_packet *packet = &packet_queue[queue_hi];          struct audio_packet *packet;
176          unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;          ssize_t len;
177            STREAM out;
178            static long startedat_us;
179            static long startedat_s;
180            static BOOL started = False;
181            struct timeval tv;
182    
183          if (next_hi == queue_lo)          if (rdpsnd_queue_empty())
184          {          {
185                  error("No space to queue audio packet\n");                  g_dsp_busy = 0;
186                  return;                  return;
187          }          }
188    
189          queue_hi = next_hi;          packet = rdpsnd_queue_current_packet();
190            out = &packet->s;
191    
192          packet->s = *s;          if (!started)
193          packet->tick = tick;          {
194          packet->index = index;                  gettimeofday(&tv, NULL);
195          packet->s.p += 4;                  startedat_us = tv.tv_usec;
196                    startedat_s = tv.tv_sec;
197          /* we steal the data buffer from s, give it a new one */                  started = True;
198          s->data = malloc(s->size);          }
199    
200          if (!g_dsp_busy)          len = out->end - out->p;
                 wave_out_play();  
 }  
201    
202  void          len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
203  wave_out_play(void)          if (len == -1)
204  {          {
205          struct audio_packet *packet;                  if (errno != EWOULDBLOCK)
206          ssize_t len;                          perror("write audio");
207          STREAM out;                  g_dsp_busy = 1;
208                    return;
209            }
210    
211          while (1)          out->p += len;
212            if (out->p == out->end)
213          {          {
214                  if (queue_lo == queue_hi)                  long long duration;
215                  {                  long elapsed;
                         g_dsp_busy = 0;  
                         return;  
                 }  
216    
217                  packet = &packet_queue[queue_lo];                  gettimeofday(&tv, NULL);
218                  out = &packet->s;                  duration = (out->size * (1000000 / (samplewidth * snd_rate)));
219                    elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);
220    
221                  len = write(g_dsp_fd, out->p, out->end-out->p);                  if (elapsed >= (duration * 85) / 100)
222                  if (len == -1)                  {
223                            /* We need to add 50 to tell windows that time has passed while
224                             * playing this packet */
225                            rdpsnd_send_completion(packet->tick + 50, packet->index);
226                            rdpsnd_queue_next();
227                            started = False;
228                    }
229                    else
230                  {                  {
                         if (errno != EWOULDBLOCK)  
                                 perror("write audio");  
231                          g_dsp_busy = 1;                          g_dsp_busy = 1;
232                          return;                          return;
233                  }                  }
234            }
235            g_dsp_busy = 1;
236            return;
237    }
238    
239    struct audio_driver *
240    oss_register(char *options)
241    {
242            oss_driver.wave_out_write = rdpsnd_queue_write;
243            oss_driver.wave_out_open = oss_open;
244            oss_driver.wave_out_close = oss_close;
245            oss_driver.wave_out_format_supported = oss_format_supported;
246            oss_driver.wave_out_set_format = oss_set_format;
247            oss_driver.wave_out_volume = oss_volume;
248            oss_driver.wave_out_play = oss_play;
249            oss_driver.name = xstrdup("oss");
250            oss_driver.description =
251                    xstrdup("OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV");
252            oss_driver.need_byteswap_on_be = 0;
253            oss_driver.next = NULL;
254    
255            if (options)
256            {
257                    dsp_dev = xstrdup(options);
258            }
259            else
260            {
261                    dsp_dev = getenv("AUDIODEV");
262    
263                  out->p += len;                  if (dsp_dev == NULL)
                 if (out->p == out->end)  
264                  {                  {
265                          rdpsnd_send_completion(packet->tick, packet->index);                          dsp_dev = xstrdup(DEFAULTDEVICE);
                         free(out->data);  
                         queue_lo = (queue_lo + 1) % MAX_QUEUE;  
266                  }                  }
267          }          }
268    
269            return &oss_driver;
270  }  }

Legend:
Removed from v.491  
changed lines
  Added in v.1275

  ViewVC Help
Powered by ViewVC 1.1.26