/[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 499 by astrand, Wed Oct 15 14:01:32 2003 UTC revision 1254 by stargo, Sun Sep 17 10:32:18 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 <unistd.h>  #include <unistd.h>
33  #include <fcntl.h>  #include <fcntl.h>
34  #include <errno.h>  #include <errno.h>
35    #include <sys/time.h>
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;  static short samplewidth;
   
 static struct audio_packet  
 {  
         struct stream s;  
         uint16 tick;  
         uint8 index;  
 } packet_queue[MAX_QUEUE];  
 static unsigned int queue_hi, queue_lo;  
44    
45  BOOL  BOOL
46  wave_out_open(void)  wave_out_open(void)
47  {  {
48          char *dsp_dev = "/dev/dsp";          char *dsp_dev = getenv("AUDIODEV");
49    
50            if (dsp_dev == NULL)
51            {
52                    dsp_dev = xstrdup(DEFAULTDEVICE);
53            }
54    
55          if ((g_dsp_fd = open(dsp_dev, O_WRONLY | O_NONBLOCK)) == -1)          if ((g_dsp_fd = open(dsp_dev, O_WRONLY)) == -1)
56          {          {
57                  perror(dsp_dev);                  perror(dsp_dev);
58                  return False;                  return False;
59          }          }
60    
         /* Non-blocking so that user interface is responsive */  
         fcntl(g_dsp_fd, F_SETFL, fcntl(g_dsp_fd, F_GETFL) | O_NONBLOCK);  
61          return True;          return True;
62  }  }
63    
# Line 77  wave_out_format_supported(WAVEFORMATEX * Line 83  wave_out_format_supported(WAVEFORMATEX *
83  BOOL  BOOL
84  wave_out_set_format(WAVEFORMATEX * pwfx)  wave_out_set_format(WAVEFORMATEX * pwfx)
85  {  {
86          int speed, channels, format;          int stereo, format, fragments;
87            static BOOL driver_broken = False;
88    
89          ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);          ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);
90          ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL);          ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL);
# Line 87  wave_out_set_format(WAVEFORMATEX * pwfx) Line 94  wave_out_set_format(WAVEFORMATEX * pwfx)
94          else if (pwfx->wBitsPerSample == 16)          else if (pwfx->wBitsPerSample == 16)
95                  format = AFMT_S16_LE;                  format = AFMT_S16_LE;
96    
97            samplewidth = pwfx->wBitsPerSample / 8;
98    
99          if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)          if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
100          {          {
101                  perror("SNDCTL_DSP_SETFMT");                  perror("SNDCTL_DSP_SETFMT");
# Line 94  wave_out_set_format(WAVEFORMATEX * pwfx) Line 103  wave_out_set_format(WAVEFORMATEX * pwfx)
103                  return False;                  return False;
104          }          }
105    
106          channels = pwfx->nChannels;          if (pwfx->nChannels == 2)
107          if (ioctl(g_dsp_fd, SNDCTL_DSP_CHANNELS, &channels) == -1)          {
108                    stereo = 1;
109                    samplewidth *= 2;
110            }
111            else
112            {
113                    stereo = 0;
114            }
115    
116            if (ioctl(g_dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
117          {          {
118                  perror("SNDCTL_DSP_CHANNELS");                  perror("SNDCTL_DSP_CHANNELS");
119                  close(g_dsp_fd);                  close(g_dsp_fd);
120                  return False;                  return False;
121          }          }
122    
123          speed = pwfx->nSamplesPerSec;          snd_rate = pwfx->nSamplesPerSec;
124          if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &speed) == -1)          if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
125          {          {
126                  perror("SNDCTL_DSP_SPEED");                  perror("SNDCTL_DSP_SPEED");
127                  close(g_dsp_fd);                  close(g_dsp_fd);
128                  return False;                  return False;
129          }          }
130    
131            /* try to get 12 fragments of 2^12 bytes size */
132            fragments = (12 << 16) + 12;
133            ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
134    
135            if (!driver_broken)
136            {
137                    audio_buf_info info;
138    
139                    memset(&info, 0, sizeof(info));
140                    if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
141                    {
142                            perror("SNDCTL_DSP_GETOSPACE");
143                            close(g_dsp_fd);
144                            return False;
145                    }
146    
147                    if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
148                    {
149                            fprintf(stderr,
150                                    "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
151                                    info.fragments, info.fragstotal, info.fragsize);
152                            driver_broken = True;
153                    }
154            }
155    
156          return True;          return True;
157  }  }
158    
159  void  void
160  wave_out_volume(uint16 left, uint16 right)  wave_out_volume(uint16 left, uint16 right)
161  {  {
162            static BOOL use_dev_mixer = False;
163          uint32 volume;          uint32 volume;
164            int fd_mix = -1;
165    
166          volume = left / (65536 / 100);          volume = left / (65536 / 100);
167          volume |= right / (65536 / 100) << 8;          volume |= right / (65536 / 100) << 8;
168    
169            if (use_dev_mixer)
170            {
171                    if ((fd_mix = open("/dev/mixer", O_RDWR | O_NONBLOCK)) == -1)
172                    {
173                            perror("open /dev/mixer");
174                            return;
175                    }
176    
177                    if (ioctl(fd_mix, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
178                    {
179                            perror("MIXER_WRITE(SOUND_MIXER_PCM)");
180                            return;
181                    }
182    
183                    close(fd_mix);
184            }
185    
186          if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)          if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
187          {          {
188                  perror("MIXER_WRITE(SOUND_MIXER_PCM)");                  perror("MIXER_WRITE(SOUND_MIXER_PCM)");
189                    use_dev_mixer = True;
190                  return;                  return;
191          }          }
192  }  }
193    
194  void  void
195  wave_out_write(STREAM s, uint16 tick, uint8 index)  wave_out_play(void)
196  {  {
197          struct audio_packet *packet = &packet_queue[queue_hi];          struct audio_packet *packet;
198          unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;          ssize_t len;
199            STREAM out;
200            static long startedat_us;
201            static long startedat_s;
202            static BOOL started = False;
203            struct timeval tv;
204    
205          if (next_hi == queue_lo)          if (rdpsnd_queue_empty())
206          {          {
207                  error("No space to queue audio packet\n");                  g_dsp_busy = 0;
208                  return;                  return;
209          }          }
210    
211          queue_hi = next_hi;          packet = rdpsnd_queue_current_packet();
212            out = &packet->s;
         packet->s = *s;  
         packet->tick = tick;  
         packet->index = index;  
         packet->s.p += 4;  
213    
214          /* we steal the data buffer from s, give it a new one */          if (!started)
215          s->data = malloc(s->size);          {
216                    gettimeofday(&tv, NULL);
217                    startedat_us = tv.tv_usec;
218                    startedat_s = tv.tv_sec;
219                    started = True;
220            }
221    
222          if (!g_dsp_busy)          len = out->end - out->p;
                 wave_out_play();  
 }  
223    
224  void          len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
225  wave_out_play(void)          if (len == -1)
226  {          {
227          struct audio_packet *packet;                  if (errno != EWOULDBLOCK)
228          ssize_t len;                          perror("write audio");
229          STREAM out;                  g_dsp_busy = 1;
230                    return;
231            }
232    
233          while (1)          out->p += len;
234            if (out->p == out->end)
235          {          {
236                  if (queue_lo == queue_hi)                  long long duration;
237                  {                  long elapsed;
                         g_dsp_busy = 0;  
                         return;  
                 }  
238    
239                  packet = &packet_queue[queue_lo];                  gettimeofday(&tv, NULL);
240                  out = &packet->s;                  duration = (out->size * (1000000 / (samplewidth * snd_rate)));
241                    elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);
242    
243                  len = write(g_dsp_fd, out->p, out->end - out->p);                  if (elapsed >= (duration * 85) / 100)
                 if (len == -1)  
244                  {                  {
245                          if (errno != EWOULDBLOCK)                          /* We need to add 50 to tell windows that time has passed while
246                                  perror("write audio");                           * playing this packet */
247                          g_dsp_busy = 1;                          rdpsnd_send_completion(packet->tick + 50, packet->index);
248                          return;                          rdpsnd_queue_next();
249                            started = False;
250                  }                  }
251                    else
                 out->p += len;  
                 if (out->p == out->end)  
252                  {                  {
253                          rdpsnd_send_completion(packet->tick, packet->index);                          g_dsp_busy = 1;
254                          free(out->data);                          return;
                         queue_lo = (queue_lo + 1) % MAX_QUEUE;  
255                  }                  }
256          }          }
257            g_dsp_busy = 1;
258            return;
259  }  }

Legend:
Removed from v.499  
changed lines
  Added in v.1254

  ViewVC Help
Powered by ViewVC 1.1.26