From c48149133f36b24fb87924209a950681be0727c7 Mon Sep 17 00:00:00 2001 From: Daniel Caujolle-Bert Date: Mon, 1 Oct 2001 23:04:57 +0000 Subject: Add simple mixer control in xine-engine/ao plugins. Fixed some missings in audio_decoder. xine-ui warn at compile time due of a #warning i added, i will remove it pretty soon. CVS patchset: 715 CVS date: 2001/10/01 23:04:57 --- src/audio_out/audio_alsa_out.c | 315 ++++++++++++++++++++++++++++++++++++++-- src/audio_out/audio_oss_out.c | 220 ++++++++++++++++++++++++---- src/xine-engine/audio_decoder.c | 6 +- src/xine-engine/audio_out.c | 19 ++- src/xine-engine/audio_out.h | 10 +- src/xine-engine/xine.c | 25 +++- 6 files changed, 546 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/audio_out/audio_alsa_out.c b/src/audio_out/audio_alsa_out.c index e887b277d..0ec7de759 100644 --- a/src/audio_out/audio_alsa_out.c +++ b/src/audio_out/audio_alsa_out.c @@ -26,7 +26,7 @@ * (c) 2001 James Courtier-Dutton * * - * $Id: audio_alsa_out.c,v 1.28 2001/09/14 20:44:01 jcdutton Exp $ + * $Id: audio_alsa_out.c,v 1.29 2001/10/01 23:04:57 f1rmb Exp $ */ #ifdef HAVE_CONFIG_H @@ -40,7 +40,8 @@ #include #include #include -#include +#include +#include #include #include @@ -75,11 +76,18 @@ #define AO_OUT_ALSA_IFACE_VERSION 2 -#define GAP_TOLERANCE 5000 +#define GAP_TOLERANCE 5000 + +#define MIXER_MASK_LEFT (1 << 0) +#define MIXER_MASK_RIGHT (1 << 1) +#define MIXER_MASK_STEREO (MIXER_MASK_LEFT|MIXER_MASK_RIGHT) typedef struct alsa_driver_s { ao_driver_t ao_driver; + + config_values_t *config; + char audio_default_device[20]; char audio_front_device[20]; char audio_surround40_device[20]; @@ -97,9 +105,46 @@ typedef struct alsa_driver_s { uint32_t bytes_per_frame; uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */ + struct { + char *name; + snd_mixer_t *handle; + snd_mixer_elem_t *elem; + long min; + long max; + long left_vol; + long right_vol; + int mute; + } mixer; + } alsa_driver_t; - static snd_output_t *jcd_out; +static snd_output_t *jcd_out; + +static int ao_alsa_get_percent_from_volume(long val, long min, long max) +{ + int range = max - min; + int tmp; + + if (range == 0) + return 0; + val -= min; + tmp = rint((double)val / (double)range * 100); + return tmp; +} + +static long ao_alsa_get_volume_from_percent(int val, long min, long max) +{ + int range = max - min; + long tmp; + + if (range == 0) + return 0; + val -= min; + tmp = (long) ((range * val) / 100); + return tmp; +} + + /* * open the audio device for writing to */ @@ -402,44 +447,283 @@ static uint32_t ao_alsa_get_capabilities (ao_driver_t *this_gen) { static void ao_alsa_exit(ao_driver_t *this_gen) { alsa_driver_t *this = (alsa_driver_t *) this_gen; + + config_values_t *config = this->config; + + config->set_int (config, "mixer_volume", + (((ao_alsa_get_percent_from_volume(this->mixer.left_vol, + this->mixer.min, this->mixer.max)) + + (ao_alsa_get_percent_from_volume(this->mixer.right_vol, + this->mixer.min, this->mixer.max))) /2)); + config->save(config); + if (this->audio_fd) snd_pcm_close(this->audio_fd); free (this); } -static int ao_alsa_get_property (ao_driver_t *this, int property) { +static int ao_alsa_get_property (ao_driver_t *this_gen, int property) { + alsa_driver_t *this = (alsa_driver_t *) this_gen; + int err; - /* FIXME: implement some properties switch(property) { case AO_PROP_MIXER_VOL: - break; case AO_PROP_PCM_VOL: + if(this->mixer.elem) { + if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, + &this->mixer.left_vol)) < 0) { + printf("snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); + goto __done; + } + + if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, + &this->mixer.right_vol)) < 0) { + printf("snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); + goto __done; + } + + __done: + return (((ao_alsa_get_percent_from_volume(this->mixer.left_vol, + this->mixer.min, this->mixer.max)) + + (ao_alsa_get_percent_from_volume(this->mixer.right_vol, + this->mixer.min, this->mixer.max))) /2); + } break; + case AO_PROP_MUTE_VOL: + return (this->mixer.mute) ? 1 : 0; break; } - */ + return 0; } /* * */ -static int ao_alsa_set_property (ao_driver_t *this, int property, int value) { +static int ao_alsa_set_property (ao_driver_t *this_gen, int property, int value) { + alsa_driver_t *this = (alsa_driver_t *) this_gen; + int err; - /* FIXME: Implement property support. switch(property) { case AO_PROP_MIXER_VOL: - break; case AO_PROP_PCM_VOL: + if(this->mixer.elem) { + + this->mixer.left_vol = this->mixer.right_vol = ao_alsa_get_volume_from_percent(value, this->mixer.min, this->mixer.max); + + if((err = snd_mixer_selem_set_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, + this->mixer.left_vol)) < 0) { + printf("snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); + return ~value; + } + + if((err = snd_mixer_selem_set_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, + this->mixer.right_vol)) < 0) { + printf("snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); + return ~value; + } + + return value; + } break; + case AO_PROP_MUTE_VOL: + if(this->mixer.elem) { + int sw; + int old_mute = this->mixer.mute; + + this->mixer.mute = (value) ? MIXER_MASK_STEREO : 0; + + if ((this->mixer.mute != old_mute) + && snd_mixer_selem_has_playback_switch(this->mixer.elem)) { + if (snd_mixer_selem_has_playback_switch_joined(this->mixer.elem)) { + snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &sw); + snd_mixer_selem_set_playback_switch_all(this->mixer.elem, !sw); + } else { + if (this->mixer.mute & MIXER_MASK_LEFT) { + snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &sw); + snd_mixer_selem_set_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, !sw); + } + if (SND_MIXER_SCHN_FRONT_RIGHT != SND_MIXER_SCHN_UNKNOWN && + (this->mixer.mute & MIXER_MASK_RIGHT)) { + snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, &sw); + snd_mixer_selem_set_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, !sw); + } + } + } + + return value; + } + + return ~value; break; } - */ return ~value; } +static void ao_alsa_mixer_init(ao_driver_t *this_gen) { + alsa_driver_t *this = (alsa_driver_t *) this_gen; + config_values_t *config = this->config; + snd_ctl_card_info_t *hw_info; + snd_ctl_t *ctl_handle; + int err; + void *mixer_sid; + snd_mixer_elem_t *elem; + int mixer_n_selems = 0; + snd_mixer_selem_id_t *sid; + int loop = 0; + int found; + int sw; + + snd_ctl_card_info_alloca(&hw_info); + + if ((err = snd_ctl_open (&ctl_handle, this->audio_default_device, 0)) < 0) { + printf("snd_ctl_open(): %s\n", snd_strerror(err)); + return; + } + + if ((err = snd_ctl_card_info (ctl_handle, hw_info)) < 0) { + printf("snd_ctl_card_info(): %s\n", snd_strerror(err)); + snd_ctl_close(ctl_handle); + return; + } + + snd_ctl_close (ctl_handle); + + /* + * Open mixer device + */ + if ((err = snd_mixer_open (&this->mixer.handle, 0)) < 0) { + printf("snd_mixer_open(): %s\n", snd_strerror(err)); + return; + } + + if ((err = snd_mixer_attach (this->mixer.handle, this->audio_default_device)) < 0) { + printf("snd_mixer_attach(): %s\n", snd_strerror(err)); + snd_mixer_close(this->mixer.handle); + return; + } + + if ((err = snd_mixer_selem_register (this->mixer.handle, NULL, NULL)) < 0) { + printf("snd_mixer_selem_register(): %s\n", snd_strerror(err)); + snd_mixer_close(this->mixer.handle); + return; + } + + // snd_mixer_set_callback (mixer_handle, mixer_event); + + if ((err = snd_mixer_load (this->mixer.handle)) < 0) { + printf("snd_mixer_load(): %s\n", snd_strerror(err)); + snd_mixer_close(this->mixer.handle); + return; + } + + mixer_sid = alloca(snd_mixer_selem_id_sizeof() * snd_mixer_get_count(this->mixer.handle)); + if (mixer_sid == NULL) { + printf("alloca() failed: %s\n", strerror(errno)); + snd_mixer_close(this->mixer.handle); + return; + } + + __again: + + found = 0; + mixer_n_selems = 0; + for (elem = snd_mixer_first_elem(this->mixer.handle); elem; elem = snd_mixer_elem_next(elem)) { + sid = (snd_mixer_selem_id_t *)(((char *)mixer_sid) + snd_mixer_selem_id_sizeof() * mixer_n_selems); + + if (!snd_mixer_selem_is_active(elem)) + continue; + + snd_mixer_selem_get_id(elem, sid); + mixer_n_selems++; + + if(!strcmp((snd_mixer_selem_get_name(elem)), this->mixer.name)) { + + // printf("found %s\n", snd_mixer_selem_get_name(elem)); + + this->mixer.elem = elem; + + snd_mixer_selem_get_playback_volume_range(this->mixer.elem, + &this->mixer.min, &this->mixer.max); + if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, + &this->mixer.left_vol)) < 0) { + printf("snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); + snd_mixer_close(this->mixer.handle); + return; + } + + if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, + &this->mixer.right_vol)) < 0) { + printf("snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); + snd_mixer_close(this->mixer.handle); + return; + } + + /* Channels mute */ + this->mixer.mute = 0; + if(snd_mixer_selem_has_playback_switch(this->mixer.elem)) { + + if (snd_mixer_selem_has_playback_switch_joined(this->mixer.elem)) { + snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &sw); + if(!sw) + this->mixer.mute = MIXER_MASK_STEREO; + } + else { + if (this->mixer.mute & MIXER_MASK_LEFT) { + snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &sw); + if(!sw) + this->mixer.mute |= MIXER_MASK_LEFT; + } + if (SND_MIXER_SCHN_FRONT_RIGHT != SND_MIXER_SCHN_UNKNOWN && + (this->mixer.mute & MIXER_MASK_RIGHT)) { + snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, &sw); + if(!sw) + this->mixer.mute |= MIXER_MASK_RIGHT; + } + } + + this->capabilities |= AO_CAP_MUTE_VOL; + } + + found++; + + goto __mixer_found; + } + } + + if(loop) + goto __mixer_found; /* Yes, untrue but... ;-) */ + + if(!strcmp(this->mixer.name, "PCM")) { + config->set_str(config, "mixer_name", "Master"); + loop++; + } + else { + config->set_str(config, "mixer_name", "PCM"); + } + + config->save(config); + + this->mixer.name = config->lookup_str(config, "mixer_name", "PCM"); + + goto __again; + + __mixer_found: + + /* + * Ugly: yes[*] no[ ] + */ + if(found) { + if(!strcmp(this->mixer.name, "Master")) + this->capabilities |= AO_CAP_MIXER_VOL; + else + this->capabilities |= AO_CAP_PCM_VOL; + } + +} + ao_driver_t *init_audio_out_plugin (config_values_t *config) { alsa_driver_t *this; @@ -514,7 +798,12 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { this->capabilities |= AO_CAP_MODE_AC5; } printf("audio_alsa_out: Capabilities 0x%X\n",this->capabilities); - + + this->config = config; + + this->mixer.name = config->lookup_str(config, "mixer_name", "PCM"); + ao_alsa_mixer_init(&this->ao_driver); + this->ao_driver.get_capabilities = ao_alsa_get_capabilities; this->ao_driver.get_property = ao_alsa_get_property; this->ao_driver.set_property = ao_alsa_set_property; diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c index b176cfb14..cdf1dcf44 100644 --- a/src/audio_out/audio_oss_out.c +++ b/src/audio_out/audio_oss_out.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_oss_out.c,v 1.40 2001/09/30 23:12:05 heikos Exp $ + * $Id: audio_oss_out.c,v 1.41 2001/10/01 23:04:57 f1rmb Exp $ * * 20-8-2001 First implementation of Audio sync and Audio driver separation. * Copyright (C) 2001 James Courtier-Dutton James@superbug.demon.co.uk @@ -100,21 +100,31 @@ static int use_getodelay = 0; typedef struct oss_driver_s { - ao_driver_t ao_driver; - char audio_dev[20]; - int audio_fd; - int capabilities; - int mode; - - int32_t output_sample_rate, input_sample_rate; - uint32_t num_channels; - uint32_t bits_per_sample; - uint32_t bytes_per_frame; - uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */ + ao_driver_t ao_driver; + char audio_dev[20]; + int audio_fd; + int capabilities; + int mode; + + config_values_t *config; + + int32_t output_sample_rate, input_sample_rate; + uint32_t num_channels; + uint32_t bits_per_sample; + uint32_t bytes_per_frame; + uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */ - int audio_started; - int audio_has_realtime; /* OSS driver supports real-time */ - int static_delay; /* estimated delay for non-realtime drivers */ + int audio_started; + int audio_has_realtime; /* OSS driver supports real-time */ + int static_delay; /* estimated delay for non-realtime drivers */ + + struct { + char *name; + int prop; + int volume; + int mute; + } mixer; + } oss_driver_t; /* @@ -368,6 +378,10 @@ static uint32_t ao_oss_get_capabilities (ao_driver_t *this_gen) { static void ao_oss_exit(ao_driver_t *this_gen) { oss_driver_t *this = (oss_driver_t *) this_gen; + config_values_t *config = this->config; + + config->set_int (config, "mixer_volume", this->mixer.volume); + config->save(config); if (this->audio_fd != -1) close(this->audio_fd); @@ -375,41 +389,128 @@ static void ao_oss_exit(ao_driver_t *this_gen) free (this); } -/* - * - */ static int ao_oss_get_property (ao_driver_t *this_gen, int property) { - oss_driver_t *this = (oss_driver_t *) this; + oss_driver_t *this = (oss_driver_t *) this_gen; + int mixer_fd; + int audio_devs; - /* FIXME: implement some properties switch(property) { - case AO_PROP_MIXER_VOL: - break; case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: + mixer_fd = open(this->mixer.name, O_RDONLY); + if(mixer_fd != -1) { + int cmd = 0; + int v; + + ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &audio_devs); + + if(audio_devs & SOUND_MASK_PCM) + cmd = SOUND_MIXER_READ_PCM; + else if(audio_devs & SOUND_MASK_VOLUME) + cmd = SOUND_MIXER_READ_VOLUME; + else { + close(mixer_fd); + return 0; + } + ioctl(mixer_fd, cmd, &v); + this->mixer.volume = (((v & 0xFF00) >> 8) + (v & 0x00FF)) / 2; + close(mixer_fd); + } + else + printf("%s(): open() %s failed: %s\n", + __FUNCTION__, this->mixer.name, strerror(errno)); + + return this->mixer.volume; break; + case AO_PROP_MUTE_VOL: + return this->mixer.mute; break; } - */ + return 0; } -/* - * - */ static int ao_oss_set_property (ao_driver_t *this_gen, int property, int value) { - oss_driver_t *this = (oss_driver_t *) this; + oss_driver_t *this = (oss_driver_t *) this_gen; + int mixer_fd; + int audio_devs; - /* FIXME: Implement property support. switch(property) { - case AO_PROP_MIXER_VOL: - break; case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: + if(!this->mixer.mute) { + + mixer_fd = open(this->mixer.name, O_RDONLY); + + if(mixer_fd != -1) { + int cmd = 0; + int v; + + ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &audio_devs); + + if(audio_devs & SOUND_MASK_PCM) + cmd = SOUND_MIXER_WRITE_PCM; + else if(audio_devs & SOUND_MASK_VOLUME) + cmd = SOUND_MIXER_WRITE_VOLUME; + else { + close(mixer_fd); + return ~value; + } + v = (value << 8) | value; + ioctl(mixer_fd, cmd, &v); + close(mixer_fd); + + if(!this->mixer.mute) + this->mixer.volume = value; + + } + else + printf("%s(): open() %s failed: %s\n", + __FUNCTION__, this->mixer.name, strerror(errno)); + } + else + this->mixer.volume = value; + + return this->mixer.volume; break; + case AO_PROP_MUTE_VOL: + this->mixer.mute = (value) ? 1 : 0; + + if(this->mixer.mute) { + + mixer_fd = open(this->mixer.name, O_RDONLY); + + if(mixer_fd != -1) { + int cmd = 0; + int v = 0; + + ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &audio_devs); + + if(audio_devs & SOUND_MASK_PCM) + cmd = SOUND_MIXER_WRITE_PCM; + else if(audio_devs & SOUND_MASK_VOLUME) + cmd = SOUND_MIXER_WRITE_VOLUME; + else { + close(mixer_fd); + return ~value; + } + + ioctl(mixer_fd, cmd, &v); + close(mixer_fd); + + } + else + printf("%s(): open() %s failed: %s\n", + __FUNCTION__, this->mixer.name, strerror(errno)); + } + else + (void) ao_oss_set_property(&this->ao_driver, this->mixer.prop, this->mixer.volume); + + return value; break; } - */ return ~value; } @@ -428,7 +529,7 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { int devnum; int audio_fd; int num_channels, status, arg; - + this = (oss_driver_t *) malloc (sizeof (oss_driver_t)); /* @@ -574,7 +675,61 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { } printf ("\n"); + + /* + * Mixer initialisation. + */ + __again: + this->mixer.name = config->lookup_str(config, "mixer_name", "/dev/mixer"); + { + int mixer_fd; + int audio_devs; + + mixer_fd = open(this->mixer.name, O_RDONLY); + + if(mixer_fd != -1) { + ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &audio_devs); + + if(audio_devs & SOUND_MASK_PCM) { + this->capabilities |= AO_CAP_PCM_VOL; + this->mixer.prop = AO_PROP_PCM_VOL; + } + else if(audio_devs & SOUND_MASK_VOLUME) { + this->capabilities |= AO_CAP_MIXER_VOL; + this->mixer.prop = AO_PROP_MIXER_VOL; + } + + /* + * This is obsolete in Linux kernel OSS + * implementation, so this will certainly doesn't work. + * So we just simulate the mute stuff + */ + /* + if(audio_devs & SOUND_MASK_MUTE) + this->capabilities |= AO_CAP_MUTE_VOL; + */ + this->capabilities |= AO_CAP_MUTE_VOL; + + } + else { + if(strcmp(this->mixer.name, "/dev/mixer")) { + config->set_str(config, "mixer_name", "/dev/mixer"); + config->save(config); + goto __again; + } + else + printf("%s(): open() %s failed: %s\n", + __FUNCTION__, this->mixer.name, strerror(errno)); + } + + this->mixer.mute = 0; + this->mixer.volume = ao_oss_get_property (&this->ao_driver, this->mixer.prop); + this->mixer.volume = config->lookup_int (config, "mixer_volume", 50); + + (void) ao_oss_set_property(&this->ao_driver, this->mixer.prop, this->mixer.volume); + + } close (audio_fd); this->output_sample_rate = 0; @@ -582,6 +737,7 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { this->static_delay = config->lookup_int (config, "oss_static_delay", 1000); + this->config = config; this->ao_driver.get_capabilities = ao_oss_get_capabilities; this->ao_driver.get_property = ao_oss_get_property; this->ao_driver.set_property = ao_oss_set_property; diff --git a/src/xine-engine/audio_decoder.c b/src/xine-engine/audio_decoder.c index 2b5320dd6..f6995c439 100644 --- a/src/xine-engine/audio_decoder.c +++ b/src/xine-engine/audio_decoder.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_decoder.c,v 1.41 2001/09/25 23:27:02 guenter Exp $ + * $Id: audio_decoder.c,v 1.42 2001/10/01 23:04:57 f1rmb Exp $ * * * functions that implement audio decoding @@ -300,5 +300,9 @@ void audio_decoder_shutdown (xine_t *this) { pthread_join (this->audio_thread, &p); } + + if(this->audio_out) + this->audio_out->exit (this->audio_out); + } diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c index 20fd26876..27fb336b2 100644 --- a/src/xine-engine/audio_out.c +++ b/src/xine-engine/audio_out.c @@ -17,7 +17,7 @@ * along with self program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_out.c,v 1.17 2001/09/12 22:00:51 joachim_koenig Exp $ + * $Id: audio_out.c,v 1.18 2001/10/01 23:04:57 f1rmb Exp $ * * 22-8-2001 James imported some useful AC3 sections from the previous alsa driver. * (c) 2001 Andy Lo A Foe @@ -406,12 +406,26 @@ static void ao_close(ao_instance_t *this) this->driver->close(this->driver); } +static void ao_exit(ao_instance_t *this) { + this->driver->exit(this->driver); +} + static uint32_t ao_get_capabilities (ao_instance_t *this) { uint32_t result; result=this->driver->get_capabilities(this->driver); return result; } +static int ao_get_property (ao_instance_t *this, int property) { + + return(this->driver->get_property(this->driver, property)); +} + +static int ao_set_property (ao_instance_t *this, int property, int value) { + + return(this->driver->set_property(this->driver, property, value)); +} + ao_instance_t *ao_new_instance (ao_driver_t *driver, metronom_t *metronom, config_values_t *config) { @@ -425,7 +439,10 @@ ao_instance_t *ao_new_instance (ao_driver_t *driver, metronom_t *metronom, this->open = ao_open; this->write = ao_write; this->close = ao_close; + this->exit = ao_exit; this->get_capabilities = ao_get_capabilities; + this->get_property = ao_get_property; + this->set_property = ao_set_property; this->audio_loop_running = 0; this->frame_buffer = xmalloc (40000); this->zero_space = xmalloc (ZERO_BUF_SIZE * 2 * 6); diff --git a/src/xine-engine/audio_out.h b/src/xine-engine/audio_out.h index d23db13f5..501eac29a 100644 --- a/src/xine-engine/audio_out.h +++ b/src/xine-engine/audio_out.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_out.h,v 1.17 2001/09/14 20:44:01 jcdutton Exp $ + * $Id: audio_out.h,v 1.18 2001/10/01 23:04:57 f1rmb Exp $ */ #ifndef HAVE_AUDIO_OUT_H #define HAVE_AUDIO_OUT_H @@ -126,6 +126,14 @@ typedef struct ao_instance_s ao_instance_t; struct ao_instance_s { uint32_t (*get_capabilities) (ao_instance_t *this); /* for constants see below */ + /* + * Get/Set audio property + * + * See AO_PROP_* bellow + */ + int (*get_property) (ao_instance_t *this, int property); + int (*set_property) (ao_instance_t *this, int property, int value); + /* open audio driver for audio output * return value: 0:failure, >0:output sample rate */ diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index 837a3180d..6d6721be8 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine.c,v 1.60 2001/09/10 13:36:56 jkeil Exp $ + * $Id: xine.c,v 1.61 2001/10/01 23:04:57 f1rmb Exp $ * * top-level xine functions * @@ -621,4 +621,27 @@ int xine_get_stream_length (xine_t *this) { return 0; } +int xine_get_audio_capabilities(xine_t *this) { + + if(this->audio_out) + return (this->audio_out->get_capabilities(this->audio_out)); + + return AO_CAP_NOCAP; +} + +int xine_get_audio_property(xine_t *this, int property) { + + if(this->audio_out) + return(this->audio_out->get_property(this->audio_out, property)); + + return 0; +} + +int xine_set_audio_property(xine_t *this, int property, int value) { + + if(this->audio_out) + return(this->audio_out->set_property(this->audio_out, property, value)); + + return ~value; +} -- cgit v1.2.3