diff options
author | Michael Roitzsch <mroi@users.sourceforge.net> | 2003-06-18 12:59:39 +0000 |
---|---|---|
committer | Michael Roitzsch <mroi@users.sourceforge.net> | 2003-06-18 12:59:39 +0000 |
commit | 06f2301713235341fe3d43b1b959f414d2cfc340 (patch) | |
tree | 92eb189fca7bb6a53983f759e686e53643ce9d53 | |
parent | d96ed959351fb17f515e82405dec199e40dc581c (diff) | |
download | xine-lib-06f2301713235341fe3d43b1b959f414d2cfc340.tar.gz xine-lib-06f2301713235341fe3d43b1b959f414d2cfc340.tar.bz2 |
Daniel's patch for audio level reporting with alsa
CVS patchset: 5064
CVS date: 2003/06/18 12:59:39
-rw-r--r-- | include/xine.h.in | 7 | ||||
-rw-r--r-- | src/audio_out/audio_alsa_out.c | 180 |
2 files changed, 124 insertions, 63 deletions
diff --git a/include/xine.h.in b/include/xine.h.in index 2fec4c118..1c5ae1650 100644 --- a/include/xine.h.in +++ b/include/xine.h.in @@ -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.h.in,v 1.88 2003/06/02 06:36:30 f1rmb Exp $ + * $Id: xine.h.in,v 1.89 2003/06/18 12:59:39 mroi Exp $ * * public xine-lib (libxine) interface and documentation * @@ -1250,7 +1250,7 @@ void xine_config_reset (xine_t *self); #define XINE_EVENT_UI_SET_TITLE 3 /* request title display change in ui */ #define XINE_EVENT_UI_MESSAGE 4 /* message (dialog) for the ui to display */ #define XINE_EVENT_FRAME_FORMAT_CHANGE 5 /* e.g. aspect ratio change during dvd playback */ -#define XINE_EVENT_AUDIO_LEVEL 6 /* report current audio level (l/r) */ +#define XINE_EVENT_AUDIO_LEVEL 6 /* report current audio level (l/r/mute) */ #define XINE_EVENT_QUIT 7 /* last event sent when stream is disposed */ #define XINE_EVENT_PROGRESS 8 /* index creation/network connections */ #define XINE_EVENT_MRL_REFERENCE 9 /* demuxer->frontend: MRL reference(s) for the real stream */ @@ -1375,7 +1375,8 @@ typedef struct { */ typedef struct { int left; - int right; /* 0..255 */ + int right; /* 0..100 % */ + int mute; } xine_audio_level_data_t; /* diff --git a/src/audio_out/audio_alsa_out.c b/src/audio_out/audio_alsa_out.c index 854827574..d4ab10c73 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 <James@superbug.demon.co.uk> * * - * $Id: audio_alsa_out.c,v 1.93 2003/06/06 14:01:11 jcdutton Exp $ + * $Id: audio_alsa_out.c,v 1.94 2003/06/18 12:59:39 mroi Exp $ */ #ifdef HAVE_CONFIG_H @@ -84,21 +84,21 @@ typedef struct { typedef struct alsa_driver_s { - ao_driver_t ao_driver; + ao_driver_t ao_driver; - alsa_class_t *class; + alsa_class_t *class; - snd_pcm_t *audio_fd; - int capabilities; - int open_mode; - int has_pause_resume; + snd_pcm_t *audio_fd; + int capabilities; + int open_mode; + int has_pause_resume; - int32_t output_sample_rate, input_sample_rate; - double sample_rate_factor; - 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 */ + int32_t output_sample_rate, input_sample_rate; + double sample_rate_factor; + 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 */ snd_pcm_sframes_t buffer_size; int32_t mmap; @@ -119,15 +119,92 @@ typedef struct alsa_driver_s { static snd_output_t *jcd_out; /* + * Get and convert volume to percent value + */ +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; +} + +/* * Wait (blocking) till a mixer event happen */ static void *ao_alsa_handle_event_thread(void *data) { alsa_driver_t *this = (alsa_driver_t *) data; do { + int err, mute, sw, sw2; + long right_vol, left_vol; + snd_mixer_wait(this->mixer.handle, -1); pthread_mutex_lock(&this->mixer.mutex); snd_mixer_handle_events(this->mixer.handle); + + if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, + &left_vol)) < 0) { + printf("audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); + continue; + } + + if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, + &right_vol)) < 0) { + printf("audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); + continue; + } + + 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); + mute = (sw) ? 0 : 1; + } + else { + if (this->mixer.mute & MIXER_MASK_LEFT) + snd_mixer_selem_get_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, &sw2); + + mute = (sw || sw2) ? 0 : 1; + } + } + else + mute = (this->mixer.mute) ? 1 : 0; + + if((this->mixer.right_vol != right_vol) || (this->mixer.left_vol != left_vol) || + (this->mixer.mute != mute)) { + xine_event_t event; + xine_audio_level_data_t data; + xine_stream_t *stream; + + this->mixer.right_vol = right_vol; + this->mixer.left_vol = left_vol; + this->mixer.mute = (mute) ? MIXER_MASK_STEREO : 0; + + data.right = ao_alsa_get_percent_from_volume(this->mixer.right_vol, + this->mixer.min, this->mixer.max); + data.left = ao_alsa_get_percent_from_volume(this->mixer.left_vol, + this->mixer.min, this->mixer.max); + data.mute = (this->mixer.mute == MIXER_MASK_STEREO) ? 1 : 0; + + event.type = XINE_EVENT_AUDIO_LEVEL; + event.data = &data; + event.data_length = sizeof(data); + + pthread_mutex_lock(&this->class->xine->streams_lock); + for(stream = xine_list_first_content(this->class->xine->streams); + stream; stream = xine_list_next_content(this->class->xine->streams)) { + event.stream = stream; + xine_event_send(stream, &event); + } + pthread_mutex_unlock(&this->class->xine->streams_lock); + } pthread_mutex_unlock(&this->mixer.mutex); } while(1); @@ -135,25 +212,9 @@ static void *ao_alsa_handle_event_thread(void *data) { } /* - * Get and convert volume to percent value - */ -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; -} - -/* * Convert percent value to volume and set */ -static long ao_alsa_get_volume_from_percent(int val, long min, long max) -{ +static long ao_alsa_get_volume_from_percent(int val, long min, long max) { int range = max - min; long tmp; @@ -168,8 +229,7 @@ static long ao_alsa_get_volume_from_percent(int val, long min, long max) /* * open the audio device for writing to */ -static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int mode) -{ +static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int mode) { alsa_driver_t *this = (alsa_driver_t *) this_gen; config_values_t *config = this->class->xine->config; char *pcm_device; @@ -186,7 +246,7 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_output_stdio_attach(&jcd_out, stdout, 0); - + switch (mode) { case AO_CAP_MODE_MONO: this->num_channels = 1; @@ -422,7 +482,9 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int snd_pcm_dump_setup(this->audio_fd, jcd_out); snd_pcm_sw_params_dump(swparams, jcd_out); #endif + return this->output_sample_rate; + __close: snd_pcm_close (this->audio_fd); this->audio_fd=NULL; @@ -432,8 +494,7 @@ __close: /* * Return the number of audio channels */ -static int ao_alsa_num_channels(ao_driver_t *this_gen) -{ +static int ao_alsa_num_channels(ao_driver_t *this_gen) { alsa_driver_t *this = (alsa_driver_t *) this_gen; return this->num_channels; } @@ -441,8 +502,7 @@ static int ao_alsa_num_channels(ao_driver_t *this_gen) /* * Return the number of bytes per frame */ -static int ao_alsa_bytes_per_frame(ao_driver_t *this_gen) -{ +static int ao_alsa_bytes_per_frame(ao_driver_t *this_gen) { alsa_driver_t *this = (alsa_driver_t *) this_gen; return this->bytes_per_frame; } @@ -450,8 +510,7 @@ static int ao_alsa_bytes_per_frame(ao_driver_t *this_gen) /* * Return gap tolerance (in pts) */ -static int ao_alsa_get_gap_tolerance (ao_driver_t *this_gen) -{ +static int ao_alsa_get_gap_tolerance (ao_driver_t *this_gen) { return GAP_TOLERANCE; } @@ -461,8 +520,7 @@ static int ao_alsa_get_gap_tolerance (ao_driver_t *this_gen) /* FIXME: delay returns invalid data if status is not RUNNING. * e.g When there is an XRUN or we are in PREPARED mode. */ -static int ao_alsa_delay (ao_driver_t *this_gen) -{ +static int ao_alsa_delay (ao_driver_t *this_gen) { snd_pcm_sframes_t delay = 0; int err = 0; alsa_driver_t *this = (alsa_driver_t *) this_gen; @@ -485,21 +543,25 @@ static int ao_alsa_delay (ao_driver_t *this_gen) */ static void xrun(alsa_driver_t *this) { - //snd_pcm_status_t *status; + /* snd_pcm_status_t *status; */ int res; - //snd_pcm_status_alloca(&status); - //if ((res = snd_pcm_status(this->audio_fd, status))<0) { - // printf ("audio_alsa_out: status error: %s\n", snd_strerror(res)); - // return; - //} - //snd_pcm_status_dump(status, jcd_out); + /* + snd_pcm_status_alloca(&status); + if ((res = snd_pcm_status(this->audio_fd, status))<0) { + printf ("audio_alsa_out: status error: %s\n", snd_strerror(res)); + return; + } + snd_pcm_status_dump(status, jcd_out); + */ if (snd_pcm_state(this->audio_fd) == SND_PCM_STATE_XRUN) { - //struct timeval now, diff, tstamp; - //gettimeofday(&now, 0); - //snd_pcm_status_get_trigger_tstamp(status, &tstamp); - //timersub(&now, &tstamp, &diff); - //printf ("audio_alsa_out: xrun!!! (at least %.3f ms long)\n", diff.tv_sec * 1000 + diff.tv_usec / 1000.0); + /* + struct timeval now, diff, tstamp; + gettimeofday(&now, 0); + snd_pcm_status_get_trigger_tstamp(status, &tstamp); + timersub(&now, &tstamp, &diff); + printf ("audio_alsa_out: xrun!!! (at least %.3f ms long)\n", diff.tv_sec * 1000 + diff.tv_usec / 1000.0); + */ printf ("audio_alsa_out: XRUN!!!\n"); if ((res = snd_pcm_prepare(this->audio_fd))<0) { printf ("audio_alsa_out: xrun: prepare error: %s", snd_strerror(res)); @@ -512,8 +574,7 @@ static void xrun(alsa_driver_t *this) /* * Write audio data to output buffer (blocking using snd_pcm_wait) */ -static int ao_alsa_write(ao_driver_t *this_gen,int16_t *data, uint32_t count) -{ +static int ao_alsa_write(ao_driver_t *this_gen, int16_t *data, uint32_t count) { snd_pcm_sframes_t result; snd_pcm_status_t *pcm_stat; snd_pcm_state_t state; @@ -609,9 +670,9 @@ static int ao_alsa_write(ao_driver_t *this_gen,int16_t *data, uint32_t count) /* * This is called when the decoder no longer uses the audio */ -static void ao_alsa_close(ao_driver_t *this_gen) -{ +static void ao_alsa_close(ao_driver_t *this_gen) { alsa_driver_t *this = (alsa_driver_t *) this_gen; + if(this->audio_fd) snd_pcm_close(this->audio_fd); this->audio_fd = NULL; this->has_pause_resume = 0; /* This is set at open time */ @@ -628,8 +689,7 @@ static uint32_t ao_alsa_get_capabilities (ao_driver_t *this_gen) { /* * Shut down audio output driver plugin and free all resources allocated */ -static void ao_alsa_exit(ao_driver_t *this_gen) -{ +static void ao_alsa_exit(ao_driver_t *this_gen) { alsa_driver_t *this = (alsa_driver_t *) this_gen; void *p; @@ -1268,7 +1328,7 @@ static void *init_class (xine_t *xine, void *data) { /* this->config = xine->config; */ this->xine = xine; - return this; + return this; } static ao_info_t ao_info_alsa = { |