diff options
author | James Courtier-Dutton <jcdutton@users.sourceforge.net> | 2001-08-21 19:39:50 +0000 |
---|---|---|
committer | James Courtier-Dutton <jcdutton@users.sourceforge.net> | 2001-08-21 19:39:50 +0000 |
commit | 790d5baee128cb40800fee392e74c01afefe4756 (patch) | |
tree | 4aa716c83a891ca3876968ede7f74c7482bfa7f0 | |
parent | f92de1992b6c30602b6785c0fb84fe3be6730c54 (diff) | |
download | xine-lib-790d5baee128cb40800fee392e74c01afefe4756.tar.gz xine-lib-790d5baee128cb40800fee392e74c01afefe4756.tar.bz2 |
First checkin of new audio_out architecture.
Audio sync and AC3 formatting now done in xine-lib/src/xine-engine/audio_out.c
Audio out now done in xine-lib/src/audio_out/*
Currently, only xine-lib/src/audio_oss_out.c is active.
Re-support of others will follow as other people implement them.
ao_functions split into ao_instance and ao_driver
and function in a similar fashion as video_out.
All decoder plugins now call ao_instance instead of ao_functions.
ao_instance is used in xine-lib/src/xine-engine/audio_out.c
ao_driver is used in xine-lib/src/audio_out/*
See also changes in xine-ui files
CVS patchset: 459
CVS date: 2001/08/21 19:39:50
-rw-r--r-- | include/xine.h.tmpl.in | 18 | ||||
-rw-r--r-- | src/audio_out/Makefile.am | 14 | ||||
-rw-r--r-- | src/audio_out/audio_oss_out.c | 472 | ||||
-rw-r--r-- | src/libac3/xine_decoder.c | 10 | ||||
-rw-r--r-- | src/liblpcm/xine_decoder.c | 8 | ||||
-rw-r--r-- | src/libmad/xine_decoder.c | 8 | ||||
-rw-r--r-- | src/libmpg123/interface.c | 4 | ||||
-rw-r--r-- | src/libmpg123/layer1.c | 2 | ||||
-rw-r--r-- | src/libmpg123/layer2.c | 2 | ||||
-rw-r--r-- | src/libmpg123/layer3.c | 2 | ||||
-rw-r--r-- | src/libmpg123/mpglib.h | 6 | ||||
-rw-r--r-- | src/libmpg123/xine_decoder.c | 6 | ||||
-rw-r--r-- | src/libw32dll/w32codec.c | 8 | ||||
-rw-r--r-- | src/xine-engine/Makefile.am | 4 | ||||
-rw-r--r-- | src/xine-engine/audio_out.c | 336 | ||||
-rw-r--r-- | src/xine-engine/audio_out.h | 113 | ||||
-rw-r--r-- | src/xine-engine/load_plugins.c | 8 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 9 | ||||
-rw-r--r-- | src/xine-engine/xine_internal.h | 10 |
19 files changed, 641 insertions, 399 deletions
diff --git a/include/xine.h.tmpl.in b/include/xine.h.tmpl.in index b91de236b..f6adb91b5 100644 --- a/include/xine.h.tmpl.in +++ b/include/xine.h.tmpl.in @@ -28,7 +28,7 @@ \endverbatim */ /* - * $Id: xine.h.tmpl.in,v 1.36 2001/08/17 16:15:36 f1rmb Exp $ + * $Id: xine.h.tmpl.in,v 1.37 2001/08/21 19:39:50 jcdutton Exp $ * */ @@ -431,10 +431,10 @@ struct vo_driver_s { */ typedef void xine_t; /** - * \struct ao_functions_t + * \struct ao_driver_t * Opaque data type. */ -typedef void ao_functions_t; +typedef void ao_driver_t; /** * \struct cfg_data_t * Opaque data type. @@ -564,7 +564,7 @@ typedef void (*gui_branched_cb_t) (void); /** @} end of demux_strategy */ /** - * \fn xine_t *xine_init (vo_driver_t *vo, ao_functions_t *ao, config_values_t *config, gui_stream_end_cb_t stream_end_cb, gui_get_next_mrl_cb_t get_next_mrl_cb, gui_branched_cb_t branched_cb); + * \fn xine_t *xine_init (vo_driver_t *vo, ao_driver_t *ao, config_values_t *config, gui_stream_end_cb_t stream_end_cb, gui_get_next_mrl_cb_t get_next_mrl_cb, gui_branched_cb_t branched_cb); * \brief Initialisation of xine. * \param vo video driver ( #see @ref xine_load_video_output_plugin() ) * \param ao audio driver ( #see @ref xine_load_audio_output_plugin() ) @@ -573,7 +573,7 @@ typedef void (*gui_branched_cb_t) (void); * \param get_next_mrl_cb called to find out next mrl for seamless branching * \param branched_cb called if seamless branch was taken * \return Current xine engine configuration - * \sa vo_driver_t, ao_functions_t, config_values_t, gui_stream_end_cb_t, gui_get_next_mrl_cb_t, gui_branched_cb_t + * \sa vo_driver_t, ao_driver_t, config_values_t, gui_stream_end_cb_t, gui_get_next_mrl_cb_t, gui_branched_cb_t * \warning This function should be called before any other xine_*() function. * * Init of xine. It should called once at startup. @@ -582,7 +582,7 @@ typedef void (*gui_branched_cb_t) (void); * */ xine_t *xine_init (vo_driver_t *vo, - ao_functions_t *ao, + ao_driver_t *ao, config_values_t *config, gui_stream_end_cb_t stream_end_cb, gui_get_next_mrl_cb_t get_next_mrl_cb, @@ -1078,13 +1078,13 @@ vo_driver_t *xine_load_video_output_plugin(config_values_t *config, char **xine_list_audio_output_plugins (void); /** - * \fn ao_functions_t *xine_load_audio_output_plugin(config_values_t *config, char *id) + * \fn ao_driver_t *xine_load_audio_output_plugin(config_values_t *config, char *id) * \param config current configuration ( #see config_file_init() ) * \param id driver name. * \brief load a specific audio output plugin. - * \sa ao_functions_t + * \sa ao_driver_t */ -ao_functions_t *xine_load_audio_output_plugin(config_values_t *config, char *id); +ao_driver_t *xine_load_audio_output_plugin(config_values_t *config, char *id); /** @} end of loadplugins_group */ diff --git a/src/audio_out/Makefile.am b/src/audio_out/Makefile.am index 00368063d..c34fa49cd 100644 --- a/src/audio_out/Makefile.am +++ b/src/audio_out/Makefile.am @@ -1,7 +1,7 @@ CFLAGS = @GLOBAL_CFLAGS@ -DXINE_COMPILE $(ALSA_CFLAGS) $(ESD_CFLAGS) $(IRIXAL_CFLAGS) $(ARTS_CFLAGS) -EXTRA_DIST = audio_alsa_out.c audio_alsa05_out.c audio_esd_out.c \ - audio_sun_out.c audio_arts_out.c +#EXTRA_DIST = audio_alsa_out.c audio_alsa05_out.c audio_esd_out.c \ +# audio_sun_out.c audio_arts_out.c ## audio_irixal_out.c LIBTOOL = $(SHELL) $(top_builddir)/libtool-nofpic @@ -18,19 +18,19 @@ endif # if HAVE_ALSA if HAVE_ALSA05 -alsa05_module = xineplug_ao_out_alsa05.la +#alsa05_module = xineplug_ao_out_alsa05.la endif if HAVE_ALSA09 -alsa_module = xineplug_ao_out_alsa.la +#alsa_module = xineplug_ao_out_alsa.la endif endif if HAVE_ESD -esd_module = xineplug_ao_out_esd.la +#esd_module = xineplug_ao_out_esd.la endif if HAVE_SUNAUDIO -sun_module = xineplug_ao_out_sun.la +#sun_module = xineplug_ao_out_sun.la endif ## if HAVE_IRIXAL @@ -38,7 +38,7 @@ endif ## endif if HAVE_ARTS -arts_module = xineplug_ao_out_arts.la +#arts_module = xineplug_ao_out_arts.la endif ## diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c index 575ddf448..0d13bef40 100644 --- a/src/audio_out/audio_oss_out.c +++ b/src/audio_out/audio_oss_out.c @@ -17,7 +17,22 @@ * 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.29 2001/08/18 23:28:26 guenter Exp $ + * $Id: audio_oss_out.c,v 1.30 2001/08/21 19:39:50 jcdutton Exp $ + * + * 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 to a full amount of bits. + * So, it does not mater how many bits per sample, or how many audio channels are being used, the number of audio_frames is the same. + * E.g. 16 bit stereo is 4 bytes, but one frame. + * 16 bit 5.1 surround is 12 bytes, but one frame. + * The purpose of this is to make the audio_sync code a lot more readable, rather than having to multiply by the amount of channels all the time + * when dealing with audio_bytes instead of audio_frames. + * + * The number of samples passed to/from the audio driver is also sent in units of audio_frames. + * ` */ /* required for swab() */ @@ -69,7 +84,7 @@ # define AFMT_AC3 0x00000400 /* Dolby Digital AC3 */ #endif -#define AO_OUT_OSS_IFACE_VERSION 1 +#define AO_OUT_OSS_IFACE_VERSION 2 #define AUDIO_NUM_FRAGMENTS 15 #define AUDIO_FRAGMENT_SIZE 8192 @@ -88,12 +103,9 @@ static int checked_getoptr = 0; -typedef struct oss_functions_s { - - ao_functions_t ao_functions; - - metronom_t *metronom; +typedef struct oss_driver_s { + ao_driver_t ao_driver; char audio_dev[20]; int audio_fd; int capabilities; @@ -102,98 +114,89 @@ typedef struct oss_functions_s { int32_t output_sample_rate, input_sample_rate; double sample_rate_factor; uint32_t num_channels; - + uint32_t bits_per_sample; + uint32_t bytes_per_frame; uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */ - - int audio_step; /* pts per 32 768 samples (sample = #bytes/2) */ - int32_t bytes_per_kpts; /* bytes per 1024/90000 sec */ - - uint16_t *sample_buffer; - int16_t *zero_space; int audio_started; int audio_has_realtime; /* OSS driver supports real-time */ - uint32_t last_audio_vpts; - int resample_conf; - int do_resample; -} oss_functions_t; +} oss_driver_t; /* * open the audio device for writing to */ -static int ao_open(ao_functions_t *this_gen, +static int ao_oss_open(ao_driver_t *self_gen, uint32_t bits, uint32_t rate, int mode) { - oss_functions_t *this = (oss_functions_t *) this_gen; + oss_driver_t *self = (oss_driver_t *) self_gen; int tmp; printf ("audio_oss_out: ao_open rate=%d, mode=%d\n", rate, mode); - if ( (mode & this->capabilities) == 0 ) { + if ( (mode & self->capabilities) == 0 ) { printf ("audio_oss_out: unsupported mode %08x\n", mode); return -1; } - if (this->audio_fd > -1) { + if (self->audio_fd > -1) { - if ( (mode == this->mode) && (rate == this->input_sample_rate) ) { + if ( (mode == self->mode) && (rate == self->input_sample_rate) ) { return 1; } - close (this->audio_fd); + close (self->audio_fd); } - this->mode = mode; - this->input_sample_rate = rate; - this->bytes_in_buffer = 0; - this->audio_started = 0; - this->last_audio_vpts = 0; + self->mode = mode; + self->input_sample_rate = rate; + self->bits_per_sample = bits; + self->bytes_in_buffer = 0; + self->audio_started = 0; /* * open audio device */ - this->audio_fd=open(this->audio_dev,O_WRONLY|O_NDELAY); - if(this->audio_fd < 0) { + self->audio_fd=open(self->audio_dev,O_WRONLY|O_NDELAY); + if(self->audio_fd < 0) { printf("audio_oss_out: Opening audio device %s: %s\n", - this->audio_dev, strerror(errno)); + self->audio_dev, strerror(errno)); return -1; } /* We wanted non blocking open but now put it back to normal */ - fcntl(this->audio_fd, F_SETFL, fcntl(this->audio_fd, F_GETFL)&~FNDELAY); + fcntl(self->audio_fd, F_SETFL, fcntl(self->audio_fd, F_GETFL)&~FNDELAY); /* * configure audio device + * In AC3 mode, skip all other SNDCTL commands */ + if(!(mode & AO_CAP_MODE_AC3)) { + tmp = (mode & AO_CAP_MODE_STEREO) ? 1 : 0; + ioctl(self->audio_fd,SNDCTL_DSP_STEREO,&tmp); - tmp = (mode & AO_CAP_MODE_STEREO) ? 1 : 0; - ioctl(this->audio_fd,SNDCTL_DSP_STEREO,&tmp); - + tmp = bits; + ioctl(self->audio_fd,SNDCTL_DSP_SAMPLESIZE,&tmp); - tmp = bits; - ioctl(this->audio_fd,SNDCTL_DSP_SAMPLESIZE,&tmp); - - tmp = this->input_sample_rate; + tmp = self->input_sample_rate; #ifdef FORCE_44K_MAX - if(tmp > 44100) - tmp = 44100; + if(tmp > 44100) + tmp = 44100; #endif - if (ioctl(this->audio_fd,SNDCTL_DSP_SPEED, &tmp) == -1) { + if (ioctl(self->audio_fd,SNDCTL_DSP_SPEED, &tmp) == -1) { - printf ("audio_oss_out: warning: sampling rate %d Hz not supported, trying 44100 Hz\n", this->input_sample_rate); + printf ("audio_oss_out: warning: sampling rate %d Hz not supported, trying 44100 Hz\n", self->input_sample_rate); - tmp = 44100; - if (ioctl(this->audio_fd,SNDCTL_DSP_SPEED, &tmp) == -1) { - printf ("audio_oss_out: error: 44100 Hz sampling rate not supported\n"); - return -1; + tmp = 44100; + if (ioctl(self->audio_fd,SNDCTL_DSP_SPEED, &tmp) == -1) { + printf ("audio_oss_out: error: 44100 Hz sampling rate not supported\n"); + return -1; + } } + self->output_sample_rate = tmp; + xprintf (VERBOSE|AUDIO, "audio_oss_out: audio rate : %d requested, %d provided by device/sec\n", + self->input_sample_rate, self->output_sample_rate); } - this->output_sample_rate = tmp; - - xprintf (VERBOSE|AUDIO, "audio_oss_out: audio rate : %d requested, %d provided by device/sec\n", - this->input_sample_rate, this->output_sample_rate); - /* * set number of channels / ac3 throughput */ @@ -201,48 +204,43 @@ static int ao_open(ao_functions_t *this_gen, switch (mode) { case AO_CAP_MODE_MONO: tmp = 1; - ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); - this->num_channels = tmp; + ioctl(self->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); + self->num_channels = tmp; break; case AO_CAP_MODE_STEREO: tmp = 2; - ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); - this->num_channels = tmp; + ioctl(self->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); + self->num_channels = tmp; break; case AO_CAP_MODE_4CHANNEL: tmp = 4; - ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); - this->num_channels = tmp; + ioctl(self->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); + self->num_channels = tmp; break; case AO_CAP_MODE_5CHANNEL: tmp = 5; - ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); - this->num_channels = tmp; + ioctl(self->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); + self->num_channels = tmp; break; case AO_CAP_MODE_5_1CHANNEL: tmp = 6; - ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); - this->num_channels = tmp; + ioctl(self->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); + self->num_channels = tmp; break; case AO_CAP_MODE_AC3: tmp = AFMT_AC3; - ioctl(this->audio_fd,SNDCTL_DSP_SETFMT,&tmp); - this->num_channels = 2; /* FIXME: is this correct ? */ + if (ioctl(self->audio_fd, SNDCTL_DSP_SETFMT, &tmp) < 0 || tmp != AFMT_AC3) { + printf("audio_oss_out: AC3 SNDCTL_DSP_SETFMT failed. %d\n",tmp); + return -1; + } + self->num_channels = 2; /* FIXME: is this correct ? */ + self->output_sample_rate = self->input_sample_rate; printf ("audio_oss_out : AO_CAP_MODE_AC3\n"); break; } - printf ("audio_oss_out : %d channels output\n",this->num_channels); - - this->sample_rate_factor = (double) this->output_sample_rate / (double) this->input_sample_rate; - this->audio_step = (uint32_t) 90000 * (uint32_t) 32768 - / this->input_sample_rate; - this->bytes_per_kpts = this->output_sample_rate * this->num_channels * 2 * 1024 / 90000; - - xprintf (VERBOSE|AUDIO, "audio_out : audio_step %d pts per 32768 samples\n", this->audio_step); - printf ("audio_out : audio_step %d pts per 32768 samples\n", this->audio_step); - - this->metronom->set_audio_rate(this->metronom, this->audio_step); + printf ("audio_oss_out : %d channels output\n",self->num_channels); + self->bytes_per_frame=(self->bits_per_sample*self->num_channels)/8; /* * audio buffer size handling @@ -261,18 +259,18 @@ static int ao_open(ao_functions_t *this_gen, xprintf (VERBOSE|AUDIO, "Audio buffer fragment info : %x\n",tmp); - ioctl(this->audio_fd,SNDCTL_DSP_SETFRAGMENT,&tmp); + ioctl(self->audio_fd,SNDCTL_DSP_SETFRAGMENT,&tmp); */ /* * Final check of realtime capability, make sure GETOPTR * doesn't return an error. */ - if ( this->audio_has_realtime && !checked_getoptr ) { + if ( self->audio_has_realtime && !checked_getoptr ) { count_info info; - int ret = ioctl(this->audio_fd, SNDCTL_DSP_GETOPTR, &info); + int ret = ioctl(self->audio_fd, SNDCTL_DSP_GETOPTR, &info); if ( ret == -1 && errno == EINVAL ) { - this->audio_has_realtime = 0; + self->audio_has_realtime = 0; printf("audio_oss_out: Audio driver SNDCTL_DSP_GETOPTR reports %s," " disabling realtime sync...\n", strerror(errno) ); printf("audio_oss_out: ...Will use video master clock for soft-sync instead\n"); @@ -281,225 +279,69 @@ static int ao_open(ao_functions_t *this_gen, checked_getoptr = 1; } - switch (this->resample_conf) { - case 1: /* force off */ - this->do_resample = 0; - break; - case 2: /* force on */ - this->do_resample = 1; - break; - default: /* AUTO */ - this->do_resample = this->output_sample_rate != this->input_sample_rate; - } - if (this->do_resample) - printf("audio_oss_out: will resample audio from %d to %d\n", - this->input_sample_rate, this->output_sample_rate); - return 1; } -static void ao_fill_gap (oss_functions_t *this, uint32_t pts_len) { - - int num_bytes ; - - if (pts_len > MAX_GAP) - pts_len = MAX_GAP; - num_bytes = pts_len * this->bytes_per_kpts / 1024; - num_bytes = (num_bytes / (2*this->num_channels)) * (2*this->num_channels); - - if(this->mode == AO_CAP_MODE_AC3) return; /* FIXME */ - - printf ("audio_oss_out: inserting %d 0-bytes to fill a gap of %d pts\n",num_bytes, pts_len); - - this->bytes_in_buffer += num_bytes; - - while (num_bytes > 0) { - if (num_bytes > ZERO_BUF_SIZE) { - write(this->audio_fd, this->zero_space, ZERO_BUF_SIZE); - num_bytes -= ZERO_BUF_SIZE; - } else { - write(this->audio_fd, this->zero_space, num_bytes); - num_bytes = 0; - } - } +static int ao_oss_num_channels(ao_driver_t *self_gen) +{ + oss_driver_t *self = (oss_driver_t *) self_gen; + return self->num_channels; } -static int ao_write_audio_data(ao_functions_t *this_gen, - int16_t* output_samples, uint32_t num_samples, - uint32_t pts_) +static int ao_oss_bytes_per_frame(ao_driver_t *self_gen) { - - oss_functions_t *this = (oss_functions_t *) this_gen; - uint32_t vpts, buffer_vpts; - int32_t gap; - int bDropPackage; - count_info info; - int pos; - - if (this->audio_fd<0) - return 1; - - vpts = this->metronom->got_audio_samples (this->metronom, pts_, num_samples); - - xprintf (VERBOSE|AUDIO, "audio_oss_out: got %d samples, vpts=%d pts=%d\n", - num_samples, vpts,pts_); - - if (vpts<this->last_audio_vpts) { - /* reject this */ - xprintf (VERBOSE|AUDIO, "audio_oss_out: rejected sample vpts=%d, last_audio_vpts=%d\n", vpts,this->last_audio_vpts) - - return 1; - } - - this->last_audio_vpts = vpts; - - bDropPackage = 0; - - if ( this->audio_has_realtime || !this->audio_started ) { - - /* - * where, in the timeline is the "end" of the audio buffer at the moment? - */ - - buffer_vpts = this->metronom->get_current_time (this->metronom); - - if (this->audio_started) { - ioctl (this->audio_fd, SNDCTL_DSP_GETOPTR, &info); - pos = info.bytes; - } else - pos = 0; - - if (pos>this->bytes_in_buffer) /* buffer ran dry */ - this->bytes_in_buffer = pos; - - buffer_vpts += (this->bytes_in_buffer - pos) * 1024 / this->bytes_per_kpts; - - /* - * calculate gap: - */ - - gap = vpts - buffer_vpts; - xprintf (VERBOSE|AUDIO, "audio_oss_out: buff=%d pos=%d buf_vpts=%d gap=%d\n", - this->bytes_in_buffer, pos,buffer_vpts,gap); - - if (gap>GAP_TOLERANCE) { - ao_fill_gap (this, gap); - - /* keep xine responsive */ - - if (gap>MAX_GAP) - return 0; - - } else if (gap<-GAP_TOLERANCE) { - bDropPackage = 1; - xprintf (VERBOSE|AUDIO, "audio_oss_out: audio package (vpts = %d %d)" - "dropped\n", vpts, gap); - } - - } /* has realtime */ - - /* - * resample and output samples - */ - if(this->mode == AO_CAP_MODE_AC3) bDropPackage=0; - - if (!bDropPackage) { - int num_output_samples = num_samples * (this->output_sample_rate) / this->input_sample_rate; - - if (!this->do_resample) { - write(this->audio_fd, output_samples, - num_output_samples * this->num_channels * 2); - } else switch (this->mode) { - case AO_CAP_MODE_MONO: - audio_out_resample_mono (output_samples, num_samples, - this->sample_buffer, num_output_samples); - write(this->audio_fd, this->sample_buffer, num_output_samples * 2); - break; - case AO_CAP_MODE_STEREO: - audio_out_resample_stereo (output_samples, num_samples, - this->sample_buffer, num_output_samples); - write(this->audio_fd, this->sample_buffer, num_output_samples * 4); - break; - case AO_CAP_MODE_4CHANNEL: - audio_out_resample_4channel (output_samples, num_samples, - this->sample_buffer, num_output_samples); - write(this->audio_fd, this->sample_buffer, num_output_samples * 8); - break; - case AO_CAP_MODE_5CHANNEL: - audio_out_resample_5channel (output_samples, num_samples, - this->sample_buffer, num_output_samples); - write(this->audio_fd, this->sample_buffer, num_output_samples * 10); - break; - case AO_CAP_MODE_5_1CHANNEL: - audio_out_resample_6channel (output_samples, num_samples, - this->sample_buffer, num_output_samples); - write(this->audio_fd, this->sample_buffer, num_output_samples * 12); - break; - case AO_CAP_MODE_AC3: - num_output_samples = num_samples+8; - this->sample_buffer[0] = 0xf872; //spdif syncword - this->sample_buffer[1] = 0x4e1f; // ............. - this->sample_buffer[2] = 0x0001; // AC3 data - this->sample_buffer[3] = num_samples * 8; -// this->sample_buffer[4] = 0x0b77; // AC3 syncwork already in output_samples - - // ac3 seems to be swabbed data - swab(output_samples,this->sample_buffer+4, num_samples ); - write(this->audio_fd, this->sample_buffer, num_output_samples); - write(this->audio_fd, this->zero_space, 6144-num_output_samples); - num_output_samples=num_output_samples/4; - break; - } - - xprintf (AUDIO|VERBOSE, "audio_oss_out :audio package written\n"); - - /* - * step values - */ - - this->bytes_in_buffer += num_output_samples * 2 * this->num_channels; - this->audio_started = 1; - } - - return 1; - + oss_driver_t *self = (oss_driver_t *) self_gen; + return self->bytes_per_frame; } +static int ao_oss_delay(ao_driver_t *self_gen) +{ + count_info info; + oss_driver_t *self = (oss_driver_t *) self_gen; + ioctl (self->audio_fd, SNDCTL_DSP_GETOPTR, &info); + return info.bytes / self->bytes_per_frame; +} -static void ao_close(ao_functions_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. + */ +static int ao_oss_write(ao_driver_t *self_gen, + int16_t* frame_buffer, uint32_t num_frames) { - oss_functions_t *this = (oss_functions_t *) this_gen; - close(this->audio_fd); - this->audio_fd = -1; + oss_driver_t *self = (oss_driver_t *) self_gen; + return write(self->audio_fd, frame_buffer, num_frames * self->bytes_per_frame); + } -static uint32_t ao_get_capabilities (ao_functions_t *this_gen) { - oss_functions_t *this = (oss_functions_t *) this_gen; - return this->capabilities; +static void ao_oss_close(ao_driver_t *self_gen) +{ + oss_driver_t *self = (oss_driver_t *) self_gen; + close(self->audio_fd); + self->audio_fd = -1; } -static void ao_connect (ao_functions_t *this_gen, metronom_t *metronom) { - oss_functions_t *this = (oss_functions_t *) this_gen; - - this->metronom = metronom; +static uint32_t ao_oss_get_capabilities (ao_driver_t *self_gen) { + oss_driver_t *self = (oss_driver_t *) self_gen; + return self->capabilities; } -static void ao_exit(ao_functions_t *this_gen) +static void ao_oss_exit(ao_driver_t *self_gen) { - oss_functions_t *this = (oss_functions_t *) this_gen; + oss_driver_t *self = (oss_driver_t *) self_gen; - if (this->audio_fd != -1) - close(this->audio_fd); + if (self->audio_fd != -1) + close(self->audio_fd); - free (this->sample_buffer); - free (this->zero_space); - free (this); + free (self); } /* * */ -static int ao_get_property (ao_functions_t *this, int property) { +static int ao_oss_get_property (ao_driver_t *self_gen, int property) { + oss_driver_t *self = (oss_driver_t *) self; /* FIXME: implement some properties switch(property) { @@ -517,7 +359,8 @@ static int ao_get_property (ao_functions_t *this, int property) { /* * */ -static int ao_set_property (ao_functions_t *this, int property, int value) { +static int ao_oss_set_property (ao_driver_t *self_gen, int property, int value) { + oss_driver_t *self = (oss_driver_t *) self; /* FIXME: Implement property support. switch(property) { @@ -533,9 +376,9 @@ static int ao_set_property (ao_functions_t *this, int property, int value) { return ~value; } -ao_functions_t *init_audio_out_plugin (config_values_t *config) { +ao_driver_t *init_audio_out_plugin (config_values_t *config) { - oss_functions_t *this; + oss_driver_t *self; int caps; #ifdef CONFIG_DEVFS_FS char devname[] = "/dev/sound/dsp\0\0\0"; @@ -548,7 +391,7 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { int audio_fd; int num_channels, status, arg; - this = (oss_functions_t *) malloc (sizeof (oss_functions_t)); + self = (oss_driver_t *) malloc (sizeof (oss_driver_t)); /* * find best device driver/channel @@ -561,11 +404,11 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { devnum = config->lookup_int (config, "oss_device_num", -1); if (devnum >= 0) { - sprintf (this->audio_dev, DSP_TEMPLATE, devnum); + sprintf (self->audio_dev, DSP_TEMPLATE, devnum); devnum = 30; /* skip while loop */ } else { devnum = 0; - sprintf (this->audio_dev, "/dev/dsp"); + sprintf (self->audio_dev, "/dev/dsp"); } while (devnum<16) { @@ -579,14 +422,14 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { rate = 48000; ioctl(audio_fd,SNDCTL_DSP_SPEED, &rate); if (rate>best_rate) { - strncpy (this->audio_dev, devname, 19); + strncpy (self->audio_dev, devname, 19); best_rate = rate; } close (audio_fd); } /*else printf("audio_oss_out: opening audio device %s failed:\n%s\n", - this->audio_dev, strerror(errno)); + self->audio_dev, strerror(errno)); */ sprintf(devname, DSP_TEMPLATE, devnum); @@ -597,18 +440,18 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { * open that device */ - audio_fd=open(this->audio_dev, O_WRONLY|O_NDELAY); + audio_fd=open(self->audio_dev, O_WRONLY|O_NDELAY); if(audio_fd < 0) { printf("audio_oss_out: opening audio device %s failed:\n%s\n", - this->audio_dev, strerror(errno)); + self->audio_dev, strerror(errno)); - free (this); + free (self); return NULL; } else - xprintf (VERBOSE|AUDIO, " %s\n", this->audio_dev); + xprintf (VERBOSE|AUDIO, " %s\n", self->audio_dev); /* * set up driver to reasonable values for capabilities tests @@ -627,38 +470,38 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { if ((caps & DSP_CAP_REALTIME) > 0) { xprintf (VERBOSE|AUDIO, "audio_oss_out : realtime check: passed :-)\n"); - this->audio_has_realtime = 1; + self->audio_has_realtime = 1; } else { printf ("audio_oss_out : realtime check: *FAILED* :-(((((\n"); - this->audio_has_realtime = 0; + self->audio_has_realtime = 0; } - if( !this->audio_has_realtime ) { + if( !self->audio_has_realtime ) { printf("audio_oss_out: Audio driver realtime sync disabled...\n"); printf("audio_oss_out: ...Will use video master clock for soft-sync instead\n"); printf("audio_oss_out: ...There may be audio/video synchronization issues\n"); } - this->capabilities = 0; + self->capabilities = 0; printf ("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; + self->capabilities |= AO_CAP_MODE_MONO; printf ("mono "); } num_channels = 2; status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==2) ) { - this->capabilities |= AO_CAP_MODE_STEREO; + self->capabilities |= AO_CAP_MODE_STEREO; printf ("stereo "); } num_channels = 4; status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==4) ) { if (config->lookup_int (config, "four_channel", 0)) { - this->capabilities |= AO_CAP_MODE_4CHANNEL; + self->capabilities |= AO_CAP_MODE_4CHANNEL; printf ("4-channel "); } else printf ("(4-channel not enabled in .xinerc) " ); @@ -667,7 +510,7 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==5) ) { if (config->lookup_int (config, "five_channel", 0)) { - this->capabilities |= AO_CAP_MODE_5CHANNEL; + self->capabilities |= AO_CAP_MODE_5CHANNEL; printf ("5-channel "); } else printf ("(5-channel not enabled in .xinerc) " ); @@ -676,7 +519,7 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==6) ) { if (config->lookup_int (config, "five_lfe_channel", 0)) { - this->capabilities |= AO_CAP_MODE_5_1CHANNEL; + self->capabilities |= AO_CAP_MODE_5_1CHANNEL; printf ("5.1-channel "); } else printf ("(5.1-channel not enabled in .xinerc) " ); @@ -685,7 +528,7 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { ioctl(audio_fd,SNDCTL_DSP_GETFMTS,&caps); if (caps & AFMT_AC3) { if (config->lookup_int (config, "ac3_pass_through", 0)) { - this->capabilities |= AO_CAP_MODE_AC3; + self->capabilities |= AO_CAP_MODE_AC3; printf ("ac3-pass-through "); } else printf ("(ac3-pass-through not enabled in .xinerc)"); @@ -695,26 +538,21 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { close (audio_fd); - this->resample_conf = config->lookup_int (config, "oss_resample", 0); - - this->output_sample_rate = 0; - this->audio_fd = -1; - - this->sample_buffer = malloc (40000); - memset (this->sample_buffer, 0, 40000); - this->zero_space = malloc (ZERO_BUF_SIZE); - memset (this->zero_space, 0, ZERO_BUF_SIZE); - - this->ao_functions.get_capabilities = ao_get_capabilities; - this->ao_functions.get_property = ao_get_property; - this->ao_functions.set_property = ao_set_property; - this->ao_functions.connect = ao_connect; - this->ao_functions.open = ao_open; - this->ao_functions.write_audio_data = ao_write_audio_data; - this->ao_functions.close = ao_close; - this->ao_functions.exit = ao_exit; - - return &this->ao_functions; + self->output_sample_rate = 0; + self->audio_fd = -1; + + self->ao_driver.get_capabilities = ao_oss_get_capabilities; + self->ao_driver.get_property = ao_oss_get_property; + self->ao_driver.set_property = ao_oss_set_property; + self->ao_driver.open = ao_oss_open; + self->ao_driver.num_channels = ao_oss_num_channels; + self->ao_driver.bytes_per_frame = ao_oss_bytes_per_frame; + self->ao_driver.delay = ao_oss_delay; + self->ao_driver.write = ao_oss_write; + self->ao_driver.close = ao_oss_close; + self->ao_driver.exit = ao_oss_exit; + + return &self->ao_driver; } static ao_info_t ao_info_oss = { diff --git a/src/libac3/xine_decoder.c b/src/libac3/xine_decoder.c index c7ec83c35..6bd357f04 100644 --- a/src/libac3/xine_decoder.c +++ b/src/libac3/xine_decoder.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_decoder.c,v 1.22 2001/08/02 14:35:58 joachim_koenig Exp $ + * $Id: xine_decoder.c,v 1.23 2001/08/21 19:39:50 jcdutton Exp $ * * stuff needed to turn libac3 into a xine decoder plugin */ @@ -69,7 +69,7 @@ typedef struct ac3dec_decoder_s { sample_t delay[6*256]; sample_t samples[6][256]; - ao_functions_t *audio_out; + ao_instance_t *audio_out; int audio_caps; int bypass_mode; int output_sampling_rate; @@ -83,7 +83,7 @@ int ac3dec_can_handle (audio_decoder_t *this_gen, int buf_type) { } -void ac3dec_init (audio_decoder_t *this_gen, ao_functions_t *audio_out) { +void ac3dec_init (audio_decoder_t *this_gen, ao_instance_t *audio_out) { ac3dec_decoder_t *this = (ac3dec_decoder_t *) this_gen; /* int i; */ @@ -303,7 +303,7 @@ static void ac3dec_decode_frame (ac3dec_decoder_t *this, uint32_t pts) { /* output decoded samples */ - this->audio_out->write_audio_data (this->audio_out, + this->audio_out->write (this->audio_out, this->int_samples, 256*6, pts); @@ -328,7 +328,7 @@ static void ac3dec_decode_frame (ac3dec_decoder_t *this, uint32_t pts) { } if (this->output_open) { - this->audio_out->write_audio_data (this->audio_out, + this->audio_out->write (this->audio_out, (int16_t*)this->frame_buffer, this->frame_length, pts); diff --git a/src/liblpcm/xine_decoder.c b/src/liblpcm/xine_decoder.c index 59644f339..6ce388884 100644 --- a/src/liblpcm/xine_decoder.c +++ b/src/liblpcm/xine_decoder.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_decoder.c,v 1.1 2001/08/04 20:14:54 guenter Exp $ + * $Id: xine_decoder.c,v 1.2 2001/08/21 19:39:50 jcdutton Exp $ * * stuff needed to turn libac3 into a xine decoder plugin */ @@ -42,7 +42,7 @@ typedef struct lpcm_decoder_s { uint32_t pts; uint32_t last_pts; - ao_functions_t *audio_out; + ao_instance_t *audio_out; int output_open; } lpcm_decoder_t; @@ -52,7 +52,7 @@ int lpcm_can_handle (audio_decoder_t *this_gen, int buf_type) { } -void lpcm_init (audio_decoder_t *this_gen, ao_functions_t *audio_out) { +void lpcm_init (audio_decoder_t *this_gen, ao_instance_t *audio_out) { lpcm_decoder_t *this = (lpcm_decoder_t *) this_gen; @@ -87,7 +87,7 @@ void lpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { for(i=0; i<buf->size/2; i++) p[i] = ntohs(p[i]); - this->audio_out->write_audio_data (this->audio_out, + this->audio_out->write (this->audio_out, buf->content, buf->size/4, this->pts); diff --git a/src/libmad/xine_decoder.c b/src/libmad/xine_decoder.c index d79a4f57e..96f728e58 100644 --- a/src/libmad/xine_decoder.c +++ b/src/libmad/xine_decoder.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_decoder.c,v 1.1 2001/08/12 02:57:55 guenter Exp $ + * $Id: xine_decoder.c,v 1.2 2001/08/21 19:39:50 jcdutton Exp $ * * stuff needed to turn libmad into a xine decoder plugin */ @@ -43,7 +43,7 @@ typedef struct mad_decoder_s { struct mad_stream stream; struct mad_frame frame; - ao_functions_t *audio_out; + ao_instance_t *audio_out; int output_sampling_rate; int output_open; @@ -59,7 +59,7 @@ static int mad_can_handle (audio_decoder_t *this_gen, int buf_type) { } -static void mad_init (audio_decoder_t *this_gen, ao_functions_t *audio_out) { +static void mad_init (audio_decoder_t *this_gen, ao_instance_t *audio_out) { mad_decoder_t *this = (mad_decoder_t *) this_gen; @@ -193,7 +193,7 @@ static void mad_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { } - this->audio_out->write_audio_data (this->audio_out, + this->audio_out->write (this->audio_out, this->samples, pcm->length, buf->PTS); diff --git a/src/libmpg123/interface.c b/src/libmpg123/interface.c index 199c89479..45c78c604 100644 --- a/src/libmpg123/interface.c +++ b/src/libmpg123/interface.c @@ -18,7 +18,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: interface.c,v 1.4 2001/05/27 23:48:12 guenter Exp $ + * $Id: interface.c,v 1.5 2001/08/21 19:39:50 jcdutton Exp $ */ #include <stdlib.h> @@ -40,7 +40,7 @@ void mpg_audio_reset (mpgaudio_t *mp) { mp->header = 0; } -mpgaudio_t *mpg_audio_init (ao_functions_t *ao_output) +mpgaudio_t *mpg_audio_init (ao_instance_t *ao_output) { mpgaudio_t *mp; diff --git a/src/libmpg123/layer1.c b/src/libmpg123/layer1.c index 4db905947..50a333a0e 100644 --- a/src/libmpg123/layer1.c +++ b/src/libmpg123/layer1.c @@ -157,7 +157,7 @@ void do_layer1(mpgaudio_t *mp) printf ("layer1\n"); } - mp->ao_output->write_audio_data (mp->ao_output, (int16_t*)mp->osspace, num_bytes/(stereo-1 ? 4:2), + mp->ao_output->write (mp->ao_output, (int16_t*)mp->osspace, num_bytes/(stereo-1 ? 4:2), mp->pts); mp->pts = 0; diff --git a/src/libmpg123/layer2.c b/src/libmpg123/layer2.c index c4230ad5d..b5a3c27b6 100644 --- a/src/libmpg123/layer2.c +++ b/src/libmpg123/layer2.c @@ -295,7 +295,7 @@ void do_layer2(mpgaudio_t *mp) mp->sample_rate_device = fr->sample_rate; } - mp->ao_output->write_audio_data (mp->ao_output, (int16_t*)mp->osspace, num_bytes/(stereo-1 ? 4:2), + mp->ao_output->write (mp->ao_output, (int16_t*)mp->osspace, num_bytes/(stereo-1 ? 4:2), mp->pts); mp->pts = 0; diff --git a/src/libmpg123/layer3.c b/src/libmpg123/layer3.c index 08e444d69..db99e8fa6 100644 --- a/src/libmpg123/layer3.c +++ b/src/libmpg123/layer3.c @@ -1629,7 +1629,7 @@ void do_layer3(mpgaudio_t *mp) mp->sample_rate_device = fr->sample_rate; } - mp->ao_output->write_audio_data (mp->ao_output, (int16_t*)mp->osspace, num_bytes/(stereo-1 ? 4:2), + mp->ao_output->write (mp->ao_output, (int16_t*)mp->osspace, num_bytes/(stereo-1 ? 4:2), mp->pts); } mp->pts = 0; diff --git a/src/libmpg123/mpglib.h b/src/libmpg123/mpglib.h index 0b06eee60..60014828f 100644 --- a/src/libmpg123/mpglib.h +++ b/src/libmpg123/mpglib.h @@ -18,7 +18,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: mpglib.h,v 1.5 2001/08/07 14:15:04 guenter Exp $ + * $Id: mpglib.h,v 1.6 2001/08/21 19:39:50 jcdutton Exp $ */ #ifndef HAVE_MPGLIB_H @@ -48,7 +48,7 @@ typedef struct mpstr { int is_output_initialized; int sample_rate_device; - ao_functions_t *ao_output; + ao_instance_t *ao_output; unsigned char osspace[8192]; uint32_t pts; @@ -62,7 +62,7 @@ typedef struct mpstr { extern "C" { #endif -mpgaudio_t *mpg_audio_init (ao_functions_t *ao_output); +mpgaudio_t *mpg_audio_init (ao_instance_t *ao_output); void mpg_audio_reset (mpgaudio_t *mp); diff --git a/src/libmpg123/xine_decoder.c b/src/libmpg123/xine_decoder.c index 61c5c7d0d..649c51526 100644 --- a/src/libmpg123/xine_decoder.c +++ b/src/libmpg123/xine_decoder.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: xine_decoder.c,v 1.4 2001/08/07 14:15:04 guenter Exp $ + * $Id: xine_decoder.c,v 1.5 2001/08/21 19:39:50 jcdutton Exp $ * * stuff needed to turn libmpg123 into a xine decoder plugin */ @@ -44,7 +44,7 @@ typedef struct mpgdec_decoder_s { mpgaudio_t *mpg; - ao_functions_t *audio_out; + ao_instance_t *audio_out; int output_sampling_rate; int output_open; @@ -55,7 +55,7 @@ int mpgdec_can_handle (audio_decoder_t *this_gen, int buf_type) { } -void mpgdec_init (audio_decoder_t *this_gen, ao_functions_t *audio_out) { +void mpgdec_init (audio_decoder_t *this_gen, ao_instance_t *audio_out) { mpgdec_decoder_t *this = (mpgdec_decoder_t *) this_gen; diff --git a/src/libw32dll/w32codec.c b/src/libw32dll/w32codec.c index 7bb7ab461..69abf2e9f 100644 --- a/src/libw32dll/w32codec.c +++ b/src/libw32dll/w32codec.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: w32codec.c,v 1.15 2001/08/06 13:21:26 ehasenle Exp $ + * $Id: w32codec.c,v 1.16 2001/08/21 19:39:50 jcdutton Exp $ * * routines for using w32 codecs * @@ -63,7 +63,7 @@ typedef struct w32v_decoder_s { typedef struct w32a_decoder_s { audio_decoder_t audio_decoder; - ao_functions_t *audio_out; + ao_instance_t *audio_out; int decoder_ok; unsigned char buf[16384]; @@ -404,7 +404,7 @@ static char* get_auds_codec_name(w32a_decoder_t *this, int id){ return NULL; } -static void w32a_init (audio_decoder_t *this_gen, ao_functions_t *audio_out) { +static void w32a_init (audio_decoder_t *this_gen, ao_instance_t *audio_out) { w32a_decoder_t *this = (w32a_decoder_t *) this_gen; @@ -523,7 +523,7 @@ static void w32a_decode_audio (w32a_decoder_t *this, this->sample_buf[0], this->sample_buf[1], this->sample_buf[2], this->sample_buf[3], this->sample_buf[ash.cbDstLengthUsed-2], this->sample_buf[ash.cbDstLengthUsed-1]); */ - this->audio_out->write_audio_data (this->audio_out, + this->audio_out->write (this->audio_out, (int16_t*) this->sample_buf, ash.cbDstLengthUsed / (this->num_channels*2), nPTS); diff --git a/src/xine-engine/Makefile.am b/src/xine-engine/Makefile.am index c71bc26fe..0448aba9d 100644 --- a/src/xine-engine/Makefile.am +++ b/src/xine-engine/Makefile.am @@ -10,7 +10,7 @@ lib_LTLIBRARIES = libxine.la libxine_la_SOURCES = xine.c metronom.c configfile.c buffer.c monitor.c \ utils.c load_plugins.c video_decoder.c \ - audio_decoder.c video_out.c events.c + audio_decoder.c video_out.c audio_out.c resample.c events.c libxine_la_LIBADD = cpu_accel.lo \ $(THREAD_LIBS) \ $(DYNAMIC_LD_LIBS) \ @@ -20,7 +20,7 @@ libxine_la_LDFLAGS = -version-info 5:0:5 include_HEADERS = buffer.h metronom.h configfile.h \ monitor.h cpu_accel.h attributes.h utils.h \ - audio_out.h video_out.h xine_internal.h spu_decoder.h \ + audio_out.h resample.h video_out.h xine_internal.h spu_decoder.h \ events.h noinst_HEADERS = bswap.h diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c new file mode 100644 index 000000000..19273fdfd --- /dev/null +++ b/src/xine-engine/audio_out.c @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2000, 2001 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 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.3 2001/08/21 19:39:50 jcdutton Exp $ + * + * 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 to a full amount of bits. + * So, it does not mater how many bits per sample, or how many audio channels are being used, the number of audio_frames is the same. + * E.g. 16 bit stereo is 4 bytes, but one frame. + * 16 bit 5.1 surround is 12 bytes, but one frame. + * The purpose of this is to make the audio_sync code a lot more readable, rather than having to multiply by the amount of channels all the time + * when dealing with audio_bytes instead of audio_frames. + * + * The number of samples passed to/from the audio driver is also sent in units of audio_frames. + */ + +/* required for swab() */ +#define _XOPEN_SOURCE 500 +/* required for FNDELAY decl */ +#define _BSD_SOURCE 1 + +#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> +#if defined(__OpenBSD__) +#include <soundcard.h> +#elif defined(__FreeBSD__) +#include <machine/soundcard.h> +#else +#if defined(__linux__) +#include <linux/config.h> /* Check for DEVFS */ +#endif +#include <sys/soundcard.h> +#endif +#include <sys/ioctl.h> +#include <inttypes.h> + +#include "xine_internal.h" +#include "monitor.h" +#include "audio_out.h" +#include "resample.h" +#include "metronom.h" +#include "utils.h" + +#ifndef AFMT_S16_NE +# if defined(sparc) || defined(__sparc__) || defined(PPC) +/* Big endian machines */ +# define AFMT_S16_NE AFMT_S16_BE +# else +# define AFMT_S16_NE AFMT_S16_LE +# endif +#endif + +#ifndef AFMT_AC3 +# define AFMT_AC3 0x00000400 /* Dolby Digital AC3 */ +#endif + +#define AO_OUT_OSS_IFACE_VERSION 1 + +#define AUDIO_NUM_FRAGMENTS 15 +#define AUDIO_FRAGMENT_SIZE 8192 + +/* bufsize must be a multiple of 3 and 5 for 5.0 and 5.1 channel playback! */ +#define ZERO_BUF_SIZE 15360 + +#define GAP_TOLERANCE 5000 +#define MAX_GAP 90000 + +#ifdef CONFIG_DEVFS_FS +#define DSP_TEMPLATE "/dev/sound/dsp%d" +#else +#define DSP_TEMPLATE "/dev/dsp%d" +#endif + +/* + * open the audio device for writing to + */ +static int ao_open(ao_instance_t *self, + uint32_t bits, uint32_t rate, int mode) +{ + int result; + if(result=self->driver->open(self->driver,bits,rate,mode)<0) { + printf("open failed!\n"); + return -1; + }; +// self->frame_rate_factor = (double) self->output_frame_rate / (double) self->input_frame_rate; + self->mode = mode; + self->input_frame_rate = rate; + self->frames_in_buffer = 0; + self->audio_started = 0; + self->last_audio_vpts = 0; + + self->output_frame_rate=rate; + self->num_channels = self->driver->num_channels(self->driver); + + self->frame_rate_factor = (double) 1 / (double) 1; + self->audio_step = (uint32_t) 90000 * (uint32_t) 32768 + / self->input_frame_rate; + self->frames_per_kpts = self->output_frame_rate * self->num_channels * 2 * 1024 / 90000; + xprintf (VERBOSE|AUDIO, "audio_out : audio_step %d pts per 32768 frames\n", self->audio_step); + + self->metronom->set_audio_rate(self->metronom, self->audio_step); + + + return 1; +} + +static void ao_fill_gap (ao_instance_t *self, uint32_t pts_len) { + + int num_bytes ; + xprintf (VERBOSE|AUDIO, "audio_out : fill_gap\n"); + + if (pts_len > MAX_GAP) + pts_len = MAX_GAP; + num_bytes = pts_len * self->frames_per_kpts / 1024; + num_bytes = (num_bytes / (2*self->num_channels)) * (2*self->num_channels); + + if(self->mode == AO_CAP_MODE_AC3) return; /* FIXME */ + + printf ("audio_out: inserting %d 0-bytes to fill a gap of %d pts\n",num_bytes, pts_len); + + self->frames_in_buffer += num_bytes; + + while (num_bytes > 0) { + if (num_bytes > ZERO_BUF_SIZE) { + self->driver->write(self->driver, self->zero_space, ZERO_BUF_SIZE); + num_bytes -= ZERO_BUF_SIZE; + } else { + self->driver->write(self->driver, self->zero_space, num_bytes); + num_bytes = 0; + } + } +} + + + +static int ao_write(ao_instance_t *self, + int16_t* output_frames, uint32_t num_frames, + uint32_t pts_) +{ + uint32_t vpts, buffer_vpts; + int32_t gap; + int bDropPackage; + int pos; + + if (self->driver<0) + return 1; + + vpts = self->metronom->got_audio_samples (self->metronom, pts_, num_frames); + + xprintf (VERBOSE|AUDIO, "audio_out: got %d frames, vpts=%d pts=%d\n", + num_frames, vpts,pts_); + + if (vpts<self->last_audio_vpts) { + /* reject self */ + xprintf (VERBOSE|AUDIO, "audio_out: rejected frame vpts=%d, last_audio_vpts=%d\n", vpts,self->last_audio_vpts) + + return 1; + } + + self->last_audio_vpts = vpts; + + bDropPackage = 0; + + if ( self->audio_has_realtime || !self->audio_started ) { + + /* + * where, in the timeline is the "end" of the audio buffer at the moment? + */ + + buffer_vpts = self->metronom->get_current_time (self->metronom); + + if (self->audio_started) { + pos = self->driver->delay(self->driver); + } else + pos = 0; + if ( (self->mode==AO_CAP_MODE_AC3) && (pos>10) ) pos-=10; /* External AC3 decoder delay correction */ + + if (pos>self->frames_in_buffer) /* buffer ran dry */ + self->frames_in_buffer = pos; + + buffer_vpts += (self->frames_in_buffer - pos) * 1024 / self->frames_per_kpts; + + /* + * calculate gap: + */ + + gap = vpts - buffer_vpts; + xprintf (VERBOSE|AUDIO, "audio_out: buff=%d pos=%d buf_vpts=%d gap=%d\n", + self->frames_in_buffer, pos,buffer_vpts,gap); + + if (gap>GAP_TOLERANCE) { + ao_fill_gap (self, gap); + + /* keep xine responsive */ + + if (gap>MAX_GAP) + return 0; + + } else if (gap<-GAP_TOLERANCE) { + bDropPackage = 1; + xprintf (VERBOSE|AUDIO, "audio_out: audio package (vpts = %d %d)" + "dropped\n", vpts, gap); + } + + } /* has realtime */ + + /* + * resample and output frames + */ + if(self->mode == AO_CAP_MODE_AC3) bDropPackage=0; + + if (!bDropPackage) { + int num_output_frames = num_frames * (self->output_frame_rate) / self->input_frame_rate; + + if ((!self->do_resample) && (self->mode != AO_CAP_MODE_AC3)) { + xprintf (VERBOSE|AUDIO, "audio_out: writing without resampling\n"); + self->driver->write(self->driver, output_frames, + num_output_frames ); + } else switch (self->mode) { + case AO_CAP_MODE_MONO: + audio_out_resample_mono (output_frames, num_frames, + self->frame_buffer, num_output_frames); + self->driver->write(self->driver, self->frame_buffer, num_output_frames); + break; + case AO_CAP_MODE_STEREO: + audio_out_resample_stereo (output_frames, num_frames, + self->frame_buffer, num_output_frames); + self->driver->write(self->driver, self->frame_buffer, num_output_frames); + break; + case AO_CAP_MODE_4CHANNEL: + audio_out_resample_4channel (output_frames, num_frames, + self->frame_buffer, num_output_frames); + self->driver->write(self->driver, self->frame_buffer, num_output_frames); + break; + case AO_CAP_MODE_5CHANNEL: + audio_out_resample_5channel (output_frames, num_frames, + self->frame_buffer, num_output_frames); + self->driver->write(self->driver, self->frame_buffer, num_output_frames); + break; + case AO_CAP_MODE_5_1CHANNEL: + audio_out_resample_6channel (output_frames, num_frames, + self->frame_buffer, num_output_frames); + self->driver->write(self->driver, self->frame_buffer, num_output_frames); + break; + case AO_CAP_MODE_AC3: + num_output_frames = (num_frames+8)/4; + self->frame_buffer[0] = 0xf872; //spdif syncword + self->frame_buffer[1] = 0x4e1f; // ............. + self->frame_buffer[2] = 0x0001; // AC3 data + self->frame_buffer[3] = num_frames * 8; + self->frame_buffer[4] = 0x0b77; // AC3 syncwork already in output_frames + + // ac3 seems to be swabbed data + swab(output_frames,self->frame_buffer+4, num_frames ); + self->driver->write(self->driver, self->zero_space, 2); /* Prevents crackle at start. */ + self->driver->write(self->driver, self->frame_buffer, num_output_frames); + self->driver->write(self->driver, self->zero_space, 1534-num_output_frames); + num_output_frames=num_output_frames; + break; + } + + xprintf (AUDIO|VERBOSE, "audio_out :audio package written\n"); + + /* + * step values + */ + + self->frames_in_buffer += num_output_frames ; + self->audio_started = 1; + } + + return 1; + +} + + +static void ao_close(ao_instance_t *self) +{ + self->driver->close(self->driver); +} + +static uint32_t ao_get_capabilities (ao_instance_t *self) { + uint32_t result; + result=self->driver->get_capabilities(self->driver); + return result; +} + +ao_instance_t *ao_new_instance (ao_driver_t *driver, metronom_t *metronom) { + + ao_instance_t *self; + + self = xmalloc (sizeof (ao_instance_t)) ; + self->driver = driver; + self->metronom = metronom; + + self->open = ao_open; + self->write = ao_write; + self->close = ao_close; + self->get_capabilities = ao_get_capabilities; + self->audio_loop_running = 0; + self->frame_buffer = malloc (40000); + memset (self->frame_buffer, 0, 40000); + self->zero_space = malloc (ZERO_BUF_SIZE); + memset (self->zero_space, 0, ZERO_BUF_SIZE); + return self; +} + diff --git a/src/xine-engine/audio_out.h b/src/xine-engine/audio_out.h index c3e1fffbc..27b4c2f2d 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.8 2001/07/20 22:37:56 guenter Exp $ + * $Id: audio_out.h,v 1.9 2001/08/21 19:39:50 jcdutton Exp $ */ #ifndef HAVE_AUDIO_OUT_H #define HAVE_AUDIO_OUT_H @@ -37,13 +37,13 @@ extern "C" { #define AUDIO_OUT_IFACE_VERSION 1 /* - * ao_functions_s contains the functions every audio output + * ao_driver_s contains the driver every audio output * driver plugin has to implement. */ -typedef struct ao_functions_s ao_functions_t; +typedef struct ao_driver_s ao_driver_t; -struct ao_functions_s { +struct ao_driver_s { /* * @@ -52,12 +52,7 @@ struct ao_functions_s { * * See AO_CAP_* bellow. */ - uint32_t (*get_capabilities) (ao_functions_t *this); - - /* - * connect this driver to the xine engine - */ - void (*connect) (ao_functions_t *this, metronom_t *metronom); + uint32_t (*get_capabilities) (ao_driver_t *this); /* * open the driver and make it ready to receive audio data @@ -65,8 +60,21 @@ struct ao_functions_s { * * return value: <=0 : failure, 1 : ok */ + int (*open)(ao_driver_t *this, uint32_t bits, uint32_t rate, int mode); + + /* return the number of audio channels + */ + int (*num_channels)(ao_driver_t *self_gen); + + /* return the number of bytes per frame. + * A frame is equivalent to one sample being output on every audio channel. + */ + int (*bytes_per_frame)(ao_driver_t *self_gen); - int (*open)(ao_functions_t *this, uint32_t bits, uint32_t rate, int mode); + /* return the delay is frames measured by + * looking at pending samples in the audio output device + */ + int (*delay)(ao_driver_t *self_gen); /* * write audio data to output buffer @@ -76,24 +84,20 @@ struct ao_functions_s { * 0 => audio samples were not yet processed, * call write_audio_data with the _same_ samples again */ - - int (*write_audio_data)(ao_functions_t *this, - int16_t* audio_data, uint32_t num_samples, - uint32_t pts); + int (*write)(ao_driver_t *this, + int16_t* audio_data, uint32_t num_samples); /* * this is called when the decoder no longer uses the audio * output driver - the driver should get ready to get opened() again */ - - void (*close)(ao_functions_t *this); + void (*close)(ao_driver_t *this); /* * shut down this audio output driver plugin and * free all resources allocated */ - - void (*exit) (ao_functions_t *this); + void (*exit) (ao_driver_t *this); /* * Get, Set a property of audio driver. @@ -103,19 +107,82 @@ struct ao_functions_s { * * See AC_PROP_* bellow for available properties. */ - int (*get_property) (ao_functions_t *this, int property); + int (*get_property) (ao_driver_t *this, int property); - int (*set_property) (ao_functions_t *this, int property, int value); + int (*set_property) (ao_driver_t *this, int property, int value); }; +/* + * ao_instance_s contains the instance every audio decoder talks to + */ +typedef struct ao_instance_s ao_instance_t; + +struct ao_instance_s { + uint32_t (*get_capabilities) (ao_instance_t *this); /* for constants see below */ + + /* open display driver for video output */ + int (*open) (ao_instance_t *this, + uint32_t bits, uint32_t rate, int mode); + + /* + * write audio data to output buffer + * audio driver must sync sample playback with metronom + * return value: + * 1 => audio samples were processed ok + * 0 => audio samples were not yet processed, + * call write_audio_data with the _same_ samples again + */ + + int (*write)(ao_driver_t *this, + int16_t* audio_data, uint32_t num_frames, + uint32_t pts); + + /* audio driver is no longer used by decoder => close */ + void (*close) (ao_instance_t *self); + + /* called on xine exit */ + void (*exit) (ao_instance_t *this); + + /* private stuff */ + + ao_driver_t *driver; + metronom_t *metronom; + + int audio_loop_running; + pthread_t audio_thread; + int audio_step; /* pts per 32 768 samples (sample = #bytes/2) */ + int32_t frames_per_kpts; /* bytes per 1024/90000 sec */ + int32_t output_frame_rate, input_frame_rate; + double frame_rate_factor; + uint32_t num_channels; + uint32_t frames_in_buffer; /* a frame is equivalent to one sample in each channel. */ + int audio_started; + int audio_has_realtime; /* OSS driver supports real-time */ + uint32_t last_audio_vpts; + int resample_conf; + int do_resample; + int mode; + uint16_t *frame_buffer; + int16_t *zero_space; + int pts_per_half_frame; + int pts_per_frame; + + int num_frames_delivered; + int num_frames_skipped; + int num_frames_discarded; +}; +/* This initiates the audio_out sync routines + * found in ./src/xine-engine/audio_out.c + */ +ao_instance_t *ao_new_instance (ao_driver_t *driver, metronom_t *metronom) ; /* * to build a dynamic audio output plugin, - * you have to implement these functions: + * you have to implement these driver: * * - * ao_functions_t *init_audio_out_plugin (config_values_t *config) + * ao_driver_t *init_audio_out_plugin (config_values_t *config) * * init this plugin, check if device is available * diff --git a/src/xine-engine/load_plugins.c b/src/xine-engine/load_plugins.c index 619717545..56936d1a1 100644 --- a/src/xine-engine/load_plugins.c +++ b/src/xine-engine/load_plugins.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: load_plugins.c,v 1.37 2001/08/14 01:38:17 guenter Exp $ + * $Id: load_plugins.c,v 1.38 2001/08/21 19:39:50 jcdutton Exp $ * * * Load input/demux/audio_out/video_out/codec plugins @@ -713,11 +713,11 @@ char **xine_list_audio_output_plugins(void) { return plugin_ids; } -ao_functions_t *xine_load_audio_output_plugin(config_values_t *config, +ao_driver_t *xine_load_audio_output_plugin(config_values_t *config, char *id) { DIR *dir; - ao_functions_t *aod = NULL; + ao_driver_t *aod = NULL; dir = opendir (XINE_PLUGINDIR); @@ -757,7 +757,7 @@ ao_functions_t *xine_load_audio_output_plugin(config_values_t *config, if((initplug = dlsym(plugin, "init_audio_out_plugin")) != NULL) { - aod = (ao_functions_t *) initplug(config); + aod = (ao_driver_t *) initplug(config); if (aod) printf("load_plugins: audio output plugin %s successfully" diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index 83d1e4ebe..17fd9385b 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.44 2001/08/20 20:49:51 f1rmb Exp $ + * $Id: xine.c,v 1.45 2001/08/21 19:39:50 jcdutton Exp $ * * top-level xine functions * @@ -452,7 +452,7 @@ static void event_handler(xine_t *xine, event_t *event, void *data) { } xine_t *xine_init (vo_driver_t *vo, - ao_functions_t *ao, + ao_driver_t *ao, config_values_t *config, gui_stream_end_cb_t stream_end_cb, gui_get_next_mrl_cb_t get_next_mrl_cb, @@ -515,8 +515,9 @@ xine_t *xine_init (vo_driver_t *vo, video_decoder_init (this); if(ao) { - this->audio_out = ao; - this->audio_out->connect (this->audio_out, this->metronom); + this->audio_out = ao_new_instance (ao, this->metronom); +// this->audio_out = ao; +// this->audio_out->connect (this->audio_out, this->metronom); } audio_decoder_init (this); printf("xine_init returning\n"); diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h index 13fc9803b..8c91426e6 100644 --- a/src/xine-engine/xine_internal.h +++ b/src/xine-engine/xine_internal.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: xine_internal.h,v 1.38 2001/08/17 16:15:37 f1rmb Exp $ + * $Id: xine_internal.h,v 1.39 2001/08/21 19:39:50 jcdutton Exp $ * */ @@ -93,7 +93,7 @@ struct audio_decoder_s { int (*can_handle) (audio_decoder_t *this, int buf_type); - void (*init) (audio_decoder_t *this, ao_functions_t *audio_out); + void (*init) (audio_decoder_t *this, ao_instance_t *audio_out); void (*decode_data) (audio_decoder_t *this, buf_element_t *buf); @@ -167,7 +167,7 @@ struct xine_s { video_decoder_t *cur_video_decoder_plugin; int video_finished; - ao_functions_t *audio_out; + ao_instance_t *audio_out; fifo_buffer_t *audio_fifo; pthread_t audio_thread; audio_decoder_t *audio_decoder_plugins[DECODER_PLUGIN_MAX]; @@ -202,7 +202,7 @@ config_values_t *config_file_init (char *filename); */ xine_t *xine_init (vo_driver_t *vo, - ao_functions_t *ao, + ao_driver_t *ao, config_values_t *config, gui_stream_end_cb_t stream_end_cb, gui_get_next_mrl_cb_t get_next_mrl_cb, @@ -447,7 +447,7 @@ char **xine_list_audio_output_plugins (); * load a specific audio output plugin */ -ao_functions_t *xine_load_audio_output_plugin(config_values_t *config, char *id); +ao_driver_t *xine_load_audio_output_plugin(config_values_t *config, char *id); /** * @defgroup eventgroup Sending events |