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:
parent
139e42d9ef
commit
c6712a8945
1
proto.h
1
proto.h
@ -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
104
rdpsnd.c
@ -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 *
|
||||||
|
10
rdpsnd.h
10
rdpsnd.h
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
74
rdpsnd_oss.c
74
rdpsnd_oss.c
@ -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,
|
||||||
|
26
rdpsnd_sgi.c
26
rdpsnd_sgi.c
@ -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,
|
||||||
|
58
rdpsnd_sun.c
58
rdpsnd_sun.c
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user