22 |
|
|
23 |
#include "rdesktop.h" |
#include "rdesktop.h" |
24 |
#include "rdpsnd.h" |
#include "rdpsnd.h" |
25 |
|
#include "rdpsnd_dsp.h" |
26 |
#include <unistd.h> |
#include <unistd.h> |
27 |
#include <fcntl.h> |
#include <fcntl.h> |
28 |
#include <errno.h> |
#include <errno.h> |
32 |
#define DEFAULTDEVICE "default" |
#define DEFAULTDEVICE "default" |
33 |
#define MAX_FRAMES 32 |
#define MAX_FRAMES 32 |
34 |
|
|
35 |
|
static struct pollfd pfds[32]; |
36 |
|
static int num_fds; |
37 |
|
|
38 |
static snd_pcm_t *pcm_handle = NULL; |
static snd_pcm_t *pcm_handle = NULL; |
39 |
static snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; |
static snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; |
40 |
static BOOL reopened; |
static BOOL reopened; |
41 |
static short samplewidth; |
static short samplewidth; |
42 |
static int audiochannels; |
static int audiochannels; |
43 |
|
static unsigned int rate; |
44 |
static char *pcm_name; |
static char *pcm_name; |
45 |
|
|
46 |
|
void alsa_play(void); |
47 |
|
|
48 |
|
void |
49 |
|
alsa_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) |
50 |
|
{ |
51 |
|
int err; |
52 |
|
struct pollfd *f; |
53 |
|
|
54 |
|
if (!pcm_handle) |
55 |
|
return; |
56 |
|
|
57 |
|
if (rdpsnd_queue_empty()) |
58 |
|
return; |
59 |
|
|
60 |
|
num_fds = snd_pcm_poll_descriptors_count(pcm_handle); |
61 |
|
|
62 |
|
if (num_fds > sizeof(pfds) / sizeof(*pfds)) |
63 |
|
return; |
64 |
|
|
65 |
|
err = snd_pcm_poll_descriptors(pcm_handle, pfds, num_fds); |
66 |
|
if (err < 0) |
67 |
|
return; |
68 |
|
|
69 |
|
for (f = pfds; f < &pfds[num_fds]; f++) |
70 |
|
{ |
71 |
|
if (f->events & POLLIN) |
72 |
|
FD_SET(f->fd, rfds); |
73 |
|
if (f->events & POLLOUT) |
74 |
|
FD_SET(f->fd, wfds); |
75 |
|
if (f->fd > *n && (f->events & (POLLIN | POLLOUT))) |
76 |
|
*n = f->fd; |
77 |
|
} |
78 |
|
} |
79 |
|
|
80 |
|
void |
81 |
|
alsa_check_fds(fd_set * rfds, fd_set * wfds) |
82 |
|
{ |
83 |
|
struct pollfd *f; |
84 |
|
int err; |
85 |
|
unsigned short revents; |
86 |
|
|
87 |
|
if (!pcm_handle) |
88 |
|
return; |
89 |
|
|
90 |
|
for (f = pfds; f < &pfds[num_fds]; f++) |
91 |
|
{ |
92 |
|
f->revents = 0; |
93 |
|
if (f->fd != -1) |
94 |
|
{ |
95 |
|
/* Fixme: This doesn't properly deal with things like POLLHUP */ |
96 |
|
if (FD_ISSET(f->fd, rfds)) |
97 |
|
f->revents |= POLLIN; |
98 |
|
if (FD_ISSET(f->fd, wfds)) |
99 |
|
f->revents |= POLLOUT; |
100 |
|
} |
101 |
|
} |
102 |
|
|
103 |
|
err = snd_pcm_poll_descriptors_revents(pcm_handle, pfds, num_fds, &revents); |
104 |
|
if (err < 0) |
105 |
|
return; |
106 |
|
|
107 |
|
if (revents & POLLOUT) |
108 |
|
alsa_play(); |
109 |
|
} |
110 |
|
|
111 |
BOOL |
BOOL |
112 |
alsa_open(void) |
alsa_open(void) |
113 |
{ |
{ |
119 |
return False; |
return False; |
120 |
} |
} |
121 |
|
|
|
g_dsp_fd = 0; |
|
|
rdpsnd_queue_init(); |
|
|
|
|
122 |
reopened = True; |
reopened = True; |
123 |
|
|
124 |
return True; |
return True; |
129 |
{ |
{ |
130 |
/* Ack all remaining packets */ |
/* Ack all remaining packets */ |
131 |
while (!rdpsnd_queue_empty()) |
while (!rdpsnd_queue_empty()) |
132 |
{ |
rdpsnd_queue_next(0); |
|
rdpsnd_send_completion(rdpsnd_queue_current_packet()->tick, |
|
|
rdpsnd_queue_current_packet()->index); |
|
|
rdpsnd_queue_next(); |
|
|
} |
|
133 |
|
|
134 |
if (pcm_handle) |
if (pcm_handle) |
135 |
{ |
{ |
|
snd_pcm_drop(pcm_handle); |
|
136 |
snd_pcm_close(pcm_handle); |
snd_pcm_close(pcm_handle); |
137 |
|
pcm_handle = NULL; |
138 |
} |
} |
139 |
} |
} |
140 |
|
|
175 |
alsa_set_format(WAVEFORMATEX * pwfx) |
alsa_set_format(WAVEFORMATEX * pwfx) |
176 |
{ |
{ |
177 |
snd_pcm_hw_params_t *hwparams = NULL; |
snd_pcm_hw_params_t *hwparams = NULL; |
|
unsigned int rate, exact_rate; |
|
178 |
int err; |
int err; |
179 |
unsigned int buffertime; |
unsigned int buffertime; |
180 |
|
|
226 |
} |
} |
227 |
#endif |
#endif |
228 |
|
|
229 |
exact_rate = rate = pwfx->nSamplesPerSec; |
rate = pwfx->nSamplesPerSec; |
230 |
if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0)) < 0) |
if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, 0)) < 0) |
231 |
{ |
{ |
232 |
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)); |
233 |
return False; |
return False; |
269 |
} |
} |
270 |
|
|
271 |
void |
void |
|
alsa_volume(uint16 left, uint16 right) |
|
|
{ |
|
|
static int warned = 0; |
|
|
|
|
|
if (!warned) |
|
|
{ |
|
|
warning("volume changes currently not supported with alsa-output\n"); |
|
|
warned = 1; |
|
|
} |
|
|
} |
|
|
|
|
|
void |
|
272 |
alsa_play(void) |
alsa_play(void) |
273 |
{ |
{ |
274 |
struct audio_packet *packet; |
struct audio_packet *packet; |
287 |
prev_us = tv.tv_usec; |
prev_us = tv.tv_usec; |
288 |
} |
} |
289 |
|
|
290 |
|
/* We shouldn't be called if the queue is empty, but still */ |
291 |
if (rdpsnd_queue_empty()) |
if (rdpsnd_queue_empty()) |
|
{ |
|
|
g_dsp_busy = 0; |
|
292 |
return; |
return; |
|
} |
|
293 |
|
|
294 |
packet = rdpsnd_queue_current_packet(); |
packet = rdpsnd_queue_current_packet(); |
295 |
out = &packet->s; |
out = &packet->s; |
313 |
|
|
314 |
if ((out->p == out->end) || duration > next_tick - packet->tick + 500) |
if ((out->p == out->end) || duration > next_tick - packet->tick + 500) |
315 |
{ |
{ |
316 |
|
snd_pcm_sframes_t delay_frames; |
317 |
|
unsigned long delay_us; |
318 |
|
|
319 |
prev_s = tv.tv_sec; |
prev_s = tv.tv_sec; |
320 |
prev_us = tv.tv_usec; |
prev_us = tv.tv_usec; |
321 |
|
|
326 |
(packet->tick + duration) % 65536, next_tick % 65536)); |
(packet->tick + duration) % 65536, next_tick % 65536)); |
327 |
} |
} |
328 |
|
|
329 |
rdpsnd_send_completion(((packet->tick + duration) % 65536), packet->index); |
if (snd_pcm_delay(pcm_handle, &delay_frames) < 0) |
330 |
rdpsnd_queue_next(); |
delay_frames = out->size / (samplewidth * audiochannels); |
331 |
} |
if (delay_frames < 0) |
332 |
|
delay_frames = 0; |
333 |
|
|
334 |
g_dsp_busy = 1; |
delay_us = delay_frames * (1000000 / rate); |
|
return; |
|
|
} |
|
335 |
|
|
336 |
static struct audio_driver alsa_driver = { |
rdpsnd_queue_next(delay_us); |
337 |
wave_out_write:rdpsnd_queue_write, |
} |
338 |
wave_out_open:alsa_open, |
} |
|
wave_out_close:alsa_close, |
|
|
wave_out_format_supported:alsa_format_supported, |
|
|
wave_out_set_format:alsa_set_format, |
|
|
wave_out_volume:alsa_volume, |
|
|
wave_out_play:alsa_play, |
|
|
name:"alsa", |
|
|
description:"ALSA output driver, default device: " DEFAULTDEVICE, |
|
|
next:NULL, |
|
|
}; |
|
339 |
|
|
340 |
struct audio_driver * |
struct audio_driver * |
341 |
alsa_register(char *options) |
alsa_register(char *options) |
342 |
{ |
{ |
343 |
|
static struct audio_driver alsa_driver; |
344 |
|
|
345 |
|
memset(&alsa_driver, 0, sizeof(alsa_driver)); |
346 |
|
|
347 |
|
alsa_driver.name = "alsa"; |
348 |
|
alsa_driver.description = "ALSA output driver, default device: " DEFAULTDEVICE; |
349 |
|
|
350 |
|
alsa_driver.add_fds = alsa_add_fds; |
351 |
|
alsa_driver.check_fds = alsa_check_fds; |
352 |
|
|
353 |
|
alsa_driver.wave_out_open = alsa_open; |
354 |
|
alsa_driver.wave_out_close = alsa_close; |
355 |
|
alsa_driver.wave_out_format_supported = alsa_format_supported; |
356 |
|
alsa_driver.wave_out_set_format = alsa_set_format; |
357 |
|
alsa_driver.wave_out_volume = rdpsnd_dsp_softvol_set; |
358 |
|
|
359 |
|
alsa_driver.need_byteswap_on_be = 0; |
360 |
|
alsa_driver.need_resampling = 0; |
361 |
|
|
362 |
if (options) |
if (options) |
363 |
{ |
{ |
364 |
pcm_name = xstrdup(options); |
pcm_name = xstrdup(options); |
365 |
} |
} |
366 |
else |
else |
367 |
{ |
{ |
368 |
pcm_name = xstrdup(DEFAULTDEVICE); |
pcm_name = DEFAULTDEVICE; |
369 |
} |
} |
370 |
|
|
371 |
return &alsa_driver; |
return &alsa_driver; |