/[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 1286 by stargo, Sun Oct 1 18:47:04 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 "rdpsnd_dsp.h"
33  #include <unistd.h>  #include <unistd.h>
34  #include <fcntl.h>  #include <fcntl.h>
35  #include <errno.h>  #include <errno.h>
# Line 27  Line 37 
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
 int g_dsp_fd;  
 BOOL g_dsp_busy = False;  
 static int g_snd_rate;  
 static short g_samplewidth;  
 static BOOL g_driver_broken = False;  
42    
43  static struct audio_packet  static int snd_rate;
44  {  static short samplewidth;
45          struct stream s;  static char *dsp_dev;
46          uint16 tick;  static struct audio_driver oss_driver;
         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 = 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)  
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 84  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 stereo, format, fragments;          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 96  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          g_samplewidth = pwfx->wBitsPerSample / 8;          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          {          {
# Line 108  wave_out_set_format(WAVEFORMATEX * pwfx) Line 102  wave_out_set_format(WAVEFORMATEX * pwfx)
102          if (pwfx->nChannels == 2)          if (pwfx->nChannels == 2)
103          {          {
104                  stereo = 1;                  stereo = 1;
105                  g_samplewidth *= 2;                  samplewidth *= 2;
106          }          }
107          else          else
108          {          {
# Line 122  wave_out_set_format(WAVEFORMATEX * pwfx) Line 116  wave_out_set_format(WAVEFORMATEX * pwfx)
116                  return False;                  return False;
117          }          }
118    
119          g_snd_rate = pwfx->nSamplesPerSec;          oss_driver.need_resampling = 0;
120          if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &g_snd_rate) == -1)          snd_rate = pwfx->nSamplesPerSec;
121            if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
122          {          {
123                  perror("SNDCTL_DSP_SPEED");                  int rates[] = { 44100, 48000, 0 };
124                  close(g_dsp_fd);                  int *prates = rates;
125                  return False;  
126                    while (*prates != 0)
127                    {
128                            if ((pwfx->nSamplesPerSec != *prates)
129                                && (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, prates) != -1))
130                            {
131                                    oss_driver.need_resampling = 1;
132                                    snd_rate = *prates;
133                                    if (rdpsnd_dsp_resample_set
134                                        (snd_rate, pwfx->wBitsPerSample, pwfx->nChannels) == False)
135                                    {
136                                            error("rdpsnd_dsp_resample_set failed");
137                                            close(g_dsp_fd);
138                                            return False;
139                                    }
140    
141                                    break;
142                            }
143                            prates++;
144                    }
145    
146                    if (*prates == 0)
147                    {
148                            perror("SNDCTL_DSP_SPEED");
149                            close(g_dsp_fd);
150                            return False;
151                    }
152          }          }
153    
154          /* try to get 7 fragments of 2^12 bytes size */          /* try to get 12 fragments of 2^12 bytes size */
155          fragments = (7 << 16) + 12;          fragments = (12 << 16) + 12;
156          ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);          ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
157    
158          if (!g_driver_broken)          if (!driver_broken)
159          {          {
160                  audio_buf_info info;                  audio_buf_info info;
161    
# Line 151  wave_out_set_format(WAVEFORMATEX * pwfx) Line 172  wave_out_set_format(WAVEFORMATEX * pwfx)
172                          fprintf(stderr,                          fprintf(stderr,
173                                  "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",                                  "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
174                                  info.fragments, info.fragstotal, info.fragsize);                                  info.fragments, info.fragstotal, info.fragsize);
175                          g_driver_broken = True;                          driver_broken = True;
176                  }                  }
177          }          }
178    
# Line 159  wave_out_set_format(WAVEFORMATEX * pwfx) Line 180  wave_out_set_format(WAVEFORMATEX * pwfx)
180  }  }
181    
182  void  void
183  wave_out_volume(uint16 left, uint16 right)  oss_volume(uint16 left, uint16 right)
184  {  {
         static BOOL use_dev_mixer = False;  
185          uint32 volume;          uint32 volume;
         int fd_mix = -1;  
186    
187          volume = left / (65536 / 100);          volume = left / (65536 / 100);
188          volume |= right / (65536 / 100) << 8;          volume |= right / (65536 / 100) << 8;
189    
         if (use_dev_mixer)  
         {  
                 if ((fd_mix = open("/dev/mixer", O_RDWR | O_NONBLOCK)) == -1)  
                 {  
                         perror("open /dev/mixer");  
                         return;  
                 }  
   
                 if (ioctl(fd_mix, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)  
                 {  
                         perror("MIXER_WRITE(SOUND_MIXER_PCM)");  
                         return;  
                 }  
   
                 close(fd_mix);  
         }  
   
190          if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)          if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
191          {          {
192                  perror("MIXER_WRITE(SOUND_MIXER_PCM)");                  warning("hardware volume control unavailable, falling back to software volume control!\n");
193                  use_dev_mixer = True;                  oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
194                  return;                  rdpsnd_dsp_softvol_set(left, right);
         }  
 }  
   
 void  
 wave_out_write(STREAM s, uint16 tick, uint8 index)  
 {  
         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");  
195                  return;                  return;
196          }          }
   
         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();  
197  }  }
198    
199  void  void
200  wave_out_play(void)  oss_play(void)
201  {  {
202          struct audio_packet *packet;          struct audio_packet *packet;
203          ssize_t len;          ssize_t len;
# Line 229  wave_out_play(void) Line 206  wave_out_play(void)
206          static long startedat_s;          static long startedat_s;
207          static BOOL started = False;          static BOOL started = False;
208          struct timeval tv;          struct timeval tv;
         audio_buf_info info;  
209    
210          while (1)          if (rdpsnd_queue_empty())
211          {          {
212                  if (queue_lo == queue_hi)                  g_dsp_busy = 0;
213                  {                  return;
214                          g_dsp_busy = 0;          }
                         return;  
                 }  
   
                 packet = &packet_queue[queue_lo];  
                 out = &packet->s;  
215    
216                  if (!started)          packet = rdpsnd_queue_current_packet();
217                  {          out = &packet->s;
                         gettimeofday(&tv, NULL);  
                         startedat_us = tv.tv_usec;  
                         startedat_s = tv.tv_sec;  
                         started = True;  
                 }  
218    
219                  len = out->end - out->p;          if (!started)
220            {
221                    gettimeofday(&tv, NULL);
222                    startedat_us = tv.tv_usec;
223                    startedat_s = tv.tv_sec;
224                    started = True;
225            }
226    
227                  if (!g_driver_broken)          len = out->end - out->p;
                 {  
                         memset(&info, 0, sizeof(info));  
                         if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)  
                         {  
                                 perror("SNDCTL_DSP_GETOSPACE");  
                                 return;  
                         }  
228    
229                          if (info.fragments == 0)          len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
230                          {          if (len == -1)
231                                  g_dsp_busy = 1;          {
232                                  return;                  if (errno != EWOULDBLOCK)
233                          }                          perror("write audio");
234                    g_dsp_busy = 1;
235                    return;
236            }
237    
238                          if (info.fragments * info.fragsize < len          out->p += len;
239                              && info.fragments * info.fragsize > 0)          if (out->p == out->end)
240                          {          {
241                                  len = info.fragments * info.fragsize;                  long long duration;
242                          }                  long elapsed;
                 }  
243    
244                    gettimeofday(&tv, NULL);
245                    duration = (out->size * (1000000 / (samplewidth * snd_rate)));
246                    elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);
247    
248                  len = write(g_dsp_fd, out->p, len);                  if (elapsed >= (duration * 85) / 100)
249                  if (len == -1)                  {
250                            /* We need to add 50 to tell windows that time has passed while
251                             * playing this packet */
252                            rdpsnd_send_completion(packet->tick + 50, packet->index);
253                            rdpsnd_queue_next();
254                            started = False;
255                    }
256                    else
257                  {                  {
                         if (errno != EWOULDBLOCK)  
                                 perror("write audio");  
258                          g_dsp_busy = 1;                          g_dsp_busy = 1;
259                          return;                          return;
260                  }                  }
261            }
262            g_dsp_busy = 1;
263            return;
264    }
265    
266                  out->p += len;  struct audio_driver *
267                  if (out->p == out->end)  oss_register(char *options)
268                  {  {
269                          long long duration;          oss_driver.wave_out_write = rdpsnd_queue_write;
270                          long elapsed;          oss_driver.wave_out_open = oss_open;
271            oss_driver.wave_out_close = oss_close;
272            oss_driver.wave_out_format_supported = oss_format_supported;
273            oss_driver.wave_out_set_format = oss_set_format;
274            oss_driver.wave_out_volume = oss_volume;
275            oss_driver.wave_out_play = oss_play;
276            oss_driver.name = xstrdup("oss");
277            oss_driver.description =
278                    xstrdup("OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV");
279            oss_driver.need_byteswap_on_be = 0;
280            oss_driver.need_resampling = 0;
281            oss_driver.next = NULL;
282    
283                          gettimeofday(&tv, NULL);          if (options)
284                          duration = (out->size * (1000000 / (g_samplewidth * g_snd_rate)));          {
285                          elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);                  dsp_dev = xstrdup(options);
286            }
287            else
288            {
289                    dsp_dev = getenv("AUDIODEV");
290    
291                          if (elapsed >= (duration * 85) / 100)                  if (dsp_dev == NULL)
292                          {                  {
293                                  rdpsnd_send_completion(packet->tick, packet->index);                          dsp_dev = xstrdup(DEFAULTDEVICE);
                                 free(out->data);  
                                 queue_lo = (queue_lo + 1) % MAX_QUEUE;  
                                 started = False;  
                         }  
                         else  
                         {  
                                 g_dsp_busy = 1;  
                                 return;  
                         }  
294                  }                  }
295          }          }
296    
297            return &oss_driver;
298  }  }

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

  ViewVC Help
Powered by ViewVC 1.1.26