/[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 1333 by stargo, Tue Nov 7 14:21:39 2006 UTC revision 1364 by jsorg71, Thu Jan 4 04:55:56 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 snd_pcm_t *pcm_handle = NULL;  static struct pollfd pfds_out[32];
37  static snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;  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    
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  BOOL  void alsa_play(void);
58  alsa_open(void)  void alsa_record(void);
59    
60    void
61    alsa_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
62  {  {
63          int err;          int err;
64            struct pollfd *f;
65    
66          if ((err = snd_pcm_open(&pcm_handle, pcm_name, stream, 0)) < 0)          if (out_handle && !rdpsnd_queue_empty())
67          {          {
68                  error("snd_pcm_open: %s\n", snd_strerror(err));                  num_fds_out = snd_pcm_poll_descriptors_count(out_handle);
                 return False;  
         }  
69    
70          g_dsp_fd = 0;                  if (num_fds_out > sizeof(pfds_out) / sizeof(*pfds_out))
71                            return;
72    
73          reopened = True;                  err = snd_pcm_poll_descriptors(out_handle, pfds_out, num_fds_out);
74                    if (err < 0)
75                            return;
76    
77          return True;                  for (f = pfds_out; f < &pfds_out[num_fds_out]; f++)
78  }                  {
79                            if (f->events & POLLIN)
80  void                                  FD_SET(f->fd, rfds);
81  alsa_close(void)                          if (f->events & POLLOUT)
82  {                                  FD_SET(f->fd, wfds);
83          /* Ack all remaining packets */                          if (f->fd > *n && (f->events & (POLLIN | POLLOUT)))
84          while (!rdpsnd_queue_empty())                                  *n = f->fd;
85                  rdpsnd_queue_next(0);                  }
86            }
87    
88          if (pcm_handle)          if (in_handle)
89          {          {
90                  snd_pcm_close(pcm_handle);                  num_fds_in = snd_pcm_poll_descriptors_count(in_handle);
91                  pcm_handle = NULL;  
92                    if (num_fds_in > sizeof(pfds_in) / sizeof(*pfds_in))
93                            return;
94    
95                    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    
111  BOOL  void
112  alsa_format_supported(WAVEFORMATEX * pwfx)  alsa_check_fds(fd_set * rfds, fd_set * wfds)
113  {  {
114  #if 0          struct pollfd *f;
115          int err;          int err;
116          snd_pcm_hw_params_t *hwparams = NULL;          unsigned short revents;
117    
118          if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)          if (out_handle && !rdpsnd_queue_empty())
119          {          {
120                  error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));                  for (f = pfds_out; f < &pfds_out[num_fds_out]; f++)
121                  return False;                  {
122                            f->revents = 0;
123                            if (f->fd != -1)
124                            {
125                                    /* Fixme: This doesn't properly deal with things like POLLHUP */
126                                    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(out_handle, pfds_out, num_fds_out, &revents);
134                    if (err < 0)
135                            return;
136    
137                    if (revents & POLLOUT)
138                            alsa_play();
139          }          }
140    
141          if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)  
142            if (in_handle)
143          {          {
144                  error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));                  for (f = pfds_in; f < &pfds_in[num_fds_in]; f++)
145                  return False;                  {
146          }                          f->revents = 0;
147          snd_pcm_hw_params_free(hwparams);                          if (f->fd != -1)
148  #endif                          {
149                                    /* Fixme: This doesn't properly deal with things like POLLHUP */
150                                    if (FD_ISSET(f->fd, rfds))
151                                            f->revents |= POLLIN;
152                                    if (FD_ISSET(f->fd, wfds))
153                                            f->revents |= POLLOUT;
154                            }
155                    }
156    
157          if (pwfx->wFormatTag != WAVE_FORMAT_PCM)                  err = snd_pcm_poll_descriptors_revents(in_handle, pfds_in, num_fds_in, &revents);
158                  return False;                  if (err < 0)
159          if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))                          return;
                 return False;  
         if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))  
                 return False;  
         if ((pwfx->nSamplesPerSec != 44100) && (pwfx->nSamplesPerSec != 22050))  
                 return False;  
160    
161          return True;                  if (revents & POLLIN)
162                            alsa_record();
163            }
164  }  }
165    
166  BOOL  static BOOL
167  alsa_set_format(WAVEFORMATEX * pwfx)  alsa_set_format(snd_pcm_t * pcm, RD_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 120  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 135  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 144  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 153  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 161  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 176  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 191  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 202  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 221  alsa_play(void) Line 354  alsa_play(void)
354                  prev_us = tv.tv_usec;                  prev_us = tv.tv_usec;
355          }          }
356    
357            /* We shouldn't be called if the queue is empty, but still */
358          if (rdpsnd_queue_empty())          if (rdpsnd_queue_empty())
         {  
                 g_dsp_busy = 0;  
359                  return;                  return;
         }  
360    
361          packet = rdpsnd_queue_current_packet();          packet = rdpsnd_queue_current_packet();
362          out = &packet->s;          out = &packet->s;
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 262  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          g_dsp_busy = 1;          rdpsnd_record(buffer, len * samplewidth_in * audiochannels_in);
         return;  
469  }  }
470    
471  struct audio_driver *  struct audio_driver *
# Line 281  alsa_register(char *options) Line 473  alsa_register(char *options)
473  {  {
474          static struct audio_driver alsa_driver;          static struct audio_driver alsa_driver;
475    
476          alsa_driver.wave_out_open = alsa_open;          memset(&alsa_driver, 0, sizeof(alsa_driver));
477          alsa_driver.wave_out_close = alsa_close;  
478            alsa_driver.name = "alsa";
479            alsa_driver.description = "ALSA output driver, default device: " DEFAULTDEVICE;
480    
481            alsa_driver.add_fds = alsa_add_fds;
482            alsa_driver.check_fds = alsa_check_fds;
483    
484            alsa_driver.wave_out_open = alsa_open_out;
485            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          alsa_driver.wave_out_play = alsa_play;  
490          alsa_driver.name = xstrdup("alsa");          alsa_driver.wave_in_open = alsa_open_in;
491          alsa_driver.description = xstrdup("ALSA output driver, default device: " DEFAULTDEVICE);          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;
         alsa_driver.next = NULL;  
498    
499          if (options)          if (options)
500          {          {
# Line 299  alsa_register(char *options) Line 502  alsa_register(char *options)
502          }          }
503          else          else
504          {          {
505                  pcm_name = xstrdup(DEFAULTDEVICE);                  pcm_name = DEFAULTDEVICE;
506          }          }
507    
508          return &alsa_driver;          return &alsa_driver;

Legend:
Removed from v.1333  
changed lines
  Added in v.1364

  ViewVC Help
Powered by ViewVC 1.1.26