/[rdesktop]/sourceforge.net/trunk/rdesktop/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

Annotation of /sourceforge.net/trunk/rdesktop/rdpsnd_alsa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1255 - (hide annotations)
Sun Sep 17 11:04:50 2006 UTC (17 years, 8 months ago) by stargo
File MIME type: text/plain
File size: 7137 byte(s)
allow multiple sound-drivers to be compiled in simultaneously and
make the runtime selectable

1 stargo 1253 /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.
3     Sound Channel Process Functions - alsa-driver
4     Copyright (C) Matthew Chapman 2003
5     Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6     Copyright (C) Michael Gernoth mike@zerfleddert.de 2006
7    
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12    
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     GNU General Public License for more details.
17    
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     */
22    
23     #include "rdesktop.h"
24 stargo 1254 #include "rdpsnd.h"
25 stargo 1253 #include <unistd.h>
26     #include <fcntl.h>
27     #include <errno.h>
28     #include <alsa/asoundlib.h>
29     #include <sys/time.h>
30    
31     #define DEFAULTDEVICE "default"
32     #define MAX_FRAMES 32
33    
34     static snd_pcm_t *pcm_handle = NULL;
35     static snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
36     static BOOL reopened;
37     static short samplewidth;
38     static int audiochannels;
39 stargo 1255 static char *pcm_name;
40 stargo 1253
41     BOOL
42 stargo 1255 alsa_open(void)
43 stargo 1253 {
44     int err;
45    
46     if ((err = snd_pcm_open(&pcm_handle, pcm_name, stream, 0)) < 0)
47     {
48     error("snd_pcm_open: %s\n", snd_strerror(err));
49     return False;
50     }
51    
52     g_dsp_fd = 0;
53 stargo 1254 rdpsnd_queue_init();
54 stargo 1253
55     reopened = True;
56    
57     return True;
58     }
59    
60     void
61 stargo 1255 alsa_close(void)
62 stargo 1253 {
63     /* Ack all remaining packets */
64 stargo 1254 while (!rdpsnd_queue_empty())
65 stargo 1253 {
66 stargo 1254 rdpsnd_send_completion(rdpsnd_queue_current_packet()->tick,
67     rdpsnd_queue_current_packet()->index);
68     rdpsnd_queue_next();
69 stargo 1253 }
70    
71     if (pcm_handle)
72     {
73     snd_pcm_drop(pcm_handle);
74     snd_pcm_close(pcm_handle);
75     }
76     }
77    
78     BOOL
79 stargo 1255 alsa_format_supported(WAVEFORMATEX * pwfx)
80 stargo 1253 {
81     #if 0
82     int err;
83     snd_pcm_hw_params_t *hwparams = NULL;
84    
85     if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
86     {
87     error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
88     return False;
89     }
90    
91     if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
92     {
93     error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
94     return False;
95     }
96     snd_pcm_hw_params_free(hwparams);
97     #endif
98    
99     if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
100     return False;
101     if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
102     return False;
103     if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
104     return False;
105     if ((pwfx->nSamplesPerSec != 44100) && (pwfx->nSamplesPerSec != 22050))
106     return False;
107    
108     return True;
109     }
110    
111     BOOL
112 stargo 1255 alsa_set_format(WAVEFORMATEX * pwfx)
113 stargo 1253 {
114     snd_pcm_hw_params_t *hwparams = NULL;
115     unsigned int rate, exact_rate;
116     int err;
117     unsigned int buffertime;
118    
119     samplewidth = pwfx->wBitsPerSample / 8;
120    
121     if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
122     {
123     error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
124     return False;
125     }
126    
127     if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
128     {
129     error("snd_pcm_hw_params_any: %s\n", snd_strerror(err));
130     return False;
131     }
132    
133     if ((err =
134     snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
135     {
136     error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err));
137     return False;
138     }
139    
140     if (pwfx->wBitsPerSample == 16)
141     {
142     if ((err =
143     snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
144     {
145     error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
146     return False;
147     }
148     }
149     else
150     {
151     if ((err =
152     snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S8)) < 0)
153     {
154     error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
155     return False;
156     }
157     }
158    
159     #if 0
160     if ((err = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 1)) < 0)
161     {
162     error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err));
163     return False;
164     }
165     #endif
166    
167     exact_rate = rate = pwfx->nSamplesPerSec;
168     if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0)) < 0)
169     {
170     error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err));
171     return False;
172     }
173    
174     audiochannels = pwfx->nChannels;
175     if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, pwfx->nChannels)) < 0)
176     {
177     error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err));
178     return False;
179     }
180    
181    
182     buffertime = 500000; /* microseconds */
183     if ((err =
184     snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &buffertime, 0)) < 0)
185     {
186     error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err));
187     return False;
188     }
189    
190     if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
191     {
192     error("snd_pcm_hw_params: %s\n", snd_strerror(err));
193     return False;
194     }
195    
196     snd_pcm_hw_params_free(hwparams);
197    
198     if ((err = snd_pcm_prepare(pcm_handle)) < 0)
199     {
200     error("snd_pcm_prepare: %s\n", snd_strerror(err));
201     return False;
202     }
203    
204     reopened = True;
205    
206     return True;
207     }
208    
209     void
210 stargo 1255 alsa_volume(uint16 left, uint16 right)
211 stargo 1253 {
212     static int warned = 0;
213    
214     if (!warned)
215     {
216 stargo 1255 warning("volume changes currently not supported with alsa-output\n");
217 stargo 1253 warned = 1;
218     }
219     }
220    
221     void
222 stargo 1255 alsa_play(void)
223 stargo 1253 {
224     struct audio_packet *packet;
225     STREAM out;
226     int len;
227     static long prev_s, prev_us;
228     unsigned int duration;
229     struct timeval tv;
230     int next_tick;
231    
232     if (reopened)
233     {
234     reopened = False;
235     gettimeofday(&tv, NULL);
236     prev_s = tv.tv_sec;
237     prev_us = tv.tv_usec;
238     }
239    
240 stargo 1254 if (rdpsnd_queue_empty())
241 stargo 1253 {
242     g_dsp_busy = 0;
243     return;
244     }
245    
246 stargo 1254 packet = rdpsnd_queue_current_packet();
247 stargo 1253 out = &packet->s;
248    
249 stargo 1254 next_tick = rdpsnd_queue_next_tick();
250 stargo 1253
251     len = (out->end - out->p) / (samplewidth * audiochannels);
252     if ((len = snd_pcm_writei(pcm_handle, out->p, ((MAX_FRAMES < len) ? MAX_FRAMES : len))) < 0)
253     {
254     snd_pcm_prepare(pcm_handle);
255     len = 0;
256     }
257     out->p += (len * samplewidth * audiochannels);
258    
259     gettimeofday(&tv, NULL);
260    
261     duration = ((tv.tv_sec - prev_s) * 1000000 + (tv.tv_usec - prev_us)) / 1000;
262    
263     if (packet->tick > next_tick)
264     next_tick += 65536;
265    
266     if ((out->p == out->end) || duration > next_tick - packet->tick + 500)
267     {
268     prev_s = tv.tv_sec;
269     prev_us = tv.tv_usec;
270    
271     if (abs((next_tick - packet->tick) - duration) > 20)
272     {
273     DEBUG(("duration: %d, calc: %d, ", duration, next_tick - packet->tick));
274     DEBUG(("last: %d, is: %d, should: %d\n", packet->tick,
275     (packet->tick + duration) % 65536, next_tick % 65536));
276     }
277    
278 stargo 1254 rdpsnd_send_completion(((packet->tick + duration) % 65536), packet->index);
279     rdpsnd_queue_next();
280 stargo 1253 }
281    
282     g_dsp_busy = 1;
283     return;
284     }
285 stargo 1255
286     static struct audio_driver alsa_driver = {
287     wave_out_write:rdpsnd_queue_write,
288     wave_out_open:alsa_open,
289     wave_out_close:alsa_close,
290     wave_out_format_supported:alsa_format_supported,
291     wave_out_set_format:alsa_set_format,
292     wave_out_volume:alsa_volume,
293     wave_out_play:alsa_play,
294     name:"alsa",
295     description:"ALSA output driver, default device: " DEFAULTDEVICE,
296     next:NULL,
297     };
298    
299     struct audio_driver *
300     alsa_register(char *options)
301     {
302     if (options)
303     {
304     pcm_name = xstrdup(options);
305     }
306     else
307     {
308     pcm_name = xstrdup(DEFAULTDEVICE);
309     }
310    
311     return &alsa_driver;
312     }

  ViewVC Help
Powered by ViewVC 1.1.26