--- sourceforge.net/trunk/rdesktop/rdpsnd_sun.c 2004/05/07 12:01:53 694 +++ sourceforge.net/trunk/rdesktop/rdpsnd_sun.c 2006/12/07 15:23:45 1346 @@ -1,9 +1,9 @@ -/* +/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. Sound Channel Process Functions - Sun Copyright (C) Matthew Chapman 2003 Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003 - Copyright (C) Michael Gernoth mike@zerfleddert.de 2003 + Copyright (C) Michael Gernoth mike@zerfleddert.de 2003-2006 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ */ #include "rdesktop.h" +#include "rdpsnd.h" #include #include #include @@ -31,70 +32,75 @@ #include #endif -#define MAX_QUEUE 10 +#define DEFAULTDEVICE "/dev/audio" + +static int dsp_fd = -1; +static BOOL dsp_busy; -int g_dsp_fd; -BOOL g_dsp_busy = False; static BOOL g_reopened; -static BOOL g_swapaudio; static short g_samplewidth; +static char *dsp_dev; -static struct audio_packet -{ - struct stream s; - uint16 tick; - uint8 index; -} packet_queue[MAX_QUEUE]; -static unsigned int queue_hi, queue_lo; +void oss_play(void); -BOOL -wave_out_open(void) +void +sun_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv) { - char *dsp_dev = getenv("AUDIODEV"); + if (dsp_fd == -1) + return; - if (dsp_dev == NULL) - { - dsp_dev = "/dev/audio"; - } + 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(); +} - if ((g_dsp_fd = open(dsp_dev, O_WRONLY | O_NONBLOCK)) == -1) +BOOL +sun_open(void) +{ + if ((dsp_fd = open(dsp_dev, O_WRONLY | O_NONBLOCK)) == -1) { perror(dsp_dev); return False; } /* 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); - queue_lo = queue_hi = 0; g_reopened = True; return True; } void -wave_out_close(void) +sun_close(void) { /* Ack all remaining packets */ - while (queue_lo != queue_hi) - { - rdpsnd_send_completion(packet_queue[queue_lo].tick, packet_queue[queue_lo].index); - free(packet_queue[queue_lo].s.data); - queue_lo = (queue_lo + 1) % MAX_QUEUE; - } + while (!rdpsnd_queue_empty()) + rdpsnd_queue_next(0); #if defined I_FLUSH && defined FLUSHW /* Flush the audiobuffer */ - ioctl(g_dsp_fd, I_FLUSH, FLUSHW); + ioctl(dsp_fd, I_FLUSH, FLUSHW); #endif #if defined AUDIO_FLUSH - ioctl(g_dsp_fd, AUDIO_FLUSH, NULL); + ioctl(dsp_fd, AUDIO_FLUSH, NULL); #endif - close(g_dsp_fd); + close(dsp_fd); + dsp_fd = -1; } BOOL -wave_out_format_supported(WAVEFORMATEX * pwfx) +sun_format_supported(WAVEFORMATEX * pwfx) { if (pwfx->wFormatTag != WAVE_FORMAT_PCM) return False; @@ -107,12 +113,11 @@ } BOOL -wave_out_set_format(WAVEFORMATEX * pwfx) +sun_set_format(WAVEFORMATEX * pwfx) { audio_info_t info; - ioctl(g_dsp_fd, AUDIO_DRAIN, 0); - g_swapaudio = False; + ioctl(dsp_fd, AUDIO_DRAIN, 0); AUDIO_INITINFO(&info); @@ -123,12 +128,6 @@ else if (pwfx->wBitsPerSample == 16) { info.play.encoding = AUDIO_ENCODING_LINEAR; - /* Do we need to swap the 16bit values? (Are we BigEndian) */ -#ifdef B_ENDIAN - g_swapaudio = 1; -#else - g_swapaudio = 0; -#endif } g_samplewidth = pwfx->wBitsPerSample / 8; @@ -150,10 +149,10 @@ info.play.error = 0; g_reopened = True; - if (ioctl(g_dsp_fd, AUDIO_SETINFO, &info) == -1) + if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1) { perror("AUDIO_SETINFO"); - close(g_dsp_fd); + sun_close(); return False; } @@ -161,17 +160,13 @@ } void -wave_out_volume(uint16 left, uint16 right) +sun_volume(uint16 left, uint16 right) { audio_info_t info; uint balance; uint volume; - if (ioctl(g_dsp_fd, AUDIO_GETINFO, &info) == -1) - { - perror("AUDIO_GETINFO"); - return; - } + AUDIO_INITINFO(&info); volume = (left > right) ? left : right; @@ -189,7 +184,7 @@ info.play.gain = volume / (65536 / AUDIO_MAX_GAIN); info.play.balance = balance; - if (ioctl(g_dsp_fd, AUDIO_SETINFO, &info) == -1) + if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1) { perror("AUDIO_SETINFO"); return; @@ -197,41 +192,13 @@ } void -wave_out_write(STREAM s, uint16 tick, uint8 index) -{ - struct audio_packet *packet = &packet_queue[queue_hi]; - unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE; - - if (next_hi == queue_lo) - { - error("No space to queue audio packet\n"); - return; - } - - queue_hi = next_hi; - - packet->s = *s; - packet->tick = tick; - packet->index = index; - packet->s.p += 4; - - /* we steal the data buffer from s, give it a new one */ - s->data = malloc(s->size); - - if (!g_dsp_busy) - wave_out_play(); -} - -void -wave_out_play(void) +sun_play(void) { struct audio_packet *packet; audio_info_t info; ssize_t len; unsigned int i; - uint8 swap; STREAM out; - static BOOL swapped = False; static BOOL sentcompletion = True; static uint32 samplecnt = 0; static uint32 numsamples; @@ -242,32 +209,16 @@ { /* Device was just (re)openend */ samplecnt = 0; - swapped = False; sentcompletion = True; g_reopened = False; } - if (queue_lo == queue_hi) - { - g_dsp_busy = 0; + if (rdpsnd_queue_empty()) return; - } - packet = &packet_queue[queue_lo]; + packet = rdpsnd_queue_current_packet(); out = &packet->s; - /* Swap the current packet, but only once */ - if (g_swapaudio && !swapped) - { - for (i = 0; i < out->end - out->p; i += 2) - { - swap = *(out->p + i); - *(out->p + i) = *(out->p + i + 1); - *(out->p + i + 1) = swap; - } - swapped = True; - } - if (sentcompletion) { sentcompletion = False; @@ -278,12 +229,11 @@ 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 (errno != EWOULDBLOCK) perror("write audio"); - g_dsp_busy = 1; return; } } @@ -291,7 +241,7 @@ out->p += len; 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"); return; @@ -301,17 +251,52 @@ if (info.play.samples >= samplecnt + ((numsamples * 7) / 10)) { samplecnt += numsamples; - rdpsnd_send_completion(packet->tick, packet->index); - free(out->data); - queue_lo = (queue_lo + 1) % MAX_QUEUE; - swapped = False; + /* We need to add 50 to tell windows that time has passed while + * playing this packet */ + rdpsnd_queue_next(50); sentcompletion = True; } else { - g_dsp_busy = 1; return; } } } } + +static struct audio_driver sun_driver = { + .name = "sun", + .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_close = sun_close, + .wave_out_format_supported = sun_format_supported, + .wave_out_set_format = sun_set_format, + .wave_out_volume = sun_volume, + + .need_byteswap_on_be = 1, + .need_resampling = 0, +}; + +struct audio_driver * +sun_register(char *options) +{ + if (options) + { + dsp_dev = xstrdup(options); + } + else + { + dsp_dev = getenv("AUDIODEV"); + + if (dsp_dev == NULL) + { + dsp_dev = xstrdup(DEFAULTDEVICE); + } + } + + return &sun_driver; +}