/[rdesktop]/jpeg/rdesktop/trunk/rdpsnd_alsa.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 /jpeg/rdesktop/trunk/rdpsnd_alsa.c

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

revision 1359 by ossman_, Tue Jan 2 11:39:56 2007 UTC revision 1360 by ossman_, Tue Jan 2 16:36:51 2007 UTC
# Line 4  Line 4 
4     Copyright (C) Matthew Chapman 2003     Copyright (C) Matthew Chapman 2003
5     Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003     Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6     Copyright (C) Michael Gernoth mike@zerfleddert.de 2006     Copyright (C) Michael Gernoth mike@zerfleddert.de 2006
7       Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8    
9     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
# Line 32  Line 33 
33  #define DEFAULTDEVICE   "default"  #define DEFAULTDEVICE   "default"
34  #define MAX_FRAMES      32  #define MAX_FRAMES      32
35    
36  static struct pollfd pfds[32];  static struct pollfd pfds_out[32];
37  static int num_fds;  static int num_fds_out;
38    
39    static struct pollfd pfds_in[32];
40    static int num_fds_in;
41    
42    static snd_pcm_t *out_handle = NULL;
43    static snd_pcm_t *in_handle = NULL;
44    
 static snd_pcm_t *pcm_handle = NULL;  
 static snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;  
45  static BOOL reopened;  static BOOL reopened;
46  static short samplewidth;  
47  static int audiochannels;  static short samplewidth_out;
48  static unsigned int rate;  static int audiochannels_out;
49    static unsigned int rate_out;
50    
51    static short samplewidth_in;
52    static int audiochannels_in;
53    static unsigned int rate_in;
54    
55  static char *pcm_name;  static char *pcm_name;
56    
57  void alsa_play(void);  void alsa_play(void);
58    void alsa_record(void);
59    
60  void  void
61  alsa_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)  alsa_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
# Line 51  alsa_add_fds(int *n, fd_set * rfds, fd_s Line 63  alsa_add_fds(int *n, fd_set * rfds, fd_s
63          int err;          int err;
64          struct pollfd *f;          struct pollfd *f;
65    
66          if (!pcm_handle)          if (out_handle && !rdpsnd_queue_empty())
67                  return;          {
68                    num_fds_out = snd_pcm_poll_descriptors_count(out_handle);
         if (rdpsnd_queue_empty())  
                 return;  
69    
70          num_fds = snd_pcm_poll_descriptors_count(pcm_handle);                  if (num_fds_out > sizeof(pfds_out) / sizeof(*pfds_out))
71                            return;
72    
73          if (num_fds > sizeof(pfds) / sizeof(*pfds))                  err = snd_pcm_poll_descriptors(out_handle, pfds_out, num_fds_out);
74                  return;                  if (err < 0)
75                            return;
76    
77          err = snd_pcm_poll_descriptors(pcm_handle, pfds, num_fds);                  for (f = pfds_out; f < &pfds_out[num_fds_out]; f++)
78          if (err < 0)                  {
79                  return;                          if (f->events & POLLIN)
80                                    FD_SET(f->fd, rfds);
81                            if (f->events & POLLOUT)
82                                    FD_SET(f->fd, wfds);
83                            if (f->fd > *n && (f->events & (POLLIN | POLLOUT)))
84                                    *n = f->fd;
85                    }
86            }
87    
88          for (f = pfds; f < &pfds[num_fds]; f++)          if (in_handle)
89          {          {
90                  if (f->events & POLLIN)                  num_fds_in = snd_pcm_poll_descriptors_count(in_handle);
91                          FD_SET(f->fd, rfds);  
92                  if (f->events & POLLOUT)                  if (num_fds_in > sizeof(pfds_in) / sizeof(*pfds_in))
93                          FD_SET(f->fd, wfds);                          return;
94                  if (f->fd > *n && (f->events & (POLLIN | POLLOUT)))  
95                          *n = f->fd;                  err = snd_pcm_poll_descriptors(in_handle, pfds_in, num_fds_in);
96                    if (err < 0)
97                            return;
98    
99                    for (f = pfds_in; f < &pfds_in[num_fds_in]; f++)
100                    {
101                            if (f->events & POLLIN)
102                                    FD_SET(f->fd, rfds);
103                            if (f->events & POLLOUT)
104                                    FD_SET(f->fd, wfds);
105                            if (f->fd > *n && (f->events & (POLLIN | POLLOUT)))
106                                    *n = f->fd;
107                    }
108          }          }
109  }  }
110    
# Line 84  alsa_check_fds(fd_set * rfds, fd_set * w Line 115  alsa_check_fds(fd_set * rfds, fd_set * w
115          int err;          int err;
116          unsigned short revents;          unsigned short revents;
117    
118          if (!pcm_handle)          if (out_handle && !rdpsnd_queue_empty())
                 return;  
   
         for (f = pfds; f < &pfds[num_fds]; f++)  
119          {          {
120                  f->revents = 0;                  for (f = pfds_out; f < &pfds_out[num_fds_out]; f++)
                 if (f->fd != -1)  
121                  {                  {
122                          /* Fixme: This doesn't properly deal with things like POLLHUP */                          f->revents = 0;
123                          if (FD_ISSET(f->fd, rfds))                          if (f->fd != -1)
124                                  f->revents |= POLLIN;                          {
125                          if (FD_ISSET(f->fd, wfds))                                  /* Fixme: This doesn't properly deal with things like POLLHUP */
126                                  f->revents |= POLLOUT;                                  if (FD_ISSET(f->fd, rfds))
127                                            f->revents |= POLLIN;
128                                    if (FD_ISSET(f->fd, wfds))
129                                            f->revents |= POLLOUT;
130                            }
131                  }                  }
         }  
132    
133          err = snd_pcm_poll_descriptors_revents(pcm_handle, pfds, num_fds, &revents);                  err = snd_pcm_poll_descriptors_revents(out_handle, pfds_out, num_fds_out, &revents);
134          if (err < 0)                  if (err < 0)
135                  return;                          return;
136    
137          if (revents & POLLOUT)                  if (revents & POLLOUT)
138                  alsa_play();                          alsa_play();
 }  
   
 BOOL  
 alsa_open(void)  
 {  
         int err;  
   
         if ((err = snd_pcm_open(&pcm_handle, pcm_name, stream, 0)) < 0)  
         {  
                 error("snd_pcm_open: %s\n", snd_strerror(err));  
                 return False;  
139          }          }
140    
         reopened = True;  
   
         return True;  
 }  
141    
142  void          if (in_handle)
 alsa_close(void)  
 {  
         /* Ack all remaining packets */  
         while (!rdpsnd_queue_empty())  
                 rdpsnd_queue_next(0);  
   
         if (pcm_handle)  
143          {          {
144                  snd_pcm_close(pcm_handle);                  for (f = pfds_in; f < &pfds_in[num_fds_in]; f++)
145                  pcm_handle = NULL;                  {
146          }                          f->revents = 0;
147  }                          if (f->fd != -1)
148                            {
149  BOOL                                  /* Fixme: This doesn't properly deal with things like POLLHUP */
150  alsa_format_supported(WAVEFORMATEX * pwfx)                                  if (FD_ISSET(f->fd, rfds))
151  {                                          f->revents |= POLLIN;
152  #if 0                                  if (FD_ISSET(f->fd, wfds))
153          int err;                                          f->revents |= POLLOUT;
154          snd_pcm_hw_params_t *hwparams = NULL;                          }
155                    }
156    
157          if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)                  err = snd_pcm_poll_descriptors_revents(in_handle, pfds_in, num_fds_in, &revents);
158          {                  if (err < 0)
159                  error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));                          return;
                 return False;  
         }  
160    
161          if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)                  if (revents & POLLIN)
162          {                          alsa_record();
                 error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));  
                 return False;  
163          }          }
         snd_pcm_hw_params_free(hwparams);  
 #endif  
   
         if (pwfx->wFormatTag != WAVE_FORMAT_PCM)  
                 return False;  
         if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))  
                 return False;  
         if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))  
                 return False;  
         if ((pwfx->nSamplesPerSec != 44100) && (pwfx->nSamplesPerSec != 22050))  
                 return False;  
   
         return True;  
164  }  }
165    
166  BOOL  static BOOL
167  alsa_set_format(WAVEFORMATEX * pwfx)  alsa_set_format(snd_pcm_t * pcm, WAVEFORMATEX * pwfx)
168  {  {
169          snd_pcm_hw_params_t *hwparams = NULL;          snd_pcm_hw_params_t *hwparams = NULL;
170          int err;          int err;
171          unsigned int buffertime;          unsigned int buffertime;
172            short samplewidth;
173            int audiochannels;
174            unsigned int rate;
175    
176          samplewidth = pwfx->wBitsPerSample / 8;          samplewidth = pwfx->wBitsPerSample / 8;
177    
# Line 186  alsa_set_format(WAVEFORMATEX * pwfx) Line 181  alsa_set_format(WAVEFORMATEX * pwfx)
181                  return False;                  return False;
182          }          }
183    
184          if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)          if ((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0)
185          {          {
186                  error("snd_pcm_hw_params_any: %s\n", snd_strerror(err));                  error("snd_pcm_hw_params_any: %s\n", snd_strerror(err));
187                  return False;                  return False;
188          }          }
189    
190          if ((err =          if ((err = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
              snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)  
191          {          {
192                  error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err));                  error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err));
193                  return False;                  return False;
# Line 201  alsa_set_format(WAVEFORMATEX * pwfx) Line 195  alsa_set_format(WAVEFORMATEX * pwfx)
195    
196          if (pwfx->wBitsPerSample == 16)          if (pwfx->wBitsPerSample == 16)
197          {          {
198                  if ((err =                  if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
                      snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)  
199                  {                  {
200                          error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));                          error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
201                          return False;                          return False;
# Line 210  alsa_set_format(WAVEFORMATEX * pwfx) Line 203  alsa_set_format(WAVEFORMATEX * pwfx)
203          }          }
204          else          else
205          {          {
206                  if ((err =                  if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S8)) < 0)
                      snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S8)) < 0)  
207                  {                  {
208                          error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));                          error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
209                          return False;                          return False;
# Line 219  alsa_set_format(WAVEFORMATEX * pwfx) Line 211  alsa_set_format(WAVEFORMATEX * pwfx)
211          }          }
212    
213  #if 0  #if 0
214          if ((err = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 1)) < 0)          if ((err = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 1)) < 0)
215          {          {
216                  error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err));                  error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err));
217                  return False;                  return False;
# Line 227  alsa_set_format(WAVEFORMATEX * pwfx) Line 219  alsa_set_format(WAVEFORMATEX * pwfx)
219  #endif  #endif
220    
221          rate = pwfx->nSamplesPerSec;          rate = pwfx->nSamplesPerSec;
222          if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, 0)) < 0)          if ((err = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, 0)) < 0)
223          {          {
224                  error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err));                  error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err));
225                  return False;                  return False;
226          }          }
227    
228          audiochannels = pwfx->nChannels;          audiochannels = pwfx->nChannels;
229          if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, pwfx->nChannels)) < 0)          if ((err = snd_pcm_hw_params_set_channels(pcm, hwparams, pwfx->nChannels)) < 0)
230          {          {
231                  error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err));                  error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err));
232                  return False;                  return False;
# Line 242  alsa_set_format(WAVEFORMATEX * pwfx) Line 234  alsa_set_format(WAVEFORMATEX * pwfx)
234    
235    
236          buffertime = 500000;    /* microseconds */          buffertime = 500000;    /* microseconds */
237          if ((err =          if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hwparams, &buffertime, 0)) < 0)
              snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &buffertime, 0)) < 0)  
238          {          {
239                  error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err));                  error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err));
240                  return False;                  return False;
241          }          }
242    
243          if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)          if ((err = snd_pcm_hw_params(pcm, hwparams)) < 0)
244          {          {
245                  error("snd_pcm_hw_params: %s\n", snd_strerror(err));                  error("snd_pcm_hw_params: %s\n", snd_strerror(err));
246                  return False;                  return False;
# Line 257  alsa_set_format(WAVEFORMATEX * pwfx) Line 248  alsa_set_format(WAVEFORMATEX * pwfx)
248    
249          snd_pcm_hw_params_free(hwparams);          snd_pcm_hw_params_free(hwparams);
250    
251          if ((err = snd_pcm_prepare(pcm_handle)) < 0)          if ((err = snd_pcm_prepare(pcm)) < 0)
252          {          {
253                  error("snd_pcm_prepare: %s\n", snd_strerror(err));                  error("snd_pcm_prepare: %s\n", snd_strerror(err));
254                  return False;                  return False;
# Line 268  alsa_set_format(WAVEFORMATEX * pwfx) Line 259  alsa_set_format(WAVEFORMATEX * pwfx)
259          return True;          return True;
260  }  }
261    
262    BOOL
263    alsa_open_out(void)
264    {
265            int err;
266    
267            if ((err = snd_pcm_open(&out_handle, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
268            {
269                    error("snd_pcm_open: %s\n", snd_strerror(err));
270                    return False;
271            }
272    
273            reopened = True;
274    
275            return True;
276    }
277    
278    void
279    alsa_close_out(void)
280    {
281            /* Ack all remaining packets */
282            while (!rdpsnd_queue_empty())
283                    rdpsnd_queue_next(0);
284    
285            if (out_handle)
286            {
287                    snd_pcm_close(out_handle);
288                    out_handle = NULL;
289            }
290    }
291    
292    BOOL
293    alsa_format_supported(WAVEFORMATEX * pwfx)
294    {
295    #if 0
296            int err;
297            snd_pcm_hw_params_t *hwparams = NULL;
298    
299            if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
300            {
301                    error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
302                    return False;
303            }
304    
305            if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
306            {
307                    error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
308                    return False;
309            }
310            snd_pcm_hw_params_free(hwparams);
311    #endif
312    
313            if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
314                    return False;
315            if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
316                    return False;
317            if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
318                    return False;
319            if ((pwfx->nSamplesPerSec != 44100) && (pwfx->nSamplesPerSec != 22050))
320                    return False;
321    
322            return True;
323    }
324    
325    BOOL
326    alsa_set_format_out(WAVEFORMATEX * pwfx)
327    {
328            if (!alsa_set_format(out_handle, pwfx))
329                    return False;
330    
331            samplewidth_out = pwfx->wBitsPerSample / 8;
332            audiochannels_out = pwfx->nChannels;
333            rate_out = pwfx->nSamplesPerSec;
334    
335            return True;
336    }
337    
338  void  void
339  alsa_play(void)  alsa_play(void)
340  {  {
# Line 296  alsa_play(void) Line 363  alsa_play(void)
363    
364          next_tick = rdpsnd_queue_next_tick();          next_tick = rdpsnd_queue_next_tick();
365    
366          len = (out->end - out->p) / (samplewidth * audiochannels);          len = (out->end - out->p) / (samplewidth_out * audiochannels_out);
367          if ((len = snd_pcm_writei(pcm_handle, out->p, ((MAX_FRAMES < len) ? MAX_FRAMES : len))) < 0)          if ((len = snd_pcm_writei(out_handle, out->p, ((MAX_FRAMES < len) ? MAX_FRAMES : len))) < 0)
368          {          {
369                  snd_pcm_prepare(pcm_handle);                  printf("Fooo!\n");
370                    snd_pcm_prepare(out_handle);
371                  len = 0;                  len = 0;
372          }          }
373          out->p += (len * samplewidth * audiochannels);          out->p += (len * samplewidth_out * audiochannels_out);
374    
375          gettimeofday(&tv, NULL);          gettimeofday(&tv, NULL);
376    
# Line 326  alsa_play(void) Line 394  alsa_play(void)
394                                 (packet->tick + duration) % 65536, next_tick % 65536));                                 (packet->tick + duration) % 65536, next_tick % 65536));
395                  }                  }
396    
397                  if (snd_pcm_delay(pcm_handle, &delay_frames) < 0)                  if (snd_pcm_delay(out_handle, &delay_frames) < 0)
398                          delay_frames = out->size / (samplewidth * audiochannels);                          delay_frames = out->size / (samplewidth_out * audiochannels_out);
399                  if (delay_frames < 0)                  if (delay_frames < 0)
400                          delay_frames = 0;                          delay_frames = 0;
401    
402                  delay_us = delay_frames * (1000000 / rate);                  delay_us = delay_frames * (1000000 / rate_out);
403    
404                  rdpsnd_queue_next(delay_us);                  rdpsnd_queue_next(delay_us);
405          }          }
406  }  }
407    
408    BOOL
409    alsa_open_in(void)
410    {
411            int err;
412    
413            if ((err =
414                 snd_pcm_open(&in_handle, pcm_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0)
415            {
416                    error("snd_pcm_open: %s\n", snd_strerror(err));
417                    return False;
418            }
419    
420            return True;
421    }
422    
423    void
424    alsa_close_in(void)
425    {
426            if (in_handle)
427            {
428                    snd_pcm_close(in_handle);
429                    in_handle = NULL;
430            }
431    }
432    
433    BOOL
434    alsa_set_format_in(WAVEFORMATEX * pwfx)
435    {
436            int err;
437    
438            if (!alsa_set_format(in_handle, pwfx))
439                    return False;
440    
441            if ((err = snd_pcm_start(in_handle)) < 0)
442            {
443                    error("snd_pcm_start: %s\n", snd_strerror(err));
444                    return False;
445            }
446    
447            samplewidth_in = pwfx->wBitsPerSample / 8;
448            audiochannels_in = pwfx->nChannels;
449            rate_in = pwfx->nSamplesPerSec;
450    
451            return True;
452    }
453    
454    void
455    alsa_record(void)
456    {
457            int len;
458            char buffer[32768];
459    
460            len = snd_pcm_readi(in_handle, buffer,
461                                sizeof(buffer) / (samplewidth_in * audiochannels_in));
462            if (len < 0)
463            {
464                    snd_pcm_prepare(in_handle);
465                    len = 0;
466            }
467    
468            rdpsnd_record(buffer, len * samplewidth_in * audiochannels_in);
469    }
470    
471  struct audio_driver *  struct audio_driver *
472  alsa_register(char *options)  alsa_register(char *options)
473  {  {
# Line 350  alsa_register(char *options) Line 481  alsa_register(char *options)
481          alsa_driver.add_fds = alsa_add_fds;          alsa_driver.add_fds = alsa_add_fds;
482          alsa_driver.check_fds = alsa_check_fds;          alsa_driver.check_fds = alsa_check_fds;
483    
484          alsa_driver.wave_out_open = alsa_open;          alsa_driver.wave_out_open = alsa_open_out;
485          alsa_driver.wave_out_close = alsa_close;          alsa_driver.wave_out_close = alsa_close_out;
486          alsa_driver.wave_out_format_supported = alsa_format_supported;          alsa_driver.wave_out_format_supported = alsa_format_supported;
487          alsa_driver.wave_out_set_format = alsa_set_format;          alsa_driver.wave_out_set_format = alsa_set_format_out;
488          alsa_driver.wave_out_volume = rdpsnd_dsp_softvol_set;          alsa_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
489    
490            alsa_driver.wave_in_open = alsa_open_in;
491            alsa_driver.wave_in_close = alsa_close_in;
492            alsa_driver.wave_in_format_supported = alsa_format_supported;
493            alsa_driver.wave_in_set_format = alsa_set_format_in;
494            alsa_driver.wave_in_volume = NULL;      /* FIXME */
495    
496          alsa_driver.need_byteswap_on_be = 0;          alsa_driver.need_byteswap_on_be = 0;
497          alsa_driver.need_resampling = 0;          alsa_driver.need_resampling = 0;
498    

Legend:
Removed from v.1359  
changed lines
  Added in v.1360

  ViewVC Help
Powered by ViewVC 1.1.26