diff --git a/configure.ac b/configure.ac index 0ab065a..fa379fe 100644 --- a/configure.ac +++ b/configure.ac @@ -132,12 +132,13 @@ AC_ARG_WITH(libvncserver, # sound="yes" AC_ARG_WITH(sound, - [ --with-sound select sound system ("oss" or "sun") ], + [ --with-sound select sound system ("oss", "sgi" or "sun") ], [ sound="$withval" ]) if test "$sound" = yes; then AC_CHECK_HEADER(sys/soundcard.h, [sound=oss]) + AC_CHECK_HEADER(dmedia/audio.h, [sound=sgi]) AC_CHECK_HEADER(sys/audioio.h, [sound=sun]) fi if test "$sound" = no; then @@ -145,12 +146,16 @@ if test "$sound" = no; then elif test "$sound" = oss; then SOUNDOBJ="rdpsnd.o rdpsnd_oss.o" AC_DEFINE(WITH_RDPSND) +elif test "$sound" = sgi; then + SOUNDOBJ="rdpsnd.o rdpsnd_sgi.o" + LDFLAGS="$LDFLAGS -laudio" + AC_DEFINE(WITH_RDPSND) elif test "$sound" = sun; then SOUNDOBJ="rdpsnd.o rdpsnd_sun.o" AC_DEFINE(WITH_RDPSND) else AC_MSG_WARN([sound support disabled (no sys/soundcard.h or sys/audioio.h)]) - AC_MSG_WARN([Currently supported systems are Open Sound System (oss) and Sun/BSD (sun)]) + AC_MSG_WARN([Currently supported systems are Open Sound System (oss), SGI AL (sgi) and Sun/BSD (sun)]) fi AC_SUBST(SOUNDOBJ) @@ -273,6 +278,10 @@ case "$host" in *-*-hpux*) CFLAGS="$CFLAGS -D_XOPEN_SOURCE_EXTENDED" ;; +*-*-irix6.5*) + LIBS="$LIBS -L$ssldir/lib32 -lcrypto" + CFLAGS="$CFLAGS -D__SGI_IRIX__" + ;; esac diff --git a/rdpsnd_sgi.c b/rdpsnd_sgi.c new file mode 100644 index 0000000..dc905aa --- /dev/null +++ b/rdpsnd_sgi.c @@ -0,0 +1,358 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Sound Channel Process Functions - SGI/IRIX + 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 + +#define IRIX_DEBUG 1 + +#define IRIX_MAX_VOL 65535 + +#define MAX_QUEUE 10 + +int g_dsp_fd; +ALconfig audioconfig; +ALport output_port; + +BOOL g_dsp_busy = False; +static BOOL g_swapaudio; +static int g_snd_rate; +static BOOL g_swapaudio; +static short g_samplewidth; +static int width = AL_SAMPLE_16; + +double min_volume, max_volume, volume_range; +int resource, maxFillable; +int combinedFrameSize; + +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) +{ + ALparamInfo pinfo; + +#if (defined(IRIX_DEBUG)) + fprintf(stderr, "wave_out_open: begin\n"); +#endif + + if ( alGetParamInfo(AL_DEFAULT_OUTPUT, AL_GAIN, &pinfo) < 0 ) + { + fprintf(stderr, "wave_out_open: alGetParamInfo failed: %s\n", + alGetErrorString(oserror())); + } + min_volume = alFixedToDouble(pinfo.min.ll); + max_volume = alFixedToDouble(pinfo.max.ll); + volume_range = (max_volume - min_volume); +#if (defined(IRIX_DEBUG)) + fprintf(stderr, "wave_out_open: minvol = %lf, maxvol= %lf, range = %lf.\n", + min_volume, max_volume, volume_range); +#endif + + queue_lo = queue_hi = 0; + + audioconfig = alNewConfig(); + if (audioconfig < 0) { + fprintf(stderr, "wave_out_open: alNewConfig failed: %s\n", + alGetErrorString(oserror())); + return False; + } + + output_port = alOpenPort("rdpsnd", "w", 0); + if (output_port == (ALport) 0) { + fprintf(stderr, "wave_out_open: alOpenPort failed: %s\n", + alGetErrorString(oserror())); + return False; + } + +#if (defined(IRIX_DEBUG)) + fprintf(stderr, "wave_out_open: returning\n"); +#endif + return True; +} + +void +wave_out_close(void) +{ + /* Ack all remaining packets */ +#if (defined(IRIX_DEBUG)) + fprintf(stderr, "wave_out_close: begin\n"); +#endif + + 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; + } + alDiscardFrames(output_port, 0); + + alClosePort(output_port); + alFreeConfig(audioconfig); +#if (defined(IRIX_DEBUG)) + fprintf(stderr, "wave_out_close: returning\n"); +#endif +} + +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) +{ + int channels; + int frameSize, channelCount; + ALpv params; + +#if (defined(IRIX_DEBUG)) + fprintf(stderr, "wave_out_set_format: init...\n"); +#endif + /* limited support to configure an opened audio port in IRIX */ + /* have to reopen the audio port, using same config */ + alClosePort(output_port); + + g_swapaudio = False; + + if (pwfx->wBitsPerSample == 8) + width = AL_SAMPLE_8; + else if (pwfx->wBitsPerSample == 16) { + width = AL_SAMPLE_16; + /* Do we need to swap the 16bit values? (Are we BigEndian) */ +#if (defined(IRIX_DEBUG)) + g_swapaudio = 1; +#else + g_swapaudio = 0; +#endif + } + + g_samplewidth = pwfx->wBitsPerSample / 8; + channels = pwfx->nChannels; + g_snd_rate = pwfx->nSamplesPerSec; + + alSetSampFmt(audioconfig, AL_SAMPFMT_TWOSCOMP); + alSetWidth(audioconfig, width); + alSetChannels(audioconfig, channels); + + output_port = alOpenPort("rdpsnd", "w", audioconfig); + + if (output_port == (ALport) 0) { + fprintf(stderr, "wave_out_set_format: alOpenPort failed: %s\n", + alGetErrorString(oserror())); + return False; + } + + resource = alGetResource(output_port); + maxFillable = alGetFillable(output_port); + channelCount = alGetChannels(audioconfig); + frameSize = alGetWidth(audioconfig); + + if (frameSize == 0 || channelCount == 0) + { + fprintf(stderr, "wave_out_set_format: bad frameSize or channelCount\n"); + return False; + } + combinedFrameSize = frameSize * channelCount; + + params.param = AL_RATE; + params.value.ll = (long long) g_snd_rate << 32; + + if (alSetParams(resource, ¶ms, 1) < 0) + { + fprintf(stderr, "wave_set_format: alSetParams failed: %s\n", + alGetErrorString(oserror())); + return False; + } + if( params.sizeOut < 0 ) + { + fprintf(stderr, "wave_set_format: invalid rate %d\n", g_snd_rate); + return False; + } + +#if (defined(IRIX_DEBUG)) + fprintf(stderr, "wave_out_set_format: returning...\n"); +#endif + return True; +} + +void +wave_out_volume(uint16 left, uint16 right) +{ + double gainleft, gainright; + ALpv pv[1]; + ALfixed gain[8]; + +#if (defined(IRIX_DEBUG)) + fprintf(stderr, "wave_out_volume: begin\n"); + fprintf(stderr, "left='%d', right='%d'\n", left, right); +#endif + + gainleft = (double) left / IRIX_MAX_VOL; + gainright = (double) right / IRIX_MAX_VOL; + + gain[0] = alDoubleToFixed(min_volume + gainleft * volume_range); + gain[1] = alDoubleToFixed(min_volume + gainright * volume_range); + + pv[0].param = AL_GAIN; + pv[0].value.ptr = gain; + pv[0].sizeIn = 8; + if( alSetParams(AL_DEFAULT_OUTPUT, pv, 1) < 0) + { + fprintf(stderr, "wave_out_volume: alSetParams failed: %s\n", alGetErrorString(oserror())); + return; + } + +#if (defined(IRIX_DEBUG)) + fprintf(stderr, "wave_out_volume: returning\n"); +#endif +} + +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) + { + fprintf(stderr, "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) +{ + struct audio_packet *packet; + ssize_t len; + unsigned int i; + uint8 swap; + STREAM out; + static long startedat_us; + static long startedat_s; + static BOOL started = False; + static BOOL swapped = False; + struct timeval tv; + int gf; + static long long temp; + + while (1) + { + if (queue_lo == queue_hi) + { + g_dsp_busy = False; + return; + } + + packet = &packet_queue[queue_lo]; + 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 (!started) + { + gettimeofday(&tv, NULL); + startedat_us = tv.tv_usec; + startedat_s = tv.tv_sec; + started = True; + } + + len = out->end - out->p; + gf = alGetFillable(output_port); + if (len > gf) { + //len = gf * combinedFrameSize; +#if (defined(IRIX_DEBUG)) + //fprintf(stderr,"Fillable...\n"); +#endif + } + + alWriteFrames(output_port, out->p, len/combinedFrameSize); + + out->p += len; + if (out->p == out->end) + { + long long duration; + long elapsed; + + gettimeofday(&tv, NULL); + duration = (out->size * (1000000 / (g_samplewidth * g_snd_rate))); + elapsed = (tv.tv_sec - startedat_s) * 1000000 + + (tv.tv_usec - startedat_us); + /* 7/10 is not good for IRIX audio port, 4x/100 is suitable */ + if (elapsed >= (duration * 485) / 1000) + { + rdpsnd_send_completion(packet->tick, packet->index); + free(out->data); + queue_lo = (queue_lo + 1) % MAX_QUEUE; + started = False; + swapped = False; + } + else + { +#if (defined(IRIX_DEBUG)) + //fprintf(stderr,"Busy playing...\n"); +#endif + g_dsp_busy = True; + return; + } + } + } +}