Rewrite the queue management a bit so that blocks are not completed until
they have finished playing. This also makes the queue system mandatory for all backends. git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@1301 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
parent
227fad6d96
commit
22d88645ff
7
proto.h
7
proto.h
@ -163,15 +163,14 @@ struct async_iorequest *rdpdr_remove_iorequest(struct async_iorequest *prev,
|
|||||||
void rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out);
|
void rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out);
|
||||||
BOOL rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status);
|
BOOL rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status);
|
||||||
/* rdpsnd.c */
|
/* rdpsnd.c */
|
||||||
void rdpsnd_send_completion(uint16 tick, uint8 packet_index);
|
|
||||||
BOOL rdpsnd_init(char *optarg);
|
BOOL rdpsnd_init(char *optarg);
|
||||||
void rdpsnd_show_help(void);
|
void rdpsnd_show_help(void);
|
||||||
void rdpsnd_play(void);
|
void rdpsnd_play(void);
|
||||||
void rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index);
|
void rdpsnd_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv);
|
||||||
|
void rdpsnd_check_fds(fd_set * rfds, fd_set * wfds);
|
||||||
struct audio_packet *rdpsnd_queue_current_packet(void);
|
struct audio_packet *rdpsnd_queue_current_packet(void);
|
||||||
BOOL rdpsnd_queue_empty(void);
|
BOOL rdpsnd_queue_empty(void);
|
||||||
void rdpsnd_queue_init(void);
|
void rdpsnd_queue_next(unsigned long completed_in_us);
|
||||||
void rdpsnd_queue_next(void);
|
|
||||||
int rdpsnd_queue_next_tick(void);
|
int rdpsnd_queue_next_tick(void);
|
||||||
/* secure.c */
|
/* secure.c */
|
||||||
void sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt);
|
void sec_hash_48(uint8 * out, uint8 * in, uint8 * salt1, uint8 * salt2, uint8 salt);
|
||||||
|
125
rdpsnd.c
125
rdpsnd.c
@ -47,11 +47,16 @@ static BOOL device_open;
|
|||||||
static WAVEFORMATEX formats[MAX_FORMATS];
|
static WAVEFORMATEX formats[MAX_FORMATS];
|
||||||
static unsigned int format_count;
|
static unsigned int format_count;
|
||||||
static unsigned int current_format;
|
static unsigned int current_format;
|
||||||
unsigned int queue_hi, queue_lo;
|
unsigned int queue_hi, queue_lo, queue_pending;
|
||||||
struct audio_packet packet_queue[MAX_QUEUE];
|
struct audio_packet packet_queue[MAX_QUEUE];
|
||||||
|
|
||||||
void (*wave_out_play) (void);
|
void (*wave_out_play) (void);
|
||||||
|
|
||||||
|
static void rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index);
|
||||||
|
static void rdpsnd_queue_init(void);
|
||||||
|
static void rdpsnd_queue_complete_pending(void);
|
||||||
|
static long rdpsnd_queue_next_completion(void);
|
||||||
|
|
||||||
static STREAM
|
static STREAM
|
||||||
rdpsnd_init_packet(uint16 type, uint16 size)
|
rdpsnd_init_packet(uint16 type, uint16 size)
|
||||||
{
|
{
|
||||||
@ -74,7 +79,7 @@ rdpsnd_send(STREAM s)
|
|||||||
channel_send(s, rdpsnd_channel);
|
channel_send(s, rdpsnd_channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
rdpsnd_send_completion(uint16 tick, uint8 packet_index)
|
rdpsnd_send_completion(uint16 tick, uint8 packet_index)
|
||||||
{
|
{
|
||||||
STREAM s;
|
STREAM s;
|
||||||
@ -232,8 +237,7 @@ rdpsnd_process(STREAM s)
|
|||||||
/* Insert the 4 missing bytes retrieved from last RDPSND_WRITE */
|
/* Insert the 4 missing bytes retrieved from last RDPSND_WRITE */
|
||||||
memcpy(s->data, missing_bytes, 4);
|
memcpy(s->data, missing_bytes, 4);
|
||||||
|
|
||||||
current_driver->
|
rdpsnd_queue_write(rdpsnd_dsp_process
|
||||||
wave_out_write(rdpsnd_dsp_process
|
|
||||||
(s, current_driver, &formats[current_format]), tick,
|
(s, current_driver, &formats[current_format]), tick,
|
||||||
packet_index);
|
packet_index);
|
||||||
awaiting_data_packet = False;
|
awaiting_data_packet = False;
|
||||||
@ -362,6 +366,8 @@ rdpsnd_init(char *optarg)
|
|||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rdpsnd_queue_init();
|
||||||
|
|
||||||
if (optarg != NULL && strlen(optarg) > 0)
|
if (optarg != NULL && strlen(optarg) > 0)
|
||||||
{
|
{
|
||||||
driver = options = optarg;
|
driver = options = optarg;
|
||||||
@ -424,12 +430,46 @@ rdpsnd_play(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
rdpsnd_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
|
||||||
|
{
|
||||||
|
long next_pending;
|
||||||
|
|
||||||
|
if (g_dsp_busy)
|
||||||
|
{
|
||||||
|
FD_SET(g_dsp_fd, wfds);
|
||||||
|
*n = (g_dsp_fd > *n) ? g_dsp_fd : *n;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_pending = rdpsnd_queue_next_completion();
|
||||||
|
if (next_pending >= 0)
|
||||||
|
{
|
||||||
|
long cur_timeout;
|
||||||
|
|
||||||
|
cur_timeout = tv->tv_sec * 1000000 + tv->tv_usec;
|
||||||
|
if (cur_timeout > next_pending)
|
||||||
|
{
|
||||||
|
tv->tv_sec = next_pending / 1000000;
|
||||||
|
tv->tv_usec = next_pending % 1000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rdpsnd_check_fds(fd_set * rfds, fd_set * wfds)
|
||||||
|
{
|
||||||
|
rdpsnd_queue_complete_pending();
|
||||||
|
|
||||||
|
if (g_dsp_busy && FD_ISSET(g_dsp_fd, wfds))
|
||||||
|
rdpsnd_play();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index)
|
rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index)
|
||||||
{
|
{
|
||||||
struct audio_packet *packet = &packet_queue[queue_hi];
|
struct audio_packet *packet = &packet_queue[queue_hi];
|
||||||
unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;
|
unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;
|
||||||
|
|
||||||
if (next_hi == queue_lo)
|
if (next_hi == queue_pending)
|
||||||
{
|
{
|
||||||
error("No space to queue audio packet\n");
|
error("No space to queue audio packet\n");
|
||||||
return;
|
return;
|
||||||
@ -441,6 +481,8 @@ rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index)
|
|||||||
packet->tick = tick;
|
packet->tick = tick;
|
||||||
packet->index = index;
|
packet->index = index;
|
||||||
|
|
||||||
|
gettimeofday(&packet->arrive_tv, NULL);
|
||||||
|
|
||||||
if (!g_dsp_busy)
|
if (!g_dsp_busy)
|
||||||
current_driver->wave_out_play();
|
current_driver->wave_out_play();
|
||||||
}
|
}
|
||||||
@ -457,17 +499,30 @@ rdpsnd_queue_empty(void)
|
|||||||
return (queue_lo == queue_hi);
|
return (queue_lo == queue_hi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
rdpsnd_queue_init(void)
|
rdpsnd_queue_init(void)
|
||||||
{
|
{
|
||||||
queue_lo = queue_hi = 0;
|
queue_pending = queue_lo = queue_hi = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rdpsnd_queue_next(void)
|
rdpsnd_queue_next(unsigned long completed_in_us)
|
||||||
{
|
{
|
||||||
xfree(packet_queue[queue_lo].s.data);
|
struct audio_packet *packet;
|
||||||
|
|
||||||
|
assert(!rdpsnd_queue_empty());
|
||||||
|
|
||||||
|
packet = &packet_queue[queue_lo];
|
||||||
|
|
||||||
|
gettimeofday(&packet->completion_tv, NULL);
|
||||||
|
|
||||||
|
packet->completion_tv.tv_usec += completed_in_us;
|
||||||
|
packet->completion_tv.tv_sec += packet->completion_tv.tv_usec / 1000000;
|
||||||
|
packet->completion_tv.tv_usec %= 1000000;
|
||||||
|
|
||||||
queue_lo = (queue_lo + 1) % MAX_QUEUE;
|
queue_lo = (queue_lo + 1) % MAX_QUEUE;
|
||||||
|
|
||||||
|
rdpsnd_queue_complete_pending();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -482,3 +537,55 @@ rdpsnd_queue_next_tick(void)
|
|||||||
return (packet_queue[queue_lo].tick + 65535) % 65536;
|
return (packet_queue[queue_lo].tick + 65535) % 65536;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rdpsnd_queue_complete_pending(void)
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
long elapsed;
|
||||||
|
struct audio_packet *packet;
|
||||||
|
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
|
||||||
|
while (queue_pending != queue_lo)
|
||||||
|
{
|
||||||
|
packet = &packet_queue[queue_pending];
|
||||||
|
|
||||||
|
if (now.tv_sec < packet->completion_tv.tv_sec)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((now.tv_sec == packet->completion_tv.tv_sec) &&
|
||||||
|
(now.tv_usec < packet->completion_tv.tv_usec))
|
||||||
|
break;
|
||||||
|
|
||||||
|
elapsed = (packet->completion_tv.tv_sec - packet->arrive_tv.tv_sec) * 1000000 +
|
||||||
|
(packet->completion_tv.tv_usec - packet->arrive_tv.tv_usec);
|
||||||
|
|
||||||
|
xfree(packet->s.data);
|
||||||
|
rdpsnd_send_completion((packet->tick + elapsed) % 65536, packet->index);
|
||||||
|
queue_pending = (queue_pending + 1) % MAX_QUEUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long
|
||||||
|
rdpsnd_queue_next_completion(void)
|
||||||
|
{
|
||||||
|
struct audio_packet *packet;
|
||||||
|
long remaining;
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
if (queue_pending == queue_lo)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
|
||||||
|
packet = &packet_queue[queue_pending];
|
||||||
|
|
||||||
|
remaining = (packet->completion_tv.tv_sec - now.tv_sec) * 1000000 +
|
||||||
|
(packet->completion_tv.tv_usec - now.tv_usec);
|
||||||
|
|
||||||
|
if (remaining < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return remaining;
|
||||||
|
}
|
||||||
|
4
rdpsnd.h
4
rdpsnd.h
@ -23,11 +23,13 @@ struct audio_packet
|
|||||||
struct stream s;
|
struct stream s;
|
||||||
uint16 tick;
|
uint16 tick;
|
||||||
uint8 index;
|
uint8 index;
|
||||||
|
|
||||||
|
struct timeval arrive_tv;
|
||||||
|
struct timeval completion_tv;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct audio_driver
|
struct audio_driver
|
||||||
{
|
{
|
||||||
void (*wave_out_write) (STREAM s, uint16 tick, uint8 index);
|
|
||||||
BOOL(*wave_out_open) (void);
|
BOOL(*wave_out_open) (void);
|
||||||
void (*wave_out_close) (void);
|
void (*wave_out_close) (void);
|
||||||
BOOL(*wave_out_format_supported) (WAVEFORMATEX * pwfx);
|
BOOL(*wave_out_format_supported) (WAVEFORMATEX * pwfx);
|
||||||
|
@ -37,6 +37,7 @@ static snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
|
|||||||
static BOOL reopened;
|
static BOOL reopened;
|
||||||
static short samplewidth;
|
static short samplewidth;
|
||||||
static int audiochannels;
|
static int audiochannels;
|
||||||
|
static unsigned int rate;
|
||||||
static char *pcm_name;
|
static char *pcm_name;
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
@ -51,7 +52,6 @@ alsa_open(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_dsp_fd = 0;
|
g_dsp_fd = 0;
|
||||||
rdpsnd_queue_init();
|
|
||||||
|
|
||||||
reopened = True;
|
reopened = True;
|
||||||
|
|
||||||
@ -63,11 +63,7 @@ alsa_close(void)
|
|||||||
{
|
{
|
||||||
/* Ack all remaining packets */
|
/* Ack all remaining packets */
|
||||||
while (!rdpsnd_queue_empty())
|
while (!rdpsnd_queue_empty())
|
||||||
{
|
rdpsnd_queue_next(0);
|
||||||
rdpsnd_send_completion(rdpsnd_queue_current_packet()->tick,
|
|
||||||
rdpsnd_queue_current_packet()->index);
|
|
||||||
rdpsnd_queue_next();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pcm_handle)
|
if (pcm_handle)
|
||||||
{
|
{
|
||||||
@ -113,7 +109,6 @@ BOOL
|
|||||||
alsa_set_format(WAVEFORMATEX * pwfx)
|
alsa_set_format(WAVEFORMATEX * pwfx)
|
||||||
{
|
{
|
||||||
snd_pcm_hw_params_t *hwparams = NULL;
|
snd_pcm_hw_params_t *hwparams = NULL;
|
||||||
unsigned int rate, exact_rate;
|
|
||||||
int err;
|
int err;
|
||||||
unsigned int buffertime;
|
unsigned int buffertime;
|
||||||
|
|
||||||
@ -165,8 +160,8 @@ alsa_set_format(WAVEFORMATEX * pwfx)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
exact_rate = rate = pwfx->nSamplesPerSec;
|
rate = pwfx->nSamplesPerSec;
|
||||||
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)
|
||||||
{
|
{
|
||||||
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));
|
||||||
return False;
|
return False;
|
||||||
@ -254,6 +249,9 @@ alsa_play(void)
|
|||||||
|
|
||||||
if ((out->p == out->end) || duration > next_tick - packet->tick + 500)
|
if ((out->p == out->end) || duration > next_tick - packet->tick + 500)
|
||||||
{
|
{
|
||||||
|
snd_pcm_sframes_t delay_frames;
|
||||||
|
unsigned long delay_us;
|
||||||
|
|
||||||
prev_s = tv.tv_sec;
|
prev_s = tv.tv_sec;
|
||||||
prev_us = tv.tv_usec;
|
prev_us = tv.tv_usec;
|
||||||
|
|
||||||
@ -264,8 +262,14 @@ alsa_play(void)
|
|||||||
(packet->tick + duration) % 65536, next_tick % 65536));
|
(packet->tick + duration) % 65536, next_tick % 65536));
|
||||||
}
|
}
|
||||||
|
|
||||||
rdpsnd_send_completion(((packet->tick + duration) % 65536), packet->index);
|
if (snd_pcm_delay(pcm_handle, &delay_frames) < 0)
|
||||||
rdpsnd_queue_next();
|
delay_frames = out->size / (samplewidth * audiochannels);
|
||||||
|
if (delay_frames < 0)
|
||||||
|
delay_frames = 0;
|
||||||
|
|
||||||
|
delay_us = delay_frames * (1000000 / rate);
|
||||||
|
|
||||||
|
rdpsnd_queue_next(delay_us);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_dsp_busy = 1;
|
g_dsp_busy = 1;
|
||||||
@ -277,7 +281,6 @@ alsa_register(char *options)
|
|||||||
{
|
{
|
||||||
static struct audio_driver alsa_driver;
|
static struct audio_driver alsa_driver;
|
||||||
|
|
||||||
alsa_driver.wave_out_write = rdpsnd_queue_write;
|
|
||||||
alsa_driver.wave_out_open = alsa_open;
|
alsa_driver.wave_out_open = alsa_open;
|
||||||
alsa_driver.wave_out_close = alsa_close;
|
alsa_driver.wave_out_close = alsa_close;
|
||||||
alsa_driver.wave_out_format_supported = alsa_format_supported;
|
alsa_driver.wave_out_format_supported = alsa_format_supported;
|
||||||
|
@ -65,7 +65,6 @@ libao_open(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_dsp_fd = 0;
|
g_dsp_fd = 0;
|
||||||
rdpsnd_queue_init();
|
|
||||||
|
|
||||||
reopened = True;
|
reopened = True;
|
||||||
|
|
||||||
@ -78,9 +77,7 @@ libao_close(void)
|
|||||||
/* Ack all remaining packets */
|
/* Ack all remaining packets */
|
||||||
while (!rdpsnd_queue_empty())
|
while (!rdpsnd_queue_empty())
|
||||||
{
|
{
|
||||||
rdpsnd_send_completion(rdpsnd_queue_current_packet()->tick,
|
rdpsnd_queue_next(0);
|
||||||
rdpsnd_queue_current_packet()->index);
|
|
||||||
rdpsnd_queue_next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o_device != NULL)
|
if (o_device != NULL)
|
||||||
@ -171,8 +168,7 @@ libao_play(void)
|
|||||||
(packet->tick + duration) % 65536, next_tick % 65536));
|
(packet->tick + duration) % 65536, next_tick % 65536));
|
||||||
}
|
}
|
||||||
|
|
||||||
rdpsnd_send_completion(((packet->tick + duration) % 65536), packet->index);
|
rdpsnd_queue_next(duration);
|
||||||
rdpsnd_queue_next();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_dsp_busy = 1;
|
g_dsp_busy = 1;
|
||||||
@ -186,7 +182,6 @@ libao_register(char *options)
|
|||||||
struct ao_info *libao_info;
|
struct ao_info *libao_info;
|
||||||
static char description[101];
|
static char description[101];
|
||||||
|
|
||||||
libao_driver.wave_out_write = rdpsnd_queue_write;
|
|
||||||
libao_driver.wave_out_open = libao_open;
|
libao_driver.wave_out_open = libao_open;
|
||||||
libao_driver.wave_out_close = libao_close;
|
libao_driver.wave_out_close = libao_close;
|
||||||
libao_driver.wave_out_format_supported = rdpsnd_dsp_resample_supported;
|
libao_driver.wave_out_format_supported = rdpsnd_dsp_resample_supported;
|
||||||
|
87
rdpsnd_oss.c
87
rdpsnd_oss.c
@ -33,9 +33,12 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/soundcard.h>
|
#include <sys/soundcard.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#define DEFAULTDEVICE "/dev/dsp"
|
#define DEFAULTDEVICE "/dev/dsp"
|
||||||
#define MAX_LEN 512
|
#define MAX_LEN 512
|
||||||
@ -44,6 +47,29 @@ static int snd_rate;
|
|||||||
static short samplewidth;
|
static short samplewidth;
|
||||||
static char *dsp_dev;
|
static char *dsp_dev;
|
||||||
static struct audio_driver oss_driver;
|
static struct audio_driver oss_driver;
|
||||||
|
static BOOL in_esddsp;
|
||||||
|
|
||||||
|
static BOOL
|
||||||
|
detect_esddsp(void)
|
||||||
|
{
|
||||||
|
struct stat s;
|
||||||
|
char *preload;
|
||||||
|
|
||||||
|
if (fstat(g_dsp_fd, &s) == -1)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
|
||||||
|
return False;
|
||||||
|
|
||||||
|
preload = getenv("LD_PRELOAD");
|
||||||
|
if (preload == NULL)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
if (strstr(preload, "esddsp") == NULL)
|
||||||
|
return False;
|
||||||
|
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
oss_open(void)
|
oss_open(void)
|
||||||
@ -54,6 +80,8 @@ oss_open(void)
|
|||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
in_esddsp = detect_esddsp();
|
||||||
|
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,10 +230,6 @@ oss_play(void)
|
|||||||
struct audio_packet *packet;
|
struct audio_packet *packet;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
STREAM out;
|
STREAM out;
|
||||||
static long startedat_us;
|
|
||||||
static long startedat_s;
|
|
||||||
static BOOL started = False;
|
|
||||||
struct timeval tv;
|
|
||||||
|
|
||||||
if (rdpsnd_queue_empty())
|
if (rdpsnd_queue_empty())
|
||||||
{
|
{
|
||||||
@ -216,14 +240,6 @@ oss_play(void)
|
|||||||
packet = rdpsnd_queue_current_packet();
|
packet = rdpsnd_queue_current_packet();
|
||||||
out = &packet->s;
|
out = &packet->s;
|
||||||
|
|
||||||
if (!started)
|
|
||||||
{
|
|
||||||
gettimeofday(&tv, NULL);
|
|
||||||
startedat_us = tv.tv_usec;
|
|
||||||
startedat_s = tv.tv_sec;
|
|
||||||
started = True;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = out->end - out->p;
|
len = out->end - out->p;
|
||||||
|
|
||||||
len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
|
len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
|
||||||
@ -236,37 +252,52 @@ oss_play(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out->p += len;
|
out->p += len;
|
||||||
|
|
||||||
if (out->p == out->end)
|
if (out->p == out->end)
|
||||||
{
|
{
|
||||||
long long duration;
|
int delay_bytes;
|
||||||
long elapsed;
|
unsigned long delay_us;
|
||||||
|
audio_buf_info info;
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
if (in_esddsp)
|
||||||
duration = (out->size * (1000000 / (samplewidth * snd_rate)));
|
|
||||||
elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);
|
|
||||||
|
|
||||||
if (elapsed >= (duration * 85) / 100)
|
|
||||||
{
|
{
|
||||||
/* We need to add 50 to tell windows that time has passed while
|
/* EsounD has no way of querying buffer status, so we have to
|
||||||
* playing this packet */
|
* go with a fixed size. */
|
||||||
rdpsnd_send_completion(packet->tick + 50, packet->index);
|
delay_bytes = out->size;
|
||||||
rdpsnd_queue_next();
|
}
|
||||||
started = False;
|
else
|
||||||
|
{
|
||||||
|
#ifdef SNDCTL_DSP_GETODELAY
|
||||||
|
delay_bytes = 0;
|
||||||
|
if (ioctl(g_dsp_fd, SNDCTL_DSP_GETODELAY, &delay_bytes) == -1)
|
||||||
|
delay_bytes = -1;
|
||||||
|
#else
|
||||||
|
delay_bytes = -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (delay_bytes == -1)
|
||||||
|
{
|
||||||
|
if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) != -1)
|
||||||
|
delay_bytes = info.fragstotal * info.fragsize - info.bytes;
|
||||||
|
else
|
||||||
|
delay_bytes = out->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delay_us = delay_bytes * (1000000 / (samplewidth * snd_rate));
|
||||||
|
rdpsnd_queue_next(delay_us);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
g_dsp_busy = 1;
|
g_dsp_busy = 1;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
g_dsp_busy = 1;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct audio_driver *
|
struct audio_driver *
|
||||||
oss_register(char *options)
|
oss_register(char *options)
|
||||||
{
|
{
|
||||||
oss_driver.wave_out_write = rdpsnd_queue_write;
|
|
||||||
oss_driver.wave_out_open = oss_open;
|
oss_driver.wave_out_open = oss_open;
|
||||||
oss_driver.wave_out_close = oss_close;
|
oss_driver.wave_out_close = oss_close;
|
||||||
oss_driver.wave_out_format_supported = oss_format_supported;
|
oss_driver.wave_out_format_supported = oss_format_supported;
|
||||||
|
@ -68,8 +68,6 @@ sgi_open(void)
|
|||||||
min_volume, max_volume, volume_range);
|
min_volume, max_volume, volume_range);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rdpsnd_queue_init();
|
|
||||||
|
|
||||||
audioconfig = alNewConfig();
|
audioconfig = alNewConfig();
|
||||||
if (audioconfig == (ALconfig) 0)
|
if (audioconfig == (ALconfig) 0)
|
||||||
{
|
{
|
||||||
@ -266,8 +264,7 @@ sgi_play(void)
|
|||||||
gf = alGetFilled(output_port);
|
gf = alGetFilled(output_port);
|
||||||
if (gf < (4 * maxFillable / 10))
|
if (gf < (4 * maxFillable / 10))
|
||||||
{
|
{
|
||||||
rdpsnd_send_completion(packet->tick, packet->index);
|
rdpsnd_queue_next(0);
|
||||||
rdpsnd_queue_next();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -287,7 +284,6 @@ sgi_register(char *options)
|
|||||||
{
|
{
|
||||||
static struct audio_driver sgi_driver;
|
static struct audio_driver sgi_driver;
|
||||||
|
|
||||||
sgi_driver.wave_out_write = rdpsnd_queue_write;
|
|
||||||
sgi_driver.wave_out_open = sgi_open;
|
sgi_driver.wave_out_open = sgi_open;
|
||||||
sgi_driver.wave_out_close = sgi_close;
|
sgi_driver.wave_out_close = sgi_close;
|
||||||
sgi_driver.wave_out_format_supported = sgi_format_supported;
|
sgi_driver.wave_out_format_supported = sgi_format_supported;
|
||||||
|
@ -50,7 +50,6 @@ sun_open(void)
|
|||||||
/* Non-blocking so that user interface is responsive */
|
/* Non-blocking so that user interface is responsive */
|
||||||
fcntl(g_dsp_fd, F_SETFL, fcntl(g_dsp_fd, F_GETFL) | O_NONBLOCK);
|
fcntl(g_dsp_fd, F_SETFL, fcntl(g_dsp_fd, F_GETFL) | O_NONBLOCK);
|
||||||
|
|
||||||
rdpsnd_queue_init();
|
|
||||||
g_reopened = True;
|
g_reopened = True;
|
||||||
|
|
||||||
return True;
|
return True;
|
||||||
@ -235,8 +234,7 @@ sun_play(void)
|
|||||||
samplecnt += numsamples;
|
samplecnt += numsamples;
|
||||||
/* We need to add 50 to tell windows that time has passed while
|
/* We need to add 50 to tell windows that time has passed while
|
||||||
* playing this packet */
|
* playing this packet */
|
||||||
rdpsnd_send_completion(packet->tick + 50, packet->index);
|
rdpsnd_queue_next(50);
|
||||||
rdpsnd_queue_next();
|
|
||||||
sentcompletion = True;
|
sentcompletion = True;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -253,7 +251,6 @@ sun_register(char *options)
|
|||||||
{
|
{
|
||||||
static struct audio_driver sun_driver;
|
static struct audio_driver sun_driver;
|
||||||
|
|
||||||
sun_driver.wave_out_write = rdpsnd_queue_write;
|
|
||||||
sun_driver.wave_out_open = sun_open;
|
sun_driver.wave_out_open = sun_open;
|
||||||
sun_driver.wave_out_close = sun_close;
|
sun_driver.wave_out_close = sun_close;
|
||||||
sun_driver.wave_out_format_supported = sun_format_supported;
|
sun_driver.wave_out_format_supported = sun_format_supported;
|
||||||
|
24
xwin.c
24
xwin.c
@ -2268,18 +2268,14 @@ ui_select(int rdp_socket)
|
|||||||
FD_SET(rdp_socket, &rfds);
|
FD_SET(rdp_socket, &rfds);
|
||||||
FD_SET(g_x_socket, &rfds);
|
FD_SET(g_x_socket, &rfds);
|
||||||
|
|
||||||
#ifdef WITH_RDPSND
|
|
||||||
/* FIXME: there should be an API for registering fds */
|
|
||||||
if (g_dsp_busy)
|
|
||||||
{
|
|
||||||
FD_SET(g_dsp_fd, &wfds);
|
|
||||||
n = (g_dsp_fd > n) ? g_dsp_fd : n;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* default timeout */
|
/* default timeout */
|
||||||
tv.tv_sec = 60;
|
tv.tv_sec = 60;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
#ifdef WITH_RDPSND
|
||||||
|
rdpsnd_add_fds(&n, &rfds, &wfds, &tv);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* add redirection handles */
|
/* add redirection handles */
|
||||||
rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
|
rdpdr_add_fds(&n, &rfds, &wfds, &tv, &s_timeout);
|
||||||
seamless_select_timeout(&tv);
|
seamless_select_timeout(&tv);
|
||||||
@ -2292,21 +2288,25 @@ ui_select(int rdp_socket)
|
|||||||
error("select: %s\n", strerror(errno));
|
error("select: %s\n", strerror(errno));
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
|
#ifdef WITH_RDPSND
|
||||||
|
rdpsnd_check_fds(&rfds, &wfds);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Abort serial read calls */
|
/* Abort serial read calls */
|
||||||
if (s_timeout)
|
if (s_timeout)
|
||||||
rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
|
rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_RDPSND
|
||||||
|
rdpsnd_check_fds(&rfds, &wfds);
|
||||||
|
#endif
|
||||||
|
|
||||||
rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
|
rdpdr_check_fds(&rfds, &wfds, (BOOL) False);
|
||||||
|
|
||||||
if (FD_ISSET(rdp_socket, &rfds))
|
if (FD_ISSET(rdp_socket, &rfds))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
#ifdef WITH_RDPSND
|
|
||||||
if (g_dsp_busy && FD_ISSET(g_dsp_fd, &wfds))
|
|
||||||
rdpsnd_play();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user