From 0c659ecd83e777b2494bced30534adcdd965250b Mon Sep 17 00:00:00 2001 From: Michael Gernoth Date: Tue, 8 Mar 2005 03:33:36 +0000 Subject: [PATCH] basic libao output-driver. works on Mac OSX. no volume control possible git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@832 423420c4-83ab-492f-b58f-81f9feb106b5 --- configure.ac | 23 +++++- rdpsnd_libao.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 rdpsnd_libao.c diff --git a/configure.ac b/configure.ac index 92711c6..11cabd9 100644 --- a/configure.ac +++ b/configure.ac @@ -135,13 +135,24 @@ AC_ARG_WITH(libvncserver, # # sound # +AC_ARG_WITH(libao, + [ --with-libao=DIR look for libao at DIR/include, DIR/lib], + [ + CFLAGS="$CFLAGS -I$withval/include" + CPPFLAGS="$CPPFLAGS -I$withval/include" + LIBS="$LIBS -L$withval/lib" + rpath="$rpath:$withval/lib" + ] +) + sound="yes" AC_ARG_WITH(sound, - [ --with-sound select sound system ("oss", "sgi" or "sun") ], + [ --with-sound select sound system ("oss", "sgi", "sun" or "libao") ], [ sound="$withval" ]) if test "$sound" = yes; then + AC_CHECK_HEADER(ao/ao.h, [sound=libao]) AC_CHECK_HEADER(sys/soundcard.h, [sound=oss]) AC_CHECK_HEADER(dmedia/audio.h, [sound=sgi]) AC_CHECK_HEADER(sys/audioio.h, [sound=sun]) @@ -158,12 +169,18 @@ elif test "$sound" = sgi; then elif test "$sound" = sun; then SOUNDOBJ="rdpsnd.o rdpsnd_sun.o" AC_DEFINE(WITH_RDPSND) +elif test "$sound" = libao; then + SOUNDOBJ="rdpsnd.o rdpsnd_libao.o" + LDFLAGS="$LDFLAGS -lao" + 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), SGI AL (sgi) and Sun/BSD (sun)]) + AC_MSG_WARN([sound support disabled]) + AC_MSG_WARN([Currently supported systems are Open Sound System (oss), SGI AL (sgi), Sun/BSD (sun) and libao]) fi AC_SUBST(SOUNDOBJ) +AC_MSG_CHECKING([checking for sound support]) + # # dirfd # diff --git a/rdpsnd_libao.c b/rdpsnd_libao.c new file mode 100644 index 0000000..131ff0b --- /dev/null +++ b/rdpsnd_libao.c @@ -0,0 +1,200 @@ +/* + rdesktop: A Remote Desktop Protocol client. + Sound Channel Process Functions - libao-driver + Copyright (C) Matthew Chapman 2003 + Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003 + Copyright (C) Michael Gernoth mike@zerfleddert.de 2005 + + 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 + +#define MAX_QUEUE 10 + +int g_dsp_fd; +ao_device *o_device = NULL; +int default_driver; +BOOL g_dsp_busy = False; +static short g_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) +{ + ao_sample_format format; + + ao_initialize(); + default_driver = ao_default_driver_id(); + + format.bits = 16; + format.channels = 2; + format.rate = 44100; + format.byte_format = AO_FMT_LITTLE; + + o_device = ao_open_live(default_driver, &format, NULL); + if (o_device == NULL) + { + return False; + } + + g_dsp_fd = 0; + queue_lo = queue_hi = 0; + + return True; +} + +void +wave_out_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; + } + + if (o_device != NULL) + ao_close(o_device); + ao_shutdown(); +} + +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; + /* The only common denominator between libao output drivers is a sample-rate of + 44100, windows gives a max of 22050. we need to upsample that... + TODO: support 11025, too */ + if (pwfx->nSamplesPerSec != 22050) + return False; + + return True; +} + +BOOL +wave_out_set_format(WAVEFORMATEX * pwfx) +{ + ao_sample_format format; + + printf("%d\n",pwfx->wBitsPerSample); + format.bits = pwfx->wBitsPerSample; + format.channels = pwfx->nChannels; + format.rate = 44100; + format.byte_format = AO_FMT_LITTLE; + + g_samplewidth = pwfx->wBitsPerSample / 8; + + if(o_device != NULL) + ao_close(o_device); + + o_device = ao_open_live(default_driver, &format, NULL); + if (o_device == NULL) + { + return False; + } + + + return True; +} + +void +wave_out_volume(uint16 left, uint16 right) +{ +} + +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) +{ + struct audio_packet *packet; + STREAM out; + unsigned char expanded[8]; + + while (1) + { + if (queue_lo == queue_hi) + { + g_dsp_busy = 0; + return; + } + + packet = &packet_queue[queue_lo]; + out = &packet->s; + + /* Resample 22050 -> 44100 */ + /* TODO: Do this for 11025, too... */ + memcpy(&expanded[0],out->p,g_samplewidth); + memcpy(&expanded[2*g_samplewidth],out->p,g_samplewidth); + out->p += 2; + memcpy(&expanded[1*g_samplewidth],out->p,g_samplewidth); + memcpy(&expanded[3*g_samplewidth],out->p,g_samplewidth); + out->p += 2; + + ao_play(o_device, expanded, g_samplewidth*4); + + if (out->p == out->end) + { + rdpsnd_send_completion(packet->tick, packet->index); + free(out->data); + queue_lo = (queue_lo + 1) % MAX_QUEUE; + } else { + g_dsp_busy = 1; + return; + } + } +}