diff --git a/configure b/configure index b4f0f4a..73c2264 100755 --- a/configure +++ b/configure @@ -242,9 +242,14 @@ if [ -f /usr/include/sys/soundcard.h ]; then echo echo "SOUNDOBJ = rdpsnd.o rdpsnd_oss.o" >>Makeconf cflags="$cflags -DWITH_RDPSND" +elif [ -f /usr/include/sys/audio.h ]; then + echo Sound support enabled: Sun + echo + echo "SOUNDOBJ = rdpsnd.o rdpsnd_sun.o" >>Makeconf + cflags="$cflags -DWITH_RDPSND" else - echo "WARNING: sound support disabled (no /usr/include/sys/soundcard.h)" - echo "Only Open Sound System audio is supported at present" + echo "WARNING: sound support disabled (no /usr/include/sys/soundcard.h or /usr/include/sys/audio.h)" + echo "Currently supported systems are Open Sound System and Sun" echo fi diff --git a/rdpsnd_oss.c b/rdpsnd_oss.c index 6178fe8..c1e89f9 100644 --- a/rdpsnd_oss.c +++ b/rdpsnd_oss.c @@ -115,8 +115,8 @@ wave_out_set_format(WAVEFORMATEX *pwfx) void wave_out_write(STREAM s, uint16 tick, uint8 index) { - struct audio_packet *packet = &packet_queue[queue_lo]; - unsigned int next_hi = (queue_lo + 1) % MAX_QUEUE; + struct audio_packet *packet = &packet_queue[queue_hi]; + unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE; if (next_hi == queue_lo) { diff --git a/rdpsnd_sun.c b/rdpsnd_sun.c new file mode 100644 index 0000000..9a56c98 --- /dev/null +++ b/rdpsnd_sun.c @@ -0,0 +1,242 @@ +/* + 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 + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "rdesktop.h" +#include +#include +#include +#include +#include +#include + +#define MAX_QUEUE 10 + +int g_dsp_fd; +BOOL g_dsp_busy; +static BOOL swapaudio; +static short samplewidth; + +static struct audio_packet { + struct stream s; + uint16 tick; + uint8 index; +} packet_queue[MAX_QUEUE]; +static unsigned int queue_hi, queue_lo; + +BOOL +wave_out_open(void) +{ + char *dsp_dev = "/dev/audio"; + + if ((g_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); + queue_lo = queue_hi = 0; + return True; +} + +void +wave_out_close(void) +{ + ioctl(g_dsp_fd,I_FLUSH,FLUSHW); + close(g_dsp_fd); +} + +BOOL +wave_out_format_supported(WAVEFORMATEX *pwfx) +{ + if (pwfx->wFormatTag != WAVE_FORMAT_PCM) + return False; + if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2)) + return False; + if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16)) + return False; + + return True; +} + +BOOL +wave_out_set_format(WAVEFORMATEX *pwfx) +{ + audio_info_t info; + int test = 1; + + ioctl(g_dsp_fd, AUDIO_DRAIN, 0); + swapaudio = False; + AUDIO_INITINFO(&info); + + + if (pwfx->wBitsPerSample == 8) + { + info.play.encoding = AUDIO_ENCODING_LINEAR8; + samplewidth=1; + } + else if (pwfx->wBitsPerSample == 16) + { + info.play.encoding = AUDIO_ENCODING_LINEAR; + swapaudio = !(*(uint8 *) (&test)); + samplewidth=2; + } + + if (pwfx->nChannels == 1 ) + { + info.play.channels = AUDIO_CHANNELS_MONO; + } + else if (pwfx->nChannels == 2 ) + { + info.play.channels = AUDIO_CHANNELS_STEREO; + samplewidth*=2; + } + + info.play.sample_rate = pwfx->nSamplesPerSec; + info.play.precision = pwfx->wBitsPerSample; + info.play.samples = 0; + info.play.eof = 0; + info.play.error = 0; + + if (ioctl(g_dsp_fd, AUDIO_SETINFO, &info) == -1) + { + perror("AUDIO_SETINFO"); + close(g_dsp_fd); + return False; + } + + return True; +} + +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; + + /* 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) +{ + 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 int samplecnt; + static int numsamples; + + while (1) + { + if (queue_lo == queue_hi) + { + g_dsp_busy = 0; + return; + } + + packet = &packet_queue[queue_lo]; + out = &packet->s; + + if ( 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 ) + { + if (ioctl(g_dsp_fd, AUDIO_GETINFO, &info) == -1) + { + perror("AUDIO_GETINFO"); + return; + } + samplecnt=info.play.samples; + sentcompletion = False; + numsamples = (out->end-out->p)/samplewidth; + } + + len=0; + + if ( out->end - out->p != 0 ) + { + len = write(g_dsp_fd, out->p, out->end - out->p); + if (len == -1) + { + if (errno != EWOULDBLOCK) + perror("write audio"); + g_dsp_busy = 1; + return; + } + } + + out->p += len; + if (out->p == out->end) + { + if (ioctl(g_dsp_fd, AUDIO_GETINFO, &info) == -1) + { + perror("AUDIO_GETINFO"); + return; + } + if ( info.play.samples >= samplecnt+(numsamples)*0.9 ) + { + rdpsnd_send_completion(packet->tick, packet->index); + free(out->data); + queue_lo = (queue_lo + 1) % MAX_QUEUE; + swapped = False; + sentcompletion = True; + } + else + { + g_dsp_busy = 1; + return; + } + } + } +}