Abstract select() handling in rdpsnd so that backends can do their thing

more correctly.


git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@1345 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
Pierre Ossman 2006-12-07 15:23:45 +00:00
parent 139e42d9ef
commit c6712a8945
9 changed files with 257 additions and 131 deletions

View File

@ -168,7 +168,6 @@ BOOL rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status);
/* rdpsnd.c */ /* rdpsnd.c */
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_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv); 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); 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);

104
rdpsnd.c
View File

@ -37,9 +37,6 @@
#define MAX_FORMATS 10 #define MAX_FORMATS 10
#define MAX_QUEUE 10 #define MAX_QUEUE 10
BOOL g_dsp_busy = False;
int g_dsp_fd;
static VCHANNEL *rdpsnd_channel; static VCHANNEL *rdpsnd_channel;
static struct audio_driver *drivers = NULL; static struct audio_driver *drivers = NULL;
struct audio_driver *current_driver = NULL; struct audio_driver *current_driver = NULL;
@ -94,6 +91,34 @@ rdpsnd_send_completion(uint16 tick, uint8 packet_index)
(unsigned) tick, (unsigned) packet_index)); (unsigned) tick, (unsigned) packet_index));
} }
static BOOL
rdpsnd_auto_select(void)
{
static BOOL failed = False;
if (!failed)
{
current_driver = drivers;
while (current_driver != NULL)
{
DEBUG(("trying %s...\n", current_driver->name));
if (current_driver->wave_out_open())
{
DEBUG(("selected %s\n", current_driver->name));
return True;
}
current_driver = current_driver->next;
}
warning("no working audio-driver found\n");
failed = True;
current_driver = NULL;
}
return False;
}
static void static void
rdpsnd_process_negotiate(STREAM in) rdpsnd_process_negotiate(STREAM in)
{ {
@ -115,7 +140,10 @@ rdpsnd_process_negotiate(STREAM in)
DEBUG_SOUND(("RDPSND: RDPSND_NEGOTIATE(formats: %d, pad: 0x%02x, version: %x)\n", DEBUG_SOUND(("RDPSND: RDPSND_NEGOTIATE(formats: %d, pad: 0x%02x, version: %x)\n",
(int) in_format_count, (unsigned) pad, (unsigned) version)); (int) in_format_count, (unsigned) pad, (unsigned) version));
if (current_driver->wave_out_open()) if (!current_driver)
rdpsnd_auto_select();
if (current_driver && current_driver->wave_out_open())
{ {
current_driver->wave_out_close(); current_driver->wave_out_close();
device_available = True; device_available = True;
@ -230,6 +258,16 @@ rdpsnd_process_packet(uint8 opcode, STREAM s)
if (!device_open || (format != current_format)) if (!device_open || (format != current_format))
{ {
/*
* If we haven't selected a device by now, then either
* we've failed to find a working device, or the server
* is sending bogus RDPSND_WRITE.
*/
if (!current_driver)
{
rdpsnd_send_completion(tick, packet_index);
break;
}
if (!device_open && !current_driver->wave_out_open()) if (!device_open && !current_driver->wave_out_open())
{ {
rdpsnd_send_completion(tick, packet_index); rdpsnd_send_completion(tick, packet_index);
@ -253,7 +291,8 @@ rdpsnd_process_packet(uint8 opcode, STREAM s)
break; break;
case RDPSND_CLOSE: case RDPSND_CLOSE:
DEBUG_SOUND(("RDPSND: RDPSND_CLOSE()\n")); DEBUG_SOUND(("RDPSND: RDPSND_CLOSE()\n"));
current_driver->wave_out_close(); if (device_open)
current_driver->wave_out_close();
device_open = False; device_open = False;
break; break;
case RDPSND_NEGOTIATE: case RDPSND_NEGOTIATE:
@ -333,36 +372,6 @@ rdpsnd_process(STREAM s)
} }
} }
static BOOL
rdpsnd_auto_open(void)
{
static BOOL failed = False;
if (!failed)
{
struct audio_driver *auto_driver = current_driver;
current_driver = drivers;
while (current_driver != NULL)
{
DEBUG(("trying %s...\n", current_driver->name));
if (current_driver->wave_out_open())
{
DEBUG(("selected %s\n", current_driver->name));
return True;
}
g_dsp_fd = 0;
current_driver = current_driver->next;
}
warning("no working audio-driver found\n");
failed = True;
current_driver = auto_driver;
}
return False;
}
static void static void
rdpsnd_register_drivers(char *options) rdpsnd_register_drivers(char *options)
{ {
@ -402,7 +411,6 @@ rdpsnd_register_drivers(char *options)
BOOL BOOL
rdpsnd_init(char *optarg) rdpsnd_init(char *optarg)
{ {
static struct audio_driver auto_driver;
struct audio_driver *pos; struct audio_driver *pos;
char *driver = NULL, *options = NULL; char *driver = NULL, *options = NULL;
@ -444,11 +452,7 @@ rdpsnd_init(char *optarg)
rdpsnd_register_drivers(options); rdpsnd_register_drivers(options);
if (!driver) if (!driver)
{
auto_driver.wave_out_open = &rdpsnd_auto_open;
current_driver = &auto_driver;
return True; return True;
}
pos = drivers; pos = drivers;
while (pos != NULL) while (pos != NULL)
@ -479,22 +483,13 @@ rdpsnd_show_help(void)
} }
} }
void
rdpsnd_play(void)
{
current_driver->wave_out_play();
}
void void
rdpsnd_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) rdpsnd_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
{ {
long next_pending; long next_pending;
if (g_dsp_busy) if (device_open)
{ current_driver->add_fds(n, rfds, wfds, tv);
FD_SET(g_dsp_fd, wfds);
*n = (g_dsp_fd > *n) ? g_dsp_fd : *n;
}
next_pending = rdpsnd_queue_next_completion(); next_pending = rdpsnd_queue_next_completion();
if (next_pending >= 0) if (next_pending >= 0)
@ -515,8 +510,8 @@ rdpsnd_check_fds(fd_set * rfds, fd_set * wfds)
{ {
rdpsnd_queue_complete_pending(); rdpsnd_queue_complete_pending();
if (g_dsp_busy && FD_ISSET(g_dsp_fd, wfds)) if (device_open)
rdpsnd_play(); current_driver->check_fds(rfds, wfds);
} }
static void static void
@ -538,9 +533,6 @@ rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index)
packet->index = index; packet->index = index;
gettimeofday(&packet->arrive_tv, NULL); gettimeofday(&packet->arrive_tv, NULL);
if (!g_dsp_busy)
current_driver->wave_out_play();
} }
struct audio_packet * struct audio_packet *

View File

@ -30,12 +30,15 @@ struct audio_packet
struct audio_driver struct audio_driver
{ {
BOOL(*wave_out_open) (void); void (*add_fds) (int *n, fd_set * rfds, fd_set * wfds, struct timeval * tv);
void (*check_fds) (fd_set * rfds, fd_set * wfds);
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);
BOOL(*wave_out_set_format) (WAVEFORMATEX * pwfx); BOOL(*wave_out_set_format) (WAVEFORMATEX * pwfx);
void (*wave_out_volume) (uint16 left, uint16 right); void (*wave_out_volume) (uint16 left, uint16 right);
void (*wave_out_play) (void);
char *name; char *name;
char *description; char *description;
int need_byteswap_on_be; int need_byteswap_on_be;
@ -43,9 +46,6 @@ struct audio_driver
struct audio_driver *next; struct audio_driver *next;
}; };
extern BOOL g_dsp_busy;
extern int g_dsp_fd;
/* Driver register functions */ /* Driver register functions */
struct audio_driver *alsa_register(char *options); struct audio_driver *alsa_register(char *options);
struct audio_driver *libao_register(char *options); struct audio_driver *libao_register(char *options);

View File

@ -32,6 +32,9 @@
#define DEFAULTDEVICE "default" #define DEFAULTDEVICE "default"
#define MAX_FRAMES 32 #define MAX_FRAMES 32
static struct pollfd pfds[32];
static int num_fds;
static snd_pcm_t *pcm_handle = NULL; static snd_pcm_t *pcm_handle = NULL;
static snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; static snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
static BOOL reopened; static BOOL reopened;
@ -40,6 +43,71 @@ static int audiochannels;
static unsigned int rate; static unsigned int rate;
static char *pcm_name; static char *pcm_name;
void alsa_play(void);
void
alsa_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
{
int err;
struct pollfd *f;
if (!pcm_handle)
return;
if (rdpsnd_queue_empty())
return;
num_fds = snd_pcm_poll_descriptors_count(pcm_handle);
if (num_fds > sizeof(pfds) / sizeof(*pfds))
return;
err = snd_pcm_poll_descriptors(pcm_handle, pfds, num_fds);
if (err < 0)
return;
for (f = pfds; f < &pfds[num_fds]; f++)
{
if (f->events & POLLIN)
FD_SET(f->fd, rfds);
if (f->events & POLLOUT)
FD_SET(f->fd, wfds);
if (f->fd > *n && (f->events & (POLLIN | POLLOUT)))
*n = f->fd;
}
}
void
alsa_check_fds(fd_set * rfds, fd_set * wfds)
{
struct pollfd *f;
int err;
unsigned short revents;
if (!pcm_handle)
return;
for (f = pfds; f < &pfds[num_fds]; f++)
{
f->revents = 0;
if (f->fd != -1)
{
/* Fixme: This doesn't properly deal with things like POLLHUP */
if (FD_ISSET(f->fd, rfds))
f->revents |= POLLIN;
if (FD_ISSET(f->fd, wfds))
f->revents |= POLLOUT;
}
}
err = snd_pcm_poll_descriptors_revents(pcm_handle, pfds, num_fds, &revents);
if (err < 0)
return;
if (revents & POLLOUT)
alsa_play();
}
BOOL BOOL
alsa_open(void) alsa_open(void)
{ {
@ -51,8 +119,6 @@ alsa_open(void)
return False; return False;
} }
g_dsp_fd = 0;
reopened = True; reopened = True;
return True; return True;
@ -221,11 +287,9 @@ alsa_play(void)
prev_us = tv.tv_usec; prev_us = tv.tv_usec;
} }
/* We shouldn't be called if the queue is empty, but still */
if (rdpsnd_queue_empty()) if (rdpsnd_queue_empty())
{
g_dsp_busy = 0;
return; return;
}
packet = rdpsnd_queue_current_packet(); packet = rdpsnd_queue_current_packet();
out = &packet->s; out = &packet->s;
@ -271,21 +335,20 @@ alsa_play(void)
rdpsnd_queue_next(delay_us); rdpsnd_queue_next(delay_us);
} }
g_dsp_busy = 1;
return;
} }
static struct audio_driver alsa_driver = { static struct audio_driver alsa_driver = {
.name = "alsa", .name = "alsa",
.description = "ALSA output driver, default device: " DEFAULTDEVICE, .description = "ALSA output driver, default device: " DEFAULTDEVICE,
.add_fds = alsa_add_fds,
.check_fds = alsa_check_fds,
.wave_out_open = alsa_open, .wave_out_open = alsa_open,
.wave_out_close = alsa_close, .wave_out_close = alsa_close,
.wave_out_format_supported = alsa_format_supported, .wave_out_format_supported = alsa_format_supported,
.wave_out_set_format = alsa_set_format, .wave_out_set_format = alsa_set_format,
.wave_out_volume = rdpsnd_dsp_softvol_set, .wave_out_volume = rdpsnd_dsp_softvol_set,
.wave_out_play = alsa_play,
.need_byteswap_on_be = 0, .need_byteswap_on_be = 0,
.need_resampling = 0, .need_resampling = 0,

View File

@ -36,6 +36,23 @@ static int default_driver;
static BOOL reopened; static BOOL reopened;
static char *libao_device = NULL; static char *libao_device = NULL;
void libao_play(void);
void
libao_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
{
}
void
libao_check_fds(fd_set * rfds, fd_set * wfds)
{
if (o_device == NULL)
return;
if (!rdpsnd_queue_empty())
libao_play();
}
BOOL BOOL
libao_open(void) libao_open(void)
{ {
@ -64,8 +81,6 @@ libao_open(void)
return False; return False;
} }
g_dsp_fd = 0;
reopened = True; reopened = True;
return True; return True;
@ -83,6 +98,8 @@ libao_close(void)
if (o_device != NULL) if (o_device != NULL)
ao_close(o_device); ao_close(o_device);
o_device = NULL;
ao_shutdown(); ao_shutdown();
} }
@ -134,11 +151,9 @@ libao_play(void)
prev_us = tv.tv_usec; prev_us = tv.tv_usec;
} }
/* We shouldn't be called if the queue is empty, but still */
if (rdpsnd_queue_empty()) if (rdpsnd_queue_empty())
{
g_dsp_busy = 0;
return; return;
}
packet = rdpsnd_queue_current_packet(); packet = rdpsnd_queue_current_packet();
out = &packet->s; out = &packet->s;
@ -170,21 +185,20 @@ libao_play(void)
rdpsnd_queue_next(duration); rdpsnd_queue_next(duration);
} }
g_dsp_busy = 1;
return;
} }
static struct audio_driver libao_driver = { static struct audio_driver libao_driver = {
.name = "libao", .name = "libao",
.description = "libao output driver, default device: system dependent", .description = "libao output driver, default device: system dependent",
.add_fds = libao_add_fds,
.check_fds = libao_check_fds,
.wave_out_open = libao_open, .wave_out_open = libao_open,
.wave_out_close = libao_close, .wave_out_close = libao_close,
.wave_out_format_supported = rdpsnd_dsp_resample_supported, .wave_out_format_supported = rdpsnd_dsp_resample_supported,
.wave_out_set_format = libao_set_format, .wave_out_set_format = libao_set_format,
.wave_out_volume = rdpsnd_dsp_softvol_set, .wave_out_volume = rdpsnd_dsp_softvol_set,
.wave_out_play = libao_play,
.need_byteswap_on_be = 1, .need_byteswap_on_be = 1,
.need_resampling = 1, .need_resampling = 1,

View File

@ -43,6 +43,9 @@
#define DEFAULTDEVICE "/dev/dsp" #define DEFAULTDEVICE "/dev/dsp"
#define MAX_LEN 512 #define MAX_LEN 512
static int dsp_fd = -1;
static BOOL dsp_busy;
static int snd_rate; static int snd_rate;
static short samplewidth; static short samplewidth;
static char *dsp_dev; static char *dsp_dev;
@ -51,13 +54,36 @@ static BOOL in_esddsp;
/* This is a just a forward declaration */ /* This is a just a forward declaration */
static struct audio_driver oss_driver; static struct audio_driver oss_driver;
void oss_play(void);
void
oss_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
{
if (dsp_fd == -1)
return;
if (rdpsnd_queue_empty())
return;
FD_SET(dsp_fd, wfds);
if (dsp_fd > *n)
*n = dsp_fd;
}
void
oss_check_fds(fd_set * rfds, fd_set * wfds)
{
if (FD_ISSET(dsp_fd, wfds))
oss_play();
}
static BOOL static BOOL
detect_esddsp(void) detect_esddsp(void)
{ {
struct stat s; struct stat s;
char *preload; char *preload;
if (fstat(g_dsp_fd, &s) == -1) if (fstat(dsp_fd, &s) == -1)
return False; return False;
if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode)) if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
@ -76,7 +102,7 @@ detect_esddsp(void)
BOOL BOOL
oss_open(void) oss_open(void)
{ {
if ((g_dsp_fd = open(dsp_dev, O_WRONLY)) == -1) if ((dsp_fd = open(dsp_dev, O_WRONLY)) == -1)
{ {
perror(dsp_dev); perror(dsp_dev);
return False; return False;
@ -90,8 +116,9 @@ oss_open(void)
void void
oss_close(void) oss_close(void)
{ {
close(g_dsp_fd); close(dsp_fd);
g_dsp_busy = 0; dsp_fd = -1;
dsp_busy = False;
} }
BOOL BOOL
@ -113,8 +140,8 @@ oss_set_format(WAVEFORMATEX * pwfx)
int stereo, format, fragments; int stereo, format, fragments;
static BOOL driver_broken = False; static BOOL driver_broken = False;
ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL); ioctl(dsp_fd, SNDCTL_DSP_RESET, NULL);
ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL); ioctl(dsp_fd, SNDCTL_DSP_SYNC, NULL);
if (pwfx->wBitsPerSample == 8) if (pwfx->wBitsPerSample == 8)
format = AFMT_U8; format = AFMT_U8;
@ -123,7 +150,7 @@ oss_set_format(WAVEFORMATEX * pwfx)
samplewidth = pwfx->wBitsPerSample / 8; samplewidth = pwfx->wBitsPerSample / 8;
if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1) if (ioctl(dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
{ {
perror("SNDCTL_DSP_SETFMT"); perror("SNDCTL_DSP_SETFMT");
oss_close(); oss_close();
@ -140,7 +167,7 @@ oss_set_format(WAVEFORMATEX * pwfx)
stereo = 0; stereo = 0;
} }
if (ioctl(g_dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1) if (ioctl(dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
{ {
perror("SNDCTL_DSP_CHANNELS"); perror("SNDCTL_DSP_CHANNELS");
oss_close(); oss_close();
@ -149,7 +176,7 @@ oss_set_format(WAVEFORMATEX * pwfx)
oss_driver.need_resampling = 0; oss_driver.need_resampling = 0;
snd_rate = pwfx->nSamplesPerSec; snd_rate = pwfx->nSamplesPerSec;
if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1) if (ioctl(dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
{ {
int rates[] = { 44100, 48000, 0 }; int rates[] = { 44100, 48000, 0 };
int *prates = rates; int *prates = rates;
@ -157,7 +184,7 @@ oss_set_format(WAVEFORMATEX * pwfx)
while (*prates != 0) while (*prates != 0)
{ {
if ((pwfx->nSamplesPerSec != *prates) if ((pwfx->nSamplesPerSec != *prates)
&& (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, prates) != -1)) && (ioctl(dsp_fd, SNDCTL_DSP_SPEED, prates) != -1))
{ {
oss_driver.need_resampling = 1; oss_driver.need_resampling = 1;
snd_rate = *prates; snd_rate = *prates;
@ -184,14 +211,14 @@ oss_set_format(WAVEFORMATEX * pwfx)
/* try to get 12 fragments of 2^12 bytes size */ /* try to get 12 fragments of 2^12 bytes size */
fragments = (12 << 16) + 12; fragments = (12 << 16) + 12;
ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments); ioctl(dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
if (!driver_broken) if (!driver_broken)
{ {
audio_buf_info info; audio_buf_info info;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1) if (ioctl(dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
{ {
perror("SNDCTL_DSP_GETOSPACE"); perror("SNDCTL_DSP_GETOSPACE");
oss_close(); oss_close();
@ -218,7 +245,7 @@ oss_volume(uint16 left, uint16 right)
volume = left / (65536 / 100); volume = left / (65536 / 100);
volume |= right / (65536 / 100) << 8; volume |= right / (65536 / 100) << 8;
if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1) if (ioctl(dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
{ {
warning("hardware volume control unavailable, falling back to software volume control!\n"); warning("hardware volume control unavailable, falling back to software volume control!\n");
oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set; oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
@ -234,23 +261,20 @@ oss_play(void)
ssize_t len; ssize_t len;
STREAM out; STREAM out;
/* We shouldn't be called if the queue is empty, but still */
if (rdpsnd_queue_empty()) if (rdpsnd_queue_empty())
{
g_dsp_busy = 0;
return; return;
}
packet = rdpsnd_queue_current_packet(); packet = rdpsnd_queue_current_packet();
out = &packet->s; out = &packet->s;
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(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
if (len == -1) if (len == -1)
{ {
if (errno != EWOULDBLOCK) if (errno != EWOULDBLOCK)
perror("write audio"); perror("write audio");
g_dsp_busy = 1;
return; return;
} }
@ -272,7 +296,7 @@ oss_play(void)
{ {
#ifdef SNDCTL_DSP_GETODELAY #ifdef SNDCTL_DSP_GETODELAY
delay_bytes = 0; delay_bytes = 0;
if (ioctl(g_dsp_fd, SNDCTL_DSP_GETODELAY, &delay_bytes) == -1) if (ioctl(dsp_fd, SNDCTL_DSP_GETODELAY, &delay_bytes) == -1)
delay_bytes = -1; delay_bytes = -1;
#else #else
delay_bytes = -1; delay_bytes = -1;
@ -280,7 +304,7 @@ oss_play(void)
if (delay_bytes == -1) if (delay_bytes == -1)
{ {
if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) != -1) if (ioctl(dsp_fd, SNDCTL_DSP_GETOSPACE, &info) != -1)
delay_bytes = info.fragstotal * info.fragsize - info.bytes; delay_bytes = info.fragstotal * info.fragsize - info.bytes;
else else
delay_bytes = out->size; delay_bytes = out->size;
@ -290,24 +314,20 @@ oss_play(void)
delay_us = delay_bytes * (1000000 / (samplewidth * snd_rate)); delay_us = delay_bytes * (1000000 / (samplewidth * snd_rate));
rdpsnd_queue_next(delay_us); rdpsnd_queue_next(delay_us);
} }
else
{
g_dsp_busy = 1;
}
return;
} }
static struct audio_driver oss_driver = { static struct audio_driver oss_driver = {
.name = "oss", .name = "oss",
.description = "OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV", .description = "OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV",
.add_fds = oss_add_fds,
.check_fds = oss_check_fds,
.wave_out_open = oss_open, .wave_out_open = oss_open,
.wave_out_close = oss_close, .wave_out_close = oss_close,
.wave_out_format_supported = oss_format_supported, .wave_out_format_supported = oss_format_supported,
.wave_out_set_format = oss_set_format, .wave_out_set_format = oss_set_format,
.wave_out_volume = oss_volume, .wave_out_volume = oss_volume,
.wave_out_play = oss_play,
.need_byteswap_on_be = 0, .need_byteswap_on_be = 0,
.need_resampling = 0, .need_resampling = 0,

View File

@ -39,6 +39,23 @@ double min_volume, max_volume, volume_range;
int resource, maxFillable; int resource, maxFillable;
int combinedFrameSize; int combinedFrameSize;
void sgi_play(void);
void
sgi_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
{
}
void
sgi_check_fds(fd_set * rfds, fd_set * wfds)
{
if (output_port == (ALport) 0)
return;
if (!rdpsnd_queue_empty())
sgi_play();
}
BOOL BOOL
sgi_open(void) sgi_open(void)
{ {
@ -101,6 +118,7 @@ sgi_close(void)
alDiscardFrames(output_port, 0); alDiscardFrames(output_port, 0);
alClosePort(output_port); alClosePort(output_port);
output_port = (ALport) 0;
alFreeConfig(audioconfig); alFreeConfig(audioconfig);
#if (defined(IRIX_DEBUG)) #if (defined(IRIX_DEBUG))
fprintf(stderr, "sgi_close: returning\n"); fprintf(stderr, "sgi_close: returning\n");
@ -240,10 +258,7 @@ sgi_play(void)
while (1) while (1)
{ {
if (rdpsnd_queue_empty()) if (rdpsnd_queue_empty())
{
g_dsp_busy = False;
return; return;
}
packet = rdpsnd_queue_current_packet(); packet = rdpsnd_queue_current_packet();
out = &packet->s; out = &packet->s;
@ -265,7 +280,6 @@ sgi_play(void)
#if (defined(IRIX_DEBUG)) #if (defined(IRIX_DEBUG))
/* fprintf(stderr,"Busy playing...\n"); */ /* fprintf(stderr,"Busy playing...\n"); */
#endif #endif
g_dsp_busy = True;
usleep(10); usleep(10);
return; return;
} }
@ -277,12 +291,14 @@ static struct audio_driver sgi_driver = {
.name = "sgi", .name = "sgi",
.description = "SGI output driver", .description = "SGI output driver",
.add_fds = sgi_add_fds,
.check_fds = sgi_check_fds,
.wave_out_open = sgi_open, .wave_out_open = sgi_open,
.wave_out_close = sgi_close, .wave_out_close = sgi_close,
.wave_out_format_supported = sgi_format_supported, .wave_out_format_supported = sgi_format_supported,
.wave_out_set_format = sgi_set_format, .wave_out_set_format = sgi_set_format,
.wave_out_volume = sgi_volume, .wave_out_volume = sgi_volume,
.wave_out_play = sgi_play,
.need_byteswap_on_be = 1, .need_byteswap_on_be = 1,
.need_resampling = 0, .need_resampling = 0,

View File

@ -34,21 +34,47 @@
#define DEFAULTDEVICE "/dev/audio" #define DEFAULTDEVICE "/dev/audio"
static int dsp_fd = -1;
static BOOL dsp_busy;
static BOOL g_reopened; static BOOL g_reopened;
static short g_samplewidth; static short g_samplewidth;
static char *dsp_dev; static char *dsp_dev;
void oss_play(void);
void
sun_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
{
if (dsp_fd == -1)
return;
if (rdpsnd_queue_empty())
return;
FD_SET(dsp_fd, wfds);
if (dsp_fd > *n)
*n = dsp_fd;
}
void
sun_check_fds(fd_set * rfds, fd_set * wfds)
{
if (FD_ISSET(dsp_fd, wfds))
sun_play();
}
BOOL BOOL
sun_open(void) sun_open(void)
{ {
if ((g_dsp_fd = open(dsp_dev, O_WRONLY | O_NONBLOCK)) == -1) if ((dsp_fd = open(dsp_dev, O_WRONLY | O_NONBLOCK)) == -1)
{ {
perror(dsp_dev); perror(dsp_dev);
return False; return False;
} }
/* 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(dsp_fd, F_SETFL, fcntl(dsp_fd, F_GETFL) | O_NONBLOCK);
g_reopened = True; g_reopened = True;
@ -64,12 +90,13 @@ sun_close(void)
#if defined I_FLUSH && defined FLUSHW #if defined I_FLUSH && defined FLUSHW
/* Flush the audiobuffer */ /* Flush the audiobuffer */
ioctl(g_dsp_fd, I_FLUSH, FLUSHW); ioctl(dsp_fd, I_FLUSH, FLUSHW);
#endif #endif
#if defined AUDIO_FLUSH #if defined AUDIO_FLUSH
ioctl(g_dsp_fd, AUDIO_FLUSH, NULL); ioctl(dsp_fd, AUDIO_FLUSH, NULL);
#endif #endif
close(g_dsp_fd); close(dsp_fd);
dsp_fd = -1;
} }
BOOL BOOL
@ -90,7 +117,7 @@ sun_set_format(WAVEFORMATEX * pwfx)
{ {
audio_info_t info; audio_info_t info;
ioctl(g_dsp_fd, AUDIO_DRAIN, 0); ioctl(dsp_fd, AUDIO_DRAIN, 0);
AUDIO_INITINFO(&info); AUDIO_INITINFO(&info);
@ -122,10 +149,10 @@ sun_set_format(WAVEFORMATEX * pwfx)
info.play.error = 0; info.play.error = 0;
g_reopened = True; g_reopened = True;
if (ioctl(g_dsp_fd, AUDIO_SETINFO, &info) == -1) if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
{ {
perror("AUDIO_SETINFO"); perror("AUDIO_SETINFO");
close(g_dsp_fd); sun_close();
return False; return False;
} }
@ -157,7 +184,7 @@ sun_volume(uint16 left, uint16 right)
info.play.gain = volume / (65536 / AUDIO_MAX_GAIN); info.play.gain = volume / (65536 / AUDIO_MAX_GAIN);
info.play.balance = balance; info.play.balance = balance;
if (ioctl(g_dsp_fd, AUDIO_SETINFO, &info) == -1) if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
{ {
perror("AUDIO_SETINFO"); perror("AUDIO_SETINFO");
return; return;
@ -187,10 +214,7 @@ sun_play(void)
} }
if (rdpsnd_queue_empty()) if (rdpsnd_queue_empty())
{
g_dsp_busy = 0;
return; return;
}
packet = rdpsnd_queue_current_packet(); packet = rdpsnd_queue_current_packet();
out = &packet->s; out = &packet->s;
@ -205,12 +229,11 @@ sun_play(void)
if (out->end != out->p) if (out->end != out->p)
{ {
len = write(g_dsp_fd, out->p, out->end - out->p); len = write(dsp_fd, out->p, out->end - out->p);
if (len == -1) if (len == -1)
{ {
if (errno != EWOULDBLOCK) if (errno != EWOULDBLOCK)
perror("write audio"); perror("write audio");
g_dsp_busy = 1;
return; return;
} }
} }
@ -218,7 +241,7 @@ sun_play(void)
out->p += len; out->p += len;
if (out->p == out->end) if (out->p == out->end)
{ {
if (ioctl(g_dsp_fd, AUDIO_GETINFO, &info) == -1) if (ioctl(dsp_fd, AUDIO_GETINFO, &info) == -1)
{ {
perror("AUDIO_GETINFO"); perror("AUDIO_GETINFO");
return; return;
@ -235,7 +258,6 @@ sun_play(void)
} }
else else
{ {
g_dsp_busy = 1;
return; return;
} }
} }
@ -246,12 +268,14 @@ static struct audio_driver sun_driver = {
.name = "sun", .name = "sun",
.description = "SUN/BSD output driver, default device: " DEFAULTDEVICE " or $AUDIODEV", .description = "SUN/BSD output driver, default device: " DEFAULTDEVICE " or $AUDIODEV",
.add_fds = sun_add_fds,
.check_fds = sun_check_fds,
.wave_out_open = sun_open, .wave_out_open = sun_open,
.wave_out_close = sun_close, .wave_out_close = sun_close,
.wave_out_format_supported = sun_format_supported, .wave_out_format_supported = sun_format_supported,
.wave_out_set_format = sun_set_format, .wave_out_set_format = sun_set_format,
.wave_out_volume = sun_volume, .wave_out_volume = sun_volume,
.wave_out_play = sun_play,
.need_byteswap_on_be = 1, .need_byteswap_on_be = 1,
.need_resampling = 0, .need_resampling = 0,

2
xwin.c
View File

@ -147,8 +147,6 @@ static int g_move_y_offset = 0;
static BOOL g_using_full_workarea = False; static BOOL g_using_full_workarea = False;
#ifdef WITH_RDPSND #ifdef WITH_RDPSND
extern int g_dsp_fd;
extern BOOL g_dsp_busy;
extern BOOL g_rdpsnd; extern BOOL g_rdpsnd;
#endif #endif