VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.3/rdpsnd_alsa.c@ 55121

最後變更 在這個檔案從55121是 55121,由 vboxsync 提交於 10 年 前

rdesktop 1.8.3 unmodified

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 11.0 KB
 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Sound Channel Process Functions - alsa-driver
4 Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 2003-2008
5 Copyright (C) GuoJunBo <[email protected]> 2003
6 Copyright (C) Michael Gernoth <[email protected]> 2006-2008
7 Copyright 2006-2008 Pierre Ossman <[email protected]> for Cendio AB
8
9 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
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23#include "rdesktop.h"
24#include "rdpsnd.h"
25#include "rdpsnd_dsp.h"
26#include <unistd.h>
27#include <fcntl.h>
28#include <errno.h>
29#include <alsa/asoundlib.h>
30#include <sys/time.h>
31
32#define DEFAULTDEVICE "default"
33#define MAX_FRAMES 32
34
35static struct pollfd pfds_out[32];
36static int num_fds_out;
37
38static struct pollfd pfds_in[32];
39static int num_fds_in;
40
41static snd_pcm_t *out_handle = NULL;
42static snd_pcm_t *in_handle = NULL;
43
44static RD_BOOL reopened;
45
46static short samplewidth_out;
47static int audiochannels_out;
48static unsigned int rate_out;
49
50static short samplewidth_in;
51static int audiochannels_in;
52static unsigned int rate_in;
53
54static char *pcm_name;
55
56void alsa_play(void);
57void alsa_record(void);
58
59void
60alsa_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
61{
62 int err;
63 struct pollfd *f;
64
65 if (out_handle && !rdpsnd_queue_empty())
66 {
67 num_fds_out = snd_pcm_poll_descriptors_count(out_handle);
68
69 if (num_fds_out > sizeof(pfds_out) / sizeof(*pfds_out))
70 return;
71
72 err = snd_pcm_poll_descriptors(out_handle, pfds_out, num_fds_out);
73 if (err < 0)
74 return;
75
76 for (f = pfds_out; f < &pfds_out[num_fds_out]; f++)
77 {
78 if (f->events & POLLIN)
79 FD_SET(f->fd, rfds);
80 if (f->events & POLLOUT)
81 FD_SET(f->fd, wfds);
82 if (f->fd > *n && (f->events & (POLLIN | POLLOUT)))
83 *n = f->fd;
84 }
85 }
86
87 if (in_handle)
88 {
89 num_fds_in = snd_pcm_poll_descriptors_count(in_handle);
90
91 if (num_fds_in > sizeof(pfds_in) / sizeof(*pfds_in))
92 return;
93
94 err = snd_pcm_poll_descriptors(in_handle, pfds_in, num_fds_in);
95 if (err < 0)
96 return;
97
98 for (f = pfds_in; f < &pfds_in[num_fds_in]; f++)
99 {
100 if (f->events & POLLIN)
101 FD_SET(f->fd, rfds);
102 if (f->events & POLLOUT)
103 FD_SET(f->fd, wfds);
104 if (f->fd > *n && (f->events & (POLLIN | POLLOUT)))
105 *n = f->fd;
106 }
107 }
108}
109
110void
111alsa_check_fds(fd_set * rfds, fd_set * wfds)
112{
113 struct pollfd *f;
114 int err;
115 unsigned short revents;
116
117 if (out_handle && !rdpsnd_queue_empty())
118 {
119 for (f = pfds_out; f < &pfds_out[num_fds_out]; f++)
120 {
121 f->revents = 0;
122 if (f->fd != -1)
123 {
124 /* Fixme: This doesn't properly deal with things like POLLHUP */
125 if (FD_ISSET(f->fd, rfds))
126 f->revents |= POLLIN;
127 if (FD_ISSET(f->fd, wfds))
128 f->revents |= POLLOUT;
129 }
130 }
131
132 err = snd_pcm_poll_descriptors_revents(out_handle, pfds_out, num_fds_out, &revents);
133 if (err < 0)
134 return;
135
136 if (revents & POLLOUT)
137 alsa_play();
138 }
139
140
141 if (in_handle)
142 {
143 for (f = pfds_in; f < &pfds_in[num_fds_in]; f++)
144 {
145 f->revents = 0;
146 if (f->fd != -1)
147 {
148 /* Fixme: This doesn't properly deal with things like POLLHUP */
149 if (FD_ISSET(f->fd, rfds))
150 f->revents |= POLLIN;
151 if (FD_ISSET(f->fd, wfds))
152 f->revents |= POLLOUT;
153 }
154 }
155
156 err = snd_pcm_poll_descriptors_revents(in_handle, pfds_in, num_fds_in, &revents);
157 if (err < 0)
158 return;
159
160 if (revents & POLLIN)
161 alsa_record();
162 }
163}
164
165static RD_BOOL
166alsa_set_format(snd_pcm_t * pcm, RD_WAVEFORMATEX * pwfx)
167{
168 snd_pcm_hw_params_t *hwparams = NULL;
169 int err;
170 unsigned int buffertime;
171 short samplewidth;
172 int audiochannels;
173 unsigned int rate;
174
175 samplewidth = pwfx->wBitsPerSample / 8;
176
177 if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
178 {
179 error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
180 return False;
181 }
182
183 if ((err = snd_pcm_hw_params_any(pcm, hwparams)) < 0)
184 {
185 error("snd_pcm_hw_params_any: %s\n", snd_strerror(err));
186 return False;
187 }
188
189 if ((err = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
190 {
191 error("snd_pcm_hw_params_set_access: %s\n", snd_strerror(err));
192 return False;
193 }
194
195 if (pwfx->wBitsPerSample == 16)
196 {
197 if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE)) < 0)
198 {
199 error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
200 return False;
201 }
202 }
203 else
204 {
205 if ((err = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S8)) < 0)
206 {
207 error("snd_pcm_hw_params_set_format: %s\n", snd_strerror(err));
208 return False;
209 }
210 }
211
212#if 0
213 if ((err = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 1)) < 0)
214 {
215 error("snd_pcm_hw_params_set_rate_resample: %s\n", snd_strerror(err));
216 return False;
217 }
218#endif
219
220 rate = pwfx->nSamplesPerSec;
221 if ((err = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, 0)) < 0)
222 {
223 error("snd_pcm_hw_params_set_rate_near: %s\n", snd_strerror(err));
224 return False;
225 }
226
227 audiochannels = pwfx->nChannels;
228 if ((err = snd_pcm_hw_params_set_channels(pcm, hwparams, pwfx->nChannels)) < 0)
229 {
230 error("snd_pcm_hw_params_set_channels: %s\n", snd_strerror(err));
231 return False;
232 }
233
234
235 buffertime = 500000; /* microseconds */
236 if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm, hwparams, &buffertime, 0)) < 0)
237 {
238 error("snd_pcm_hw_params_set_buffer_time_near: %s\n", snd_strerror(err));
239 return False;
240 }
241
242 if ((err = snd_pcm_hw_params(pcm, hwparams)) < 0)
243 {
244 error("snd_pcm_hw_params: %s\n", snd_strerror(err));
245 return False;
246 }
247
248 snd_pcm_hw_params_free(hwparams);
249
250 if ((err = snd_pcm_prepare(pcm)) < 0)
251 {
252 error("snd_pcm_prepare: %s\n", snd_strerror(err));
253 return False;
254 }
255
256 reopened = True;
257
258 return True;
259}
260
261RD_BOOL
262alsa_open_out(void)
263{
264 int err;
265
266 if ((err = snd_pcm_open(&out_handle, pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
267 {
268 error("snd_pcm_open: %s\n", snd_strerror(err));
269 return False;
270 }
271
272 reopened = True;
273
274 return True;
275}
276
277void
278alsa_close_out(void)
279{
280 /* Ack all remaining packets */
281 while (!rdpsnd_queue_empty())
282 rdpsnd_queue_next(0);
283
284 if (out_handle)
285 {
286 snd_pcm_close(out_handle);
287 out_handle = NULL;
288 }
289}
290
291RD_BOOL
292alsa_format_supported(RD_WAVEFORMATEX * pwfx)
293{
294#if 0
295 int err;
296 snd_pcm_hw_params_t *hwparams = NULL;
297
298 if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0)
299 {
300 error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
301 return False;
302 }
303
304 if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
305 {
306 error("snd_pcm_hw_params_malloc: %s\n", snd_strerror(err));
307 return False;
308 }
309 snd_pcm_hw_params_free(hwparams);
310#endif
311
312 if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
313 return False;
314 if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
315 return False;
316 if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
317 return False;
318 if ((pwfx->nSamplesPerSec != 44100) && (pwfx->nSamplesPerSec != 22050))
319 return False;
320
321 return True;
322}
323
324RD_BOOL
325alsa_set_format_out(RD_WAVEFORMATEX * pwfx)
326{
327 if (!alsa_set_format(out_handle, pwfx))
328 return False;
329
330 samplewidth_out = pwfx->wBitsPerSample / 8;
331 audiochannels_out = pwfx->nChannels;
332 rate_out = pwfx->nSamplesPerSec;
333
334 return True;
335}
336
337void
338alsa_play(void)
339{
340 struct audio_packet *packet;
341 STREAM out;
342 int len;
343 static long prev_s, prev_us;
344 unsigned int duration;
345 struct timeval tv;
346 int next_tick;
347
348 if (reopened)
349 {
350 reopened = False;
351 gettimeofday(&tv, NULL);
352 prev_s = tv.tv_sec;
353 prev_us = tv.tv_usec;
354 }
355
356 /* We shouldn't be called if the queue is empty, but still */
357 if (rdpsnd_queue_empty())
358 return;
359
360 packet = rdpsnd_queue_current_packet();
361 out = &packet->s;
362
363 next_tick = rdpsnd_queue_next_tick();
364
365 len = (out->end - out->p) / (samplewidth_out * audiochannels_out);
366 if ((len = snd_pcm_writei(out_handle, out->p, ((MAX_FRAMES < len) ? MAX_FRAMES : len))) < 0)
367 {
368 printf("Fooo!\n");
369 snd_pcm_prepare(out_handle);
370 len = 0;
371 }
372 out->p += (len * samplewidth_out * audiochannels_out);
373
374 gettimeofday(&tv, NULL);
375
376 duration = ((tv.tv_sec - prev_s) * 1000000 + (tv.tv_usec - prev_us)) / 1000;
377
378 if (packet->tick > next_tick)
379 next_tick += 65536;
380
381 if ((out->p == out->end) || duration > next_tick - packet->tick + 500)
382 {
383 snd_pcm_sframes_t delay_frames;
384 unsigned long delay_us;
385
386 prev_s = tv.tv_sec;
387 prev_us = tv.tv_usec;
388
389 if (abs((next_tick - packet->tick) - duration) > 20)
390 {
391 DEBUG(("duration: %d, calc: %d, ", duration, next_tick - packet->tick));
392 DEBUG(("last: %d, is: %d, should: %d\n", packet->tick,
393 (packet->tick + duration) % 65536, next_tick % 65536));
394 }
395
396 if (snd_pcm_delay(out_handle, &delay_frames) < 0)
397 delay_frames = out->size / (samplewidth_out * audiochannels_out);
398 if (delay_frames < 0)
399 delay_frames = 0;
400
401 delay_us = delay_frames * (1000000 / rate_out);
402
403 rdpsnd_queue_next(delay_us);
404 }
405}
406
407RD_BOOL
408alsa_open_in(void)
409{
410 int err;
411
412 if ((err =
413 snd_pcm_open(&in_handle, pcm_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0)
414 {
415 error("snd_pcm_open: %s\n", snd_strerror(err));
416 return False;
417 }
418
419 return True;
420}
421
422void
423alsa_close_in(void)
424{
425 if (in_handle)
426 {
427 snd_pcm_close(in_handle);
428 in_handle = NULL;
429 }
430}
431
432RD_BOOL
433alsa_set_format_in(RD_WAVEFORMATEX * pwfx)
434{
435 int err;
436
437 if (!alsa_set_format(in_handle, pwfx))
438 return False;
439
440 if ((err = snd_pcm_start(in_handle)) < 0)
441 {
442 error("snd_pcm_start: %s\n", snd_strerror(err));
443 return False;
444 }
445
446 samplewidth_in = pwfx->wBitsPerSample / 8;
447 audiochannels_in = pwfx->nChannels;
448 rate_in = pwfx->nSamplesPerSec;
449
450 return True;
451}
452
453void
454alsa_record(void)
455{
456 int len;
457 char buffer[32768];
458
459 len = snd_pcm_readi(in_handle, buffer,
460 sizeof(buffer) / (samplewidth_in * audiochannels_in));
461 if (len < 0)
462 {
463 snd_pcm_prepare(in_handle);
464 len = 0;
465 }
466
467 rdpsnd_record(buffer, len * samplewidth_in * audiochannels_in);
468}
469
470struct audio_driver *
471alsa_register(char *options)
472{
473 static struct audio_driver alsa_driver;
474
475 memset(&alsa_driver, 0, sizeof(alsa_driver));
476
477 alsa_driver.name = "alsa";
478 alsa_driver.description = "ALSA output driver, default device: " DEFAULTDEVICE;
479
480 alsa_driver.add_fds = alsa_add_fds;
481 alsa_driver.check_fds = alsa_check_fds;
482
483 alsa_driver.wave_out_open = alsa_open_out;
484 alsa_driver.wave_out_close = alsa_close_out;
485 alsa_driver.wave_out_format_supported = alsa_format_supported;
486 alsa_driver.wave_out_set_format = alsa_set_format_out;
487 alsa_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
488
489 alsa_driver.wave_in_open = alsa_open_in;
490 alsa_driver.wave_in_close = alsa_close_in;
491 alsa_driver.wave_in_format_supported = alsa_format_supported;
492 alsa_driver.wave_in_set_format = alsa_set_format_in;
493 alsa_driver.wave_in_volume = NULL; /* FIXME */
494
495 alsa_driver.need_byteswap_on_be = 0;
496 alsa_driver.need_resampling = 0;
497
498 if (options)
499 {
500 pcm_name = xstrdup(options);
501 }
502 else
503 {
504 pcm_name = DEFAULTDEVICE;
505 }
506
507 return &alsa_driver;
508}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette