/[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 963 by astrand, Wed Aug 3 10:56:16 2005 UTC revision 1256 by stargo, Sun Sep 17 11:42:22 2006 UTC
# 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 <unistd.h>  #include <unistd.h>
33  #include <fcntl.h>  #include <fcntl.h>
34  #include <errno.h>  #include <errno.h>
# Line 27  Line 36 
36  #include <sys/ioctl.h>  #include <sys/ioctl.h>
37  #include <sys/soundcard.h>  #include <sys/soundcard.h>
38    
39  #define MAX_QUEUE       10  #define DEFAULTDEVICE   "/dev/dsp"
40    #define MAX_LEN         512
41    
42  int g_dsp_fd;  static int snd_rate;
43  BOOL g_dsp_busy = False;  static short samplewidth;
44  static int g_snd_rate;  static char *dsp_dev;
 static short g_samplewidth;  
 static BOOL g_driver_broken = False;  
   
 static struct audio_packet  
 {  
         struct stream s;  
         uint16 tick;  
         uint8 index;  
 } packet_queue[MAX_QUEUE];  
 static unsigned int queue_hi, queue_lo;  
45    
46  BOOL  BOOL
47  wave_out_open(void)  oss_open(void)
48  {  {
49          char *dsp_dev = getenv("AUDIODEV");          if ((g_dsp_fd = open(dsp_dev, O_WRONLY)) == -1)
   
         if (dsp_dev == NULL)  
         {  
                 dsp_dev = strdup("/dev/dsp");  
         }  
   
         if ((g_dsp_fd = open(dsp_dev, O_WRONLY | O_NONBLOCK)) == -1)  
50          {          {
51                  perror(dsp_dev);                  perror(dsp_dev);
52                  return False;                  return False;
53          }          }
54    
         /* Non-blocking so that user interface is responsive */  
         fcntl(g_dsp_fd, F_SETFL, fcntl(g_dsp_fd, F_GETFL) | O_NONBLOCK);  
55          return True;          return True;
56  }  }
57    
58  void  void
59  wave_out_close(void)  oss_close(void)
60  {  {
61          close(g_dsp_fd);          close(g_dsp_fd);
62  }  }
63    
64  BOOL  BOOL
65  wave_out_format_supported(WAVEFORMATEX * pwfx)  oss_format_supported(WAVEFORMATEX * pwfx)
66  {  {
67          if (pwfx->wFormatTag != WAVE_FORMAT_PCM)          if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
68                  return False;                  return False;
# Line 84  wave_out_format_supported(WAVEFORMATEX * Line 75  wave_out_format_supported(WAVEFORMATEX *
75  }  }
76    
77  BOOL  BOOL
78  wave_out_set_format(WAVEFORMATEX * pwfx)  oss_set_format(WAVEFORMATEX * pwfx)
79  {  {
80          int stereo, format, fragments;          int stereo, format, fragments;
81            static BOOL driver_broken = False;
82    
83          ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);          ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);
84          ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL);          ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL);
# Line 96  wave_out_set_format(WAVEFORMATEX * pwfx) Line 88  wave_out_set_format(WAVEFORMATEX * pwfx)
88          else if (pwfx->wBitsPerSample == 16)          else if (pwfx->wBitsPerSample == 16)
89                  format = AFMT_S16_LE;                  format = AFMT_S16_LE;
90    
91          g_samplewidth = pwfx->wBitsPerSample / 8;          samplewidth = pwfx->wBitsPerSample / 8;
92    
93          if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)          if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
94          {          {
# Line 108  wave_out_set_format(WAVEFORMATEX * pwfx) Line 100  wave_out_set_format(WAVEFORMATEX * pwfx)
100          if (pwfx->nChannels == 2)          if (pwfx->nChannels == 2)
101          {          {
102                  stereo = 1;                  stereo = 1;
103                  g_samplewidth *= 2;                  samplewidth *= 2;
104          }          }
105          else          else
106          {          {
# Line 122  wave_out_set_format(WAVEFORMATEX * pwfx) Line 114  wave_out_set_format(WAVEFORMATEX * pwfx)
114                  return False;                  return False;
115          }          }
116    
117          g_snd_rate = pwfx->nSamplesPerSec;          snd_rate = pwfx->nSamplesPerSec;
118          if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &g_snd_rate) == -1)          if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
119          {          {
120                  perror("SNDCTL_DSP_SPEED");                  perror("SNDCTL_DSP_SPEED");
121                  close(g_dsp_fd);                  close(g_dsp_fd);
122                  return False;                  return False;
123          }          }
124    
125          /* try to get 7 fragments of 2^12 bytes size */          /* try to get 12 fragments of 2^12 bytes size */
126          fragments = (7 << 16) + 12;          fragments = (12 << 16) + 12;
127          ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);          ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
128    
129          if (!g_driver_broken)          if (!driver_broken)
130          {          {
131                  audio_buf_info info;                  audio_buf_info info;
132    
# Line 151  wave_out_set_format(WAVEFORMATEX * pwfx) Line 143  wave_out_set_format(WAVEFORMATEX * pwfx)
143                          fprintf(stderr,                          fprintf(stderr,
144                                  "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",                                  "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
145                                  info.fragments, info.fragstotal, info.fragsize);                                  info.fragments, info.fragstotal, info.fragsize);
146                          g_driver_broken = True;                          driver_broken = True;
147                  }                  }
148          }          }
149    
# Line 159  wave_out_set_format(WAVEFORMATEX * pwfx) Line 151  wave_out_set_format(WAVEFORMATEX * pwfx)
151  }  }
152    
153  void  void
154  wave_out_volume(uint16 left, uint16 right)  oss_volume(uint16 left, uint16 right)
155  {  {
156          static BOOL use_dev_mixer = False;          static BOOL use_dev_mixer = False;
157          uint32 volume;          uint32 volume;
# Line 194  wave_out_volume(uint16 left, uint16 righ Line 186  wave_out_volume(uint16 left, uint16 righ
186  }  }
187    
188  void  void
189  wave_out_write(STREAM s, uint16 tick, uint8 index)  oss_play(void)
 {  
         struct audio_packet *packet = &packet_queue[queue_hi];  
         unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;  
   
         if (next_hi == queue_lo)  
         {  
                 error("No space to queue audio packet\n");  
                 return;  
         }  
   
         queue_hi = next_hi;  
   
         packet->s = *s;  
         packet->tick = tick;  
         packet->index = index;  
         packet->s.p += 4;  
   
         /* we steal the data buffer from s, give it a new one */  
         s->data = (uint8 *) malloc(s->size);  
   
         if (!g_dsp_busy)  
                 wave_out_play();  
 }  
   
 void  
 wave_out_play(void)  
190  {  {
191          struct audio_packet *packet;          struct audio_packet *packet;
192          ssize_t len;          ssize_t len;
# Line 229  wave_out_play(void) Line 195  wave_out_play(void)
195          static long startedat_s;          static long startedat_s;
196          static BOOL started = False;          static BOOL started = False;
197          struct timeval tv;          struct timeval tv;
         audio_buf_info info;  
198    
199          while (1)          if (rdpsnd_queue_empty())
200          {          {
201                  if (queue_lo == queue_hi)                  g_dsp_busy = 0;
202                  {                  return;
203                          g_dsp_busy = 0;          }
                         return;  
                 }  
204    
205                  packet = &packet_queue[queue_lo];          packet = rdpsnd_queue_current_packet();
206                  out = &packet->s;          out = &packet->s;
207    
208                  if (!started)          if (!started)
209                  {          {
210                          gettimeofday(&tv, NULL);                  gettimeofday(&tv, NULL);
211                          startedat_us = tv.tv_usec;                  startedat_us = tv.tv_usec;
212                          startedat_s = tv.tv_sec;                  startedat_s = tv.tv_sec;
213                          started = True;                  started = True;
214                  }          }
215    
216                  len = out->end - out->p;          len = out->end - out->p;
217    
218                  if (!g_driver_broken)          len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
219                  {          if (len == -1)
220                          memset(&info, 0, sizeof(info));          {
221                          if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)                  if (errno != EWOULDBLOCK)
222                          {                          perror("write audio");
223                                  perror("SNDCTL_DSP_GETOSPACE");                  g_dsp_busy = 1;
224                                  return;                  return;
225                          }          }
226    
227                          if (info.fragments == 0)          out->p += len;
228                          {          if (out->p == out->end)
229                                  g_dsp_busy = 1;          {
230                                  return;                  long long duration;
231                          }                  long elapsed;
   
                         if (info.fragments * info.fragsize < len  
                             && info.fragments * info.fragsize > 0)  
                         {  
                                 len = info.fragments * info.fragsize;  
                         }  
                 }  
232    
233                    gettimeofday(&tv, NULL);
234                    duration = (out->size * (1000000 / (samplewidth * snd_rate)));
235                    elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);
236    
237                  len = write(g_dsp_fd, out->p, len);                  if (elapsed >= (duration * 85) / 100)
238                  if (len == -1)                  {
239                            /* We need to add 50 to tell windows that time has passed while
240                             * playing this packet */
241                            rdpsnd_send_completion(packet->tick + 50, packet->index);
242                            rdpsnd_queue_next();
243                            started = False;
244                    }
245                    else
246                  {                  {
                         if (errno != EWOULDBLOCK)  
                                 perror("write audio");  
247                          g_dsp_busy = 1;                          g_dsp_busy = 1;
248                          return;                          return;
249                  }                  }
250            }
251            g_dsp_busy = 1;
252            return;
253    }
254    
255                  out->p += len;  struct audio_driver *
256                  if (out->p == out->end)  oss_register(char *options)
257                  {  {
258                          long long duration;          static struct audio_driver oss_driver;
259                          long elapsed;  
260            oss_driver.wave_out_write = rdpsnd_queue_write;
261            oss_driver.wave_out_open = oss_open;
262            oss_driver.wave_out_close = oss_close;
263            oss_driver.wave_out_format_supported = oss_format_supported;
264            oss_driver.wave_out_set_format = oss_set_format;
265            oss_driver.wave_out_volume = oss_volume;
266            oss_driver.wave_out_play = oss_play;
267            oss_driver.name = xstrdup("oss");
268            oss_driver.description =
269                    xstrdup("OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV");
270            oss_driver.next = NULL;
271    
272            if (options)
273            {
274                    dsp_dev = xstrdup(options);
275            }
276            else
277            {
278                    dsp_dev = getenv("AUDIODEV");
279    
280                          gettimeofday(&tv, NULL);                  if (dsp_dev == NULL)
281                          duration = (out->size * (1000000 / (g_samplewidth * g_snd_rate)));                  {
282                          elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);                          dsp_dev = xstrdup(DEFAULTDEVICE);
   
                         if (elapsed >= (duration * 85) / 100)  
                         {  
                                 rdpsnd_send_completion(packet->tick, packet->index);  
                                 free(out->data);  
                                 queue_lo = (queue_lo + 1) % MAX_QUEUE;  
                                 started = False;  
                         }  
                         else  
                         {  
                                 g_dsp_busy = 1;  
                                 return;  
                         }  
283                  }                  }
284          }          }
285    
286            return &oss_driver;
287  }  }

Legend:
Removed from v.963  
changed lines
  Added in v.1256

  ViewVC Help
Powered by ViewVC 1.1.26