diff options
author | Juergen Keil <jkeil@users.sourceforge.net> | 2002-03-11 19:58:00 +0000 |
---|---|---|
committer | Juergen Keil <jkeil@users.sourceforge.net> | 2002-03-11 19:58:00 +0000 |
commit | a1bc7578243bd93e106fc426374363da16652797 (patch) | |
tree | 616d2ae6848b68cc9cc0e152184c916e12d14fcf | |
parent | 619e78fc07c1b8622eb4f8f43d979fab476c24a2 (diff) | |
download | xine-lib-a1bc7578243bd93e106fc426374363da16652797.tar.gz xine-lib-a1bc7578243bd93e106fc426374363da16652797.tar.bz2 |
Add a "control" method to the audio drivers, to allow pause/resume of the
playback stream and to flush buffered samples from from the audio driver.
(Currently implemented in the 'Sun' audio driver, + some untested code in the
alsa 0.9 driver).
The pause/resume method can be used by the engine to immediatelly stop playing
buffered audio samples when the video is paused.
Flushing buffered samples is useful when a video is stopped. And it'll be
useful for better seeking support, too.
CVS patchset: 1556
CVS date: 2002/03/11 19:58:00
-rw-r--r-- | src/audio_out/audio_alsa_out.c | 37 | ||||
-rw-r--r-- | src/audio_out/audio_arts_out.c | 29 | ||||
-rw-r--r-- | src/audio_out/audio_esd_out.c | 24 | ||||
-rw-r--r-- | src/audio_out/audio_irixal_out.c | 26 | ||||
-rw-r--r-- | src/audio_out/audio_oss_out.c | 23 | ||||
-rw-r--r-- | src/audio_out/audio_sun_out.c | 54 | ||||
-rw-r--r-- | src/xine-engine/audio_out.c | 20 | ||||
-rw-r--r-- | src/xine-engine/audio_out.h | 30 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 57 |
9 files changed, 255 insertions, 45 deletions
diff --git a/src/audio_out/audio_alsa_out.c b/src/audio_out/audio_alsa_out.c index 574c5ca0f..5f9226b25 100644 --- a/src/audio_out/audio_alsa_out.c +++ b/src/audio_out/audio_alsa_out.c @@ -26,7 +26,7 @@ * (c) 2001 James Courtier-Dutton <James@superbug.demon.co.uk> * * - * $Id: audio_alsa_out.c,v 1.46 2002/02/08 13:13:47 f1rmb Exp $ + * $Id: audio_alsa_out.c,v 1.47 2002/03/11 19:58:00 jkeil Exp $ */ #ifdef HAVE_CONFIG_H @@ -60,7 +60,7 @@ # endif #endif -#define AO_OUT_ALSA_IFACE_VERSION 3 +#define AO_OUT_ALSA_IFACE_VERSION 4 #define GAP_TOLERANCE 5000 @@ -77,6 +77,7 @@ typedef struct alsa_driver_s { snd_pcm_t *audio_fd; int capabilities; int open_mode; + int has_pause_resume; int32_t output_sample_rate, input_sample_rate; double sample_rate_factor; @@ -633,6 +634,34 @@ static int ao_alsa_set_property (ao_driver_t *this_gen, int property, int value) return ~value; } + +static int ao_alsa_ctrl(ao_driver_t *this_gen, int cmd, ...) { + alsa_driver_t *this = (alsa_driver_t *) this_gen; + +#if 0 + switch (cmd) { + + case AO_CTRL_PLAY_PAUSE: + if (this->has_pause_resume) + snd_pcm_pause(this->audio_fd, 1); + break; + + case AO_CTRL_PLAY_RESUME: + if (this->has_pause_resume) + snd_pcm_pause(this->audio_fd, 0); + break; + + case AO_CTRL_FLUSH_BUFFERS: + snd_pcm_drop(this->audio_fd); + snd_pcm_prepare(this->audio_fd); + break; + } +#endif + + return 0; +} + + static void ao_alsa_mixer_init(ao_driver_t *this_gen) { alsa_driver_t *this = (alsa_driver_t *) this_gen; config_values_t *config = this->config; @@ -961,6 +990,9 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { printf ("(5.1-channel not enabled in xine config) " ); } + this->has_pause_resume = ( snd_pcm_hw_params_can_pause (this->audio_fd) + && snd_pcm_hw_params_can_resume (this->audio_fd) ); + snd_pcm_close (this->audio_fd); this->audio_fd=NULL; this->output_sample_rate = 0; @@ -1005,6 +1037,7 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { 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; + this->ao_driver.control = ao_alsa_ctrl; return &this->ao_driver; } diff --git a/src/audio_out/audio_arts_out.c b/src/audio_out/audio_arts_out.c index b4d3933b2..6a98e6738 100644 --- a/src/audio_out/audio_arts_out.c +++ b/src/audio_out/audio_arts_out.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_arts_out.c,v 1.8 2001/11/18 15:08:30 guenter Exp $ + * $Id: audio_arts_out.c,v 1.9 2002/03/11 19:58:00 jkeil Exp $ */ /* required for swab() */ @@ -41,7 +41,7 @@ #include "xineutils.h" #include "audio_out.h" -#define AO_OUT_ARTS_IFACE_VERSION 3 +#define AO_OUT_ARTS_IFACE_VERSION 4 #define AUDIO_NUM_FRAGMENTS 15 #define AUDIO_FRAGMENT_SIZE 8192 @@ -239,6 +239,28 @@ static int ao_arts_set_property (ao_driver_t *this, int property, int value) { return ~value; } +/* + * + */ +static int ao_arts_ctrl(ao_driver_t *this_gen, int cmd, ...) { + arts_driver_t *this = (arts_driver_t *) this_gen; + + switch (cmd) { + + case AO_CTRL_PLAY_PAUSE: + break; + + case AO_CTRL_PLAY_RESUME: + break; + + case AO_CTRL_FLUSH_BUFFERS: + break; + } + + return 0; +} + + ao_driver_t *init_audio_out_plugin (config_values_t *config) { arts_driver_t *this; @@ -278,7 +300,8 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { this->ao_driver.close = ao_arts_close; this->ao_driver.exit = ao_arts_exit; this->ao_driver.get_gap_tolerance = ao_arts_get_gap_tolerance; - + this->ao_driver.control = ao_arts_ctrl; + return &this->ao_driver; } diff --git a/src/audio_out/audio_esd_out.c b/src/audio_out/audio_esd_out.c index 1c3036cbd..a04e3525a 100644 --- a/src/audio_out/audio_esd_out.c +++ b/src/audio_out/audio_esd_out.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_esd_out.c,v 1.17 2001/12/18 22:46:16 f1rmb Exp $ + * $Id: audio_esd_out.c,v 1.18 2002/03/11 19:58:00 jkeil Exp $ */ #ifdef HAVE_CONFIG_H @@ -39,7 +39,7 @@ #include "audio_out.h" #include "metronom.h" -#define AO_OUT_ESD_IFACE_VERSION 3 +#define AO_OUT_ESD_IFACE_VERSION 4 #define GAP_TOLERANCE 5000 @@ -343,6 +343,25 @@ static int ao_esd_set_property (ao_driver_t *this_gen, int property, int value) return ~value; } +static int ao_esd_ctrl(ao_driver_t *this_gen, int cmd, ...) { + esd_driver_t *this = (esd_driver_t *) this_gen; + + + switch (cmd) { + + case AO_CTRL_PLAY_PAUSE: + break; + + case AO_CTRL_PLAY_RESUME: + break; + + case AO_CTRL_FLUSH_BUFFERS: + break; + } + + return 0; +} + ao_driver_t *init_audio_out_plugin (config_values_t *config) { esd_driver_t *this; @@ -406,6 +425,7 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { this->ao_driver.write = ao_esd_write; this->ao_driver.close = ao_esd_close; this->ao_driver.exit = ao_esd_exit; + this->ao_driver.control = ao_esd_ctrl; return &this->ao_driver; } diff --git a/src/audio_out/audio_irixal_out.c b/src/audio_out/audio_irixal_out.c index d026b643b..04ba8ecc8 100644 --- a/src/audio_out/audio_irixal_out.c +++ b/src/audio_out/audio_irixal_out.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_irixal_out.c,v 1.5 2002/01/09 15:16:37 mshopf Exp $ + * $Id: audio_irixal_out.c,v 1.6 2002/03/11 19:58:00 jkeil Exp $ */ #ifdef HAVE_CONFIG_H @@ -50,7 +50,7 @@ //# endif //#endif -#define AO_IRIXAL_IFACE_VERSION 3 +#define AO_IRIXAL_IFACE_VERSION 4 #define DEFAULT_GAP_TOLERANCE 5000 @@ -286,6 +286,27 @@ static int ao_irixal_set_property (ao_driver_t *this, int property, int value) { return ~value; } +/* + * + */ +static int ao_irixal_ctrl(ao_driver_t *this_gen, int cmd, ...) { + irixal_driver_t *this = (irixal_driver_t *) this_gen; + + switch (cmd) { + + case AO_CTRL_PLAY_PAUSE: + break; + + case AO_CTRL_PLAY_RESUME: + break; + + case AO_CTRL_FLUSH_BUFFERS: + break; + } + + return 0; +} + ao_driver_t *init_audio_out_plugin (config_values_t *config) { irixal_driver_t *this; @@ -372,6 +393,7 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) 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; + this->ao_driver.control = ao_irixal_ctrl; return &this->ao_driver; } diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c index 553425927..3fcc7942f 100644 --- a/src/audio_out/audio_oss_out.c +++ b/src/audio_out/audio_oss_out.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_oss_out.c,v 1.58 2002/03/11 09:01:37 f1rmb Exp $ + * $Id: audio_oss_out.c,v 1.59 2002/03/11 19:58:00 jkeil Exp $ * * 20-8-2001 First implementation of Audio sync and Audio driver separation. * Copyright (C) 2001 James Courtier-Dutton James@superbug.demon.co.uk @@ -79,7 +79,7 @@ # define AFMT_AC3 0x00000400 #endif -#define AO_OUT_OSS_IFACE_VERSION 3 +#define AO_OUT_OSS_IFACE_VERSION 4 #define AUDIO_NUM_FRAGMENTS 15 #define AUDIO_FRAGMENT_SIZE 8192 @@ -561,6 +561,24 @@ static int ao_oss_set_property (ao_driver_t *this_gen, int property, int value) return ~value; } +static int ao_oss_ctrl(ao_driver_t *this_gen, int cmd, ...) { + oss_driver_t *this = (oss_driver_t *) this_gen; + + switch (cmd) { + + case AO_CTRL_PLAY_PAUSE: + break; + + case AO_CTRL_PLAY_RESUME: + break; + + case AO_CTRL_FLUSH_BUFFERS: + break; + } + + return 0; +} + ao_driver_t *init_audio_out_plugin (config_values_t *config) { oss_driver_t *this; @@ -837,6 +855,7 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { this->ao_driver.close = ao_oss_close; this->ao_driver.exit = ao_oss_exit; this->ao_driver.get_gap_tolerance = ao_oss_get_gap_tolerance; + this->ao_driver.control = ao_oss_ctrl; return &this->ao_driver; } diff --git a/src/audio_out/audio_sun_out.c b/src/audio_out/audio_sun_out.c index f4fb5ec00..9250e2228 100644 --- a/src/audio_out/audio_sun_out.c +++ b/src/audio_out/audio_sun_out.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_sun_out.c,v 1.17 2002/02/23 17:22:09 jkeil Exp $ + * $Id: audio_sun_out.c,v 1.18 2002/03/11 19:58:01 jkeil Exp $ */ #ifdef HAVE_CONFIG_H @@ -56,7 +56,7 @@ #define AUDIO_PRECISION_16 16 #endif -#define AO_SUN_IFACE_VERSION 3 +#define AO_SUN_IFACE_VERSION 4 #define GAP_TOLERANCE 5000 #define GAP_NONRT_TOLERANCE 15000 @@ -598,6 +598,55 @@ static int ao_sun_set_property (ao_driver_t *this_gen, int property, int value) return ~value; } +static int ao_sun_ctrl(ao_driver_t *this_gen, int cmd, ...) { + sun_driver_t *this = (sun_driver_t *) this_gen; + audio_info_t info; + + switch (cmd) { + + case AO_CTRL_PLAY_PAUSE: + AUDIO_INITINFO(&info); + info.play.pause = 1; + ioctl(this->audio_fd, AUDIO_SETINFO, &info); + break; + + case AO_CTRL_PLAY_RESUME: + AUDIO_INITINFO(&info); + info.play.pause = 0; + ioctl(this->audio_fd, AUDIO_SETINFO, &info); + break; + + case AO_CTRL_FLUSH_BUFFERS: +#ifdef __svr4__ + /* 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 + * that all samples still active playing on the sound hardware + * have finished playing. + */ + AUDIO_INITINFO(&info); + info.play.pause = 0; + ioctl(this->audio_fd, AUDIO_SETINFO, &info); + + ioctl(this->audio_fd, AUDIO_DRAIN); + + AUDIO_INITINFO(&info); + info.play.samples = 0; + ioctl(this->audio_fd, AUDIO_SETINFO, &info); + + this->frames_in_buffer = 0; + this->last_samplecnt = 0; +#endif + break; + } + + return 0; +} + ao_driver_t *init_audio_out_plugin (config_values_t *config) { sun_driver_t *this; @@ -683,6 +732,7 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { this->ao_driver.close = ao_sun_close; this->ao_driver.exit = ao_sun_exit; this->ao_driver.get_gap_tolerance = ao_sun_get_gap_tolerance; + this->ao_driver.control = ao_sun_ctrl; return &this->ao_driver; } diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c index 56f777469..4d97da9d1 100644 --- a/src/xine-engine/audio_out.c +++ b/src/xine-engine/audio_out.c @@ -17,7 +17,7 @@ * along with self program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_out.c,v 1.44 2002/03/11 12:31:26 guenter Exp $ + * $Id: audio_out.c,v 1.45 2002/03/11 19:58:01 jkeil Exp $ * * 22-8-2001 James imported some useful AC3 sections from the previous alsa driver. * (c) 2001 Andy Lo A Foe <andy@alsaplayer.org> @@ -240,7 +240,8 @@ static void *ao_loop (void *this_gen) { int64_t cur_time; int num_output_frames ; int paused_wait; - + + while ((this->audio_loop_running) || (!this->audio_loop_running && this->out_fifo->first)) { @@ -564,6 +565,20 @@ static int ao_set_property (ao_instance_t *this, int property, int value) { return(this->driver->set_property(this->driver, property, value)); } +static int ao_control (ao_instance_t *this, int cmd, ...) { + + va_list args; + void *arg; + int rval; + + va_start(args, cmd); + arg = va_arg(args, void*); + rval = this->driver->control(this->driver, cmd, arg); + va_end(args); + + return rval; +} + ao_instance_t *ao_new_instance (ao_driver_t *driver, xine_t *xine) { config_values_t *config = xine->config; @@ -585,6 +600,7 @@ ao_instance_t *ao_new_instance (ao_driver_t *driver, xine_t *xine) { this->get_capabilities = ao_get_capabilities; this->get_property = ao_get_property; this->set_property = ao_set_property; + this->control = ao_control; this->audio_loop_running = 0; this->audio_paused = 0; /* FIXME: is 4* good enough for all resample cases?? */ diff --git a/src/xine-engine/audio_out.h b/src/xine-engine/audio_out.h index dd820a6f4..471c21a2e 100644 --- a/src/xine-engine/audio_out.h +++ b/src/xine-engine/audio_out.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_out.h,v 1.25 2002/03/11 12:31:26 guenter Exp $ + * $Id: audio_out.h,v 1.26 2002/03/11 19:58:01 jkeil Exp $ */ #ifndef HAVE_AUDIO_OUT_H #define HAVE_AUDIO_OUT_H @@ -37,7 +37,7 @@ extern "C" { #endif -#define AUDIO_OUT_IFACE_VERSION 3 +#define AUDIO_OUT_IFACE_VERSION 4 /* * ao_driver_s contains the driver every audio output @@ -113,12 +113,19 @@ struct ao_driver_s { * get_property() return 1 in success, 0 on failure. * set_property() return value on success, ~value on failure. * - * See AC_PROP_* bellow for available properties. + * See AO_PROP_* below for available properties. */ int (*get_property) (ao_driver_t *this, int property); - int (*set_property) (ao_driver_t *this, int property, int value); + int (*set_property) (ao_driver_t *this, int property, int value); + + /* + * misc control operations on the audio device. + * + * See AO_CTRL_* below. + */ + int (*control) (ao_driver_t *this, int cmd, /* arg */ ...); }; /* @@ -179,6 +186,14 @@ struct ao_instance_s { /* called on xine exit */ void (*exit) (ao_instance_t *this); + /* + * misc control operations on the audio device. + * + * See AO_CTRL_* below. + */ + int (*control) (ao_driver_t *this, int cmd, /* arg */ ...); + + /* private stuff */ ao_driver_t *driver; @@ -252,6 +267,13 @@ ao_instance_t *ao_new_instance (ao_driver_t *driver, xine_t *xine) ; #define AO_PROP_PCM_VOL 1 #define AO_PROP_MUTE_VOL 2 + +/* audio device control ops */ +#define AO_CTRL_PLAY_PAUSE 0 +#define AO_CTRL_PLAY_RESUME 1 +#define AO_CTRL_FLUSH_BUFFERS 2 + + typedef struct ao_info_s { int interface_version; diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index 691700e91..2e0a2f527 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine.c,v 1.106 2002/03/11 12:31:26 guenter Exp $ + * $Id: xine.c,v 1.107 2002/03/11 19:58:01 jkeil Exp $ * * top-level xine functions * @@ -144,6 +144,27 @@ static void update_osd_display(void *this_gen, cfg_entry_t *entry) this->osd_display = entry->num_value; } + +static void xine_set_speed_internal (xine_t *this, int speed) { + + this->metronom->set_speed (this->metronom, speed); + + /* see coment on audio_out loop about audio_paused */ + if( this->audio_out ) { + this->audio_out->audio_paused = (speed != SPEED_NORMAL) + + (speed == SPEED_PAUSE); + + if (speed != SPEED_NORMAL && speed != SPEED_PAUSE) + this->audio_out->control(this->audio_out, AO_CTRL_FLUSH_BUFFERS); + + this->audio_out->control(this->audio_out, + speed == SPEED_PAUSE ? AO_CTRL_PLAY_PAUSE : AO_CTRL_PLAY_RESUME); + } + + this->speed = speed; +} + + void xine_stop_internal (xine_t *this) { pthread_mutex_lock (&this->xine_lock); @@ -158,12 +179,10 @@ void xine_stop_internal (xine_t *this) { return; } + if (this->audio_out) + this->audio_out->control(this->audio_out, AO_CTRL_FLUSH_BUFFERS); - this->metronom->set_speed (this->metronom, SPEED_NORMAL); - this->speed = SPEED_NORMAL; - - if( this->audio_out ) - this->audio_out->audio_paused = 0; + xine_set_speed_internal(this, SPEED_NORMAL); this->status = XINE_STOP; LOG_MSG(this, _("xine_stop: stopping demuxer\n")); @@ -300,6 +319,9 @@ int xine_play (xine_t *this, char *mrl, this->cur_input_plugin->stop(this->cur_input_plugin); } + if (this->audio_out) + this->audio_out->control(this->audio_out, AO_CTRL_FLUSH_BUFFERS); + this->status = XINE_STOP; } @@ -378,11 +400,7 @@ int xine_play (xine_t *this, char *mrl, this->status = XINE_PLAY; strncpy (this->cur_mrl, mrl, 1024); - this->metronom->set_speed (this->metronom, SPEED_NORMAL); - - if( this->audio_out ) - this->audio_out->audio_paused = 0; - this->speed = SPEED_NORMAL; + xine_set_speed_internal (this, SPEED_NORMAL); /* osd */ xine_internal_osd (this, ">", 0, 300000); @@ -679,8 +697,6 @@ int xine_get_av_offset (xine_t *this) { void xine_set_speed (xine_t *this, int speed) { - struct timespec tenth_sec; - pthread_mutex_lock (&this->xine_lock); if (speed <= SPEED_PAUSE) @@ -712,21 +728,10 @@ void xine_set_speed (xine_t *this, int speed) { } /* make sure osd can be displayed */ - tenth_sec.tv_sec = 0; - tenth_sec.tv_nsec = 100000000; - - nanosleep (&tenth_sec, NULL); + xine_usec_sleep(100000); LOG_MSG(this, _("xine: set_speed %d\n"), speed); - - this->metronom->set_speed (this->metronom, speed); - - /* see coment on audio_out loop about audio_paused */ - if( this->audio_out ) - this->audio_out->audio_paused = (speed != SPEED_NORMAL) + - (speed == SPEED_PAUSE); - - this->speed = speed; + xine_set_speed_internal (this, speed); pthread_mutex_unlock (&this->xine_lock); } |