diff options
Diffstat (limited to 'src/audio_out')
-rw-r--r-- | src/audio_out/Makefile.am | 23 | ||||
-rw-r--r-- | src/audio_out/audio_alsa_out.c | 370 | ||||
-rw-r--r-- | src/audio_out/audio_arts_out.c | 34 | ||||
-rw-r--r-- | src/audio_out/audio_coreaudio_out.c | 72 | ||||
-rw-r--r-- | src/audio_out/audio_directx2_out.c | 482 | ||||
-rw-r--r-- | src/audio_out/audio_directx_out.c | 80 | ||||
-rw-r--r-- | src/audio_out/audio_esd_out.c | 90 | ||||
-rw-r--r-- | src/audio_out/audio_file_out.c | 22 | ||||
-rw-r--r-- | src/audio_out/audio_fusionsound_out.c | 82 | ||||
-rw-r--r-- | src/audio_out/audio_irixal_out.c | 28 | ||||
-rw-r--r-- | src/audio_out/audio_jack_out.c | 1130 | ||||
-rw-r--r-- | src/audio_out/audio_none_out.c | 28 | ||||
-rw-r--r-- | src/audio_out/audio_oss_out.c | 243 | ||||
-rw-r--r-- | src/audio_out/audio_pulse_out.c | 771 | ||||
-rw-r--r-- | src/audio_out/audio_sndio_out.c | 414 | ||||
-rw-r--r-- | src/audio_out/audio_sun_out.c | 68 |
16 files changed, 2533 insertions, 1404 deletions
diff --git a/src/audio_out/Makefile.am b/src/audio_out/Makefile.am index b0c3d292e..745fafadd 100644 --- a/src/audio_out/Makefile.am +++ b/src/audio_out/Makefile.am @@ -1,3 +1,4 @@ +include $(top_builddir)/misc/Makefile.plugins include $(top_srcdir)/misc/Makefile.common AM_CPPFLAGS = -DXINE_COMPILE @@ -49,10 +50,14 @@ if HAVE_JACK jack_module = xineplug_ao_out_jack.la endif +if HAVE_SNDIO +sndio_module = xineplug_ao_out_sndio.la +endif + ## # IMPORTANT: # --------- -# all xine audio out plugins should be named like the +# all xine audio out plugins should be named like the # scheme "xineplug_ao_out_" # xineplug_LTLIBRARIES = xineplug_ao_out_none.la xineplug_ao_out_file.la \ @@ -66,7 +71,8 @@ xineplug_LTLIBRARIES = xineplug_ao_out_none.la xineplug_ao_out_file.la \ $(pulseaudio_module) \ $(directx2_module) \ $(fusionsound_module) \ - $(jack_module) + $(jack_module) \ + $(sndio_module) xineplug_ao_out_none_la_SOURCES = audio_none_out.c xineplug_ao_out_none_la_LIBADD = $(XINE_LIB) $(LTLIBINTL) @@ -88,7 +94,7 @@ xineplug_ao_out_alsa_la_LIBADD = $(XINE_LIB) $(ALSA_LIBS) $(PTHREAD_LIBS) $(LTLI xineplug_ao_out_alsa_la_CFLAGS = $(VISIBILITY_FLAG) $(ALSA_CFLAGS) xineplug_ao_out_alsa_la_LDFLAGS = -avoid-version -module -xineplug_ao_out_esd_la_SOURCES = audio_esd_out.c +xineplug_ao_out_esd_la_SOURCES = audio_esd_out.c xineplug_ao_out_esd_la_LIBADD = $(XINE_LIB) $(ESD_LIBS) $(LTLIBINTL) xineplug_ao_out_esd_la_CFLAGS = $(VISIBILITY_FLAG) $(ESD_CFLAGS) xineplug_ao_out_esd_la_LDFLAGS = -avoid-version -module @@ -98,7 +104,7 @@ xineplug_ao_out_sun_la_LIBADD = $(XINE_LIB) xineplug_ao_out_sun_la_CFLAGS = $(VISIBILITY_FLAG) xineplug_ao_out_sun_la_LDFLAGS = -avoid-version -module -#xineplug_ao_out_irixal_la_SOURCES = audio_irixal_out.c +#xineplug_ao_out_irixal_la_SOURCES = audio_irixal_out.c #xineplug_ao_out_irixal_la_LIBADD = $(IRIXAL_LIBS) #xineplug_ao_out_irixal_la_CFLAGS = $(VISIBILITY_FLAG) $(IRIXAL_CFLAGS) #xineplug_ao_out_irixal_la_LDFLAGS = -avoid-version -module @@ -110,7 +116,7 @@ xineplug_ao_out_arts_la_LDFLAGS = -avoid-version -module xineplug_ao_out_directx_la_SOURCES = audio_directx_out.c xineplug_ao_out_directx_la_CPPFLAGS = $(DIRECTX_CPPFLAGS) -xineplug_ao_out_directx_la_LIBADD = $(XINE_LIB) $(DIRECTX_AUDIO_LIBS) +xineplug_ao_out_directx_la_LIBADD = $(XINE_LIB) $(DIRECTX_AUDIO_LIBS) $(LTLIBINTL) xineplug_ao_out_directx_la_CFLAGS = $(VISIBILITY_FLAG) xineplug_ao_out_directx_la_LDFLAGS = -avoid-version -module @@ -131,7 +137,7 @@ xineplug_ao_out_pulseaudio_la_LDFLAGS = -avoid-version -module xineplug_ao_out_directx2_la_SOURCES = audio_directx2_out.c xineplug_ao_out_directx2_la_CPPFLAGS = $(DIRECTX_CPPFLAGS) -xineplug_ao_out_directx2_la_LIBADD = $(XINE_LIB) $(DIRECTX_AUDIO_LIBS) $(PTHREAD_LIBS) +xineplug_ao_out_directx2_la_LIBADD = $(XINE_LIB) $(DIRECTX_AUDIO_LIBS) $(PTHREAD_LIBS) $(LTLIBINTL) xineplug_ao_out_directx2_la_CFLAGS = $(VISIBILITY_FLAG) xineplug_ao_out_directx2_la_LDFLAGS = -avoid-version -module @@ -144,3 +150,8 @@ xineplug_ao_out_jack_la_SOURCES = audio_jack_out.c xineplug_ao_out_jack_la_LIBADD = $(XINE_LIB) $(JACK_LIBS) $(LTLIBINTL) xineplug_ao_out_jack_la_CFLAGS = $(VISIBILITY_FLAG) $(JACK_CFLAGS) xineplug_ao_out_jack_la_LDFLAGS = -avoid-version -module + +xineplug_ao_out_sndio_la_SOURCES = audio_sndio_out.c +xineplug_ao_out_sndio_la_LIBADD = $(XINE_LIB) $(SNDIO_LIBS) +xineplug_ao_out_sndio_la_CFLAGS = $(VISIBILITY_FLAG) $(SNDIO_CFLAGS) +xineplug_ao_out_sndio_la_LDFLAGS = -avoid-version -module diff --git a/src/audio_out/audio_alsa_out.c b/src/audio_out/audio_alsa_out.c index 4ce2b1be3..b18637a7b 100644 --- a/src/audio_out/audio_alsa_out.c +++ b/src/audio_out/audio_alsa_out.c @@ -1,23 +1,23 @@ -/* +/* * Copyright (C) 2000-2006 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine 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. - * + * * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * - * Credits go + * Credits go * - for the SPDIF A/52 sync part * - frame size calculation added (16-08-2001) * (c) 2001 Andy Lo A Foe <andy@alsaplayer.org> @@ -99,7 +99,7 @@ typedef struct alsa_driver_s { uint32_t bytes_per_frame; uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */ snd_pcm_uframes_t buffer_size; - int32_t mmap; + int32_t mmap; struct { pthread_t thread; @@ -136,10 +136,10 @@ static int my_snd_mixer_wait(snd_mixer_t *mixer, int timeout) { if (count < 0) return count; - + if ((unsigned int) count > sizeof(spfds) / sizeof(spfds[0])) { pfds = malloc(count * sizeof(*pfds)); - + if (!pfds) return -ENOMEM; @@ -169,44 +169,44 @@ static void *ao_alsa_handle_event_thread(void *data) { int old_mute; pthread_mutex_lock(&this->mixer.mutex); - + old_mute = (this->mixer.mute & MIXER_MASK_MUTE) ? 1 : 0; if((err = snd_mixer_handle_events(this->mixer.handle)) < 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_handle_events(): %s\n", snd_strerror(err)); pthread_mutex_unlock(&this->mixer.mutex); continue; } - + if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &left_vol)) < 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); pthread_mutex_unlock(&this->mixer.mutex); continue; } - + if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, &right_vol)) < 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); pthread_mutex_unlock(&this->mixer.mutex); continue; } - + if(this->mixer.mute & MIXER_HAS_MUTE_SWITCH) { - + if(this->mixer.mute & MIXER_MASK_STEREO) { snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl); mute = (swl) ? 0 : 1; } else { - + if (this->mixer.mute & MIXER_MASK_LEFT) snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl); - + 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, &swr); - + mute = (swl || swr) ? 0 : 1; } } @@ -216,26 +216,26 @@ static void *ao_alsa_handle_event_thread(void *data) { xine_audio_level_data_t data; xine_stream_t *stream; xine_list_iterator_t ite; - + this->mixer.right_vol = right_vol; this->mixer.left_vol = left_vol; if(mute) this->mixer.mute |= MIXER_MASK_MUTE; else this->mixer.mute &= ~MIXER_MASK_MUTE; - - data.right = ao_alsa_get_percent_from_volume(this->mixer.right_vol, + + 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, + 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_MUTE) ? 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(ite = xine_list_front(this->class->xine->streams); + for(ite = xine_list_front(this->class->xine->streams); ite; ite = xine_list_next(this->class->xine->streams, ite)) { stream = xine_list_get_value(this->class->xine->streams, ite); event.stream = stream; @@ -243,12 +243,12 @@ static void *ao_alsa_handle_event_thread(void *data) { } pthread_mutex_unlock(&this->class->xine->streams_lock); } - + pthread_mutex_unlock(&this->mixer.mutex); } } while(this->mixer.running); - + pthread_exit(NULL); } @@ -261,11 +261,11 @@ static long ao_alsa_get_volume_from_percent(int val, long min, long max) { } /* - * Error callback, we need to control this, + * Error callback, we need to control this, * error message should be printed only in DEBUG mode. */ static void XINE_FORMAT_PRINTF(5, 6) - error_callback(const char *file, int line, + error_callback(const char *file, int line, const char *function, int err, const char *fmt, ...) { #ifdef DEBUG va_list args; @@ -286,13 +286,13 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int alsa_driver_t *this = (alsa_driver_t *) this_gen; config_values_t *config = this->class->xine->config; char *pcm_device; - snd_pcm_stream_t direction = SND_PCM_STREAM_PLAYBACK; + snd_pcm_stream_t direction = SND_PCM_STREAM_PLAYBACK; snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_access_mask_t *mask; snd_pcm_uframes_t period_size; - snd_pcm_uframes_t period_size_min; - snd_pcm_uframes_t period_size_max; + snd_pcm_uframes_t period_size_min; + snd_pcm_uframes_t period_size_max; snd_pcm_uframes_t buffer_size_min; snd_pcm_uframes_t buffer_size_max; snd_pcm_format_t format; @@ -310,7 +310,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; @@ -336,10 +336,10 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int pcm_device = config->lookup_entry(config, "audio.device.alsa_passthrough_device")->str_value; break; default: - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: ALSA Driver does not support the requested mode: 0x%X\n",mode); return 0; - } + } #ifdef ALSA_LOG printf("audio_alsa_out: Audio Device name = %s\n",pcm_device); @@ -362,25 +362,25 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int */ gettimeofday(&start_time, NULL); do { - err = snd_pcm_open(&this->audio_fd, pcm_device, direction, open_mode); + err = snd_pcm_open(&this->audio_fd, pcm_device, direction, open_mode); gettimeofday(&end_time, NULL); if( err == -EBUSY ) { - if( (double)end_time.tv_sec + 1E-6*end_time.tv_usec + if( (double)end_time.tv_sec + 1E-6*end_time.tv_usec - (double)start_time.tv_sec - 1E-6*start_time.tv_usec > 0.8) break; else usleep(10000); } } while( err == -EBUSY ); - - if(err <0 ) { - xprintf (this->class->xine, XINE_VERBOSITY_LOG, - _("audio_alsa_out: snd_pcm_open() of %s failed: %s\n"), pcm_device, snd_strerror(err)); - xprintf (this->class->xine, XINE_VERBOSITY_LOG, + + if(err <0 ) { + xprintf (this->class->xine, XINE_VERBOSITY_LOG, + _("audio_alsa_out: snd_pcm_open() of %s failed: %s\n"), pcm_device, snd_strerror(err)); + xprintf (this->class->xine, XINE_VERBOSITY_LOG, _("audio_alsa_out: >>> check if another program already uses PCM <<<\n")); return 0; } - /* printf ("audio_alsa_out: snd_pcm_open() opened %s\n", pcm_device); */ + /* printf ("audio_alsa_out: snd_pcm_open() opened %s\n", pcm_device); */ /* We wanted non blocking open but now put it back to normal */ //snd_pcm_nonblock(this->audio_fd, 0); snd_pcm_nonblock(this->audio_fd, 1); @@ -389,7 +389,7 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int */ err = snd_pcm_hw_params_any(this->audio_fd, params); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_LOG, + xprintf (this->class->xine, XINE_VERBOSITY_LOG, _("audio_alsa_out: broken configuration for this PCM: no configurations available: %s\n"), snd_strerror(err)); goto close; @@ -403,7 +403,7 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX); err = snd_pcm_hw_params_set_access_mask(this->audio_fd, params, mask); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: mmap not availiable, falling back to compatiblity mode\n"); this->mmap=0; err = snd_pcm_hw_params_set_access(this->audio_fd, params, @@ -413,9 +413,9 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int err = snd_pcm_hw_params_set_access(this->audio_fd, params, SND_PCM_ACCESS_RW_INTERLEAVED); } - + if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: access type not available: %s\n", snd_strerror(err)); goto close; } @@ -438,23 +438,23 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int case 4: format = SND_PCM_FORMAT_FLOAT; break; - default: + default: format = SND_PCM_FORMAT_S16; - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: pcm format bits=%d unknown. failed: %s\n", bits, snd_strerror(err)); break; } err = snd_pcm_hw_params_set_format(this->audio_fd, params, format ); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: sample format non available: %s\n", snd_strerror(err)); goto close; } /* set the number of channels */ err = snd_pcm_hw_params_set_channels(this->audio_fd, params, this->num_channels); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, - "audio_alsa_out: Cannot set number of channels to %d (err=%d:%s)\n", + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + "audio_alsa_out: Cannot set number of channels to %d (err=%d:%s)\n", this->num_channels, err, snd_strerror(err)); goto close; } @@ -466,13 +466,13 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int dir=0; err = snd_pcm_hw_params_set_rate_near(this->audio_fd, params, &rate, &dir); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: rate not available: %s\n", snd_strerror(err)); goto close; } this->output_sample_rate = (uint32_t)rate; if (this->input_sample_rate != this->output_sample_rate) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: audio rate : %d requested, %d provided by device/sec\n", this->input_sample_rate, this->output_sample_rate); } @@ -504,7 +504,7 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int periods=8; err = snd_pcm_hw_params_set_periods_near(this->audio_fd, params, &periods ,&dir); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: unable to set any periods: %s\n", snd_strerror(err)); goto close; } @@ -512,7 +512,7 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int dir=0; err = snd_pcm_hw_params_set_buffer_time_near(this->audio_fd, params, &buffer_time, &dir); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: buffer time not available: %s\n", snd_strerror(err)); goto close; } @@ -522,7 +522,7 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int dir=0; err = snd_pcm_hw_params_set_period_size_near(this->audio_fd, params, &period_size, &dir); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: period time not available: %s\n", snd_strerror(err)); goto close; } @@ -533,7 +533,7 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int dir=0; err = snd_pcm_hw_params_set_buffer_size_near(this->audio_fd, params, &this->buffer_size); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: buffer time not available: %s\n", snd_strerror(err)); goto close; } @@ -543,22 +543,22 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int printf("was set buffer_size = %ld\n",this->buffer_size); #endif if (2*period_size > this->buffer_size) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: buffer to small, could not use\n"); goto close; } - + /* write the parameters to device */ err = snd_pcm_hw_params(this->audio_fd, params); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: pcm hw_params failed: %s\n", snd_strerror(err)); goto close; } /* Check for pause/resume support */ this->has_pause_resume = ( snd_pcm_hw_params_can_pause (params) && snd_pcm_hw_params_can_resume (params) ); - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out:open pause_resume=%d\n", this->has_pause_resume); this->sample_rate_factor = (double) this->output_sample_rate / (double) this->input_sample_rate; this->bytes_per_frame = snd_pcm_frames_to_bytes (this->audio_fd, 1); @@ -568,28 +568,28 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int /* Copy current parameters into swparams */ err = snd_pcm_sw_params_current(this->audio_fd, swparams); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Unable to determine current swparams: %s\n", snd_strerror(err)); goto close; } /* align all transfers to 1 sample */ err = snd_pcm_sw_params_set_xfer_align(this->audio_fd, swparams, 1); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Unable to set transfer alignment: %s\n", snd_strerror(err)); goto close; } /* allow the transfer when at least period_size samples can be processed */ err = snd_pcm_sw_params_set_avail_min(this->audio_fd, swparams, period_size); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Unable to set available min: %s\n", snd_strerror(err)); goto close; } /* start the transfer when the buffer contains at least period_size samples */ err = snd_pcm_sw_params_set_start_threshold(this->audio_fd, swparams, period_size); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Unable to set start threshold: %s\n", snd_strerror(err)); goto close; } @@ -597,7 +597,7 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int /* never stop the transfer, even on xruns */ err = snd_pcm_sw_params_set_stop_threshold(this->audio_fd, swparams, this->buffer_size); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Unable to set stop threshold: %s\n", snd_strerror(err)); goto close; } @@ -605,15 +605,15 @@ static int ao_alsa_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int /* Install swparams into current parameters */ err = snd_pcm_sw_params(this->audio_fd, swparams); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Unable to set swparams: %s\n", snd_strerror(err)); goto close; } #ifdef ALSA_LOG - snd_pcm_dump_setup(this->audio_fd, jcd_out); + snd_pcm_dump_setup(this->audio_fd, jcd_out); snd_pcm_sw_params_dump(swparams, jcd_out); #endif - + return this->output_sample_rate; close: @@ -648,7 +648,7 @@ static int ao_alsa_get_gap_tolerance (ao_driver_t *this_gen) { /* * Return the delay. is frames measured by looking at pending samples */ -/* FIXME: delay returns invalid data if status is not RUNNING. +/* 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) { @@ -678,12 +678,12 @@ static int ao_alsa_delay (ao_driver_t *this_gen) { /* * Handle over/under-run */ -static void xrun(alsa_driver_t *this) +static void xrun(alsa_driver_t *this) { /* 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)); @@ -759,7 +759,7 @@ static int ao_alsa_write(ao_driver_t *this_gen, int16_t *data, uint32_t count) { #ifdef LOG_DEBUG printf("audio_alsa_out:write:XRUN before\n"); snd_pcm_status(this->audio_fd, pcm_stat); - snd_pcm_status_dump(pcm_stat, jcd_out); + snd_pcm_status_dump(pcm_stat, jcd_out); #endif if ((res = snd_pcm_prepare(this->audio_fd))<0) { return 0; @@ -771,14 +771,14 @@ static int ao_alsa_write(ao_driver_t *this_gen, int16_t *data, uint32_t count) { #ifdef LOG_DEBUG printf("audio_alsa_out:write:XRUN after\n"); #endif - } + } if ( (state != SND_PCM_STATE_PREPARED) && (state != SND_PCM_STATE_RUNNING) && (state != SND_PCM_STATE_DRAINING) ) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out:write:BAD STATE, state = %d\n",state); } - + while( number_of_frames > 0) { if ( (state == SND_PCM_STATE_RUNNING) ) { #ifdef LOG_DEBUG @@ -816,7 +816,7 @@ static int ao_alsa_write(ao_driver_t *this_gen, int16_t *data, uint32_t count) { } else if ( (state != SND_PCM_STATE_PREPARED) && (state != SND_PCM_STATE_RUNNING) && (state != SND_PCM_STATE_DRAINING) ) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out:write:BAD STATE2, state = %d, going to try XRUN\n",state); if ((res = snd_pcm_prepare(this->audio_fd))<0) { xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, @@ -895,7 +895,7 @@ static void ao_alsa_exit(ao_driver_t *this_gen) { this->mixer.handle=0; } pthread_mutex_destroy(&this->mixer.mutex); - + if (this->audio_fd) snd_pcm_close(this->audio_fd); this->audio_fd=NULL; free (this); @@ -913,45 +913,45 @@ static int ao_alsa_get_property (ao_driver_t *this_gen, int property) { case AO_PROP_PCM_VOL: if(this->mixer.elem) { int vol; - + pthread_mutex_lock(&this->mixer.mutex); if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &this->mixer.left_vol)) < 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: 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) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); goto done; } - + done: vol = (((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); pthread_mutex_unlock(&this->mixer.mutex); - + return vol; } break; - + case AO_PROP_MUTE_VOL: { int mute; - + pthread_mutex_lock(&this->mixer.mutex); mute = ((this->mixer.mute & MIXER_HAS_MUTE_SWITCH) && (this->mixer.mute & MIXER_MASK_MUTE)) ? 1 : 0; pthread_mutex_unlock(&this->mixer.mutex); - + return mute; } break; } - + return 0; } @@ -970,18 +970,18 @@ static int ao_alsa_set_property (ao_driver_t *this_gen, int property, int value) pthread_mutex_lock(&this->mixer.mutex); 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) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); pthread_mutex_unlock(&this->mixer.mutex); return ~value; } - + if((err = snd_mixer_selem_set_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, this->mixer.right_vol)) < 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); pthread_mutex_unlock(&this->mixer.mutex); return ~value; @@ -997,20 +997,20 @@ static int ao_alsa_set_property (ao_driver_t *this_gen, int property, int value) if(this->mixer.mute & MIXER_HAS_MUTE_SWITCH) { int swl = 0, swr = 0; int old_mute; - + pthread_mutex_lock(&this->mixer.mutex); - + old_mute = this->mixer.mute; if(value) this->mixer.mute |= MIXER_MASK_MUTE; else this->mixer.mute &= ~MIXER_MASK_MUTE; - + if ((this->mixer.mute & MIXER_MASK_MUTE) != (old_mute & MIXER_MASK_MUTE)) { if(this->mixer.mute & MIXER_MASK_STEREO) { snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl); snd_mixer_selem_set_playback_switch_all(this->mixer.elem, !swl); - } + } else { if (this->mixer.mute & MIXER_MASK_LEFT) { snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl); @@ -1050,7 +1050,7 @@ static int ao_alsa_ctrl(ao_driver_t *this_gen, int cmd, ...) { if (this->audio_fd) { if (this->has_pause_resume) { if ((err=snd_pcm_pause(this->audio_fd, 1)) < 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Pause call failed. (err=%d:%s)\n",err, snd_strerror(err)); this->has_pause_resume = 0; ao_alsa_ctrl(this_gen, AO_CTRL_PLAY_PAUSE, NULL); @@ -1059,15 +1059,15 @@ static int ao_alsa_ctrl(ao_driver_t *this_gen, int cmd, ...) { } } else { if ((err=snd_pcm_reset(this->audio_fd)) < 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Reset call failed. (err=%d:%s)\n",err, snd_strerror(err)); } if ((err=snd_pcm_drain(this->audio_fd)) < 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Drain call failed. (err=%d:%s)\n",err, snd_strerror(err)); } if ((err=snd_pcm_prepare(this->audio_fd)) < 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Prepare call failed. (err=%d:%s)\n",err, snd_strerror(err)); } } @@ -1079,12 +1079,12 @@ static int ao_alsa_ctrl(ao_driver_t *this_gen, int cmd, ...) { if (this->has_pause_resume && this->is_paused) { if ((err=snd_pcm_pause(this->audio_fd, 0)) < 0) { if (err == -77) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Warning: How am I supposed to RESUME, if I am not PAUSED. " "audio_out.c, please don't call me!\n"); break; } - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Resume call failed. (err=%d:%s)\n",err, snd_strerror(err)); this->has_pause_resume = 0; } else { @@ -1097,11 +1097,11 @@ static int ao_alsa_ctrl(ao_driver_t *this_gen, int cmd, ...) { case AO_CTRL_FLUSH_BUFFERS: if (this->audio_fd) { if ((err=snd_pcm_drop(this->audio_fd)) < 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Drop call failed. (err=%d:%s)\n",err, snd_strerror(err)); } if ((err=snd_pcm_prepare(this->audio_fd)) < 0) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: Prepare call failed. (err=%d:%s)\n",err, snd_strerror(err)); } } @@ -1129,43 +1129,43 @@ static void ao_alsa_mixer_init(ao_driver_t *this_gen) { int found; int swl = 0, swr = 0, send_events; - this->mixer.elem = 0; + this->mixer.elem = 0; snd_ctl_card_info_alloca(&hw_info); pcm_device = config->lookup_entry(config, "audio.device.alsa_default_device")->str_value; if ((err = snd_ctl_open (&ctl_handle, pcm_device, 0)) < 0) { xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_ctl_open(): %s\n", snd_strerror(err)); return; } - + if ((err = snd_ctl_card_info (ctl_handle, hw_info)) < 0) { xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: 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) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_open(): %s\n", snd_strerror(err)); this->mixer.handle=0; return; } - + if ((err = snd_mixer_attach (this->mixer.handle, pcm_device)) < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_attach(): %s\n", snd_strerror(err)); snd_mixer_close(this->mixer.handle); this->mixer.handle=0; return; } - + if ((err = snd_mixer_selem_register (this->mixer.handle, NULL, NULL)) < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_selem_register(): %s\n", snd_strerror(err)); snd_mixer_close(this->mixer.handle); this->mixer.handle=0; @@ -1173,77 +1173,77 @@ static void ao_alsa_mixer_init(ao_driver_t *this_gen) { } if ((err = snd_mixer_load (this->mixer.handle)) < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_load(): %s\n", snd_strerror(err)); snd_mixer_close(this->mixer.handle); this->mixer.handle=0; return; } - + mixer_sid = alloca(snd_mixer_selem_id_sizeof() * snd_mixer_get_count(this->mixer.handle)); if (mixer_sid == NULL) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: alloca() failed: %s\n", strerror(errno)); snd_mixer_close(this->mixer.handle); this->mixer.handle=0; 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_elem_get_type(elem) != SND_MIXER_ELEM_SIMPLE) || !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, + + 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) { - xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); this->mixer.elem = NULL; continue; } - + if((err = snd_mixer_selem_get_playback_volume(this->mixer.elem, SND_MIXER_SCHN_FRONT_RIGHT, &this->mixer.right_vol)) < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: snd_mixer_selem_get_playback_volume(): %s\n", snd_strerror(err)); this->mixer.elem = NULL; continue; } - + /* Channels mute */ this->mixer.mute = 0; if(snd_mixer_selem_has_playback_switch(this->mixer.elem)) { this->mixer.mute |= MIXER_HAS_MUTE_SWITCH; - + if (snd_mixer_selem_has_playback_switch_joined(this->mixer.elem)) { this->mixer.mute |= MIXER_MASK_STEREO; snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl); - } + } else { this->mixer.mute |= MIXER_MASK_LEFT; snd_mixer_selem_get_playback_switch(this->mixer.elem, SND_MIXER_SCHN_FRONT_LEFT, &swl); - + 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, &swr); } - + if(!swl || !swr) this->mixer.mute |= MIXER_MASK_MUTE; } @@ -1256,10 +1256,10 @@ static void ao_alsa_mixer_init(ao_driver_t *this_gen) { goto mixer_found; } } - + if(loop) goto mixer_found; /* Yes, untrue but... ;-) */ - + if(!strcmp(this->mixer.name, "PCM")) { config->update_string(config, "audio.device.alsa_mixer_name", "Master"); loop++; @@ -1267,14 +1267,14 @@ static void ao_alsa_mixer_init(ao_driver_t *this_gen) { else { config->update_string(config, "audio.device.alsa_mixer_name", "PCM"); } - + this->mixer.name = config->lookup_entry(config, "audio.device.alsa_mixer_name")->str_value; - + goto again; mixer_found: - - /* + + /* * Ugly: yes[*] no[ ] */ if(found) { @@ -1301,11 +1301,11 @@ static void ao_alsa_mixer_init(ao_driver_t *this_gen) { if (send_events && found) { pthread_attr_t pth_attrs; struct sched_param pth_params; - + this->mixer.running = 1; pthread_attr_init(&pth_attrs); - + pthread_attr_getschedparam(&pth_attrs, &pth_params); pth_params.sched_priority = sched_get_priority_min(SCHED_OTHER); pthread_attr_setschedparam(&pth_attrs, &pth_params); @@ -1317,7 +1317,7 @@ static void ao_alsa_mixer_init(ao_driver_t *this_gen) { } static void alsa_speaker_arrangement_cb (void *user_data, - xine_cfg_entry_t *entry); + xine_cfg_entry_t *entry); /* * Initialize plugin @@ -1350,7 +1350,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da #define A52_PASSTHRU 12 int speakers; - this = (alsa_driver_t *) xine_xmalloc (sizeof (alsa_driver_t)); + this = calloc(1, sizeof (alsa_driver_t)); if (!this) return NULL; @@ -1358,8 +1358,8 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da err = snd_lib_error_set_handler(error_callback); if(err < 0) - xine_log(this->class->xine, XINE_LOG_MSG, _("snd_lib_error_set_handler() failed: %d"), err); - + xine_log(this->class->xine, XINE_LOG_MSG, _("snd_lib_error_set_handler() failed: %d"), err); + snd_pcm_hw_params_alloca(¶ms); this->mmap = config->register_bool (config, @@ -1424,7 +1424,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da /* Use the default device to open first */ pcm_device = config->lookup_entry(config, "audio.device.alsa_default_device")->str_value; - + /* * find best device driver/channel */ @@ -1434,11 +1434,11 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da err=snd_pcm_open(&this->audio_fd, pcm_device, SND_PCM_STREAM_PLAYBACK, 1); /* NON-BLOCK mode */ if(err <0 ) { xine_log (this->class->xine, XINE_LOG_MSG, - _("snd_pcm_open() failed:%d:%s\n"), err, snd_strerror(err)); + _("snd_pcm_open() failed:%d:%s\n"), err, snd_strerror(err)); xine_log (this->class->xine, XINE_LOG_MSG, - _(">>> Check if another program already uses PCM <<<\n")); + _(">>> Check if another program already uses PCM <<<\n")); free(this); - return NULL; + return NULL; } /* @@ -1446,7 +1446,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da */ err = snd_pcm_hw_params_any(this->audio_fd, params); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: broken configuration for this PCM: no configurations available\n"); snd_pcm_close(this->audio_fd); free(this); @@ -1455,7 +1455,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da err = snd_pcm_hw_params_set_access(this->audio_fd, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, "audio_alsa_out: access type not available"); snd_pcm_close(this->audio_fd); free(this); @@ -1497,70 +1497,73 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da "formats you want to play to your sound card's digital output."), 0, alsa_speaker_arrangement_cb, this); - xprintf(class->xine, XINE_VERBOSITY_LOG, _("audio_alsa_out : supported modes are ")); + char *logmsg = strdup (_("audio_alsa_out : supported modes are")); + if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_U8))) { this->capabilities |= AO_CAP_8BITS; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("8bit ")); + xine_strcat_realloc (&logmsg, _(" 8bit")); } /* ALSA automatically appends _LE or _BE depending on the CPU */ if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_S16))) { this->capabilities |= AO_CAP_16BITS; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("16bit ")); + xine_strcat_realloc (&logmsg, _(" 16bit")); } if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_S24))) { this->capabilities |= AO_CAP_24BITS; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("24bit ")); + xine_strcat_realloc (&logmsg, _(" 24bit")); } if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_FLOAT))) { this->capabilities |= AO_CAP_FLOAT32; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("32bit ")); + xine_strcat_realloc (&logmsg, _(" 32bit")); } if (0 == (this->capabilities & (AO_CAP_FLOAT32 | AO_CAP_24BITS | AO_CAP_16BITS | AO_CAP_8BITS))) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, - "\naudio_alsa_out: no supported PCM format found\n"); + xprintf(class->xine, XINE_VERBOSITY_LOG, "%s\n", logmsg); + free (logmsg); + xprintf (class->xine, XINE_VERBOSITY_DEBUG, + "audio_alsa_out: no supported PCM format found\n"); snd_pcm_close(this->audio_fd); free(this); return NULL; } if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 1))) { this->capabilities |= AO_CAP_MODE_MONO; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("mono ")); + xine_strcat_realloc (&logmsg, _(" mono")); } if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 2))) { this->capabilities |= AO_CAP_MODE_STEREO; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("stereo ")); + xine_strcat_realloc (&logmsg, _(" stereo")); } if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 4)) && ( speakers == SURROUND4 )) { this->capabilities |= AO_CAP_MODE_4CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("4-channel ")); - } + xine_strcat_realloc (&logmsg, _(" 4-channel")); + } else - xprintf(class->xine, XINE_VERBOSITY_LOG, _("(4-channel not enabled in xine config) ")); - - if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) && + xine_strcat_realloc (&logmsg, _(" (4-channel not enabled in xine config)")); + + if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) && ( speakers == SURROUND41 )) { this->capabilities |= AO_CAP_MODE_4_1CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("4.1-channel ")); - } + xine_strcat_realloc (&logmsg, _(" 4.1-channel")); + } else - xprintf(class->xine, XINE_VERBOSITY_LOG, _("(4.1-channel not enabled in xine config) ")); + xine_strcat_realloc (&logmsg, _(" (4.1-channel not enabled in xine config)")); - if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) && + if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) && ( speakers == SURROUND5 )) { this->capabilities |= AO_CAP_MODE_5CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("5-channel ")); - } + xine_strcat_realloc (&logmsg, _(" 5-channel")); + } else - xprintf(class->xine, XINE_VERBOSITY_LOG, _("(5-channel not enabled in xine config) ")); + xine_strcat_realloc (&logmsg, _(" (5-channel not enabled in xine config)")); - if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) && + if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) && ( speakers >= SURROUND51 )) { this->capabilities |= AO_CAP_MODE_5_1CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("5.1-channel ")); - } + xine_strcat_realloc (&logmsg, _(" 5.1-channel")); + } else - xprintf(class->xine, XINE_VERBOSITY_LOG, _("(5.1-channel not enabled in xine config) ")); + xine_strcat_realloc (&logmsg, _(" (5.1-channel not enabled in xine config)")); this->has_pause_resume = 0; /* This is checked at open time instead */ this->is_paused = 0; @@ -1583,10 +1586,13 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da if ( speakers == A52_PASSTHRU ) { this->capabilities |= AO_CAP_MODE_A52; this->capabilities |= AO_CAP_MODE_AC5; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("a/52 and DTS pass-through\n")); - } + xine_strcat_realloc (&logmsg, _(" a/52 and DTS pass-through")); + } else - xprintf(class->xine, XINE_VERBOSITY_LOG, _("(a/52 and DTS pass-through not enabled in xine config)\n")); + xine_strcat_realloc (&logmsg, _(" (a/52 and DTS pass-through not enabled in xine config)")); + + xprintf(class->xine, XINE_VERBOSITY_LOG, "%s\n", logmsg); + free (logmsg); /* printf("audio_alsa_out: capabilities 0x%X\n",this->capabilities); */ @@ -1616,7 +1622,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da this->ao_driver.num_channels = ao_alsa_num_channels; this->ao_driver.bytes_per_frame = ao_alsa_bytes_per_frame; this->ao_driver.delay = ao_alsa_delay; - this->ao_driver.write = ao_alsa_write; + this->ao_driver.write = ao_alsa_write; this->ao_driver.close = ao_alsa_close; this->ao_driver.exit = ao_alsa_exit; this->ao_driver.get_gap_tolerance = ao_alsa_get_gap_tolerance; @@ -1682,7 +1688,7 @@ static void *init_class (xine_t *xine, void *data) { alsa_class_t *this; - this = (alsa_class_t *) xine_xmalloc (sizeof (alsa_class_t)); + this = calloc(1, sizeof (alsa_class_t)); if (!this) return NULL; @@ -1705,7 +1711,7 @@ static ao_info_t ao_info_alsa = { */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_OUT_ALSA_IFACE_VERSION, "alsa", XINE_VERSION_CODE, &ao_info_alsa, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/audio_out/audio_arts_out.c b/src/audio_out/audio_arts_out.c index 0f0467b4a..7f796f2b3 100644 --- a/src/audio_out/audio_arts_out.c +++ b/src/audio_out/audio_arts_out.c @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2000-2003 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine 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. - * + * * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -42,7 +42,7 @@ #define AUDIO_NUM_FRAGMENTS 15 #define AUDIO_FRAGMENT_SIZE 8192 -#define GAP_TOLERANCE AO_MAX_GAP +#define GAP_TOLERANCE AO_MAX_GAP typedef struct arts_driver_s { @@ -84,7 +84,7 @@ typedef struct { static void ao_arts_volume(void *buffer, int length, int volume) { int v; short *data = (short *)buffer; - + while (length--) { v=(int) ((*(data) * volume) / 100); *(data)=(v>32767) ? 32767 : ((v<-32768) ? -32768 : v); @@ -118,7 +118,7 @@ static int ao_arts_open(ao_driver_t *this_gen, sleep(2); /* arts might segfault if we are still playing */ arts_close_stream(this->audio_stream); } - + this->mode = mode; this->sample_rate = rate; this->bits_per_sample = bits; @@ -139,7 +139,7 @@ static int ao_arts_open(ao_driver_t *this_gen, this->audio_stream=arts_play_stream(this->sample_rate, bits, this->num_channels, "xine"); this->latency = arts_stream_get (this->audio_stream, ARTS_P_TOTAL_LATENCY); - + /* try to keep latency low, if we don't do this we might end with very high latencies for low quality sound and audio_out will try to fill gaps every time...(values in ms) */ @@ -181,7 +181,7 @@ static int ao_arts_write(ao_driver_t *this_gen, int16_t *data, arts_driver_t *this = (arts_driver_t *) this_gen; int size = num_frames * this->bytes_per_frame; - ao_arts_volume(data, num_frames * this->num_channels, this->mixer.vol_scale ); + ao_arts_volume(data, num_frames * this->num_channels, this->mixer.vol_scale ); arts_write(this->audio_stream, data, size ); return 1; @@ -220,7 +220,7 @@ static uint32_t ao_arts_get_capabilities (ao_driver_t *this_gen) { static void ao_arts_exit(ao_driver_t *this_gen) { arts_driver_t *this = (arts_driver_t *) this_gen; - + ao_arts_close(this_gen); /* FIXME: arts_free() freezes on BSD, so don't use it there */ #if !defined(__OpenBSD__) && !defined (__FreeBSD__) && !defined(__NetBSD__) @@ -233,7 +233,7 @@ static void ao_arts_exit(ao_driver_t *this_gen) static int ao_arts_get_property (ao_driver_t *this_gen, int property) { arts_driver_t *this = (arts_driver_t *) this_gen; - + switch(property) { case AO_PROP_PCM_VOL: case AO_PROP_MIXER_VOL: @@ -269,7 +269,7 @@ static int ao_arts_set_property (ao_driver_t *this_gen, int property, int value) } else { this->mixer.volume = this->mixer.v_mixer; this->mixer.vol_scale = this->mixer.volume; - } + } this->mixer.mute = mute; return value; break; @@ -303,7 +303,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da lprintf ("audio_arts_out: open_plugin called\n"); - this = (arts_driver_t *) xine_xmalloc (sizeof (arts_driver_t)); + this = calloc(1, sizeof (arts_driver_t)); if (!this) return NULL; @@ -323,7 +323,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da free(this); return NULL; } - + /* * set volume control */ @@ -384,7 +384,7 @@ static void *init_class (xine_t *xine, void *data) { lprintf ("audio_arts_out: init class\n"); - this = (arts_class_t *) xine_xmalloc (sizeof (arts_class_t)); + this = calloc(1, sizeof (arts_class_t)); if (!this) return NULL; @@ -409,7 +409,7 @@ static ao_info_t ao_info_arts = { */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_OUT_ARTS_IFACE_VERSION, "arts", XINE_VERSION_CODE, &ao_info_arts, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/audio_out/audio_coreaudio_out.c b/src/audio_out/audio_coreaudio_out.c index eecab8f95..5e31a15e5 100644 --- a/src/audio_out/audio_coreaudio_out.c +++ b/src/audio_out/audio_coreaudio_out.c @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2000-2004 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine 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. - * + * * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -54,7 +54,7 @@ #define AO_OUT_COREAUDIO_IFACE_VERSION 8 -#define GAP_TOLERANCE AO_MAX_GAP +#define GAP_TOLERANCE AO_MAX_GAP #define BUFSIZE 30720 /* Number of seconds to wait for buffered data to arrive/be used * before giving up. */ @@ -75,7 +75,7 @@ typedef struct coreaudio_driver_s { Component au_component; Component converter_component; - + AudioUnit au_unit; AudioUnit converter_unit; @@ -86,7 +86,7 @@ typedef struct coreaudio_driver_s { int mute; Float32 pre_mute_volume; - + pthread_mutex_t mutex; pthread_cond_t buffer_ready_for_reading; pthread_cond_t buffer_ready_for_writing; @@ -131,7 +131,7 @@ static OSStatus ao_coreaudio_render_proc (coreaudio_driver_t *this, pthread_mutex_lock (&this->mutex); if(this->buf_head < ((BUFSIZE) >> 2)) { set_to_future(&future); - if(pthread_cond_timedwait + if(pthread_cond_timedwait (&this->buffer_ready_for_reading, &this->mutex, &future) == ETIMEDOUT) { /* Timed out, give up and fill remainder with silence. */ @@ -143,13 +143,13 @@ static OSStatus ao_coreaudio_render_proc (coreaudio_driver_t *this, return noErr; } } - + if(this->buf_head < buffer_size - buffer_progress) { chunk_size = this->buf_head; } else { chunk_size = buffer_size - buffer_progress; } - + xine_fast_memcpy (ioData->mBuffers[i].mData, this->buf, chunk_size); if(chunk_size < this->buf_head) { memmove(this->buf, &(this->buf[chunk_size]), this->buf_head - chunk_size); @@ -188,7 +188,7 @@ static int ao_coreaudio_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate AudioStreamBasicDescription format; AudioUnitConnection connection; ComponentDescription desc; - + switch (mode) { case AO_CAP_MODE_MONO: this->num_channels = 1; @@ -209,7 +209,7 @@ static int ao_coreaudio_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate pthread_cond_init (&this->buffer_ready_for_reading, NULL); pthread_cond_init (&this->buffer_ready_for_writing, NULL); - xprintf (this->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_coreaudio_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode); /* find an audio output unit */ @@ -218,17 +218,17 @@ static int ao_coreaudio_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate desc.componentManufacturer = kAudioUnitManufacturer_Apple; desc.componentFlags = 0; desc.componentFlagsMask = 0; - + this->au_component = FindNextComponent (NULL, &desc); if (this->au_component == NULL) { - xprintf (this->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_coreaudio_out: Unable to find a usable audio output unit component\n"); return 0; } - + OpenAComponent (this->au_component, &this->au_unit); - + /* find a converter unit */ desc.componentType = kAudioUnitType_FormatConverter; desc.componentSubType = kAudioUnitSubType_AUConverter; @@ -236,11 +236,11 @@ static int ao_coreaudio_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate this->converter_component = FindNextComponent (NULL, &desc); if (this->converter_component == NULL) { - xprintf (this->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_coreaudio_out: Unable to find a usable audio converter unit component\n"); return 0; } - + OpenAComponent (this->converter_component, &this->converter_unit); /* set up the render procedure */ @@ -258,7 +258,7 @@ static int ao_coreaudio_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate connection.destInputNumber = 0; AudioUnitSetProperty (this->au_unit, kAudioUnitProperty_MakeConnection, - kAudioUnitScope_Input, 0, + kAudioUnitScope_Input, 0, &connection, sizeof(connection)); /* set up the audio format we want to use */ @@ -274,7 +274,7 @@ static int ao_coreaudio_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate format.mBytesPerFrame = this->bytes_per_frame; format.mFramesPerPacket = 1; format.mBytesPerPacket = format.mBytesPerFrame; - + AudioUnitSetProperty (this->converter_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, @@ -339,7 +339,7 @@ static int ao_coreaudio_write(ao_driver_t *this_gen, int16_t *data, pthread_mutex_lock (&this->mutex); if(this->buf_head > ((3 * BUFSIZE)>>2)) { set_to_future(&future); - if(pthread_cond_timedwait + if(pthread_cond_timedwait (&this->buffer_ready_for_writing, &this->mutex, &future) == ETIMEDOUT) { /* Timed out, give up. */ @@ -354,10 +354,10 @@ static int ao_coreaudio_write(ao_driver_t *this_gen, int16_t *data, } else { chunk_size = remaining_bytes; } - + xine_fast_memcpy(&(this->buf[this->buf_head]), data, chunk_size); this->buf_head += chunk_size; - remaining_bytes -= chunk_size; + remaining_bytes -= chunk_size; if(this->buf_head > 0) { pthread_cond_broadcast (&this->buffer_ready_for_reading); @@ -389,13 +389,13 @@ static void ao_coreaudio_close(ao_driver_t *this_gen) CloseComponent (this->au_unit); this->au_unit = 0; } - + if (this->converter_unit) { AudioUnitUninitialize (this->converter_unit); CloseComponent (this->converter_unit); this->converter_unit = 0; } - + if (this->au_component) { this->au_component = NULL; } @@ -417,7 +417,7 @@ static uint32_t ao_coreaudio_get_capabilities (ao_driver_t *this_gen) { static void ao_coreaudio_exit(ao_driver_t *this_gen) { coreaudio_driver_t *this = (coreaudio_driver_t *) this_gen; - + ao_coreaudio_close(this_gen); free (this); @@ -436,7 +436,7 @@ static int ao_coreaudio_get_property (ao_driver_t *this_gen, int property) { kAudioUnitScope_Output, 0, &val); } else { - val = this->pre_mute_volume; + val = this->pre_mute_volume; } return (int) (val * 12); break; @@ -472,12 +472,12 @@ static int ao_coreaudio_set_property (ao_driver_t *this_gen, int property, int v kHALOutputParam_Volume, kAudioUnitScope_Output, 0, &(this->pre_mute_volume)); - + AudioUnitSetParameter (this->au_unit, kHALOutputParam_Volume, kAudioUnitScope_Output, 0, 0, 0); - + this->mute = 1; } } else { @@ -487,14 +487,14 @@ static int ao_coreaudio_set_property (ao_driver_t *this_gen, int property, int v kHALOutputParam_Volume, kAudioUnitScope_Output, 0, this->pre_mute_volume, 0); - + this->mute = 0; } } return value; break; } - + return ~value; } @@ -521,7 +521,7 @@ static int ao_coreaudio_ctrl(ao_driver_t *this_gen, int cmd, ...) { return 0; } -static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, +static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) { coreaudio_class_t *class = (coreaudio_class_t *) class_gen; @@ -530,7 +530,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, lprintf ("open_plugin called\n"); - this = (coreaudio_driver_t *) xine_xmalloc (sizeof (coreaudio_driver_t)); + this = calloc(1, sizeof (coreaudio_driver_t)); if (!this) return NULL; @@ -582,7 +582,7 @@ static void *init_class (xine_t *xine, void *data) { lprintf ("init class\n"); - this = (coreaudio_class_t *) xine_xmalloc (sizeof (coreaudio_class_t)); + this = calloc(1, sizeof (coreaudio_class_t)); if (!this) return NULL; @@ -606,7 +606,7 @@ static const ao_info_t ao_info_coreaudio = { */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_OUT_COREAUDIO_IFACE_VERSION, "coreaudio", XINE_VERSION_CODE, &ao_info_coreaudio, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/audio_out/audio_directx2_out.c b/src/audio_out/audio_directx2_out.c index d9688b647..4d7fe4e65 100644 --- a/src/audio_out/audio_directx2_out.c +++ b/src/audio_out/audio_directx2_out.c @@ -31,6 +31,9 @@ * * Authors: * - Frantisek Dvorak <valtri@atlas.cz> + * - Original version with slotted ring buffer + * - Matthias Ringald <mringwal@inf.ethz.ch> + * - non-slotted simpler version for ring buffer handling * * Inspiration: * - mplayer for workarounding -lguid idea @@ -55,8 +58,8 @@ #define LOG_MODULE "audio_directx2_out" #define LOG_VERBOSE /* -#define LOG -*/ + #define LOG + */ #include "xine_internal.h" #include "audio_out.h" @@ -64,29 +67,33 @@ #define AO_OUT_DIRECTX2_IFACE_VERSION 8 -/* - * buffer size in miliseconds - * (one second takes 11-192 KB) + +/* + * If GAP_TOLERANCE is lower than AO_MAX_GAP, xine will + * try to smooth playback without skipping frames or + * inserting silence. + */ +#define GAP_TOLERANCE (AO_MAX_GAP/3) + +/* + * buffer size in miliseconds + * (one second takes 11-192 KB) */ #define BUFFER_MS 1000 -/* - * number of parts in the buffer, - * one is always locked for playing +/* + * buffer below this threshold is considered a buffer underrun */ -#define PARTS 3 +#define BUFFER_MIN_MS 200 -/* +/* * base power factor for volume remapping */ #define FACTOR 60.0 - -/* experiments */ -/*#define EXACT_WAIT*/ -/*#define EXACT_SLEEP*/ -/*#define PANIC_OVERRUN*/ - +/* + * buffer handler status + */ #define STATUS_START 0 #define STATUS_WAIT 1 #define STATUS_RUNNING 2 @@ -108,12 +115,14 @@ typedef struct { LPDIRECTSOUND ds; /* DirectSound device */ LPDIRECTSOUNDBUFFER dsbuffer; /* DirectSound buffer */ - DSBPOSITIONNOTIFY events[PARTS]; /* position events */ - LPDIRECTSOUNDNOTIFY notify; /* notify interface */ size_t buffer_size; /* size of the buffer */ - size_t part_size; /* second half of buffer */ - size_t read_size; /* size of prepared data */ + size_t write_pos; /* positition in ring buffer for writing*/ + + int status; /* current status of the driver */ + int paused; /* paused mode */ + int finished; /* driver finished */ + int failed; /* don't open modal dialog again */ uint32_t bits; uint32_t rate; @@ -123,12 +132,6 @@ typedef struct { int volume; int muted; - int status; /* current status of the driver */ - int paused; /* paused mode */ - int finished; /* driver finished */ - int failed; /* don't open modal dialog again */ - int count; /* current free part number */ - pthread_t buffer_service; /* service thread for operating with DSB */ pthread_cond_t data_cond; /* signals on data */ pthread_mutex_t data_mutex; /* data lock */ @@ -140,17 +143,19 @@ typedef struct { * Defining them here allows us to get rid of the dxguid library during * the linking stage. *****************************************************************************/ -static const GUID IID_IDirectSoundNotify = { - 0xB0210783, 0x89CD, 0x11D0, {0xAF, 0x08, 0x00, 0xA0, 0xC9, 0x25, 0xCD, 0x16} +static const GUID xine_IID_IDirectSoundNotify = { +0xB0210783, 0x89CD, 0x11D0, {0xAF, 0x08, 0x00, 0xA0, 0xC9, 0x25, 0xCD, 0x16} }; +#ifdef IID_IDirectSoundNotify +# undef IID_IDirectSoundNotify +#endif +#define IID_IDirectSoundNotify xine_IID_IDirectSoundNotify -static int buffer_ready(dx2_driver_t *this); - /* popup a dialog with error */ static void XINE_FORMAT_PRINTF(1, 2) - error_message(const char *fmt, ...) { +error_message(const char *fmt, ...) { char message[256]; va_list ap; @@ -214,7 +219,7 @@ static LPDIRECTSOUND dsound_create() { /* destroy direct sound object */ static void dsound_destroy(LPDIRECTSOUND ds) { - IDirectSound_Release(ds); + IDirectSound_Release(ds); } @@ -266,12 +271,10 @@ static int audio_create_buffers(dx2_driver_t *this) { HRESULT err; size_t buffer_size; - buffer_size = this->rate * this->frame_size * BUFFER_MS / 1000; + buffer_size = this->rate * BUFFER_MS / 1000 * this->frame_size; if (buffer_size > DSBSIZE_MAX) buffer_size = DSBSIZE_MAX; if (buffer_size < DSBSIZE_MIN) buffer_size = DSBSIZE_MIN; - this->part_size = (buffer_size / PARTS / this->frame_size) * this->frame_size; - if (!this->part_size) this->part_size = this->frame_size; - this->buffer_size = this->part_size * PARTS; + this->buffer_size = buffer_size; flags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY; dsound_fill_wfx(&wfx, this->bits, this->rate, this->channels, this->frame_size); @@ -282,7 +285,7 @@ static int audio_create_buffers(dx2_driver_t *this) { return 0; } - lprintf("created direct sound buffer, size = %u, part = %u\n", this->buffer_size, this->part_size); + lprintf("created direct sound buffer, size = %u\n", this->buffer_size); return 1; } @@ -293,43 +296,6 @@ static void audio_destroy_buffers(dx2_driver_t *this) { } -/* create position events */ -static int audio_create_events(dx2_driver_t *this) { - HANDLE handle[PARTS]; - HRESULT err; - int i; - - for (i = 0; i < PARTS; i++) { - handle[i] = CreateEvent(NULL, FALSE, FALSE, NULL); - if (!handle[i]) { - error_message(_("Unable to create buffer position events.")); - return 0; - } - this->events[i].dwOffset = i * this->part_size; - this->events[i].hEventNotify = handle[i]; - } - - if ((err = IDirectSoundBuffer_QueryInterface(this->dsbuffer, &IID_IDirectSoundNotify, (void **)&this->notify)) != DS_OK) { - audio_error(this, err, _("Unable to get notification interface")); - return 0; - } - - if ((err = IDirectSoundNotify_SetNotificationPositions(this->notify, PARTS, this->events)) != DS_OK) { - audio_error(this, err, _("Unable to set notification positions")); - IDirectSoundNotify_Release(this->notify); - return 0; - } - - return 1; -} - - -/* destroy notification interface */ -static void audio_destroy_events(dx2_driver_t *this) { - IDirectSoundNotify_Release(this->notify); -} - - /* start playback */ static int audio_play(dx2_driver_t *this) { HRESULT err; @@ -385,13 +351,12 @@ static int audio_seek(dx2_driver_t *this, size_t pos) { /* flush audio buffers */ static int audio_flush(dx2_driver_t *this) { this->status = STATUS_WAIT; - this->count = 0; - this->read_size = 0; + this->write_pos = 0; return audio_seek(this, 0); } -/* +/* * set the volume * * DirecSound can only lower the volume by software way. @@ -421,12 +386,12 @@ static int audio_fill(dx2_driver_t *this, char *data, size_t size) { HRESULT err; /* lock a part of the buffer, begin position on free space */ - err = IDirectSoundBuffer_Lock(this->dsbuffer, (this->count * this->part_size + this->read_size) % this->buffer_size, size, &ptr1, &size1, &ptr2, &size2, 0); + err = IDirectSoundBuffer_Lock(this->dsbuffer, this->write_pos, size, &ptr1, &size1, &ptr2, &size2, 0); /* try to restore the buffer, if necessary */ if (err == DSERR_BUFFERLOST) { xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": buffer lost, tryig to restore\n")); IDirectSoundBuffer_Restore(this->dsbuffer); - err = IDirectSoundBuffer_Lock(this->dsbuffer, (this->count * this->part_size + this->read_size) % this->buffer_size, size, &ptr1, &size1, &ptr2, &size2, 0); } + err = IDirectSoundBuffer_Lock(this->dsbuffer, this->write_pos, size, &ptr1, &size1, &ptr2, &size2, 0); } if (err != DS_OK) { audio_error(this, err, _("Couldn't lock direct sound buffer")); return 0; @@ -436,19 +401,15 @@ static int audio_fill(dx2_driver_t *this, char *data, size_t size) { if (ptr1 && size1) xine_fast_memcpy(ptr1, data, size1); if (ptr2 && size2) xine_fast_memcpy(ptr2, data + size1, size2); - this->read_size += size; + // this->read_size += size; + this->write_pos = (this->write_pos + size ) % this->buffer_size; + lprintf("size %u, write_pos %u\n", size, this->write_pos); if ((err = IDirectSoundBuffer_Unlock(this->dsbuffer, ptr1, size1, ptr2, size2)) != DS_OK) { audio_error(this, err, _("Couldn't unlock direct sound buffer")); return 0; } - /* signal, if are waiting and need wake up */ - if ((this->status == STATUS_WAIT) && buffer_ready(this)) { - lprintf("buffer ready, waking up\n"); - pthread_cond_signal(&this->data_cond); - } - return 1; } @@ -458,28 +419,28 @@ static int mode2channels(uint32_t mode) { int channels; switch(mode) { - case AO_CAP_MODE_MONO: - channels = 1; - break; - - case AO_CAP_MODE_STEREO: - channels = 2; - break; - - case AO_CAP_MODE_4CHANNEL: - channels = 4; - break; - - case AO_CAP_MODE_5CHANNEL: - channels = 5; - break; - - case AO_CAP_MODE_5_1CHANNEL: - channels = 6; - break; - - default: - return 0; + case AO_CAP_MODE_MONO: + channels = 1; + break; + + case AO_CAP_MODE_STEREO: + channels = 2; + break; + + case AO_CAP_MODE_4CHANNEL: + channels = 4; + break; + + case AO_CAP_MODE_5CHANNEL: + channels = 5; + break; + + case AO_CAP_MODE_5_1CHANNEL: + channels = 6; + break; + + default: + return 0; } return channels; @@ -506,8 +467,8 @@ static int test_capability(LPDIRECTSOUNDBUFFER buffer, uint32_t bits, uint32_t r } -/* - * test capabilities of driver before opening +/* + * test capabilities of driver before opening * * Passed only 8 bit and 16 bit with mono or stereo. */ @@ -556,109 +517,94 @@ static int test_capabilities(dx2_driver_t *this) { /* size of free space in the ring buffer */ static size_t buffer_free_size(dx2_driver_t *this) { - size_t used_full_size; - used_full_size = this->read_size + ((this->status != STATUS_WAIT) ? this->part_size : 0); - _x_assert(used_full_size <= this->buffer_size); - return this->buffer_size - used_full_size; + int ret; + size_t play_pos; + size_t free_space; + + // get current play pos + ret = audio_tell(this, &play_pos); + if (!ret) + return 0; + + // calc free space (-1) + free_space = (this->buffer_size + play_pos - this->write_pos - 1) % this->buffer_size; + + return free_space; } -/* enough data in the ring buffer for playing next part? */ -static int buffer_ready(dx2_driver_t *this) { - return this->read_size >= this->part_size; +/* size of occupied space in the ring buffer */ +static size_t buffer_occupied_size(dx2_driver_t *this) { + int ret; + size_t play_pos; + size_t used_space; + + // get current play pos + ret = audio_tell(this, &play_pos); + if (!ret) return 0; + + // calc used space + used_space = (this->buffer_size + this->write_pos - play_pos) % this->buffer_size; + + return used_space; } /* service thread working with direct sound buffer */ static void *buffer_service(void *data) { dx2_driver_t *this = (dx2_driver_t *)data; - HANDLE handles[PARTS]; - DWORD ret; - int i; -#if defined(EXACT_SLEEP) || defined(EXACT_WAIT) - size_t play_pos, req_delay; -#endif + size_t buffer_min; + size_t data_in_buffer; /* prepare empty buffer */ audio_flush(this); - for (i = 0; i < PARTS; i++) handles[i] = this->events[i].hEventNotify; - + /* prepare min buffer fill */ + buffer_min = BUFFER_MIN_MS * this->rate / 1000 * this->frame_size; + /* we live! */ pthread_mutex_lock(&this->data_mutex); pthread_cond_signal(&this->data_cond); pthread_mutex_unlock(&this->data_mutex); while (!this->finished) { + pthread_mutex_lock(&this->data_mutex); - if (!buffer_ready(this)) { - if (!audio_stop(this)) goto fail; - lprintf("no data (count=%d,free=%" PRIsizet ",avail=%" PRIsizet "), sleeping...\n", this->count, buffer_free_size(this), this->read_size); - this->status = STATUS_WAIT; - pthread_cond_wait(&this->data_cond, &this->data_mutex); - lprintf("wake up (count=%d,free=%" PRIsizet "--,avail=%" PRIsizet ")\n", this->count, buffer_free_size(this), this->read_size); - if (this->finished) goto finished; - if (!audio_seek(this, this->count * this->part_size)) goto fail; - if (!this->paused) { - if (!audio_play(this)) goto fail; - } - this->status = STATUS_RUNNING; - this->count = (this->count + 1) % PARTS; - this->read_size -= this->part_size; - pthread_mutex_unlock(&this->data_mutex); - lprintf("wait for playback (newcount=%d,free=%" PRIsizet ",avail=%" PRIsizet ")\n", this->count, buffer_free_size(this), this->read_size); - do { - ret = WaitForMultipleObjects(PARTS, handles, FALSE, 250) - WAIT_OBJECT_0; + switch( this->status){ + + case STATUS_WAIT: + + // pre: stop/buffer flushed + lprintf("no data, sleeping...\n"); + pthread_cond_wait(&this->data_cond, &this->data_mutex); + lprintf("woke up (write_pos=%d,free=%" PRIsizet")\n", this->write_pos, buffer_free_size(this)); if (this->finished) goto finished; - } while (ret > PARTS); - lprintf("playback started (newcount=%d,ev=%d,free=%" PRIsizet ",avail=%" PRIsizet ")\n", this->count, ret, buffer_free_size(this), this->read_size); - _x_assert(ret == ((PARTS + this->count - 1) % PARTS)); - } else { - this->count = (this->count + 1) % PARTS; - this->read_size -= this->part_size; - pthread_mutex_unlock(&this->data_mutex); + if (!audio_seek(this, 0)) goto fail; + if (!this->paused) { + if (!audio_play(this)) goto fail; + } + this->status = STATUS_RUNNING; + pthread_mutex_unlock(&this->data_mutex); + break; + + case STATUS_RUNNING: + + // check for buffer underrun + data_in_buffer = buffer_occupied_size(this); + if ( data_in_buffer < buffer_min){ + xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": play cursor overran (data %u, min %u), flushing buffers\n"), + data_in_buffer, buffer_min); + if (!audio_stop(this)) goto fail; + if (!audio_flush(this)) goto fail; + } + pthread_mutex_unlock(&this->data_mutex); + + // just wait BUFFER_MIN_MS before next check + xine_usec_sleep(BUFFER_MIN_MS * 1000); + break; } - lprintf("waiting for sound event(count=%d,free=%" PRIsizet ",avail=%" PRIsizet ")...\n", this->count, buffer_free_size(this), this->read_size); - do { - ret = WaitForMultipleObjects(PARTS, handles, FALSE, 250) - WAIT_OBJECT_0; - if (this->finished) goto finished; - } while (ret > PARTS); - lprintf("end wait(ev=%" PRIdword ",count=%d,free=%" PRIsizet ",avail=%" PRIsizet ")\n", ret, this->count, buffer_free_size(this), this->read_size); -#ifdef PANIC_OVERRUN - _x_abort(ret == this->count); -#else - if (ret != this->count) { - xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": play cursor overran, flushing buffers\n")); - pthread_mutex_lock(&this->data_mutex); - if (!audio_stop(this)) goto fail; - if (!audio_flush(this)) goto fail; - pthread_mutex_unlock(&this->data_mutex); - } -#endif - -#if defined(EXACT_SLEEP) || defined(EXACT_WAIT) - /* ugly hack: wait for right time, + little over for sure */ - pthread_mutex_lock(&this->data_mutex); - if (!audio_tell(this, &play_pos)) goto fail; - req_delay = (this->buffer_size + play_pos - this->count * this->part_size) % this->buffer_size; - pthread_mutex_unlock(&this->data_mutex); - if (req_delay > (this->buffer_size >> 1)) { - long delay; - - delay = 1000 * (this->buffer_size - req_delay) / (this->frame_size * this->rate) + 1 + BUFFER_MS / PARTS / 4; - xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": delayed by %ld msec\n"), delay); - printf("should be delayed %ld msec\n", delay); -#ifdef EXACT_SLEEP - xine_usec_sleep(delay * 1000); -#endif -#ifdef EXACT_WAIT - WaitForMultipleObjects(PARTS, handles, FALSE, delay); -#endif - } -#endif } - return NULL; fail: @@ -683,15 +629,15 @@ static int ao_dx2_get_property(ao_driver_t *this_gen, int property) { switch(property) { - case AO_PROP_MIXER_VOL: - case AO_PROP_PCM_VOL: - return this->volume; + case AO_PROP_MIXER_VOL: + case AO_PROP_PCM_VOL: + return this->volume; - case AO_PROP_MUTE_VOL: - return this->muted; + case AO_PROP_MUTE_VOL: + return this->muted; - default: - return 0; + default: + return 0; } } @@ -702,26 +648,26 @@ static int ao_dx2_set_property(ao_driver_t *this_gen, int property, int value) { switch(property) { - case AO_PROP_MIXER_VOL: - case AO_PROP_PCM_VOL: - lprintf("set volume to %d\n", value); - pthread_mutex_lock(&this->data_mutex); - if (!this->muted) { - if (this->dsbuffer && !audio_set_volume(this, value)) return ~value; - } - this->volume = value; - pthread_mutex_unlock(&this->data_mutex); - break; + case AO_PROP_MIXER_VOL: + case AO_PROP_PCM_VOL: + lprintf("set volume to %d\n", value); + pthread_mutex_lock(&this->data_mutex); + if (!this->muted) { + if (this->dsbuffer && !audio_set_volume(this, value)) return ~value; + } + this->volume = value; + pthread_mutex_unlock(&this->data_mutex); + break; - case AO_PROP_MUTE_VOL: - pthread_mutex_lock(&this->data_mutex); - if (this->dsbuffer && !audio_set_volume(this, value ? 0 : this->volume)) return ~value; - this->muted = value; - pthread_mutex_unlock(&this->data_mutex); - break; + case AO_PROP_MUTE_VOL: + pthread_mutex_lock(&this->data_mutex); + if (this->dsbuffer && !audio_set_volume(this, value ? 0 : this->volume)) return ~value; + this->muted = value; + pthread_mutex_unlock(&this->data_mutex); + break; - default: - return ~value; + default: + return ~value; } @@ -747,18 +693,17 @@ static int ao_dx2_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int this->status = STATUS_START; if (!audio_create_buffers(this)) return 0; - if (!audio_create_events(this)) goto fail_buffers; - if (!audio_set_volume(this, this->volume)) goto fail_events; + if (!audio_set_volume(this, this->volume)) goto fail_buffers; if (pthread_cond_init(&this->data_cond, NULL) != 0) { xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": can't create pthread condition: %s\n"), strerror(errno)); - goto fail_events; + goto fail_buffers; } if (pthread_mutex_init(&this->data_mutex, NULL) != 0) { xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": can't create pthread mutex: %s\n"), strerror(errno)); goto fail_cond; } - + /* creating the service thread and waiting for its signal */ pthread_mutex_lock(&this->data_mutex); if (pthread_create(&this->buffer_service, NULL, buffer_service, this) != 0) { @@ -775,8 +720,6 @@ fail_mutex: pthread_mutex_destroy(&this->data_mutex); fail_cond: pthread_cond_destroy(&this->data_cond); -fail_events: - audio_destroy_events(this); fail_buffers: audio_destroy_buffers(this); return 0; @@ -803,22 +746,26 @@ static int ao_dx2_bytes_per_frame(ao_driver_t *this_gen) { static int ao_dx2_delay(ao_driver_t *this_gen) { dx2_driver_t *this = (dx2_driver_t *)this_gen; - int frames; - size_t final_pos, play_pos; - - if (this->status != STATUS_RUNNING) return this->read_size / this->frame_size; + int frames = 0; + int ret; + size_t play_pos; pthread_mutex_lock(&this->data_mutex); - if (!audio_tell(this, &play_pos)) { - pthread_mutex_unlock(&this->data_mutex); - return 0; + + if (this->status != STATUS_RUNNING){ + frames = this->write_pos / this->frame_size; + } else { + ret = audio_tell(this, &play_pos); + if (ret){ + frames = buffer_occupied_size(this) / this->frame_size; + } } - final_pos = this->read_size + (((PARTS + this->count - 1) % PARTS) + 1) * this->part_size - 1; - frames = (this->buffer_size + final_pos - play_pos) % this->buffer_size / this->frame_size; + pthread_mutex_unlock(&this->data_mutex); #ifdef LOG - if ((rand() % 10) == 0) lprintf("frames=%d, play_pos=%" PRIdword ", block=%" PRIsizet "..%" PRIsizet "\n", frames, play_pos, final_pos - this->part_size + 1, final_pos); + if ((rand() % 10) == 0) + lprintf("frames=%d, play_pos=%" PRIdword ", write_pos=%u\n", frames, play_pos, this->write_pos); #endif return frames; @@ -840,7 +787,7 @@ static int ao_dx2_write(ao_driver_t *this_gen, int16_t* audio_data, uint32_t num while (((free_size = buffer_free_size(this)) == 0) && !this->finished) { lprintf("buffer full, waiting\n"); pthread_mutex_unlock(&this->data_mutex); - xine_usec_sleep(1000 * BUFFER_MS / PARTS / 5); + xine_usec_sleep(1000 * BUFFER_MS / 10); pthread_mutex_lock(&this->data_mutex); } if (free_size >= input_size) size = input_size; @@ -856,6 +803,12 @@ static int ao_dx2_write(ao_driver_t *this_gen, int16_t* audio_data, uint32_t num input_size -= size; } + /* signal, if are waiting and need wake up */ + if ((this->status == STATUS_WAIT) && (buffer_occupied_size(this) > BUFFER_MIN_MS * this->rate / 1000 * this->frame_size)) { + lprintf("buffer ready, waking up\n"); + pthread_cond_signal(&this->data_cond); + } + return 1; } @@ -881,7 +834,6 @@ static void ao_dx2_close(ao_driver_t *this_gen) { if (pthread_mutex_destroy(&this->data_mutex) != 0) { xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": can't destroy pthread mutex: %s\n"), strerror(errno)); } - audio_destroy_events(this); audio_destroy_buffers(this); } @@ -896,12 +848,8 @@ static void ao_dx2_exit(ao_driver_t *this_gen) { } -/* - * TODO: check - */ static int ao_dx2_get_gap_tolerance(ao_driver_t *this_gen) { - /* half of part of the buffer in pts (1 msec = 90 pts) */ - return (90 * (BUFFER_MS / PARTS)) >> 1; + return GAP_TOLERANCE; } @@ -910,36 +858,36 @@ static int ao_dx2_control(ao_driver_t *this_gen, int cmd, ...) { switch(cmd) { - case AO_CTRL_PLAY_PAUSE: - lprintf("control pause\n"); - pthread_mutex_lock(&this->data_mutex); - if (!this->paused) { - audio_stop(this); - this->paused = 1; - } - pthread_mutex_unlock(&this->data_mutex); - break; + case AO_CTRL_PLAY_PAUSE: + lprintf("control pause\n"); + pthread_mutex_lock(&this->data_mutex); + if (!this->paused) { + audio_stop(this); + this->paused = 1; + } + pthread_mutex_unlock(&this->data_mutex); + break; - case AO_CTRL_PLAY_RESUME: - lprintf("control resume\n"); - pthread_mutex_lock(&this->data_mutex); - if (this->paused) { - if (this->status != STATUS_WAIT) audio_play(this); - this->paused = 0; - } - pthread_mutex_unlock(&this->data_mutex); - break; - - case AO_CTRL_FLUSH_BUFFERS: - lprintf("control flush\n"); - pthread_mutex_lock(&this->data_mutex); - audio_stop(this); - audio_flush(this); - pthread_mutex_unlock(&this->data_mutex); - break; + case AO_CTRL_PLAY_RESUME: + lprintf("control resume\n"); + pthread_mutex_lock(&this->data_mutex); + if (this->paused) { + if (this->status != STATUS_WAIT) audio_play(this); + this->paused = 0; + } + pthread_mutex_unlock(&this->data_mutex); + break; + + case AO_CTRL_FLUSH_BUFFERS: + lprintf("control flush\n"); + pthread_mutex_lock(&this->data_mutex); + audio_stop(this); + audio_flush(this); + pthread_mutex_unlock(&this->data_mutex); + break; - default: - xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": unknown control command %d\n"), cmd); + default: + xine_log(this->class->xine, XINE_LOG_MSG, _(LOG_MODULE ": unknown control command %d\n"), cmd); } @@ -955,7 +903,7 @@ static ao_driver_t *open_plugin(audio_driver_class_t *class_gen, const void *dat lprintf("open plugin called\n"); - this = (dx2_driver_t *)xine_xmalloc(sizeof(dx2_driver_t)); + this = calloc(1, sizeof(dx2_driver_t)); if (!this) return NULL; @@ -1009,7 +957,7 @@ static void *init_class(xine_t *xine, void *data) { lprintf("init class\n"); - this = (dx2_class_t *)xine_xmalloc(sizeof(dx2_class_t)); + this = calloc(1, sizeof(dx2_class_t)); if (!this) return NULL; diff --git a/src/audio_out/audio_directx_out.c b/src/audio_out/audio_directx_out.c index 77e3e15b9..893a11976 100644 --- a/src/audio_out/audio_directx_out.c +++ b/src/audio_out/audio_directx_out.c @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2001-2003 the xine project - * + * * This file is part of xine, a unix video player. - * + * * xine 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. - * + * * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -60,9 +60,13 @@ typedef unsigned char boolean; * the linking stage. *****************************************************************************/ #if 1 -static const GUID IID_IDirectSoundNotify = { +static const GUID xine_IID_IDirectSoundNotify = { 0xB0210783,0x89CD,0x11D0,{0xAF,0x08,0x00,0xA0,0xC9,0x25,0xCD,0x16} }; +#ifdef IID_IDirectSoundNotify +# undef IID_IDirectSoundNotify +#endif +#define IID_IDirectSoundNotify xine_IID_IDirectSoundNotify #endif @@ -77,14 +81,14 @@ typedef struct { int capabilities; xine_t *xine; - + /* directx objects */ LPDIRECTSOUND dsobj; LPDIRECTSOUNDBUFFER dsbuffer; DSBCAPS dsbcaps; LPDIRECTSOUNDNOTIFY notify; DSBPOSITIONNOTIFY notify_events[ 2 ]; - + /* buffer vars */ long buffer_size; int write_status; @@ -92,13 +96,13 @@ typedef struct { uint8_t prebuff[ SOUND_BUFFER_MAX ]; uint32_t prebuff_size; - + /* current buffer properties */ int bits; int rate; int chnn; int frsz; - + /* current mixer settings */ int mute; int volume; @@ -114,7 +118,7 @@ typedef struct { * * BEGIN : Direct Sound and win32 handlers * for xine audio output plugins. - * + * * ------------------------------------------- */ void Error( HWND hwnd, LPSTR szfmt, ... ); @@ -124,7 +128,7 @@ boolean CreateSoundBuffer( ao_directx_t * ao_directx ); void DestroySoundBuffer( ao_directx_t * ao_directx ); uint32_t FillSoundBuffer( ao_directx_t * ao_directx, int code, unsigned char * samples ); -/* Display formatted error message in +/* Display formatted error message in * popup message box. */ void Error( HWND hwnd, LPSTR szfmt, ... ) @@ -225,25 +229,25 @@ boolean CreateSoundBuffer( ao_directx_t * ao_directx ) * related resources */ DestroySoundBuffer( ao_directx ); - + /* create a secondary sound buffer */ - - memset( &pcmwf, 0, sizeof( PCMWAVEFORMAT ) ); + + memset( &pcmwf, 0, sizeof( PCMWAVEFORMAT ) ); pcmwf.wBitsPerSample = ( unsigned short ) ao_directx->bits; - pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM; + pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM; pcmwf.wf.nChannels = ao_directx->chnn; - pcmwf.wf.nSamplesPerSec = ao_directx->rate; + pcmwf.wf.nSamplesPerSec = ao_directx->rate; pcmwf.wf.nBlockAlign = ao_directx->frsz; - pcmwf.wf.nAvgBytesPerSec = ao_directx->rate * ao_directx->frsz; + pcmwf.wf.nAvgBytesPerSec = ao_directx->rate * ao_directx->frsz; - memset( &dsbdesc, 0, sizeof( DSBUFFERDESC ) ); - dsbdesc.dwSize = sizeof( DSBUFFERDESC ); - dsbdesc.dwFlags = (DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | + memset( &dsbdesc, 0, sizeof( DSBUFFERDESC ) ); + dsbdesc.dwSize = sizeof( DSBUFFERDESC ); + dsbdesc.dwFlags = (DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLPOSITIONNOTIFY); dsbdesc.dwBufferBytes = ao_directx->buffer_size; dsbdesc.lpwfxFormat = ( LPWAVEFORMATEX ) &pcmwf; - if( IDirectSound_CreateSoundBuffer( ao_directx->dsobj, &dsbdesc, + if( IDirectSound_CreateSoundBuffer( ao_directx->dsobj, &dsbdesc, &ao_directx->dsbuffer, 0 ) != DS_OK ) { Error( 0, "IDirectSound_CreateSoundBuffer : Unable to create secondary sound buffer" ); @@ -278,7 +282,7 @@ boolean CreateSoundBuffer( ao_directx_t * ao_directx ) /* get the direct sound notification interface */ if( IDirectSoundBuffer_QueryInterface( ao_directx->dsbuffer, - &IID_IDirectSoundNotify, + &IID_IDirectSoundNotify, (LPVOID *)&ao_directx->notify ) != DS_OK ) { Error( 0, "IDirectSoundBuffer_QueryInterface : Unable to get notification interface" ); @@ -376,9 +380,9 @@ uint32_t FillSoundBuffer( ao_directx_t * ao_directx, int code, unsigned char * s #ifdef LOG if ((void*)samples != (void*)0) - printf("audio_directx_out: FillSoundBuffer(%08x, %d, Null) Enter\n", (unsigned long)ao_directx, code); + printf("audio_directx_out: FillSoundBuffer(%08x, %d, Null) Enter\n", (unsigned long)ao_directx, code); else - printf("audio_directx_out: FillSoundBuffer(%08x, %d, Null) Enter\n", (unsigned long)ao_directx, code); + printf("audio_directx_out: FillSoundBuffer(%08x, %d, Null) Enter\n", (unsigned long)ao_directx, code); #endif half_size = ao_directx->buffer_size / 2; @@ -481,7 +485,7 @@ uint32_t FillSoundBuffer( ao_directx_t * ao_directx, int code, unsigned char * s } /* write data to our sound buffer */ - + memcpy( buff_pointer, samples, buff_length ); /* unlock our sound buffer */ @@ -508,7 +512,7 @@ uint32_t FillSoundBuffer( ao_directx_t * ao_directx, int code, unsigned char * s * ----------------------------------------- */ static int ao_directx_control(ao_driver_t *this_gen, int cmd, ...) { - switch (cmd) + switch (cmd) { case AO_CTRL_PLAY_PAUSE: @@ -535,7 +539,7 @@ static int ao_directx_open( ao_driver_t * ao_driver, uint32_t bits, uint32_t rat ao_directx->bits = bits; ao_directx->rate = rate; - + /* store channel count */ switch( mode ) @@ -624,7 +628,7 @@ static int ao_directx_write( ao_driver_t * ao_driver, int16_t * frame_buffer, ui uint32_t wrote; /* number of bytes written */ uint32_t half_size; /* half our sound buffer size */ - lprintf("ao_directx_write(%08x, %08x, %d) Enter\n", + lprintf("ao_directx_write(%08x, %08x, %d) Enter\n", (unsigned long)ao_directx, (unsigned long)frame_buffer, num_frames); /* zero write counter */ @@ -741,7 +745,7 @@ static int ao_directx_set_property( ao_driver_t * ao_driver, int property, int v { ao_directx_t *ao_directx = ( ao_directx_t * ) ao_driver; - lprintf("ao_directx_set_property(%08x, %d, %d) Enter\n", + lprintf("ao_directx_set_property(%08x, %d, %d) Enter\n", (unsigned long)ao_directx, property, value); switch( property ) @@ -755,7 +759,7 @@ static int ao_directx_set_property( ao_driver_t * ao_driver, int property, int v if( !ao_directx->mute && ao_directx->dsbuffer ) IDirectSoundBuffer_SetVolume( ao_directx->dsbuffer, ao_directx->volume ); - xprintf(ao_directx->xine, XINE_VERBOSITY_DEBUG, + xprintf(ao_directx->xine, XINE_VERBOSITY_DEBUG, "ao_directx : volume set to %d - directX volume = %d\n", value, ao_directx->volume); return value; @@ -789,11 +793,11 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da { audiox_class_t *class = (audiox_class_t *) class_gen; ao_directx_t *ao_directx; - - ao_directx = ( ao_directx_t * ) xine_xmalloc( sizeof( ao_directx_t ) ); + + ao_directx = calloc(1, sizeof(ao_directx_t)); if (!ao_directx) return NULL; - + lprintf("open_plugin(%08x, %08x) Enter\n", (unsigned long)class_gen, (unsigned long)data); lprintf("open_plugin: ao_directx=%08x\n", (unsigned long)ao_directx); @@ -841,10 +845,10 @@ static void *init_class (xine_t *xine, void *data) { /* * from this point on, nothing should go wrong anymore */ - audiox = (audiox_class_t *) xine_xmalloc (sizeof (audiox_class_t)); + audiox = calloc(1, sizeof (audiox_class_t)); if (!audiox) return NULL; - + audiox->driver_class.open_plugin = open_plugin; audiox->driver_class.get_identifier = get_identifier; audiox->driver_class.get_description = get_description; @@ -854,7 +858,7 @@ static void *init_class (xine_t *xine, void *data) { audiox->config = xine->config; lprintf("init_class() Exit! Returning audiox=%08x\n", audiox); - + return audiox; } @@ -866,7 +870,7 @@ static const ao_info_t ao_info_directx = { * exported plugin catalog entry */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_DIRECTX_IFACE_VERSION, "directx", XINE_VERSION_CODE, &ao_info_directx, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/audio_out/audio_esd_out.c b/src/audio_out/audio_esd_out.c index 4b209bea1..ae7576259 100644 --- a/src/audio_out/audio_esd_out.c +++ b/src/audio_out/audio_esd_out.c @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2000-2003 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine 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. - * + * * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -77,7 +77,7 @@ typedef struct esd_driver_s { /* * Temporary sample buffer used to reblock the sample output stream * to writes using buffer sizes of n*ESD_BUF_SIZE bytes. - * + * * The reblocking avoids a bug with esd 0.2.18 servers and reduces * cpu load with newer versions of the esd server. * @@ -99,7 +99,7 @@ typedef struct { /* - * connect to esd + * connect to esd */ static int ao_esd_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int mode) @@ -107,7 +107,7 @@ static int ao_esd_open(ao_driver_t *this_gen, esd_driver_t *this = (esd_driver_t *) this_gen; esd_format_t format; - xprintf (this->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_esd_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode); if ( (mode & this->capabilities) == 0 ) { @@ -117,12 +117,12 @@ static int ao_esd_open(ao_driver_t *this_gen, if (this->audio_fd>=0) { - if ( (mode == this->mode) && (rate == this->input_sample_rate) ) + if ( (mode == this->mode) && (rate == this->input_sample_rate) ) return this->output_sample_rate; esd_close (this->audio_fd); } - + this->mode = mode; this->input_sample_rate = rate; this->output_sample_rate = rate; @@ -170,7 +170,7 @@ static int ao_esd_open(ao_driver_t *this_gen, return this->output_sample_rate; } -static int ao_esd_num_channels(ao_driver_t *this_gen) +static int ao_esd_num_channels(ao_driver_t *this_gen) { esd_driver_t *this = (esd_driver_t *) this_gen; return this->num_channels; @@ -200,14 +200,14 @@ static int ao_esd_delay(ao_driver_t *this_gen) frames += (tv.tv_sec - this->start_time.tv_sec) * this->output_sample_rate; - frames -= this->latency; + frames -= this->latency; if (frames < 0) frames = 0; - + /* calc delay */ - + bytes_left = this->bytes_in_buffer - frames * this->bytes_per_frame; - + if (bytes_left<=0) /* buffer ran dry */ bytes_left = 0; return bytes_left / this->bytes_per_frame; @@ -230,18 +230,18 @@ static int ao_esd_write(ao_driver_t *this_gen, /* check if simulated buffer ran dry */ gettimeofday(&tv, NULL); - + frames = (tv.tv_usec - this->start_time.tv_usec) * this->output_sample_k_rate / 1000; frames += (tv.tv_sec - this->start_time.tv_sec) * this->output_sample_rate; - - frames -= this->latency; + + frames -= this->latency; if (frames < 0) frames = 0; /* calc delay */ - + simulated_bytes_in_buffer = frames * this->bytes_per_frame; if (this->bytes_in_buffer < simulated_bytes_in_buffer) @@ -296,7 +296,7 @@ static int ao_esd_write(ao_driver_t *this_gen, if (nwritten != num_bytes) { if (nwritten < 0) xprintf(this->xine, XINE_VERBOSITY_DEBUG, "audio_esd_out: writev failed: %s\n", strerror(errno)); - else + else xprintf(this->xine, XINE_VERBOSITY_DEBUG, "audio_esd_out: warning, incomplete write: %d\n", nwritten); } if (nwritten > 0) @@ -337,7 +337,7 @@ static int ao_esd_get_gap_tolerance (ao_driver_t *this_gen) { static void ao_esd_exit(ao_driver_t *this_gen) { esd_driver_t *this = (esd_driver_t *) this_gen; - + if (this->audio_fd != -1) esd_close(this->audio_fd); @@ -351,19 +351,19 @@ static int ao_esd_get_property (ao_driver_t *this_gen, int property) { int mixer_fd; esd_player_info_t *esd_pi; esd_info_t *esd_i; - + switch(property) { case AO_PROP_MIXER_VOL: - + if((mixer_fd = esd_open_sound(NULL)) >= 0) { if((esd_i = esd_get_all_info(mixer_fd)) != NULL) { for(esd_pi = esd_i->player_list; esd_pi != NULL; esd_pi = esd_pi->next) { if(!strcmp(this->pname, esd_pi->name)) { this->mixer.source_id = esd_pi->source_id; - + if(!this->mixer.mute) - this->mixer.volume = (((esd_pi->left_vol_scale * 100) / 256) + + this->mixer.volume = (((esd_pi->left_vol_scale * 100) / 256) + ((esd_pi->right_vol_scale * 100) / 256)) >> 1; } @@ -372,7 +372,7 @@ static int ao_esd_get_property (ao_driver_t *this_gen, int property) { } esd_close(mixer_fd); } - + return this->mixer.volume; break; @@ -390,39 +390,39 @@ static int ao_esd_set_property (ao_driver_t *this_gen, int property, int value) switch(property) { case AO_PROP_MIXER_VOL: - + if(!this->mixer.mute) { - + /* need this to get source_id */ (void) ao_esd_get_property(&this->ao_driver, AO_PROP_MIXER_VOL); if((mixer_fd = esd_open_sound(NULL)) >= 0) { int v = (value * 256) / 100; - + esd_set_stream_pan(mixer_fd, this->mixer.source_id, v, v); - + if(!this->mixer.mute) this->mixer.volume = value; - + esd_close(mixer_fd); } } else this->mixer.volume = value; - + return this->mixer.volume; break; - + case AO_PROP_MUTE_VOL: { int mute = (value) ? 1 : 0; - + /* need this to get source_id */ (void) ao_esd_get_property(&this->ao_driver, AO_PROP_MIXER_VOL); - + if(mute) { if((mixer_fd = esd_open_sound(NULL)) >= 0) { int v = 0; - + esd_set_stream_pan(mixer_fd, this->mixer.source_id, v, v); esd_close(mixer_fd); } @@ -430,14 +430,14 @@ static int ao_esd_set_property (ao_driver_t *this_gen, int property, int value) else { if((mixer_fd = esd_open_sound(NULL)) >= 0) { int v = (this->mixer.volume * 256) / 100; - + esd_set_stream_pan(mixer_fd, this->mixer.source_id, v, v); esd_close(mixer_fd); } } - + this->mixer.mute = mute; - + return value; } break; @@ -465,7 +465,7 @@ static int ao_esd_ctrl(ao_driver_t *this_gen, int cmd, ...) { return 0; } -static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, +static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) { esd_class_t *class = (esd_class_t *) class_gen; @@ -491,7 +491,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, sigemptyset(&vo_mask); sigaddset(&vo_mask, SIGALRM); - if (sigprocmask(SIG_UNBLOCK, &vo_mask, &vo_mask_orig)) + if (sigprocmask(SIG_UNBLOCK, &vo_mask, &vo_mask_orig)) xprintf(class->xine, XINE_VERBOSITY_DEBUG, "audio_esd_out: cannot unblock SIGALRM: %s\n", strerror(errno)); xprintf(class->xine, XINE_VERBOSITY_LOG, _("audio_esd_out: connecting to esd server...\n")); @@ -511,7 +511,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, return NULL; } - + esd_svinfo = esd_get_server_info(audio_fd); if (esd_svinfo) { server_sample_rate = esd_svinfo->rate; @@ -521,7 +521,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, esd_close(audio_fd); - this = (esd_driver_t *) xine_xmalloc (sizeof (esd_driver_t)); + this = calloc(1, sizeof (esd_driver_t)); if (!this) return NULL; this->xine = class->xine; @@ -583,7 +583,7 @@ static void *init_class (xine_t *xine, void *data) { esd_class_t *this; - this = (esd_class_t *) xine_xmalloc (sizeof (esd_class_t)); + this = calloc(1, sizeof (esd_class_t)); if (!this) return NULL; @@ -606,7 +606,7 @@ static const ao_info_t ao_info_esd = { */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_OUT_ESD_IFACE_VERSION, "esd", XINE_VERSION_CODE, &ao_info_esd, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/audio_out/audio_file_out.c b/src/audio_out/audio_file_out.c index 225d64d0e..7b7bfe950 100644 --- a/src/audio_out/audio_file_out.c +++ b/src/audio_out/audio_file_out.c @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2000-2003 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine 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. - * + * * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -46,7 +46,7 @@ struct wavhdr { unsigned char bRiffMagic[4]; // 'RIFF' uint32_t wRiffLength ; // length of file minus the 8 byte riff header unsigned char bWaveMagic[8]; // 'WAVEfmt ' - uint32_t wFmtSize; // length of format chunk minus 8 byte header + uint32_t wFmtSize; // length of format chunk minus 8 byte header uint16_t wFormatTag; // identifies PCM, ULAW etc uint16_t wChannels; uint32_t dwSamplesPerSecond; // samples per second per channel @@ -93,7 +93,7 @@ static int ao_file_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int file_driver_t *this = (file_driver_t *) this_gen; struct wavhdr w; - xprintf (this->xine, XINE_VERBOSITY_LOG, + xprintf (this->xine, XINE_VERBOSITY_LOG, "audio_file_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode); this->mode = mode; @@ -314,7 +314,7 @@ static int ao_file_ctrl(ao_driver_t *this_gen, int cmd, ...) { return 0; } -static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, +static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) { file_class_t *class = (file_class_t *) class_gen; @@ -323,7 +323,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, lprintf ("open_plugin called\n"); - this = (file_driver_t *) xine_xmalloc (sizeof (file_driver_t)); + this = calloc(1, sizeof (file_driver_t)); if (!this) return NULL; @@ -375,7 +375,7 @@ static void *init_class (xine_t *xine, void *data) { lprintf ("init class\n"); - this = (file_class_t *) xine_xmalloc (sizeof (file_class_t)); + this = calloc(1, sizeof (file_class_t)); if (!this) return NULL; @@ -399,7 +399,7 @@ static const ao_info_t ao_info_file = { */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_OUT_FILE_IFACE_VERSION, "file", XINE_VERSION_CODE, &ao_info_file, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/audio_out/audio_fusionsound_out.c b/src/audio_out/audio_fusionsound_out.c index 92eadc6cf..873ab32e9 100644 --- a/src/audio_out/audio_fusionsound_out.c +++ b/src/audio_out/audio_fusionsound_out.c @@ -1,13 +1,13 @@ /* * Copyright (C) 2000-2006 the xine project and Claudio Ciccani - * + * * This file is part of xine, a free video player. - * + * * xine 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. - * + * * xine 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 @@ -69,10 +69,10 @@ typedef struct fusionsound_driver_s { float vol; int vol_mute; - + float amp; int amp_mute; - + int paused; } fusionsound_driver_t; @@ -90,12 +90,12 @@ static int ao_fusionsound_open(ao_driver_t *ao_driver, DFBResult ret; lprintf ("ao_open( bits=%d, rate=%d, mode=%d )\n", bits, rate, mode); - - dsc.flags = FSSDF_BUFFERSIZE | FSBDF_CHANNELS | + + dsc.flags = FSSDF_BUFFERSIZE | FSBDF_CHANNELS | FSSDF_SAMPLEFORMAT | FSSDF_SAMPLERATE; switch (mode) { - case AO_CAP_MODE_MONO: + case AO_CAP_MODE_MONO: dsc.channels = 1; break; case AO_CAP_MODE_STEREO: @@ -140,13 +140,13 @@ static int ao_fusionsound_open(ao_driver_t *ao_driver, this->playback->Release (this->playback); this->playback = NULL; } - + if (this->stream) { this->stream->Release (this->stream); this->stream = NULL; } - - ret = this->sound->CreateStream (this->sound, &dsc, &this->stream); + + ret = this->sound->CreateStream (this->sound, &dsc, &this->stream); if (ret != DFB_OK) { xprintf (this->xine, XINE_VERBOSITY_LOG, "audio_fusionsound_out: IFusionSound::CreateStream() failed [%s]\n", @@ -160,10 +160,10 @@ static int ao_fusionsound_open(ao_driver_t *ao_driver, this->channels = dsc.channels; this->rate = dsc.samplerate; this->bytes_per_frame = this->channels * FS_BYTES_PER_SAMPLE(this->format); - + ret = this->stream->GetPlayback (this->stream, &this->playback); if (ret == DFB_OK) { - this->playback->SetVolume (this->playback, + this->playback->SetVolume (this->playback, (this->vol_mute ? 0 : this->vol) * (this->amp_mute ? 0 : this->amp)); if (this->paused) @@ -182,22 +182,22 @@ static int ao_fusionsound_open(ao_driver_t *ao_driver, static int ao_fusionsound_num_channels(ao_driver_t *ao_driver) { fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; - + return this->channels; } static int ao_fusionsound_bytes_per_frame(ao_driver_t *ao_driver) { fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; - + return this->bytes_per_frame; } static int ao_fusionsound_delay(ao_driver_t *ao_driver) { fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; int delay = 0; - + this->stream->GetPresentationDelay (this->stream, &delay); - + return (delay * this->rate / 1000); } @@ -209,7 +209,7 @@ static int ao_fusionsound_write(ao_driver_t *ao_driver, int16_t *data, uint32_t num_frames) { fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; DFBResult ret; - + if (this->paused) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_fusionsound_out: " @@ -226,7 +226,7 @@ static int ao_fusionsound_write(ao_driver_t *ao_driver, FusionSoundErrorString (ret)); return 0; } - + return num_frames; } @@ -264,13 +264,13 @@ static void ao_fusionsound_exit(ao_driver_t *ao_driver) { if (this->playback) this->playback->Release (this->playback); - + if (this->stream) this->stream->Release (this->stream); if (this->sound) this->sound->Release (this->sound); - + free (this); } @@ -287,17 +287,17 @@ static int ao_fusionsound_get_property(ao_driver_t *ao_driver, int property) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_fusionsound_out: volume mute is %d\n", this->vol_mute); return this->vol_mute; - + case AO_PROP_AMP: xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_fusionsound_out: amplifier is %.2f\n", this->amp); return (int) (this->amp * 100.0); - + case AO_PROP_AMP_MUTE: xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_fusionsound_out: amplifier mute is %d\n", this->amp_mute); return this->amp_mute; - + default: break; } @@ -305,10 +305,10 @@ static int ao_fusionsound_get_property(ao_driver_t *ao_driver, int property) { return 0; } -static int ao_fusionsound_set_property(ao_driver_t *ao_driver, +static int ao_fusionsound_set_property(ao_driver_t *ao_driver, int property, int value ) { fusionsound_driver_t *this = (fusionsound_driver_t *) ao_driver; - + if (!this->playback) return 0; @@ -318,11 +318,11 @@ static int ao_fusionsound_set_property(ao_driver_t *ao_driver, xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_fusionsound_out: volume set to %.2f\n", this->vol); break; - + case AO_PROP_MUTE_VOL: this->vol_mute = value ? 1 : 0; xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "audio_fusionsound_out: volume mute set to %d\n", + "audio_fusionsound_out: volume mute set to %d\n", this->vol_mute); break; @@ -331,20 +331,20 @@ static int ao_fusionsound_set_property(ao_driver_t *ao_driver, xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_fusionsound_out: amplifier set to %.2f\n", this->amp); break; - + case AO_PROP_AMP_MUTE: this->amp_mute = value ? 1 : 0; xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "audio_fusionsound_out: amplifier mute set to %d\n", + "audio_fusionsound_out: amplifier mute set to %d\n", this->amp_mute); break; default: return 0; } - + if (this->playback) { - this->playback->SetVolume (this->playback, + this->playback->SetVolume (this->playback, (this->vol_mute ? 0 : this->vol) * (this->amp_mute ? 0 : this->amp)); } @@ -362,10 +362,10 @@ static int ao_fusionsound_control(ao_driver_t *ao_driver, int cmd, ...) { this->playback->Stop (this->playback); this->paused = 1; return 1; - + case AO_CTRL_PLAY_RESUME: lprintf ("Resume()\n"); - if (this->playback) + if (this->playback) this->playback->Continue (this->playback); this->paused = 0; return 1; @@ -384,16 +384,16 @@ static int ao_fusionsound_control(ao_driver_t *ao_driver, int cmd, ...) { } -static ao_driver_t* open_plugin(audio_driver_class_t *ao_class, +static ao_driver_t* open_plugin(audio_driver_class_t *ao_class, const void *data ) { fusionsound_class_t *class = (fusionsound_class_t *) ao_class; fusionsound_driver_t *this; const char *args[] = { "xine", "--dfb:no-sighandler", "--fs:no-banner" }; - int argn = sizeof(args) / sizeof(args[0]); + const size_t argn = sizeof(args) / sizeof(args[0]); char **argp = (char **) args; DFBResult ret; - this = (fusionsound_driver_t *) xine_xmalloc (sizeof(fusionsound_driver_t)); + this = calloc(1, sizeof(fusionsound_driver_t)); if (!this) { xprintf (class->xine, XINE_VERBOSITY_LOG, "audio_fusionsound_out: driver interface allocation failed!\n"); @@ -424,7 +424,7 @@ static ao_driver_t* open_plugin(audio_driver_class_t *ao_class, this->ao_driver.exit = ao_fusionsound_exit; this->ao_driver.get_gap_tolerance = ao_fusionsound_get_gap_tolerance; this->ao_driver.control = ao_fusionsound_control; - + this->vol = this->amp = 1.0; return &this->ao_driver; @@ -449,7 +449,7 @@ static void dispose_class(audio_driver_class_t *ao_class) { static void* init_class(xine_t *xine, void *data) { fusionsound_class_t *class; const char *error; - + /* check FusionSound version */ error = FusionSoundCheckVersion( FUSIONSOUND_MAJOR_VERSION, FUSIONSOUND_MINOR_VERSION, @@ -460,7 +460,7 @@ static void* init_class(xine_t *xine, void *data) { return NULL; } - class = (fusionsound_class_t *) xine_xmalloc (sizeof( fusionsound_class_t)); + class = calloc(1, sizeof( fusionsound_class_t)); if (!class) { xprintf (xine, XINE_VERBOSITY_LOG, "audio_fusionsound_out: class interface allocation failed!\n"); @@ -485,7 +485,7 @@ static const ao_info_t ao_info_fusionsound = { */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_OUT_FS_IFACE_VERSION, "FusionSound", XINE_VERSION_CODE, &ao_info_fusionsound, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } diff --git a/src/audio_out/audio_irixal_out.c b/src/audio_out/audio_irixal_out.c index 1654cc1a7..336996a99 100644 --- a/src/audio_out/audio_irixal_out.c +++ b/src/audio_out/audio_irixal_out.c @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2000-2003 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine 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. - * + * * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -113,7 +113,7 @@ static int ao_irixal_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, i default: xlerror ("irixal Driver does not support the requested mode: 0x%x",mode); return 0; - } + } if (! (config = alNewConfig ())) { @@ -126,7 +126,7 @@ static int ao_irixal_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, i alFreeConfig (config); return 0; } - + switch (bits) { case 8: if ( (alSetWidth (config, AL_SAMPLE_8)) == -1) @@ -211,7 +211,7 @@ static int ao_irixal_get_gap_tolerance (ao_driver_t *this_gen) return this->gap_tolerance; } -static int ao_irixal_delay (ao_driver_t *this_gen) +static int ao_irixal_delay (ao_driver_t *this_gen) { irixal_driver_t *this = (irixal_driver_t *) this_gen; stamp_t stamp, time; @@ -230,7 +230,7 @@ static int ao_irixal_write(ao_driver_t *this_gen,int16_t *data, uint32_t num_fra { irixal_driver_t *this = (irixal_driver_t *) this_gen; stamp_t stamp; - + /* Grmbf. IRIX audio does not tell us, wenn we run dry. * We have to detect this ourself. */ /* get absolute number of samples played so far @@ -249,7 +249,7 @@ static int ao_irixal_write(ao_driver_t *this_gen,int16_t *data, uint32_t num_fra * alGetFillable() would tell us, whether space was available */ alWriteFrames (this->port, data, num_frames); this->frames_in_buffer += num_frames; - + return num_frames; } @@ -376,9 +376,9 @@ static void *init_audio_out_plugin (config_values_t *config) } } } - + printf (" capabilities 0x%X\n",this->capabilities); - + /* TODO: anything can change during runtime... move check to the right location */ this->gap_tolerance = config->register_range (config, "audio.device.irixal_gap_tolerance", DEFAULT_GAP_TOLERANCE, 0, 90000, @@ -396,7 +396,7 @@ static void *init_audio_out_plugin (config_values_t *config) this->ao_driver.num_channels = ao_irixal_num_channels; this->ao_driver.bytes_per_frame = ao_irixal_bytes_per_frame; this->ao_driver.delay = ao_irixal_delay; - this->ao_driver.write = ao_irixal_write; + this->ao_driver.write = ao_irixal_write; this->ao_driver.close = ao_irixal_close; this->ao_driver.exit = ao_irixal_exit; this->ao_driver.get_gap_tolerance = ao_irixal_get_gap_tolerance; @@ -421,7 +421,7 @@ ao_info_t *get_audio_out_plugin_info() */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_OUT_IRIXAL_IFACE_VERSION, "irixal", XINE_VERSION_CODE, &ao_info_irixal, init_audio_out_plugin }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/audio_out/audio_jack_out.c b/src/audio_out/audio_jack_out.c index 1bc070527..a343310f0 100644 --- a/src/audio_out/audio_jack_out.c +++ b/src/audio_out/audio_jack_out.c @@ -1,3 +1,6 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include <stdio.h> #include <errno.h> @@ -17,431 +20,926 @@ #define AO_OUT_JACK_IFACE_VERSION 8 #define GAP_TOLERANCE AO_MAX_GAP -#define BUFSIZE 81920 +/* maximum number of channels supported, avoids lots of mallocs */ +#define MAX_CHANS 6 -typedef struct jack_driver_s { +typedef struct jack_driver_s +{ + ao_driver_t ao_driver; + xine_t *xine; + + int capabilities; + int mode; + int paused; + int underrun; + + 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 */ + uint32_t fragment_size; + + jack_client_t *client; + jack_port_t *ports[MAX_CHANS]; + + /*! buffer for audio data */ + unsigned char *buffer; + + /*! buffer read position, may only be modified by playback thread or while it is stopped */ + uint32_t read_pos; + /*! buffer write position, may only be modified by MPlayer's thread */ + uint32_t write_pos; + + struct + { + int volume; + int mute; + } mixer; - ao_driver_t ao_driver; - xine_t *xine; +} jack_driver_t; - int capabilities; +typedef struct +{ + audio_driver_class_t driver_class; + config_values_t *config; + xine_t *xine; +} jack_class_t; - int32_t sample_rate; - uint32_t num_channels; - uint32_t bits_per_sample; - uint32_t bytes_per_frame; - jack_client_t *client; - jack_port_t *port_1; - jack_port_t *port_2; - float buf_1[BUFSIZE]; - float buf_2[BUFSIZE]; - uint32_t buf_read; - uint32_t buf_write; +/************************************************************** + * + * Simple ringbuffer implementation + * Lifted from mplayer ao_jack.c + * +**************************************************************/ + + +/*! size of one chunk, if this is too small Xine will start to "stutter" */ +/*! after a short time of playback */ +#define CHUNK_SIZE (16 * 1024) +/*! number of "virtual" chunks the buffer consists of */ +#define NUM_CHUNKS 8 +/* This type of ring buffer may never fill up completely, at least */ +/* one byte must always be unused. */ +/* For performance reasons (alignment etc.) one whole chunk always stays */ +/* empty, not only one byte. */ +#define BUFFSIZE ((NUM_CHUNKS + 1) * CHUNK_SIZE) + +/** + * \brief get the number of free bytes in the buffer + * \return number of free bytes in buffer + * + * may only be called by Xine's thread + * return value may change between immediately following two calls, + * and the real number of free bytes might be larger! + */ +static int buf_free (jack_driver_t *this) +{ + int free = this->read_pos - this->write_pos - CHUNK_SIZE; + if (free < 0) + free += BUFFSIZE; + return free; +} - uint32_t volume; - uint32_t mute; +/** + * \brief get amount of data available in the buffer + * \return number of bytes available in buffer + * + * may only be called by the playback thread + * return value may change between immediately following two calls, + * and the real number of buffered bytes might be larger! + */ +static int buf_used (jack_driver_t *this) +{ + int used = this->write_pos - this->read_pos; + if (used < 0) + used += BUFFSIZE; + return used; +} -} jack_driver_t; +/** + * \brief insert len bytes into buffer + * \param data data to insert + * \param len length of data + * \return number of bytes inserted into buffer + * + * If there is not enough room, the buffer is filled up + * + * TODO: Xine should really pass data as float, perhaps in V1.2? + */ +static int write_buffer_32 (jack_driver_t *this, unsigned char *data, int len) +{ + int first_len = BUFFSIZE - this->write_pos; + int free = buf_free (this); + if (len > free) + len = free; + if (first_len > len) + first_len = len; + + /* copy from current write_pos to end of buffer */ + memcpy (&(this->buffer[this->write_pos]), data, first_len); + if (len > first_len) { /* we have to wrap around */ + /* remaining part from beginning of buffer */ + memcpy (this->buffer, &data[first_len], len - first_len); + } + this->write_pos = (this->write_pos + len) % BUFFSIZE; + + return len; +} + +static int write_buffer_16 (jack_driver_t *this, unsigned char *data, int len) +{ + int samples_free = buf_free (this) / (sizeof (float)); + int samples = len / 2; + if (samples > samples_free) + samples = samples_free; + + /* Rename some pointers so that the next bit of gymnastics is easier to read */ + uint32_t write_pos = this->write_pos; + float *p_write; + int16_t *p_read = (int16_t *) data; + int i; + for (i = 0; i < samples; i++) { + /* Read in 16bits, write out floats */ + p_write = (float *) (&(this->buffer[write_pos])); + *p_write = ((float) (p_read[i])) / 32768.0f; + write_pos = (write_pos + sizeof (float)) % BUFFSIZE; + } + this->write_pos = write_pos; + + return samples * 2; +} -typedef struct { - audio_driver_class_t driver_class; - config_values_t *config; - xine_t *xine; -} jack_class_t; -static int jack_process(jack_nframes_t nframes, void *arg) +/** + * \brief read data from buffer and splitting it into channels + * \param bufs num_bufs float buffers, each will contain the data of one channel + * \param cnt number of samples to read per channel + * \param num_bufs number of channels to split the data into + * \return number of samples read per channel, equals cnt unless there was too + * little data in the buffer + * + * Assumes the data in the buffer is of type float, the number of bytes + * read is res * num_bufs * sizeof(float), where res is the return value. + * If there is not enough data in the buffer remaining parts will be filled + * with silence. + */ +static int read_buffer (jack_driver_t *this, float **bufs, int cnt, + int num_bufs, float gain) { - jack_driver_t *this = (jack_driver_t *)arg; - uint32_t local_buf_read = this->buf_read; - uint32_t local_buf_write = this->buf_write; - uint32_t src_channel, target_channel; - uint32_t frame; - float *buf, *out; - float gain = 0; - - if (!this->client) return 0; - - if (!this->mute) { - gain = (float)this->volume / 100.0; + int buffered = buf_used (this); + int i, j; + int orig_cnt = cnt; + if (cnt * sizeof (float) * num_bufs > buffered) + cnt = buffered / (sizeof (float) * num_bufs); + + uint32_t read_pos = this->read_pos; + unsigned char *buffer = this->buffer; + for (i = 0; i < cnt; i++) { + for (j = 0; j < num_bufs; j++) { + bufs[j][i] = *((float *) (&(buffer[read_pos]))) * gain; + read_pos = (read_pos + sizeof (float)) % BUFFSIZE; } + } + this->read_pos = read_pos; + for (i = cnt; i < orig_cnt; i++) + for (j = 0; j < num_bufs; j++) + bufs[j][i] = 0; - for (target_channel = 0; target_channel < 2; ++target_channel) { - - if (target_channel < this->num_channels) src_channel = target_channel; - else src_channel = 0; + return cnt; +} - jack_port_t *port = (target_channel ? this->port_2 : this->port_1); - if (!port) continue; +/** + * \brief fill the buffers with silence + * \param bufs num_bufs float buffers, each will contain the data of one channel + * \param cnt number of samples in each buffer + * \param num_bufs number of buffers + */ +static void silence (float **bufs, int cnt, int num_bufs) +{ + int i, j; + for (i = 0; i < cnt; i++) + for (j = 0; j < num_bufs; j++) + bufs[j][i] = 0; +} - buf = (src_channel ? this->buf_2 : this->buf_1); - out = (float *)jack_port_get_buffer(port, nframes); - local_buf_read = this->buf_read; - frame = 0; +/************************************************************** + * + * Jack interface functions + * +**************************************************************/ - while (frame < nframes && local_buf_read != local_buf_write) { - // local_buf_write doesn't change during this process, - // so we can safely defer updating buf_read until after +/** + * \brief stop playing and empty buffers (for seeking/pause) + */ +static void jack_reset (jack_driver_t *this) +{ + this->paused = 1; + this->read_pos = this->write_pos = 0; + this->paused = 0; +} - out[frame++] = buf[local_buf_read] * gain; - if (++local_buf_read == BUFSIZE) local_buf_read = 0; - } +static int jack_callback (jack_nframes_t nframes, void *arg) +{ + jack_driver_t *this = (jack_driver_t *) arg; - if (frame < nframes) { -// printf("jack_process: underrun: %u required, %u available\n", -// nframes, frame); - while (frame < nframes) { - out[frame++] = 0.0f; - } - } + if (!this->client) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "jack_callback: called without a client parameter? silently trying to continue...\n"); + return 0; + } + + float gain = 0; + if (!this->mixer.mute) { + gain = (float) this->mixer.volume / 100.0; + gain *= gain; /* experiment with increasing volume range */ + } + + float *bufs[MAX_CHANS]; + int i; + for (i = 0; i < this->num_channels; i++) + bufs[i] = jack_port_get_buffer (this->ports[i], nframes); + + if (this->paused || this->underrun) { + silence (bufs, nframes, this->num_channels); + } else { + int frames_read = read_buffer (this, bufs, nframes, this->num_channels, gain); + if (frames_read < nframes) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "jack_callback: underrun - frames read: %d\n", frames_read); + this->underrun = 1; } + } - this->buf_read = local_buf_read; + return 0; +} -// printf("jack_process: buf_read %u, buf_write %u\n", this->buf_read, this->buf_write); +static void jack_shutdown (void *arg) +{ + jack_driver_t *this = (jack_driver_t *) arg; + this->client = NULL; +} - return 0; +/* + * Open the Jack audio device + * Return 1 on success, 0 on failure + * All error handling rests with the caller, we just try to open the device here + */ +static int jack_open_device (ao_driver_t *this_gen, char *jack_device, + int32_t *poutput_sample_rate, int num_channels) +{ + jack_driver_t *this = (jack_driver_t *) this_gen; + const char **matching_ports = NULL; + char *port_name = NULL; + jack_client_t *client = this->client; + + int port_flags = JackPortIsInput; + int i; + int num_ports; + + if (num_channels > MAX_CHANS) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "jack_open_device: Invalid number of channels: %i\n", + num_channels); + goto err_out; + } + /* Try to create a client called "xine[-NN]" */ + if ((client = jack_client_open ("xine", JackNullOption, NULL)) == 0) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "\njack_open_device: Error: Failed to connect to JACK server\n"); + goto err_out; + } + + /* Save the new client */ + this->client = client; + + jack_reset (this); + jack_set_process_callback (client, jack_callback, this); + + /* list matching ports */ + if (!jack_device) + port_flags |= JackPortIsPhysical; + matching_ports = jack_get_ports (client, jack_device, NULL, port_flags); + for (num_ports = 0; matching_ports && matching_ports[num_ports]; + num_ports++); + if (!num_ports) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "jack_open_device: no physical ports available\n"); + goto err_out; + } + if (num_ports < num_channels) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "jack_open_device: not enough physical ports available\n"); + goto err_out; + } + + /* create output ports */ + for (i = 0; i < num_channels; i++) { + char pname[50]; + snprintf (pname, 50, "out_%d", i); + this->ports[i] = + jack_port_register (client, pname, JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0); + if (!this->ports[i]) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "jack_open_device: could not create output ports? Why not?\n"); + goto err_out; + } + } + if (jack_activate (client)) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "jack_open_device: jack_activate() failed\n"); + goto err_out; + } + for (i = 0; i < num_channels; i++) { + if (jack_connect + (client, jack_port_name (this->ports[i]), matching_ports[i])) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "jack_open_device: jack_connect() failed\n"); + goto err_out; + } + } + *poutput_sample_rate = jack_get_sample_rate (client); + + free (matching_ports); + return 1; + +err_out: + free (matching_ports); + if (client) { + jack_client_close (client); + this->client = NULL; + } + return 0; } - -static void jack_shutdown(void *arg) + +/************************************************************** + * + * Xine interface functions + * +**************************************************************/ + + +/** + * close the device and reset the play position + */ +static void ao_jack_close (ao_driver_t *this_gen) { - jack_driver_t *this = (jack_driver_t *)arg; - this->client = 0; + jack_driver_t *this = (jack_driver_t *) this_gen; + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "ao_jack_close: closing\n"); + + jack_reset (this); + if (this->client) { + jack_client_close (this->client); + this->client = NULL; + } } /* * open the audio device for writing to */ -static int ao_jack_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int mode) +static int ao_jack_open (ao_driver_t *this_gen, uint32_t bits, uint32_t rate, + int mode) { - jack_driver_t *this = (jack_driver_t *) this_gen; + jack_driver_t *this = (jack_driver_t *) this_gen; + config_values_t *config = this->xine->config; + char *jack_device; - if (bits != 16) { - fprintf(stderr, "ao_jack_open: bits=%u expected %u\n", bits, 16); - return 0; - } + jack_device = + config->lookup_entry (config, "audio.device.jack_device_name")->str_value; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "ao_jack_open: ao_open rate=%d, mode=%d, bits=%d dev=%s\n", rate, + mode, bits, jack_device); - rate = jack_get_sample_rate(this->client); - fprintf(stderr, "ao_jack_open: JACK sample rate is %u\n", rate); + if ((bits != 16) && (bits != 32)) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "ao_jack_open: bits=%u expected 16 or 32bit only\n", bits); + return 0; + } - switch (mode) { - case AO_CAP_MODE_MONO: - this->num_channels = 1; - break; - case AO_CAP_MODE_STEREO: - this->num_channels = 2; - break; + if ((mode & this->capabilities) == 0) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "ao_jack_open: unsupported mode %08x\n", mode); + return 0; + } + + /* If device open already then either re-use it or close it */ + if (this->client) { + if ((mode == this->mode) && (rate == this->input_sample_rate)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "ao_jack_open: device already open, reusing it\n"); + return this->output_sample_rate; } - this->buf_read = this->buf_write = 0; - this->sample_rate = rate; - this->bits_per_sample = bits; - this->capabilities = AO_CAP_16BITS | AO_CAP_MODE_MONO | \ - AO_CAP_MODE_STEREO | AO_CAP_MIXER_VOL | AO_CAP_MUTE_VOL; - this->bytes_per_frame = this->num_channels * (bits / 8); + ao_jack_close (this_gen); + } + + + this->mode = mode; + this->input_sample_rate = rate; + this->bits_per_sample = bits; + this->bytes_in_buffer = 0; + this->read_pos = this->write_pos = 0; + this->paused = 0; + this->underrun = 0; + + /* + * set number of channels / a52 passthrough + */ + switch (mode) { + case AO_CAP_MODE_MONO: + this->num_channels = 1; + break; + case AO_CAP_MODE_STEREO: + this->num_channels = 2; + break; + case AO_CAP_MODE_4CHANNEL: + this->num_channels = 4; + break; + case AO_CAP_MODE_4_1CHANNEL: + case AO_CAP_MODE_5CHANNEL: + case AO_CAP_MODE_5_1CHANNEL: + this->num_channels = 6; + break; + case AO_CAP_MODE_A52: + case AO_CAP_MODE_AC5: + /* FIXME: Is this correct...? */ + this->num_channels = 2; + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "ao_jack_open: AO_CAP_MODE_A52\n"); + break; + default: + xprintf (this->xine, XINE_VERBOSITY_LOG, + "ao_jack_open: JACK Driver does not support the requested mode: 0x%X\n", + mode); + return 0; + } + + xprintf (this->xine, XINE_VERBOSITY_LOG, + "ao_jack_open: %d channels output\n", this->num_channels); + this->bytes_per_frame = (this->bits_per_sample * this->num_channels) / 8; + + /* + * open audio device + */ + if (!jack_open_device (this_gen, jack_device, &(this->output_sample_rate), + this->num_channels)) + return 0; - fprintf(stderr, "ao_jack_open: bits=%d rate=%d, mode=%d OK\n", bits, rate, mode); + if (this->input_sample_rate != this->output_sample_rate) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "ao_jack_open: audio rate : %d requested, %d provided by device\n", + this->input_sample_rate, this->output_sample_rate); + } - return rate; + return this->output_sample_rate; } -static int ao_jack_num_channels(ao_driver_t *this_gen) +static int ao_jack_num_channels (ao_driver_t *this_gen) { - jack_driver_t *this = (jack_driver_t *) this_gen; - return this->num_channels; + jack_driver_t *this = (jack_driver_t *) this_gen; + return this->num_channels; } -static int ao_jack_bytes_per_frame(ao_driver_t *this_gen) +static int ao_jack_bytes_per_frame (ao_driver_t *this_gen) { - jack_driver_t *this = (jack_driver_t *) this_gen; - return this->bytes_per_frame; + jack_driver_t *this = (jack_driver_t *) this_gen; + return this->bytes_per_frame; } static int ao_jack_get_gap_tolerance (ao_driver_t *this_gen) { - return GAP_TOLERANCE; + return GAP_TOLERANCE; } -static int last_write_space = 0; - -static int ao_jack_write(ao_driver_t *this_gen, int16_t *data, - uint32_t num_frames) +/* + * Return the number of outstanding frames in all output buffers + * need to account for ring buffer plus Jack, plus soundcard + */ +static int ao_jack_delay (ao_driver_t *this_gen) { - jack_driver_t *this = (jack_driver_t *) this_gen; - uint32_t frame, channel; - - uint32_t local_buf_read = this->buf_read; - uint32_t local_buf_write = this->buf_write; - uint32_t space = (local_buf_read + BUFSIZE - local_buf_write - 1) % BUFSIZE; - uint32_t first_frame = 0; - - int c = 0; - while (space < num_frames) { - if (++c == 10) return 0; - usleep(10000); - local_buf_read = this->buf_read; - space = (local_buf_read + BUFSIZE - local_buf_write - 1) % BUFSIZE; - } - -// if (space < num_frames) return 0; - -// printf("ao_jack_write: %u frames on %u channels, space is %u\n", num_frames, this->num_channels, space); - last_write_space = space; - - for (frame = first_frame; frame < num_frames; ++frame) { - for (channel = 0; channel < this->num_channels; ++channel) { - float *buf = (channel ? this->buf_2 : this->buf_1); - int16_t sample = data[frame * this->num_channels + channel]; - buf[local_buf_write] = ((float)sample) / 32767.0f; -// printf("%6f ", buf[local_buf_write]); -// if (++c == 8) { printf("\n"); c = 0; } - } - if (++local_buf_write == BUFSIZE) local_buf_write = 0; - } - - this->buf_write = local_buf_write; + jack_driver_t *this = (jack_driver_t *) this_gen; + int frames_played = jack_frames_since_cycle_start (this->client); -// printf("ao_jack_write: buf_read %u, buf_write %u\n", this->buf_read, this->buf_write); + int delay = 0; + /* Ring Buffer always stores floats */ + /* TODO: Unsure if the delay should be fragment_size*2 or *3? */ + delay = buf_used (this) / (sizeof (float) * this->num_channels) + + this->fragment_size * 3 - frames_played; - return 1; + return delay; } -static int ao_jack_delay (ao_driver_t *this_gen) + /* Write audio samples + * num_frames is the number of audio frames present + * audio frames are equivalent one sample on each channel. + * I.E. Stereo 16 bits audio frames are 4 bytes. + * MUST SIMULATE BLOCKING WRITES + */ +static int ao_jack_write (ao_driver_t *this_gen, int16_t *frame_buffer, + uint32_t num_frames) { - jack_driver_t *this = (jack_driver_t *) this_gen; + jack_driver_t *this = (jack_driver_t *) this_gen; + int written = 0; + int num_bytes = num_frames * this->bytes_per_frame; + + /* First try and write all the bytes in one go */ + this->underrun = 0; + /* TODO: In the future Xine should pass only floats to us, so no conversion needed */ + if (this->bits_per_sample == 16) + written = write_buffer_16 (this, (char *) frame_buffer, num_bytes); + else if (this->bits_per_sample == 32) + written = write_buffer_32 (this, (char *) frame_buffer, num_bytes); + + /* If this fails then need to spin and keep trying until everything written */ + int spin_count = 0; + while ((written < num_bytes) && (spin_count < 40)) { + num_bytes -= written; + frame_buffer += written / 2; + + /* Sleep to save CPU */ + int until_callback = + this->fragment_size - jack_frames_since_cycle_start (this->client); + if ((until_callback < 0) || (until_callback > this->fragment_size)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "ao_jack_write: Invalid until_callback %d\n", until_callback); + until_callback = this->fragment_size; + } + xine_usec_sleep (((until_callback + + 100) * 1000.0 * 1000.0) / this->output_sample_rate); - uint32_t local_buf_read = this->buf_read; - uint32_t local_buf_write = this->buf_write; + if (this->bits_per_sample == 16) + written = write_buffer_16 (this, (char *) frame_buffer, num_bytes); + else if (this->bits_per_sample == 32) + written = write_buffer_32 (this, (char *) frame_buffer, num_bytes); - int delay = 0; + if (written == 0) + spin_count++; + else + spin_count = 0; - if (local_buf_write > local_buf_read) { - delay = local_buf_write - local_buf_read; - } else { - delay = ((local_buf_write + BUFSIZE - local_buf_read) % BUFSIZE); - } + if (written == 0) + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "ao_jack_write: unusual, couldn't write anything\n"); + }; - return delay;// - jack_get_buffer_size(this->client); -} + if (spin_count) + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "Nonzero spin_count...%d\n", spin_count); -static void ao_jack_close(ao_driver_t *this_gen) -{ - // nothing + return spin_count ? 0 : 1; /* return 1 on success, 0 if we got stuck for some reason */ } -static uint32_t ao_jack_get_capabilities (ao_driver_t *this_gen) { - jack_driver_t *this = (jack_driver_t *) this_gen; - return this->capabilities; -} - -static void ao_jack_exit(ao_driver_t *this_gen) +static uint32_t ao_jack_get_capabilities (ao_driver_t *this_gen) { - jack_driver_t *this = (jack_driver_t *) this_gen; - jack_client_t *client = this->client; - ao_jack_close(this_gen); - this->client = 0; - if (client) jack_client_close(client); - free (this); + jack_driver_t *this = (jack_driver_t *) this_gen; + return this->capabilities; } -static int ao_jack_get_property (ao_driver_t *this_gen, int property) { - jack_driver_t *this = (jack_driver_t *) this_gen; - - switch(property) { - case AO_PROP_PCM_VOL: - case AO_PROP_MIXER_VOL: -// printf("ao_jack_get_property(AO_PROP_MIXER_VOL): %u\n", this->volume); - return this->volume; - break; - case AO_PROP_MUTE_VOL: -// printf("ao_jack_get_property(AO_PROP_MUTE_VOL): %u\n", this->mute); - return this->mute; - break; - } +static void ao_jack_exit (ao_driver_t *this_gen) +{ + jack_driver_t *this = (jack_driver_t *) this_gen; - return 0; + ao_jack_close (this_gen); + if (this->buffer) + free (this->buffer); + free (this); } -static int ao_jack_set_property (ao_driver_t *this_gen, int property, int value) { - jack_driver_t *this = (jack_driver_t *) this_gen; - - switch(property) { - case AO_PROP_PCM_VOL: - case AO_PROP_MIXER_VOL: -// printf("ao_jack_set_property(AO_PROP_MIXER_VOL): %u\n", value); - this->volume = value; - break; - case AO_PROP_MUTE_VOL: -// printf("ao_jack_get_property(AO_PROP_MUTE_VOL): %u\n", value); - this->mute = value; - break; - } +static int ao_jack_get_property (ao_driver_t *this_gen, int property) +{ + jack_driver_t *this = (jack_driver_t *) this_gen; + + switch (property) { + case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: + return this->mixer.volume; + break; + case AO_PROP_MUTE_VOL: + return this->mixer.mute; + break; + } + + return 0; +} - return ~value; +static int ao_jack_set_property (ao_driver_t *this_gen, int property, int value) +{ + jack_driver_t *this = (jack_driver_t *) this_gen; + + switch (property) { + case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: + this->mixer.volume = value; + return value; + break; + case AO_PROP_MUTE_VOL: + this->mixer.mute = value; + return value; + break; + } + + return -1; } -static int ao_jack_ctrl(ao_driver_t *this_gen, int cmd, ...) { - jack_driver_t *this = (jack_driver_t *) this_gen; +static int ao_jack_ctrl (ao_driver_t *this_gen, int cmd, ...) +{ + jack_driver_t *this = (jack_driver_t *) this_gen; - switch (cmd) { + switch (cmd) { - case AO_CTRL_PLAY_PAUSE: - break; + case AO_CTRL_PLAY_PAUSE: + this->paused = 1; + break; - case AO_CTRL_PLAY_RESUME: - break; + case AO_CTRL_PLAY_RESUME: + this->paused = 0; + break; - case AO_CTRL_FLUSH_BUFFERS: -// fprintf(stderr, "ao_jack_ctrl(AO_CTRL_FLUSH_BUFFERS)\n"); - this->buf_write = this->buf_read = 0; - break; - } + case AO_CTRL_FLUSH_BUFFERS: + jack_reset (this); + break; + } - return 0; + return 0; } +static void jack_speaker_arrangement_cb (void *user_data, + xine_cfg_entry_t *entry); + static ao_driver_t *open_jack_plugin (audio_driver_class_t *class_gen, const void *data) { - jack_class_t *class = (jack_class_t *) class_gen; - jack_driver_t *this; - jack_client_t *client; - uint32_t rate; - const char **port_names; - int i; - - if ((client = jack_client_new("xine")) == 0) { - - char name[20]; - sprintf(name, "xine (%d)", (int)getpid()); - - if ((client = jack_client_new(name)) == 0) { - fprintf(stderr, "\nopen_jack_plugin: Error: Failed to connect to JACK server\n"); - fprintf(stderr, "open_jack_plugin: (did you start 'jackd' server?)\n"); - return 0; - } - } - - this = (jack_driver_t *) xine_xmalloc (sizeof (jack_driver_t)); - - this->client = client; - - jack_set_process_callback(client, jack_process, this); - jack_on_shutdown(client, jack_shutdown, this); - - rate = jack_get_sample_rate(client); - fprintf(stderr, "open_jack_plugin: JACK sample rate is %u\n", rate); - - // We support up to 2-channel output - - for (i = 0; i < 2; ++i) { - jack_port_t *port = jack_port_register - (client, (i ? "out_r" : "out_l"), - JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - if (!port) { - fprintf(stderr, "ao_jack_open: failed to register port %u\n", i); - } - if (i) this->port_2 = port; - else this->port_1 = port; - } - - this->buf_read = this->buf_write = 0; - this->volume = 100; - this->mute = 0; - - if (jack_activate(client)) { - fprintf(stderr, "ao_jack_open: failed to activate JACK client\n"); - return 0; - } - - if ((port_names = jack_get_ports(client, NULL, NULL, - JackPortIsPhysical | JackPortIsInput)) != NULL) { - if (port_names[0]) { - jack_connect(client, jack_port_name(this->port_1), port_names[0]); - } - if (port_names[1] && this->port_2) { - jack_connect(client, jack_port_name(this->port_2), port_names[1]); - } - free(port_names); - } + jack_class_t *class = (jack_class_t *) class_gen; + config_values_t *config = class->config; + jack_driver_t *this; + + jack_client_t *client; + uint32_t rate; + char *jack_device; + const char **matching_ports = NULL; + const char **port_names; + + /* for usability reasons, keep this in sync with audio_oss_out.c */ + static char *speaker_arrangement[] = { + "Mono 1.0", "Stereo 2.0", "Headphones 2.0", "Stereo 2.1", + "Surround 3.0", "Surround 4.0", "Surround 4.1", "Surround 5.0", + "Surround 5.1", "Surround 6.0", + "Surround 6.1", "Surround 7.1", "Pass Through", NULL + }; +#define MONO 0 +#define STEREO 1 +#define HEADPHONES 2 +#define SURROUND21 3 +#define SURROUND3 4 +#define SURROUND4 5 +#define SURROUND41 6 +#define SURROUND5 7 +#define SURROUND51 8 +#define SURROUND6 9 +#define SURROUND61 10 +#define SURROUND71 11 +#define A52_PASSTHRU 12 + int speakers; + + /* Try to create a client called "xine[-NN]" */ + if ((client = jack_client_open ("xine", JackNullOption, NULL)) == 0) { + xprintf (class->xine, XINE_VERBOSITY_LOG, + "\nopen_jack_plugin: Error: Failed to connect to JACK server\n"); + return 0; + } + + this = calloc(1, sizeof (jack_driver_t)); + + rate = jack_get_sample_rate (client); + xprintf (class->xine, XINE_VERBOSITY_DEBUG, + "open_jack_plugin: JACK sample rate is %u\n", rate); + + /* devname_val is offset used to select auto, /dev/dsp, or /dev/sound/dsp */ + jack_device = config->register_string (config, + "audio.device.jack_device_name", + "", + _("JACK audio device name"), + _("Specifies the jack audio device name, " + "leave blank for the default physical output port."), + 10, NULL, NULL); + + this->capabilities = 0; + + + /* for usability reasons, keep this in sync with audio_alsa_out.c */ + speakers = + config->register_enum (config, "audio.output.speaker_arrangement", + STEREO, speaker_arrangement, + _("speaker arrangement"), + _("Select how your speakers are arranged, " + "this determines which speakers xine uses for sound output. " + "The individual values are:\n\n" + "Mono 1.0: You have only one speaker.\n" + "Stereo 2.0: You have two speakers for left and right channel.\n" + "Headphones 2.0: You use headphones.\n" + "Stereo 2.1: You have two speakers for left and right channel, and one " + "subwoofer for the low frequencies.\n" + "Surround 3.0: You have three speakers for left, right and rear channel.\n" + "Surround 4.0: You have four speakers for front left and right and rear " + "left and right channels.\n" + "Surround 4.1: You have four speakers for front left and right and rear " + "left and right channels, and one subwoofer for the low frequencies.\n" + "Surround 5.0: You have five speakers for front left, center and right and " + "rear left and right channels.\n" + "Surround 5.1: You have five speakers for front left, center and right and " + "rear left and right channels, and one subwoofer for the low frequencies.\n" + "Surround 6.0: You have six speakers for front left, center and right and " + "rear left, center and right channels.\n" + "Surround 6.1: You have six speakers for front left, center and right and " + "rear left, center and right channels, and one subwoofer for the low frequencies.\n" + "Surround 7.1: You have seven speakers for front left, center and right, " + "left and right and rear left and right channels, and one subwoofer for the " + "low frequencies.\n" + "Pass Through: Your sound system will receive undecoded digital sound from xine. " + "You need to connect a digital surround decoder capable of decoding the " + "formats you want to play to your sound card's digital output."), + 0, jack_speaker_arrangement_cb, this); + + int port_flags = JackPortIsInput; + int num_ports; + /* list matching ports */ + if (!jack_device) + port_flags |= JackPortIsPhysical; + /* Find all the ports matching either the desired device regexp or physical output ports */ + matching_ports = jack_get_ports (client, jack_device, NULL, port_flags); + /* Count 'em */ + for (num_ports = 0; matching_ports && matching_ports[num_ports]; + num_ports++) + /**/; + if (!num_ports) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "open_jack_plugin: no physical ports available\n"); + goto err_out; + } + + +/* TODO: We deliberately don't offer mono, let Xine upsample instead? */ +/* if (num_ports >= 1) { */ +/* this->capabilities |= AO_CAP_MODE_MONO; */ +/* xprintf(class->xine, XINE_VERBOSITY_DEBUG, "mono "); */ +/* } */ + + if (num_ports >= 2) { + this->capabilities |= AO_CAP_MODE_STEREO; + xprintf (class->xine, XINE_VERBOSITY_DEBUG, "stereo "); + } + + if (num_ports >= 4) { + if (speakers == SURROUND4) { + this->capabilities |= AO_CAP_MODE_4CHANNEL; + xprintf (class->xine, XINE_VERBOSITY_DEBUG, "4-channel "); + } else + xprintf (class->xine, XINE_VERBOSITY_DEBUG, + "(4-channel not enabled in xine config) "); + } + + if (num_ports >= 5) { + if (speakers == SURROUND5) { + this->capabilities |= AO_CAP_MODE_5CHANNEL; + xprintf (class->xine, XINE_VERBOSITY_DEBUG, "5-channel "); + } else + xprintf (class->xine, XINE_VERBOSITY_DEBUG, + "(5-channel not enabled in xine config) "); + } + + if (num_ports >= 6) { + if (speakers == SURROUND51) { + this->capabilities |= AO_CAP_MODE_5_1CHANNEL; + xprintf (class->xine, XINE_VERBOSITY_DEBUG, "5.1-channel "); + } else + xprintf (class->xine, XINE_VERBOSITY_DEBUG, + "(5.1-channel not enabled in xine config) "); + } + + this->buffer = (unsigned char *) malloc (BUFFSIZE); + jack_reset (this); + + this->capabilities |= AO_CAP_MIXER_VOL; + this->capabilities |= AO_CAP_MUTE_VOL; + /* TODO: Currently not respected by Xine, perhaps v1.2? */ + this->capabilities |= AO_CAP_FLOAT32; + + + this->mixer.mute = 0; + this->mixer.volume = 100; + + this->output_sample_rate = jack_get_sample_rate (client); + this->fragment_size = jack_get_buffer_size (client); + + /* Close our JACK client */ + jack_client_close (client); + + this->xine = class->xine; + + this->ao_driver.get_capabilities = ao_jack_get_capabilities; + this->ao_driver.get_property = ao_jack_get_property; + this->ao_driver.set_property = ao_jack_set_property; + this->ao_driver.open = ao_jack_open; + this->ao_driver.num_channels = ao_jack_num_channels; + this->ao_driver.bytes_per_frame = ao_jack_bytes_per_frame; + this->ao_driver.delay = ao_jack_delay; + this->ao_driver.write = ao_jack_write; + this->ao_driver.close = ao_jack_close; + this->ao_driver.exit = ao_jack_exit; + this->ao_driver.get_gap_tolerance = ao_jack_get_gap_tolerance; + this->ao_driver.control = ao_jack_ctrl; + + return &this->ao_driver; + +err_out: + free (matching_ports); + if (client) + jack_client_close (client); + return 0; +} - this->sample_rate = rate; - - this->xine = class->xine; - this->capabilities = AO_CAP_FLOAT32 | AO_CAP_MODE_MONO | - AO_CAP_MODE_STEREO | AO_CAP_MIXER_VOL | AO_CAP_MUTE_VOL; - - this->ao_driver.get_capabilities = ao_jack_get_capabilities; - this->ao_driver.get_property = ao_jack_get_property; - this->ao_driver.set_property = ao_jack_set_property; - this->ao_driver.open = ao_jack_open; - this->ao_driver.num_channels = ao_jack_num_channels; - this->ao_driver.bytes_per_frame = ao_jack_bytes_per_frame; - this->ao_driver.delay = ao_jack_delay; - this->ao_driver.write = ao_jack_write; - this->ao_driver.close = ao_jack_close; - this->ao_driver.exit = ao_jack_exit; - this->ao_driver.get_gap_tolerance = ao_jack_get_gap_tolerance; - this->ao_driver.control = ao_jack_ctrl; - - fprintf(stderr, "jack open_jack_plugin returning %p\n", (void *)(&this->ao_driver)); - return &this->ao_driver; +static void jack_speaker_arrangement_cb (void *user_data, + xine_cfg_entry_t *entry) +{ + jack_driver_t *this = (jack_driver_t *) user_data; + int32_t value = entry->num_value; + if (value == SURROUND4) { + this->capabilities |= AO_CAP_MODE_4CHANNEL; + } else { + this->capabilities &= ~AO_CAP_MODE_4CHANNEL; + } + if (value == SURROUND41) { + this->capabilities |= AO_CAP_MODE_4_1CHANNEL; + } else { + this->capabilities &= ~AO_CAP_MODE_4_1CHANNEL; + } + if (value == SURROUND5) { + this->capabilities |= AO_CAP_MODE_5CHANNEL; + } else { + this->capabilities &= ~AO_CAP_MODE_5CHANNEL; + } + if (value >= SURROUND51) { + this->capabilities |= AO_CAP_MODE_5_1CHANNEL; + } else { + this->capabilities &= ~AO_CAP_MODE_5_1CHANNEL; + } } /* * class functions */ -static char* get_identifier (audio_driver_class_t *this_gen) { - return "jack"; +static char *get_identifier (audio_driver_class_t *this_gen) +{ + return "jack"; } -static char* get_description (audio_driver_class_t *this_gen) { - return _("xine output plugin for JACK Audio Connection Kit"); +static char *get_description (audio_driver_class_t *this_gen) +{ + return _("xine output plugin for JACK Audio Connection Kit"); } -static void dispose_class (audio_driver_class_t *this_gen) { - - jack_class_t *this = (jack_class_t *) this_gen; - free (this); +static void dispose_class (audio_driver_class_t *this_gen) +{ + jack_class_t *this = (jack_class_t *) this_gen; + free (this); } -static void *init_class (xine_t *xine, void *data) { - - jack_class_t *this; - - this = (jack_class_t *) xine_xmalloc (sizeof (jack_class_t)); +static void *init_class (xine_t *xine, void *data) +{ + jack_class_t *this; - this->driver_class.open_plugin = open_jack_plugin; - this->driver_class.get_identifier = get_identifier; - this->driver_class.get_description = get_description; - this->driver_class.dispose = dispose_class; + this = calloc(1, sizeof (jack_class_t)); - this->config = xine->config; - this->xine = xine; + this->driver_class.open_plugin = open_jack_plugin; + this->driver_class.get_identifier = get_identifier; + this->driver_class.get_description = get_description; + this->driver_class.dispose = dispose_class; - fprintf(stderr, "jack init_class returning %p\n", (void *)this); + this->config = xine->config; + this->xine = xine; - return this; + return this; } -static ao_info_t ao_info_jack = { - 6 -}; +static ao_info_t ao_info_jack = { 6 }; /* * exported plugin catalog entry */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_AUDIO_OUT, AO_OUT_JACK_IFACE_VERSION, "jack", XINE_VERSION_CODE /* XINE_VERSION_CODE */, &ao_info_jack, init_class }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_AUDIO_OUT, AO_OUT_JACK_IFACE_VERSION, "jack", XINE_VERSION_CODE, + &ao_info_jack, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; - diff --git a/src/audio_out/audio_none_out.c b/src/audio_out/audio_none_out.c index a815d645a..c3d351035 100644 --- a/src/audio_out/audio_none_out.c +++ b/src/audio_out/audio_none_out.c @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2000-2003 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine 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. - * + * * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -40,7 +40,7 @@ #define AUDIO_NUM_FRAGMENTS 15 #define AUDIO_FRAGMENT_SIZE 8192 -#define GAP_TOLERANCE AO_MAX_GAP +#define GAP_TOLERANCE AO_MAX_GAP typedef struct none_driver_s { @@ -74,7 +74,7 @@ static int ao_none_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int { none_driver_t *this = (none_driver_t *) this_gen; - xprintf (this->xine, XINE_VERBOSITY_DEBUG, + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_none_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode); this->mode = mode; @@ -115,13 +115,13 @@ static int ao_none_write(ao_driver_t *this_gen, int16_t *data, uint32_t num_frames) { none_driver_t *this = (none_driver_t *) this_gen; - + /* take some time to pretend we are doing something. * avoids burning cpu. */ if( (1000 * num_frames / this->sample_rate) > 10 ) xine_usec_sleep ((1000 * num_frames / this->sample_rate)*1000/2); - + return 1; } @@ -143,7 +143,7 @@ static uint32_t ao_none_get_capabilities (ao_driver_t *this_gen) { static void ao_none_exit(ao_driver_t *this_gen) { none_driver_t *this = (none_driver_t *) this_gen; - + ao_none_close(this_gen); free (this); @@ -177,7 +177,7 @@ static int ao_none_ctrl(ao_driver_t *this_gen, int cmd, ...) { return 0; } -static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, +static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) { none_class_t *class = (none_class_t *) class_gen; @@ -186,7 +186,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, lprintf ("open_plugin called\n"); - this = (none_driver_t *) xine_xmalloc (sizeof (none_driver_t)); + this = calloc(1, sizeof (none_driver_t)); if (!this) return NULL; @@ -236,7 +236,7 @@ static void *init_class (xine_t *xine, void *data) { lprintf ("init class\n"); - this = (none_class_t *) xine_xmalloc (sizeof (none_class_t)); + this = calloc(1, sizeof (none_class_t)); if (!this) return NULL; @@ -260,7 +260,7 @@ static const ao_info_t ao_info_none = { */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_OUT_NONE_IFACE_VERSION, "none", XINE_VERSION_CODE, &ao_info_none, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c index a6e0fe494..bd16a6dd3 100644 --- a/src/audio_out/audio_oss_out.c +++ b/src/audio_out/audio_oss_out.c @@ -1,25 +1,25 @@ -/* - * Copyright (C) 2000-2003 the xine project - * +/* + * Copyright (C) 2000-2008 the xine project + * * This file is part of xine, a free video player. - * + * * xine 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. - * + * * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * 20-8-2001 First implementation of Audio sync and Audio driver separation. * Copyright (C) 2001 James Courtier-Dutton James@superbug.demon.co.uk - * + * * General Programming Guidelines: - * New concept of an "audio_frame". * An audio_frame consists of all the samples required to fill every audio channel @@ -90,7 +90,7 @@ #endif #ifndef AFMT_AC3 -# define AFMT_AC3 0x00000400 +# define AFMT_AC3 0x00000400 #endif #define AO_OUT_OSS_IFACE_VERSION 8 @@ -127,7 +127,7 @@ typedef struct oss_driver_s { uint32_t bytes_per_frame; uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */ uint32_t last_getoptr; - + int audio_started; int sync_method; int latency; @@ -178,7 +178,7 @@ static int ao_oss_open(ao_driver_t *this_gen, close (this->audio_fd); } - + this->mode = mode; this->input_sample_rate = rate; this->bits_per_sample = bits; @@ -192,11 +192,11 @@ static int ao_oss_open(ao_driver_t *this_gen, this->audio_fd=open(this->audio_dev,O_WRONLY|O_NONBLOCK); if (this->audio_fd < 0) { - xprintf(this->xine, XINE_VERBOSITY_LOG, + xprintf(this->xine, XINE_VERBOSITY_LOG, _("audio_oss_out: Opening audio device %s: %s\n"), this->audio_dev, strerror(errno)); return 0; } - + /* We wanted non blocking open but now put it back to normal */ fcntl(this->audio_fd, F_SETFL, fcntl(this->audio_fd, F_GETFL)&~O_NONBLOCK); @@ -213,8 +213,8 @@ static int ao_oss_open(ao_driver_t *this_gen, tmp = this->input_sample_rate; if (ioctl(this->audio_fd,SNDCTL_DSP_SPEED, &tmp) == -1) { - - xprintf(this->xine, XINE_VERBOSITY_LOG, + + xprintf(this->xine, XINE_VERBOSITY_LOG, _("audio_oss_out: warning: sampling rate %d Hz not supported, trying 44100 Hz\n"), this->input_sample_rate); @@ -272,7 +272,7 @@ static int ao_oss_open(ao_driver_t *this_gen, xprintf(this->xine, XINE_VERBOSITY_LOG, "audio_oss_out: %d channels output\n", this->num_channels); this->bytes_per_frame=(this->bits_per_sample*this->num_channels)/8; - + /* * set format */ @@ -303,7 +303,7 @@ static int ao_oss_open(ao_driver_t *this_gen, else xprintf(this->xine, XINE_VERBOSITY_DEBUG, "audio_oss_out: The AFMT_S16_NE ioctl failed.\n"); return 0; - } + } } break; case AO_CAP_MODE_A52: @@ -317,7 +317,7 @@ static int ao_oss_open(ao_driver_t *this_gen, ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); tmp = AFMT_AC3; if (ioctl(this->audio_fd, SNDCTL_DSP_SETFMT, &tmp) < 0 || tmp != AFMT_AC3) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "audio_oss_out: AC3 SNDCTL_DSP_SETFMT failed. %d. Using alternative.\n",tmp); tmp = AFMT_S16_LE; ioctl(this->audio_fd, SNDCTL_DSP_SETFMT, &tmp); @@ -344,7 +344,7 @@ static int ao_oss_open(ao_driver_t *this_gen, printf ("audio_oss_out: audio buffer fragment info : %x\n",tmp); - ioctl(this->audio_fd,SNDCTL_DSP_SETFRAGMENT,&tmp); + ioctl(this->audio_fd,SNDCTL_DSP_SETFRAGMENT,&tmp); */ return this->output_sample_rate; @@ -395,9 +395,9 @@ static int ao_oss_delay(ao_driver_t *this_gen) { * this->output_sample_k_rate / 1000; frames += (tv.tv_sec - this->start_time.tv_sec) * this->output_sample_rate; - + frames -= this->latency * this->output_sample_k_rate; - + /* calc delay */ bytes_left = this->bytes_in_buffer - frames * this->bytes_per_frame; @@ -405,35 +405,37 @@ static int ao_oss_delay(ao_driver_t *this_gen) { if (bytes_left<=0) /* buffer ran dry */ bytes_left = 0; break; + case OSS_SYNC_GETODELAY: +#ifdef SNDCTL_DSP_GETODELAY + if (ioctl (this->audio_fd, SNDCTL_DSP_GETODELAY, &bytes_left)) { + perror ("audio_oss_out: DSP_GETODELAY ioctl():"); + } + if (bytes_left<0) + bytes_left = 0; + + lprintf ("%d bytes left\n", bytes_left); + + break; +#endif case OSS_SYNC_GETOPTR: if (ioctl (this->audio_fd, SNDCTL_DSP_GETOPTR, &info)) { perror ("audio_oss_out: SNDCTL_DSP_GETOPTR failed:"); } - + lprintf ("%d bytes output\n", info.bytes); if (this->bytes_in_buffer < info.bytes) { this->bytes_in_buffer -= this->last_getoptr; /* GETOPTR wrapped */ - } - + } + bytes_left = this->bytes_in_buffer - info.bytes; /* calc delay */ - + if (bytes_left<=0) { /* buffer ran dry */ bytes_left = 0; this->bytes_in_buffer = info.bytes; } this->last_getoptr = info.bytes; break; - case OSS_SYNC_GETODELAY: - if (ioctl (this->audio_fd, SNDCTL_DSP_GETODELAY, &bytes_left)) { - perror ("audio_oss_out: DSP_GETODELAY ioctl():"); - } - if (bytes_left<0) - bytes_left = 0; - - lprintf ("%d bytes left\n", bytes_left); - - break; } return bytes_left / this->bytes_per_frame; @@ -474,7 +476,7 @@ static int ao_oss_write(ao_driver_t *this_gen, this->bytes_in_buffer += num_frames * this->bytes_per_frame; - n = write(this->audio_fd, frame_buffer, num_frames * this->bytes_per_frame); + n = write(this->audio_fd, frame_buffer, num_frames * this->bytes_per_frame); lprintf ("ao_oss_write done\n"); @@ -518,20 +520,20 @@ static int ao_oss_get_property (ao_driver_t *this_gen, int property) { case AO_PROP_PCM_VOL: case AO_PROP_MIXER_VOL: if(!this->mixer.mute) { - + if(this->mixer.fd != -1) { IOCTL_REQUEST_TYPE cmd = 0; int v; - + ioctl(this->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 return -1; - + ioctl(this->mixer.fd, cmd, &v); this->mixer.volume = (((v & 0xFF00) >> 8) + (v & 0x00FF)) / 2; } else @@ -557,20 +559,20 @@ static int ao_oss_set_property (ao_driver_t *this_gen, int property, int value) case AO_PROP_PCM_VOL: case AO_PROP_MIXER_VOL: if(!this->mixer.mute) { - + if(this->mixer.fd != -1) { IOCTL_REQUEST_TYPE cmd = 0; int v; - + ioctl(this->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 return -1; - + v = (value << 8) | value; ioctl(this->mixer.fd, cmd, &v); this->mixer.volume = value; @@ -586,26 +588,26 @@ static int ao_oss_set_property (ao_driver_t *this_gen, int property, int value) this->mixer.mute = (value) ? 1 : 0; if(this->mixer.mute) { - + if(this->mixer.fd != -1) { IOCTL_REQUEST_TYPE cmd = 0; int v = 0; - + ioctl(this->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 return -1; - + ioctl(this->mixer.fd, cmd, &v); } else return -1; } else (void) ao_oss_set_property(&this->ao_driver, this->mixer.prop, this->mixer.volume); - + return value; break; } @@ -623,7 +625,7 @@ static int ao_oss_ctrl(ao_driver_t *this_gen, int cmd, ...) { if (this->sync_method != OSS_SYNC_SOFTSYNC) ioctl(this->audio_fd, SNDCTL_DSP_RESET, NULL); - + /* close/reopen if RESET causes problems */ if (this->sync_method == OSS_SYNC_GETOPTR) { ao_oss_close(this_gen); @@ -639,7 +641,7 @@ static int ao_oss_ctrl(ao_driver_t *this_gen, int cmd, ...) { lprintf ("AO_CTRL_FLUSH_BUFFERS\n"); if (this->sync_method != OSS_SYNC_SOFTSYNC) ioctl(this->audio_fd, SNDCTL_DSP_RESET, NULL); - + if (this->sync_method == OSS_SYNC_GETOPTR) { ao_oss_close(this_gen); ao_oss_open(this_gen, this->bits_per_sample, this->input_sample_rate, this->mode); @@ -685,14 +687,14 @@ static int probe_audio_devices(oss_driver_t *this) { strcpy(this->audio_dev, devname); /* Better, keep this one */ best_rate = rate; } - + close (audio_fd); } } } return best_rate; /* Will be zero if we did not find one */ -} - +} + static void oss_speaker_arrangement_cb (void *user_data, xine_cfg_entry_t *entry); @@ -726,8 +728,8 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da #define A52_PASSTHRU 12 int speakers; - - this = (oss_driver_t *) xine_xmalloc (sizeof (oss_driver_t)); + + this = calloc(1, sizeof (oss_driver_t)); if (!this) return NULL; @@ -760,7 +762,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da xprintf(class->xine, XINE_VERBOSITY_LOG, _("audio_oss_out: audio.device.oss_device_name = auto, probing devs\n")); if ( ! probe_audio_devices(this)) { /* Returns zero on fail */ - xprintf(class->xine, XINE_VERBOSITY_LOG, + xprintf(class->xine, XINE_VERBOSITY_LOG, _("audio_oss_out: Auto probe for audio device failed\n")); free (this); return NULL; @@ -782,18 +784,18 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da audio_fd = open(this->audio_dev, O_WRONLY|O_NONBLOCK); if (audio_fd < 0) { - xprintf(class->xine, XINE_VERBOSITY_LOG, + xprintf(class->xine, XINE_VERBOSITY_LOG, _("audio_oss_out: opening audio device %s failed:\n%s\n"), this->audio_dev, strerror(errno)); free (this); return NULL; - } + } /* * set up driver to reasonable values for capabilities tests */ - arg = AFMT_S16_NE; + arg = AFMT_S16_NE; status = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &arg); arg = 44100; status = ioctl(audio_fd, SNDCTL_DSP_SPEED, &arg); @@ -803,7 +805,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da */ this->sync_method = config->register_enum (config, "audio.oss_sync_method", OSS_SYNC_AUTO_DETECT, - sync_methods, + sync_methods, _("a/v sync method to use by OSS"), _("xine can use different methods to keep audio and video " "synchronized. Which setting works best depends on the " @@ -840,10 +842,13 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da * check if SNDCTL_DSP_GETODELAY works. if so, using it is preferred. */ +#ifdef SNDCTL_DSP_GETODELAY if (ioctl(audio_fd, SNDCTL_DSP_GETODELAY, &info) != -1) { xprintf(class->xine, XINE_VERBOSITY_DEBUG, "audio_oss_out: using SNDCTL_DSP_GETODELAY\n"); this->sync_method = OSS_SYNC_GETODELAY; - } else if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &info) != -1) { + } else +#endif + if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &info) != -1) { xprintf(class->xine, XINE_VERBOSITY_DEBUG, "audio_oss_out: using SNDCTL_DSP_GETOPTR\n"); this->sync_method = OSS_SYNC_GETOPTR; } else { @@ -857,9 +862,9 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da "audio_oss_out: ...will use system real-time clock for soft-sync instead\n" "audio_oss_out: ...there may be audio/video synchronization issues\n")); xine_monotonic_clock(&this->start_time, NULL); - + this->latency = config->register_range (config, "audio.oss_latency", 0, - -3000, 3000, + -3000, 3000, _("OSS audio output latency (adjust a/v sync)"), _("If you experience audio being not in sync " "with the video, you can enter a fixed offset " @@ -868,34 +873,30 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da "of a second."), 20, NULL, NULL); } - + if (this->sync_method == OSS_SYNC_PROBEBUFFER) { char *buf; int c; - - xprintf(class->xine, XINE_VERBOSITY_LOG, - _("audio_oss_out: Audio driver realtime sync disabled...\n" - "audio_oss_out: ...probing output buffer size: ")); + this->buffer_size = 0; - - if( (buf=malloc(1024)) != NULL ) { - memset(buf,0,1024); - + + if( (buf=calloc(1, 1024)) != NULL ) { do { c = write(audio_fd,buf,1024); if( c != -1 ) this->buffer_size += c; } while( c == 1024 ); - + free(buf); } close(audio_fd); xprintf(class->xine, XINE_VERBOSITY_LOG, - _("%d bytes\naudio_oss_out: ...there may be audio/video synchronization issues\n"), this->buffer_size); + _("audio_oss_out: Audio driver realtime sync disabled...\n" + "audio_oss_out: ...probing output buffer size: %d bytes\naudio_oss_out: ...there may be audio/video synchronization issues\n"), this->buffer_size); audio_fd=open(this->audio_dev, O_WRONLY|O_NONBLOCK); - if(audio_fd < 0) + if(audio_fd < 0) { xprintf(class->xine, XINE_VERBOSITY_LOG, _("audio_oss_out: opening audio device %s failed:\n%s\n"), this->audio_dev, strerror(errno)); @@ -906,11 +907,11 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da } this->capabilities = 0; - + arg = AFMT_U8; if( ioctl(audio_fd, SNDCTL_DSP_SETFMT, &arg) != -1 && arg == AFMT_U8) this->capabilities |= AO_CAP_8BITS; - + /* switch back to 16bits, because some soundcards otherwise do not report all their capabilities */ arg = AFMT_S16_NE; if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &arg) == -1 || arg != AFMT_S16_NE) { @@ -954,48 +955,48 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da 0, oss_speaker_arrangement_cb, this); - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "audio_oss_out: supported modes are "); - num_channels = 1; - status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); + char *logmsg = strdup (_("audio_oss_out: supported modes are")); + num_channels = 1; + status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==1) ) { this->capabilities |= AO_CAP_MODE_MONO; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "mono "); + xine_strcat_realloc (&logmsg, _(" mono")); } - num_channels = 2; - status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); + num_channels = 2; + status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==2) ) { this->capabilities |= AO_CAP_MODE_STEREO; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "stereo "); + xine_strcat_realloc (&logmsg, _(" stereo")); } - num_channels = 4; - status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); + num_channels = 4; + status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==4) ) { if ( speakers == SURROUND4 ) { this->capabilities |= AO_CAP_MODE_4CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "4-channel "); - } + xine_strcat_realloc (&logmsg, _(" 4-channel")); + } else - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(4-channel not enabled in xine config) " ); + xine_strcat_realloc (&logmsg, _(" (4-channel not enabled in xine config)")); } - num_channels = 5; - status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); + num_channels = 5; + status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==5) ) { if ( speakers == SURROUND5 ) { this->capabilities |= AO_CAP_MODE_5CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "5-channel "); + xine_strcat_realloc (&logmsg, _(" 5-channel")); } else - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(5-channel not enabled in xine config) " ); + xine_strcat_realloc (&logmsg, _(" (5-channel not enabled in xine config)")); } - num_channels = 6; - status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); + num_channels = 6; + status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==6) ) { if ( speakers == SURROUND51 ) { this->capabilities |= AO_CAP_MODE_5_1CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "5.1-channel "); - } + xine_strcat_realloc (&logmsg, _(" 5.1-channel")); + } else - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(5.1-channel not enabled in xine config) " ); + xine_strcat_realloc (&logmsg, _(" (5.1-channel not enabled in xine config)")); } ioctl(audio_fd,SNDCTL_DSP_GETFMTS,&caps); @@ -1005,11 +1006,14 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da if ( speakers == A52_PASSTHRU ) { this->capabilities |= AO_CAP_MODE_A52; this->capabilities |= AO_CAP_MODE_AC5; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "a/52-pass-through "); - } - else - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(a/52-pass-through not enabled in xine config)"); - + xine_strcat_realloc (&logmsg, _(" a/52 pass-through")); + } + else + xine_strcat_realloc (&logmsg, _(" (a/52 pass-through not enabled in xine config)")); + + xprintf(class->xine, XINE_VERBOSITY_DEBUG, "%s\n", logmsg); + free (logmsg); + /* * mixer initialisation. */ @@ -1018,7 +1022,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da int mixer_num; int audio_devs; char *parse; - + mixer_num = config->register_num(config, "audio.device.oss_mixer_number", -1, _("OSS audio mixer number, -1 for none"), _("The full mixer device name is created by taking the " @@ -1029,33 +1033,30 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da "The range of this value is -1 or 0-15. This setting is " "ignored, when the OSS audio device name is set to \"auto\"."), 10, NULL, NULL); - + /* get the mixer device name from the audio device name by replacing "dsp" with "mixer" */ strcpy(mixer_name, this->audio_dev); if ((parse = strstr(mixer_name, "dsp"))) { parse[0] = '\0'; parse += 3; - this->mixer.name = (char *)malloc(strlen(mixer_name) + sizeof("mixer") + 2); if (devname_val == 0) - sprintf(this->mixer.name, "%smixer%s", mixer_name, parse); + asprintf(&(this->mixer.name), "%smixer%s", mixer_name, parse); else { if (mixer_num == -1) - sprintf(this->mixer.name, "%smixer", mixer_name); + asprintf(&(this->mixer.name), "%smixer", mixer_name); else - sprintf(this->mixer.name, "%smixer%d", mixer_name, mixer_num); + asprintf(&(this->mixer.name), "%smixer%d", mixer_name, mixer_num); } } else { - this->mixer.name = (char *)malloc(1); - this->mixer.name[0] = '\0'; + _x_abort(); } - _x_assert(this->mixer.name[0] != '\0'); - + this->mixer.fd = open(this->mixer.name, O_RDONLY); if(this->mixer.fd != -1) { ioctl(this->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; @@ -1064,9 +1065,9 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da this->capabilities |= AO_CAP_MIXER_VOL; this->mixer.prop = AO_PROP_MIXER_VOL; } - + /* - * This is obsolete in Linux kernel OSS + * This is obsolete in Linux kernel OSS * implementation, so this will certainly doesn't work. * So we just simulate the mute stuff */ @@ -1075,11 +1076,11 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da this->capabilities |= AO_CAP_MUTE_VOL; */ this->capabilities |= AO_CAP_MUTE_VOL; - - } else + + } else xprintf (class->xine, XINE_VERBOSITY_LOG, _("audio_oss_out: open() mixer %s failed: %s\n"), this->mixer.name, strerror(errno)); - + this->mixer.mute = 0; this->mixer.volume = ao_oss_get_property (&this->ao_driver, this->mixer.prop); @@ -1165,7 +1166,7 @@ static void *init_class (xine_t *xine, void *data) { oss_class_t *this; - this = (oss_class_t *) xine_xmalloc (sizeof (oss_class_t)); + this = calloc(1, sizeof (oss_class_t)); if (!this) return NULL; @@ -1189,7 +1190,7 @@ static const ao_info_t ao_info_oss = { */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_OUT_OSS_IFACE_VERSION, "oss", XINE_VERSION_CODE, &ao_info_oss, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; diff --git a/src/audio_out/audio_pulse_out.c b/src/audio_out/audio_pulse_out.c index 26d121bf6..d4d19ce1b 100644 --- a/src/audio_out/audio_pulse_out.c +++ b/src/audio_out/audio_pulse_out.c @@ -1,28 +1,28 @@ -/* - * Copyright (C) 2000-2007 the xine project - * +/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + * Copyright (C) 2000-2008 the xine project + * * This file is part of xine, a free video player. - * + * * xine 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. - * + * * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * - * ao plugin for pulseaudio (rename of polypaudio): + * ao plugin for PulseAudio: * http://0pointer.de/lennart/projects/pulsaudio/ * - * originally written for polypaudio simple api. Lennart then suggested - * using the async api for better control (such as volume), therefore, a lot - * of this code comes from Lennart's patch to mplayer. + * Diego Petteno, Lennart Poettering */ #ifdef HAVE_CONFIG_H @@ -48,15 +48,9 @@ #define GAP_TOLERANCE AO_MAX_GAP -/* CHECKME: should this be conditional on autotools? */ -extern const char *__progname; - typedef struct { audio_driver_class_t driver_class; xine_t *xine; - - struct pa_context *context; /*< Pulseaudio connection context */ - struct pa_threaded_mainloop *mainloop; /*< Main event loop object */ } pulse_class_t; typedef struct pulse_driver_s { @@ -67,11 +61,13 @@ typedef struct pulse_driver_s { char *host; /*< The host to connect to */ char *sink; /*< The sink to connect to */ - struct pa_stream *stream; /*< Pulseaudio playback stream object */ - pthread_mutex_t info_mutex; /**< Mutex for info callback signaling */ + pa_threaded_mainloop *mainloop; /*< Main event loop object */ + pa_context *context; /*< Pulseaudio connection context */ + pa_stream *stream; /*< Pulseaudio playback stream object */ pa_volume_t swvolume; + int muted; pa_cvolume cvolume; int capabilities; @@ -82,67 +78,117 @@ typedef struct pulse_driver_s { uint32_t bits_per_sample; uint32_t bytes_per_frame; - uint32_t frames_written; - } pulse_driver_t; /** - * @brief Callback function called when a stream operation succeed - * @param stream Stream which operation has succeeded - * @param success The success value for the operation (ignored) - * @param this_Gen pulse_driver_t pointer for the PulseAudio output - * instance. + * @brief Callback function called when the state of the context is changed + * @param c Context which changed status + * @param this_gen pulse_class_t pointer for the PulseAudio output class */ -static void __xine_pa_stream_success_callback(pa_stream *const stream, const int success, - void *const mutex_gen) +static void __xine_pa_context_state_callback(pa_context *c, void *this_gen) { - pthread_mutex_t *const completion_mutex = (pthread_mutex_t*)mutex_gen; + pulse_driver_t * this = (pulse_driver_t*) this_gen; + + switch (pa_context_get_state(c)) { - pthread_mutex_unlock(completion_mutex); + case PA_CONTEXT_READY: + case PA_CONTEXT_TERMINATED: + case PA_CONTEXT_FAILED: + pa_threaded_mainloop_signal(this->mainloop, 0); + break; + + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + } } /** - * @brief Callback function called when the state of the context is changed - * @param ctx Context which operation has succeeded + * @brief Callback function called when the state of the stream is changed + * @param s Stream that changed status * @param this_gen pulse_driver_t pointer for the PulseAudio output * instance. */ -static void __xine_pa_context_status_callback(pa_context *const ctx, void *const this_gen) +static void __xine_pa_stream_state_callback(pa_stream *s, void *this_gen) { - pulse_driver_t *const this = (pulse_driver_t*)this_gen; - - switch (pa_context_get_state(ctx)) { - case PA_CONTEXT_READY: - case PA_CONTEXT_TERMINATED: - case PA_CONTEXT_FAILED: - pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); - break; - - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_UNCONNECTED: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - break; + pulse_driver_t * this = (pulse_driver_t*) this_gen; + + switch (pa_stream_get_state(s)) { + + case PA_STREAM_READY: + case PA_STREAM_TERMINATED: + case PA_STREAM_FAILED: + pa_threaded_mainloop_signal(this->mainloop, 0); + break; + + case PA_STREAM_UNCONNECTED: + case PA_STREAM_CREATING: + break; } } /** - * @brief Callback function called when a context operation succeed + * @brief Callback function called when PA asks for more audio data. + * @param s Stream on which data is requested + * @param nbytes the number of bytes PA requested + * @param this_gen pulse_driver_t pointer for the PulseAudio output + * instance. + */ +static void __xine_pa_stream_request_callback(pa_stream *s, size_t nbytes, void *this_gen) +{ + pulse_driver_t * this = (pulse_driver_t*) this_gen; + + pa_threaded_mainloop_signal(this->mainloop, 0); +} + +/** + * @brief Callback function called when PA notifies about something + * @param s Stream on which the notification happened + * @param this_gen pulse_driver_t pointer for the PulseAudio output + * instance. + */ +static void __xine_pa_stream_notify_callback(pa_stream *s, void *this_gen) +{ + pulse_driver_t * this = (pulse_driver_t*) this_gen; + + pa_threaded_mainloop_signal(this->mainloop, 0); +} + +/** + * @brief Callback function called when PA completed an operation * @param ctx Context which operation has succeeded - * @param success The success value for the operation (ignored) + * @param nbytes the number of bytes PA requested + * @param this_gen pulse_driver_t pointer for the PulseAudio output + * instance. + */ +static void __xine_pa_stream_success_callback(pa_stream *s, int success, void *this_gen) +{ + pulse_driver_t * this = (pulse_driver_t*) this_gen; + + if (!success) + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: stream operation failed: %s\n", pa_strerror(pa_context_errno(this->context))); + + pa_threaded_mainloop_signal(this->mainloop, 0); +} + +/** + * @brief Callback function called when PA completed an operation + * @param c Context on which operation has succeeded + * @param nbytes the number of bytes PA requested * @param this_gen pulse_driver_t pointer for the PulseAudio output * instance. */ -static void __xine_pa_context_success_callback(pa_context *const ctx, const int success, - void *const this_gen) +static void __xine_pa_context_success_callback(pa_context *c, int success, void *this_gen) { - pulse_driver_t *const this = (pulse_driver_t*)this_gen; + pulse_driver_t *this = (pulse_driver_t*) this_gen; - _x_assert(ctx); _x_assert(this); - _x_assert(ctx == this->pa_class->context); + if (!success) + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: context operation failed: %s\n", pa_strerror(pa_context_errno(this->context))); - pa_threaded_mainloop_signal(this->pa_class->mainloop, 0); + pa_threaded_mainloop_signal(this->mainloop, 0); } /** @@ -156,14 +202,14 @@ static void __xine_pa_context_success_callback(pa_context *const ctx, const int * This function saves the volume field of the passed structure to the * @c cvolume variable of the output instance. */ -static void __xine_pa_sink_info_callback(pa_context *const ctx, const pa_sink_input_info *const info, - const int is_last, void *const userdata) { +static void __xine_pa_sink_info_callback(pa_context *c, const pa_sink_input_info *info, + int is_last, void *userdata) { pulse_driver_t *const this = (pulse_driver_t *) userdata; if (is_last < 0) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Failed to get sink input info: %s\n", - pa_strerror(pa_context_errno(this->pa_class->context))); + pa_strerror(pa_context_errno(this->context))); return; } @@ -171,36 +217,95 @@ static void __xine_pa_sink_info_callback(pa_context *const ctx, const pa_sink_in return; this->cvolume = info->volume; + this->swvolume = pa_cvolume_avg(&info->volume); +#if PA_PROTOCOL_VERSION >= 11 + /* PulseAudio 0.9.7 and newer */ + this->muted = info->mute; +#else + this->muted = pa_cvolume_is_muted (&this->cvolume); +#endif +} + +static int connect_context(pulse_driver_t *this) { + + if (this->context && (pa_context_get_state(this->context) == PA_CONTEXT_FAILED || + pa_context_get_state(this->context) == PA_CONTEXT_TERMINATED)) { + pa_context_unref(this->context); + this->context = NULL; + } + + if (!this->context) { + char fn[XINE_PATH_MAX], *p; + + if (pa_get_binary_name(fn, sizeof(fn))) + p = pa_path_get_filename(fn); + else + p = "Xine"; - pthread_mutex_unlock(&this->info_mutex); + this->context = pa_context_new(pa_threaded_mainloop_get_api(this->mainloop), p); + _x_assert(this->context); + + pa_context_set_state_callback(this->context, __xine_pa_context_state_callback, this); + } + + if (pa_context_get_state(this->context) == PA_CONTEXT_UNCONNECTED) { + + if (pa_context_connect(this->context, this->host, 0, NULL) < 0) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object %s\n", pa_strerror(pa_context_errno(this->context))); + return -1; + } + } + + for (;;) { + pa_context_state_t state = pa_context_get_state(this->context); + + if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object: %s\n", pa_strerror(pa_context_errno(this->context))); + return -1; + } + + if (state == PA_CONTEXT_READY) + break; + + pa_threaded_mainloop_wait(this->mainloop); + } + + return 0; } /* * open the audio device for writing to */ static int ao_pulse_open(ao_driver_t *this_gen, - uint32_t bits, uint32_t rate, int mode) + uint32_t bits, uint32_t rate, int mode) { pulse_driver_t *this = (pulse_driver_t *) this_gen; - struct pa_sample_spec ss; - struct pa_buffer_attr a; - pa_stream_state_t streamstate; + pa_sample_spec ss; + pa_channel_map cm; + int r; xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "audio_pulse_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode); + "audio_pulse_out: ao_open bits=%d rate=%d, mode=%d\n", bits, rate, mode); if ( (mode & this->capabilities) == 0 ) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: unsupported mode %08x\n", mode); return 0; } + pa_threaded_mainloop_lock(this->mainloop); + if (this->stream) { - if ( mode == this->mode && rate == this->sample_rate && - bits == this->bits_per_sample ) + if (mode == this->mode && rate == this->sample_rate && + bits == this->bits_per_sample) { + + pa_threaded_mainloop_unlock(this->mainloop); return this->sample_rate; + } - this_gen->close(this_gen); + pa_stream_disconnect(this->stream); + pa_stream_unref(this->stream); + this->stream = NULL; } this->mode = mode; @@ -221,6 +326,8 @@ static int ao_pulse_open(ao_driver_t *this_gen, case 32: ss.format = PA_SAMPLE_FLOAT32NE; break; + default: + _x_assert(!"Should not be reached"); } if (!pa_sample_spec_valid(&ss)) { @@ -228,69 +335,86 @@ static int ao_pulse_open(ao_driver_t *this_gen, goto fail; } - if ( this->pa_class->context && pa_context_get_state(this->pa_class->context) > PA_CONTEXT_READY ) { - pa_context_unref(this->pa_class->context); - this->pa_class->context = NULL; - } - - if ( this->pa_class->context == NULL ) { - this->pa_class->context = pa_context_new(pa_threaded_mainloop_get_api(this->pa_class->mainloop), - __progname); - } - - pa_context_ref(this->pa_class->context); + cm.channels = ss.channels; - if ( pa_context_get_state(this->pa_class->context) == PA_CONTEXT_UNCONNECTED ) { - int ret; + switch (mode) { + case AO_CAP_MODE_MONO: + cm.map[0] = PA_CHANNEL_POSITION_MONO; + _x_assert(cm.channels == 1); + break; - pa_threaded_mainloop_lock(this->pa_class->mainloop); - ret = pa_context_connect(this->pa_class->context, this->host, 1, NULL); - if ( ret < 0 ) - goto fail; + case AO_CAP_MODE_STEREO: + cm.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + cm.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + _x_assert(cm.channels == 2); + break; - pa_context_set_state_callback(this->pa_class->context, __xine_pa_context_status_callback, this); + case AO_CAP_MODE_4CHANNEL: + cm.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + cm.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + cm.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; + cm.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; + _x_assert(cm.channels == 4); + break; - pa_threaded_mainloop_wait(this->pa_class->mainloop); - pa_threaded_mainloop_unlock(this->pa_class->mainloop); + case AO_CAP_MODE_4_1CHANNEL: + case AO_CAP_MODE_5CHANNEL: + case AO_CAP_MODE_5_1CHANNEL: + cm.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + cm.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + cm.map[2] = PA_CHANNEL_POSITION_REAR_LEFT; + cm.map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; + cm.map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; + cm.map[5] = PA_CHANNEL_POSITION_LFE; + cm.channels = 6; + break; + default: + _x_assert(!"Should not be reached"); } - if (pa_context_get_state(this->pa_class->context) != PA_CONTEXT_READY) { - xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Failed to connect to server: %s\n", - pa_strerror(pa_context_errno(this->pa_class->context))); + if (!pa_channel_map_valid(&cm)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Invalid channel map\n"); goto fail; } - this->stream = pa_stream_new(this->pa_class->context, "audio stream", &ss, NULL); + if (connect_context(this) < 0) + goto fail; + + _x_assert(!this->stream); + this->stream = pa_stream_new(this->context, "Audio Stream", &ss, &cm); _x_assert(this->stream); - a.maxlength = pa_bytes_per_second(&ss)*1; - a.tlength = a.maxlength*9/10; - a.prebuf = a.tlength/2; - a.minreq = a.tlength/10; + pa_stream_set_state_callback(this->stream, __xine_pa_stream_state_callback, this); + pa_stream_set_write_callback(this->stream, __xine_pa_stream_request_callback, this); + pa_stream_set_latency_update_callback(this->stream, __xine_pa_stream_notify_callback, this); - pa_stream_connect_playback(this->stream, this->sink, &a, - PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, + r = pa_stream_connect_playback(this->stream, this->sink, NULL, + PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); - do { - xine_usec_sleep (100); + for (;;) { + pa_context_state_t cstate = pa_context_get_state(this->context); + pa_stream_state_t sstate = pa_stream_get_state(this->stream); - streamstate = pa_stream_get_state(this->stream); - } while (streamstate < PA_STREAM_READY); - - if (streamstate != PA_STREAM_READY) { - xprintf (this->xine, XINE_VERBOSITY_LOG, "audio_pulse_out: Failed to connect to server: %s\n", - pa_strerror(pa_context_errno(this->pa_class->context))); - goto fail; + if (cstate == PA_CONTEXT_FAILED || cstate == PA_CONTEXT_TERMINATED || + sstate == PA_STREAM_FAILED || sstate == PA_STREAM_TERMINATED) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to connect context object: %s\n", pa_strerror(pa_context_errno(this->context))); + goto fail; + } + + if (sstate == PA_STREAM_READY) + break; + + pa_threaded_mainloop_wait(this->mainloop); } - this->frames_written = 0; - this->ao_driver.set_property(this, AO_PROP_PCM_VOL, 100); + pa_threaded_mainloop_unlock(this->mainloop); return this->sample_rate; -fail: - pa_threaded_mainloop_unlock(this->pa_class->mainloop); + fail: + + pa_threaded_mainloop_unlock(this->mainloop); this_gen->close(this_gen); return 0; } @@ -318,217 +442,367 @@ static int ao_pulse_write(ao_driver_t *this_gen, int16_t *data, { pulse_driver_t *this = (pulse_driver_t *) this_gen; size_t size = num_frames * this->bytes_per_frame; - int ret = 0; - - if ( !this->stream || !this->pa_class->context) - return -1; + int ret = -1; + size_t done = 0; - switch( pa_stream_get_state(this->stream) ) { - case PA_STREAM_READY: - while (size > 0) { - size_t l; + pa_threaded_mainloop_lock(this->mainloop); - while (!(l = pa_stream_writable_size(this->stream))) { - xine_usec_sleep (10000); - } + while (size > 0) { + size_t l; - if (l > size) - l = size; - - pa_stream_write(this->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); - data = (int16_t *) ((uint8_t*) data + l); - size -= l; - } + for (;;) { + + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) + goto finish; - this->frames_written += num_frames; + if ((l = pa_stream_writable_size(this->stream)) == (size_t) -1) + goto finish; - if (pa_stream_get_state(this->stream) == PA_STREAM_READY) - ret = 1; + if (l > 0) + break; - break; + pa_threaded_mainloop_wait(this->mainloop); + } + + if (l > size) + l = size; + + pa_stream_write(this->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); + data = (int16_t *) ((uint8_t*) data + l); + size -= l; + done += l; } + ret = done; + +finish: + + pa_threaded_mainloop_unlock(this->mainloop); + +/* fprintf(stderr, "write-out\n"); */ + return ret; -} +} static int ao_pulse_delay (ao_driver_t *this_gen) { pulse_driver_t *this = (pulse_driver_t *) this_gen; - pa_usec_t latency = 0; - unsigned int delay_frames; + int ret = 0; - if ( ! this->stream ) return this->frames_written; +/* fprintf(stderr, "delay-in\n"); */ - if (pa_stream_get_latency(this->stream, &latency, NULL) < 0) { - pa_context_unref(this->pa_class->context); - this->pa_class->context = NULL; + pa_threaded_mainloop_lock(this->mainloop); - pa_stream_disconnect(this->stream); - pa_stream_unref(this->stream); - this->stream = NULL; + for (;;) { + pa_usec_t latency = 0; - return 0; + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) + goto finish; + + if (pa_stream_get_latency(this->stream, &latency, NULL) >= 0) { + ret = (int) ((latency * this->sample_rate) / 1000000); + goto finish; + } + + if (pa_context_errno(this->context) != PA_ERR_NODATA) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to query latency: %s\n", pa_strerror(pa_context_errno(this->context))); + goto finish; + } + + pa_threaded_mainloop_wait(this->mainloop); } - /* convert latency (us) to frame units. */ - delay_frames = (int)(latency * this->sample_rate / 1000000); +finish: + + pa_threaded_mainloop_unlock(this->mainloop); - if( delay_frames > this->frames_written ) - return this->frames_written; - else - return delay_frames; + return ret; } static void ao_pulse_close(ao_driver_t *this_gen) { pulse_driver_t *this = (pulse_driver_t *) this_gen; - - if (this->stream) { - if (pa_stream_get_state(this->stream) == PA_STREAM_READY) { - pthread_mutex_t completion_callback = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&completion_callback); - pa_stream_drain(this->stream, __xine_pa_stream_success_callback, &completion_callback); - pthread_mutex_lock(&completion_callback); - pthread_mutex_destroy(&completion_callback); - } + pa_threaded_mainloop_lock(this->mainloop); + if (this->stream) { pa_stream_disconnect(this->stream); pa_stream_unref(this->stream); this->stream = NULL; - - pa_context_unref(this->pa_class->context); } + + pa_threaded_mainloop_unlock(this->mainloop); } static uint32_t ao_pulse_get_capabilities (ao_driver_t *this_gen) { pulse_driver_t *this = (pulse_driver_t *) this_gen; + return this->capabilities; } -static void ao_pulse_exit(ao_driver_t *this_gen) -{ +static void ao_pulse_exit(ao_driver_t *this_gen) { pulse_driver_t *this = (pulse_driver_t *) this_gen; - free (this); + ao_pulse_close(this_gen); + + pa_threaded_mainloop_lock(this->mainloop); + + if (this->context) { + pa_context_disconnect(this->context); + pa_context_unref(this->context); + } + + pa_threaded_mainloop_unlock(this->mainloop); + + pa_threaded_mainloop_free(this->mainloop); + + free(this->host); + free(this->sink); + free(this); +} + +static int wait_for_operation(pulse_driver_t *this, pa_operation *o) { + + for (;;) { + + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) + return -1; + + if (pa_operation_get_state(o) != PA_OPERATION_RUNNING) + return 0; + + pa_threaded_mainloop_wait(this->mainloop); + } } static int ao_pulse_get_property (ao_driver_t *this_gen, int property) { pulse_driver_t *this = (pulse_driver_t *) this_gen; int result = 0; + pa_operation *o = NULL; - if ( ! this->stream || ! this->pa_class->context ) + pa_threaded_mainloop_lock(this->mainloop); + + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) { + pa_threaded_mainloop_unlock(this->mainloop); return 0; + } switch(property) { - case AO_PROP_PCM_VOL: - case AO_PROP_MIXER_VOL: - { - pthread_mutex_lock(&this->info_mutex); - pa_operation *o = pa_context_get_sink_input_info(this->pa_class->context, - pa_stream_get_index(this->stream), - __xine_pa_sink_info_callback, this); - if ( ! o ) return 0; - pthread_mutex_lock(&this->info_mutex); pthread_mutex_unlock(&this->info_mutex); - - result = (pa_sw_volume_to_linear(this->swvolume)*100); - } - break; - case AO_PROP_MUTE_VOL: - result = pa_cvolume_is_muted(&this->cvolume); - break; + case AO_PROP_MUTE_VOL: + case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: + + o = pa_context_get_sink_input_info(this->context, pa_stream_get_index(this->stream), + __xine_pa_sink_info_callback, this); + + break; + } + + if (o) { + wait_for_operation(this, o); + pa_operation_unref(o); + } + + switch(property) { + + case AO_PROP_MUTE_VOL: + result = this->muted; + break; + + case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: + result = (int) (pa_sw_volume_to_linear(this->swvolume)*100); + break; } - + + pa_threaded_mainloop_unlock(this->mainloop); + return result; } static int ao_pulse_set_property (ao_driver_t *this_gen, int property, int value) { pulse_driver_t *this = (pulse_driver_t *) this_gen; int result = ~value; + pa_operation *o = NULL; - if ( ! this->stream || ! this->pa_class->context ) - return result; + pa_threaded_mainloop_lock(this->mainloop); + + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) { + pa_threaded_mainloop_unlock(this->mainloop); + return 0; + } switch(property) { - case AO_PROP_PCM_VOL: - case AO_PROP_MIXER_VOL: - this->swvolume = pa_sw_volume_from_linear((double)value/100.0); - pa_cvolume_set(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels, this->swvolume); + case AO_PROP_PCM_VOL: + case AO_PROP_MIXER_VOL: + + this->swvolume = pa_sw_volume_from_linear((double)value/100.0); + pa_cvolume_set(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels, this->swvolume); - pa_context_set_sink_input_volume(this->pa_class->context, pa_stream_get_index(this->stream), - &this->cvolume, __xine_pa_context_success_callback, this); + o = pa_context_set_sink_input_volume(this->context, pa_stream_get_index(this->stream), + &this->cvolume, __xine_pa_context_success_callback, this); - result = value; - break; + result = value; + break; - case AO_PROP_MUTE_VOL: - if ( value ) - pa_cvolume_mute(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels); - else - pa_cvolume_set(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels, this->swvolume); + case AO_PROP_MUTE_VOL: - pa_context_set_sink_input_volume(this->pa_class->context, pa_stream_get_index(this->stream), - &this->cvolume, __xine_pa_context_success_callback, this); - - result = value; - break; + this->muted = value; + +#if PA_PROTOCOL_VERSION >= 11 + /* PulseAudio 0.9.7 and newer */ + o = pa_context_set_sink_input_mute(this->context, pa_stream_get_index(this->stream), + value, __xine_pa_context_success_callback, this); +#else + /* Get the current volume, so we can restore it properly. */ + o = pa_context_get_sink_input_info(this->context, pa_stream_get_index(this->stream), + __xine_pa_sink_info_callback, this); + + if (o) { + wait_for_operation(this, o); + pa_operation_unref(o); + } + + if ( value ) + pa_cvolume_mute(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels); + else + pa_cvolume_set(&this->cvolume, pa_stream_get_sample_spec(this->stream)->channels, this->swvolume); + + o = pa_context_set_sink_input_volume(this->context, pa_stream_get_index(this->stream), + &this->cvolume, __xine_pa_context_success_callback, this); +#endif + result = value; } - + + if (o) { + wait_for_operation(this, o); + pa_operation_unref(o); + } + + pa_threaded_mainloop_unlock(this->mainloop); + return result; } static int ao_pulse_ctrl(ao_driver_t *this_gen, int cmd, ...) { pulse_driver_t *this = (pulse_driver_t *) this_gen; + pa_operation *o = NULL; - if ( ! this->stream ) return 0; + pa_threaded_mainloop_lock(this->mainloop); + + if (!this->stream || + !this->context || + pa_context_get_state(this->context) != PA_CONTEXT_READY || + pa_stream_get_state(this->stream) != PA_STREAM_READY) { + pa_threaded_mainloop_unlock(this->mainloop); + return 0; + } switch (cmd) { - case AO_CTRL_FLUSH_BUFFERS: - _x_assert(this->stream && this->pa_class->context); + case AO_CTRL_FLUSH_BUFFERS: - if(pa_stream_get_state(this->stream) == PA_STREAM_READY) { - pthread_mutex_t completion_callback = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&completion_callback); - pa_stream_flush(this->stream, __xine_pa_stream_success_callback, &completion_callback); + o = pa_stream_flush(this->stream, __xine_pa_stream_success_callback, this); + break; - pthread_mutex_lock(&completion_callback); - pthread_mutex_destroy(&completion_callback); - } + case AO_CTRL_PLAY_RESUME: + case AO_CTRL_PLAY_PAUSE: - this->frames_written = 0; + o = pa_stream_cork(this->stream, cmd == AO_CTRL_PLAY_PAUSE, __xine_pa_stream_success_callback, this); + break; + } - break; + if (o) { + wait_for_operation(this, o); + pa_operation_unref(o); } + pa_threaded_mainloop_unlock(this->mainloop); + return 0; } static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) { pulse_class_t *class = (pulse_class_t *) class_gen; pulse_driver_t *this; - char *device; + const char* device; + int r; lprintf ("audio_pulse_out: open_plugin called\n"); - this = (pulse_driver_t *) xine_xmalloc (sizeof (pulse_driver_t)); + this = calloc(1, sizeof (pulse_driver_t)); if (!this) return NULL; + this->xine = class->xine; + this->host = NULL; + this->sink = NULL; + this->context = NULL; + this->mainloop = NULL; + + device = class->xine->config->register_string(class->xine->config, + "audio.pulseaudio_device", + "", + _("device used for pulseaudio"), + _("use 'server[:sink]' for setting the " + "pulseaudio sink device."), + 10, NULL, + NULL); + + if (device && *device) { + char *sep = strrchr(device, ':'); + if ( sep ) { + if (!(this->host = strndup(device, sep-device))) { + free(this); + return NULL; + } + + if (!(this->sink = strdup(sep+1))) { + free(this->host); + free(this); + return NULL; + } + } else { + + if (!(this->host = strdup(device))) { + free(this); + return NULL; + } + } + } + + this->mainloop = pa_threaded_mainloop_new(); + _x_assert(this->mainloop); + pa_threaded_mainloop_start(this->mainloop); /* * set capabilities */ - this->capabilities = AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_MODE_4CHANNEL | - AO_CAP_MODE_4_1CHANNEL | AO_CAP_MODE_5CHANNEL | - AO_CAP_MODE_5_1CHANNEL | AO_CAP_MIXER_VOL | - AO_CAP_PCM_VOL | AO_CAP_MUTE_VOL | AO_CAP_8BITS | - AO_CAP_16BITS | AO_CAP_FLOAT32; + this->capabilities = + AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_MODE_4CHANNEL | + AO_CAP_MODE_4_1CHANNEL | AO_CAP_MODE_5CHANNEL | AO_CAP_MODE_5_1CHANNEL | + AO_CAP_MIXER_VOL | AO_CAP_PCM_VOL | AO_CAP_MUTE_VOL | + AO_CAP_8BITS | AO_CAP_16BITS | AO_CAP_FLOAT32; this->sample_rate = 0; - this->host = NULL; - this->sink = NULL; - + this->ao_driver.get_capabilities = ao_pulse_get_capabilities; this->ao_driver.get_property = ao_pulse_get_property; this->ao_driver.set_property = ao_pulse_set_property; @@ -540,33 +814,22 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da this->ao_driver.close = ao_pulse_close; this->ao_driver.exit = ao_pulse_exit; this->ao_driver.get_gap_tolerance = ao_pulse_get_gap_tolerance; - this->ao_driver.control = ao_pulse_ctrl; - - device = this->xine->config->register_string(this->xine->config, - "audio.pulseaudio_device", - "", - _("device used for pulseaudio"), - _("use 'server[:sink]' for setting the " - "pulseaudio sink device."), - 10, NULL, - NULL); - - if (device && *device) { - char *sep = strchr(device, ':'); - if ( sep ) { - this->host = strndup(device, sep-device); - this->sink = strdup(&sep[1]); - } else - this->host = strdup(device); - } - - pthread_mutex_init(&this->info_mutex, NULL); + this->ao_driver.control = ao_pulse_ctrl; xprintf (class->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: host %s sink %s\n", this->host ? this->host : "(null)", this->sink ? this->sink : "(null)"); this->pa_class = class; + pa_threaded_mainloop_lock(this->mainloop); + r = connect_context(this); + pa_threaded_mainloop_unlock(this->mainloop); + + if (r < 0) { + ao_pulse_exit((ao_driver_t *) this); + return NULL; + } + return &this->ao_driver; } @@ -586,13 +849,7 @@ static void dispose_class (audio_driver_class_t *this_gen) { pulse_class_t *this = (pulse_class_t *) this_gen; - if ( this->context ) - pa_context_unref(this->context); - - pa_threaded_mainloop_stop(this->mainloop); - pa_threaded_mainloop_free(this->mainloop); - - free (this); + free(this); } static void *init_class (xine_t *xine, void *data) { @@ -601,29 +858,21 @@ static void *init_class (xine_t *xine, void *data) { lprintf ("audio_pulse_out: init class\n"); - this = (pulse_class_t *) xine_xmalloc (sizeof (pulse_class_t)); + this = calloc(1, sizeof (pulse_class_t)); if (!this) return NULL; + this->xine = xine; this->driver_class.open_plugin = open_plugin; this->driver_class.get_identifier = get_identifier; this->driver_class.get_description = get_description; this->driver_class.dispose = dispose_class; - this->xine = xine; - - this->mainloop = pa_threaded_mainloop_new(); - _x_assert(this->mainloop); - - pa_threaded_mainloop_start(this->mainloop); - - this->context = NULL; - return this; } static const ao_info_t ao_info_pulse = { - 6 + 12 }; /* @@ -635,5 +884,3 @@ const plugin_info_t xine_plugin_info[] EXPORTED = { { PLUGIN_AUDIO_OUT, 8, "pulseaudio", XINE_VERSION_CODE, &ao_info_pulse, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; - - diff --git a/src/audio_out/audio_sndio_out.c b/src/audio_out/audio_sndio_out.c new file mode 100644 index 000000000..1d789b5e8 --- /dev/null +++ b/src/audio_out/audio_sndio_out.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2008 Brad Smith <brad@comstyle.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* ao plugin for sndio by Brad Smith <brad@comstyle.com>. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <math.h> +#include <unistd.h> +#include <inttypes.h> +#include <pthread.h> + +#include <sndio.h> + +#include "xine_internal.h" +#include "xineutils.h" +#include "audio_out.h" +#include "bswap.h" + +#define GAP_TOLERANCE AO_MAX_GAP +#define PCT_TO_MIDI(p) (((p) * SIO_MAXVOL + 50) / 100) + +typedef struct { + audio_driver_class_t driver_class; + xine_t *xine; +} sndio_class_t; + +typedef struct sndio_driver_s { + ao_driver_t ao_driver; + xine_t *xine; + + struct sio_hdl *hdl; + long long realpos, playpos; + int capabilities; + + int num_channels; + u_int32_t bits_per_sample; + u_int32_t bytes_per_frame; + + struct { + int volume; + int mute; + } mixer; +} sndio_driver_t; + +/* + * Callback to notify of frames processed by the hw. It is + * called from the mail loop called from sio_write(). + */ +static void ao_sndio_onmove_cb(void *addr, int delta) +{ + sndio_driver_t *this = (sndio_driver_t *)addr; + + this->realpos += delta; +} + +/* + * Open the audio device for writing to. + */ +static int ao_sndio_open(ao_driver_t *this_gen, + uint32_t bits, uint32_t rate, int mode) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + struct sio_par par; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open bits=%d rate=%d, mode=%d\n", + bits, rate, mode); + + if (this->hdl != NULL) { + sio_close (this->hdl); + this->hdl = NULL; + } + + this->hdl = sio_open(NULL, SIO_PLAY, 0); + if (this->hdl == NULL) + goto bad; + + sio_initpar(&par); + + switch (mode) { + case AO_CAP_MODE_MONO: + par.pchan = 1; + break; + case AO_CAP_MODE_STEREO: + par.pchan = 2; + break; +#if 0 + case AO_CAP_MODE_4CHANNEL: + par.pchan = 4; + break; + case AO_CAP_MODE_4_1CHANNEL: + case AO_CAP_MODE_5CHANNEL: + case AO_CAP_MODE_5_1CHANNEL: + par.pchan = 6; + break; +#endif + default: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open does not support the requested mode: 0x%X\n", + mode); + goto bad; + } + + switch (bits) { + case 8: + par.bits = 8; + par.sig = 0; + break; + case 16: + par.bits = 16; + par.sig = 1; + break; + default: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open bits per sample not supported: %d\n", bits); + goto bad; + } + + par.rate = rate; + par.appbufsz = par.rate * 250 / 1000; /* 250ms buffer */ + + if (!sio_setpar(this->hdl, &par)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open could not set params\n"); + goto bad; + } + + if (!sio_getpar(this->hdl, &par)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open could not get params\n"); + goto bad; + } + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open %d channels output\n", + par.pchan); + + this->num_channels = par.pchan; + this->bytes_per_frame = par.bps * par.pchan; + this->playpos = 0; + this->realpos = 0; + sio_onmove(this->hdl, ao_sndio_onmove_cb, this); + + if (!sio_start(this->hdl)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_open could not start\n"); + goto bad; + } + + return par.rate; + +bad: + if (this->hdl != NULL) + sio_close(this->hdl); + return 0; +} + +static int ao_sndio_num_channels(ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + return this->num_channels; +} + +static int ao_sndio_bytes_per_frame(ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + return this->bytes_per_frame; +} + +static int ao_sndio_get_gap_tolerance (ao_driver_t *this_gen) +{ + return GAP_TOLERANCE; +} + +static int ao_sndio_write(ao_driver_t *this_gen, int16_t *data, + uint32_t num_frames) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + size_t ret, size = num_frames * this->bytes_per_frame; + + ret = sio_write(this->hdl, data, size); + if (ret == 0) + return 0; + + this->playpos += num_frames; + + return 1; +} + +static int ao_sndio_delay (ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + int bufused; + + if (this->realpos < 0) + bufused = this->playpos; + else + bufused = this->playpos - this->realpos; + + return bufused; +} + +static void ao_sndio_close(ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_close called\n"); + + if (!sio_stop(this->hdl)) { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_close could not stop\n"); + } + + sio_close(this->hdl); + this->hdl = NULL; +} + +static uint32_t ao_sndio_get_capabilities (ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + return this->capabilities; +} + +static void ao_sndio_exit(ao_driver_t *this_gen) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "audio_sndio_out: ao_sndio_exit called\n"); + + if (this->hdl != NULL) + sio_close(this->hdl); +} + +static int ao_sndio_get_property (ao_driver_t *this_gen, int property) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + switch (property) { + case AO_PROP_MIXER_VOL: + return this->mixer.volume; + break; + case AO_PROP_MUTE_VOL: + return this->mixer.mute; + break; + } + + return 0; +} + +static int ao_sndio_set_property (ao_driver_t *this_gen, int property, int value) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + int vol; + + if (this->hdl == NULL) + return 0; + + switch(property) { + case AO_PROP_MIXER_VOL: + this->mixer.volume = value; + if (!this->mixer.mute) + sio_setvol(this->hdl, PCT_TO_MIDI(this->mixer.volume)); + return this->mixer.volume; + break; + + case AO_PROP_MUTE_VOL: + this->mixer.mute = (value) ? 1 : 0; + vol = 0; + if (!this->mixer.mute) + vol = PCT_TO_MIDI(this->mixer.volume); + sio_setvol(this->hdl, vol); + return value; + break; + } + + return value; +} + +/* + * pause, resume, flush buffers + */ +static int ao_sndio_ctrl(ao_driver_t *this_gen, int cmd, ...) +{ + sndio_driver_t *this = (sndio_driver_t *) this_gen; + + /* + * sndio pauses automatically if there are no more samples to play + * and resumes when there are samples again. So we leave this empty + * for the moment. + */ + + return 0; +} + +static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *data) +{ + sndio_class_t *class = (sndio_class_t *) class_gen; + sndio_driver_t *this; + + lprintf ("audio_sndio_out: open_plugin called\n"); + + this = calloc(1, sizeof (sndio_driver_t)); + if (!this) + return NULL; + + this->xine = class->xine; + + /* + * Set capabilities + */ + this->capabilities = AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | +#if 0 + AO_CAP_MODE_4CHANNEL | AO_CAP_MODE_4_1CHANNEL | + AO_CAP_MODE_5CHANNEL | AO_CAP_MODE_5_1CHANNEL | +#endif + AO_CAP_MIXER_VOL | AO_CAP_MUTE_VOL | AO_CAP_8BITS | + AO_CAP_16BITS; + + this->ao_driver.get_capabilities = ao_sndio_get_capabilities; + this->ao_driver.get_property = ao_sndio_get_property; + this->ao_driver.set_property = ao_sndio_set_property; + this->ao_driver.open = ao_sndio_open; + this->ao_driver.num_channels = ao_sndio_num_channels; + this->ao_driver.bytes_per_frame = ao_sndio_bytes_per_frame; + this->ao_driver.delay = ao_sndio_delay; + this->ao_driver.write = ao_sndio_write; + this->ao_driver.close = ao_sndio_close; + this->ao_driver.exit = ao_sndio_exit; + this->ao_driver.get_gap_tolerance = ao_sndio_get_gap_tolerance; + this->ao_driver.control = ao_sndio_ctrl; + + return &this->ao_driver; +} + +/* + * class functions + */ + +static char* get_identifier (audio_driver_class_t *this_gen) +{ + return "sndio"; +} + +static char* get_description (audio_driver_class_t *this_gen) +{ + return _("xine audio output plugin using sndio audio devices/drivers "); +} + +static void dispose_class (audio_driver_class_t *this_gen) +{ + sndio_class_t *this = (sndio_class_t *) this_gen; + + free(this); +} + +static void *init_class (xine_t *xine, void *data) +{ + sndio_class_t *this; + + lprintf ("audio_sndio_out: init class\n"); + + this = calloc(1, sizeof (sndio_class_t)); + if (!this) + return NULL; + + this->driver_class.open_plugin = open_plugin; + this->driver_class.get_identifier = get_identifier; + this->driver_class.get_description = get_description; + this->driver_class.dispose = dispose_class; + + this->xine = xine; + + return this; +} + +static const ao_info_t ao_info_sndio = { + 12 +}; + +/* + * exported plugin catalog entry + */ + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_AUDIO_OUT, 8, "sndio", XINE_VERSION_CODE, &ao_info_sndio, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; diff --git a/src/audio_out/audio_sun_out.c b/src/audio_out/audio_sun_out.c index b23955b77..2a154c09d 100644 --- a/src/audio_out/audio_sun_out.c +++ b/src/audio_out/audio_sun_out.c @@ -1,18 +1,18 @@ -/* +/* * Copyright (C) 2001-2003 the xine project - * + * * This file is part of xine, a free video player. - * + * * xine 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. - * + * * xine 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA @@ -159,7 +159,7 @@ static int realtime_samplecounter_available(xine_t *xine, char *dev) silence = calloc(1, len); if (silence == NULL) goto error; - + if ((fd = open(dev, O_WRONLY|O_NONBLOCK)) < 0) goto error; @@ -176,7 +176,7 @@ static int realtime_samplecounter_available(xine_t *xine, char *dev) xprintf(xine, XINE_VERBOSITY_DEBUG, "rtsc: SETINFO failed\n"); goto error; } - + if (write(fd, silence, len) != len) { xprintf(xine, XINE_VERBOSITY_DEBUG, "rtsc: write failed\n"); goto error; @@ -195,7 +195,7 @@ static int realtime_samplecounter_available(xine_t *xine, char *dev) delay.tv_sec = 0; delay.tv_nsec = 10000000; nanosleep(&delay, NULL); - + gettimeofday(&end, NULL); usec_delay = (end.tv_sec - start.tv_sec) * 1000000 + end.tv_usec - start.tv_usec; @@ -230,7 +230,7 @@ static int realtime_samplecounter_available(xine_t *xine, char *dev) * sample counter increment from the soundcard driver of less than * 2000 samples, we assume that the driver provides a useable realtime * sample counter in the AUDIO_INFO play.samples field. Timing based - * on sample counts should be much more accurate than counting whole + * on sample counts should be much more accurate than counting whole * 16kbyte chunks. */ if (min_increment < 2000) @@ -238,10 +238,10 @@ static int realtime_samplecounter_available(xine_t *xine, char *dev) /* printf("audio_sun_out: minimum sample counter increment per 10msec interval: %d\n" - "\t%susing sample counter based timing code\n", + "\t%susing sample counter based timing code\n", min_increment, rtsc_ok == RTSC_ENABLED ? "" : "not "); */ - + error: if (silence != NULL) free(silence); @@ -263,7 +263,7 @@ error: } -/* +/* * match the requested sample rate |sample_rate| against the * sample rates supported by the audio device |dev|. Return * a supported sample rate, it that sample rate is close to @@ -294,7 +294,7 @@ find_close_samplerate_match(int dev, int sample_rate) if (sr->flags & MIXER_SR_LIMITS) { /* - * HW can playback any rate between + * HW can playback any rate between * sr->samp_rates[0] .. sr->samp_rates[1] */ free(sr); @@ -340,7 +340,7 @@ find_close_samplerate_match(int dev, int sample_rate) for (i = 0; audiocs_rates[i]; i++) { err = abs(audiocs_rates[i] - sample_rate); if (err == 0) { - /* + /* * exact supported sample rate match, no need to * retry something elise */ @@ -385,7 +385,7 @@ find_highest_samplerate(int dev) if (sr->flags & MIXER_SR_LIMITS) { /* - * HW can playback any rate between + * HW can playback any rate between * sr->samp_rates[0] .. sr->samp_rates[1] */ max_rate = sr->samp_rates[1]; @@ -412,7 +412,7 @@ find_highest_samplerate(int dev) * Implicit assumptions about audio format (bits/rate/mode): * * bits == 16: We always get 16-bit samples in native endian format, - * using signed linear encoding + * using signed linear encoding * * bits == 8: 8-bit samples use unsigned linear encoding, * other 8-bit formats (uLaw, aLaw, etc) are currently not supported @@ -440,7 +440,7 @@ static int ao_sun_open(ao_driver_t *this_gen, close (this->audio_fd); } - + this->mode = mode; this->input_sample_rate = rate; #ifdef __svr4__ @@ -453,11 +453,11 @@ static int ao_sun_open(ao_driver_t *this_gen, this->audio_fd = open(this->audio_dev, O_WRONLY|O_NONBLOCK); if(this->audio_fd < 0) { - xprintf(this->xine, XINE_VERBOSITY_LOG, + xprintf(this->xine, XINE_VERBOSITY_LOG, _("audio_sun_out: opening audio device %s failed: %s\n"), this->audio_dev, strerror(errno)); return 0; } - + /* We wanted non blocking open but now put it back to normal */ fcntl(this->audio_fd, F_SETFL, fcntl(this->audio_fd, F_GETFL) & ~O_NONBLOCK); @@ -485,7 +485,7 @@ static int ao_sun_open(ao_driver_t *this_gen, if (pass & 1) { /* - * on some sun audio drivers, 8-bit unsigned LINEAR8 encoding is + * on some sun audio drivers, 8-bit unsigned LINEAR8 encoding is * not supported, but 8-bit signed encoding is. * * Try S8, and if it works, use our own U8->S8 conversion before @@ -511,7 +511,7 @@ static int ao_sun_open(ao_driver_t *this_gen, */ if (!(info.play.sample_rate = find_close_samplerate_match(this->audio_fd, - this->input_sample_rate))) + this->input_sample_rate))) continue; } @@ -567,7 +567,7 @@ static int ao_sun_open(ao_driver_t *this_gen, return this->output_sample_rate; } -static int ao_sun_num_channels(ao_driver_t *this_gen) +static int ao_sun_num_channels(ao_driver_t *this_gen) { sun_driver_t *this = (sun_driver_t *) this_gen; return this->num_channels; @@ -589,7 +589,7 @@ static int ao_sun_delay(ao_driver_t *this_gen) (this->frames_in_buffer == 0 || info.play.samples > 0)) { if (info.play.samples < this->last_samplecnt) { - xprintf(this->xine, XINE_VERBOSITY_DEBUG, + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "audio_sun_out: broken sound driver, sample counter runs backwards, cur %u < prev %u\n", info.play.samples, this->last_samplecnt); } @@ -728,7 +728,7 @@ static int ao_sun_write(ao_driver_t *this_gen, int num_written; if (this->convert_u8_s8) { - /* + /* * Audio hardware does not support 8-bit unsigned format, * only 8-bit signed. Convert to 8-bit unsigned before sending * the data to the audio device. @@ -736,7 +736,7 @@ static int ao_sun_write(ao_driver_t *this_gen, uint8_t *p = (void *)frame_buffer; int i; - for (i = num_frames * this->bytes_per_frame; --i >= 0; p++) + for (i = num_frames * this->bytes_per_frame; --i >= 0; p++) *p ^= 0x80; } num_written = sun_audio_write(this, frame_buffer, num_frames * this->bytes_per_frame); @@ -747,7 +747,7 @@ static int ao_sun_write(ao_driver_t *this_gen, this->frames_in_buffer += num_written / this->bytes_per_frame; #endif - /* + /* * Avoid storing too much data in the sound driver's buffers. * * When we find more than 3 seconds of buffered audio data in the @@ -783,7 +783,7 @@ static uint32_t ao_sun_get_capabilities (ao_driver_t *this_gen) { static void ao_sun_exit(ao_driver_t *this_gen) { sun_driver_t *this = (sun_driver_t *) this_gen; - + if (this->audio_fd >= 0) close(this->audio_fd); @@ -869,7 +869,7 @@ static int ao_sun_ctrl(ao_driver_t *this_gen, int cmd, ...) { /* flush buffered STEAMS data first */ ioctl(this->audio_fd, I_FLUSH, FLUSHW); - /* + /* * the flush above discarded an unknown amount of data from the * audio device. To get the "*_delay" computation in sync again, * reset the audio device's sample counter to 0, after waiting @@ -909,7 +909,7 @@ static ao_driver_t *ao_sun_open_plugin (audio_driver_class_t *class_gen, const v int status; audio_info_t info; - this = (sun_driver_t *) xine_xmalloc (sizeof (sun_driver_t)); + this = calloc(1, sizeof (sun_driver_t)); if (!this) return NULL; @@ -944,7 +944,7 @@ static ao_driver_t *ao_sun_open_plugin (audio_driver_class_t *class_gen, const v this->audio_fd = open(this->audio_dev = devname, O_WRONLY|O_NONBLOCK); - if(this->audio_fd < 0) + if(this->audio_fd < 0) { xprintf(this->xine, XINE_VERBOSITY_LOG, _("audio_sun_out: opening audio device %s failed: %s\n"), devname, strerror(errno)); @@ -962,7 +962,7 @@ static ao_driver_t *ao_sun_open_plugin (audio_driver_class_t *class_gen, const v info.play.precision = AUDIO_PRECISION_16; info.play.sample_rate = 44100; status = ioctl(this->audio_fd, AUDIO_SETINFO, &info); - + if (status < 0) { xprintf(this->xine, XINE_VERBOSITY_LOG, _("audio_sun_out: audio ioctl on device %s failed: %s\n"), devname, strerror(errno)); @@ -976,7 +976,7 @@ static ao_driver_t *ao_sun_open_plugin (audio_driver_class_t *class_gen, const v */ this->capabilities = AO_CAP_MODE_MONO | AO_CAP_MODE_STEREO | AO_CAP_8BITS - | AO_CAP_16BITS | AO_CAP_PCM_VOL; + | AO_CAP_16BITS | AO_CAP_PCM_VOL; #ifdef __svr4__ this->capabilities |= AO_CAP_MUTE_VOL; #endif @@ -1032,7 +1032,7 @@ static void ao_sun_dispose_class (audio_driver_class_t *this_gen) { static void *ao_sun_init_class (xine_t *xine, void *data) { sun_class_t *this; - this = (sun_class_t *) xine_xmalloc (sizeof (sun_class_t)); + this = calloc(1, sizeof (sun_class_t)); if (!this) return NULL; @@ -1056,7 +1056,7 @@ static const ao_info_t ao_info_sun = { */ const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ + /* type, API, "name", version, special_info, init_function */ { PLUGIN_AUDIO_OUT, AO_SUN_IFACE_VERSION, "sun", XINE_VERSION_CODE, &ao_info_sun, ao_sun_init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; |