diff options
author | Guenter Bartsch <guenter@users.sourceforge.net> | 2001-05-27 23:48:12 +0000 |
---|---|---|
committer | Guenter Bartsch <guenter@users.sourceforge.net> | 2001-05-27 23:48:12 +0000 |
commit | e0dafdff5dc592fb47151894a6db3ce0ae045e26 (patch) | |
tree | 93b4a43ccfde5b0e7b3582ea176ca0b961cdb12f /src/audio_out | |
parent | 62386077f664574c0c2193bf0a9b408c1d55ee1a (diff) | |
download | xine-lib-e0dafdff5dc592fb47151894a6db3ce0ae045e26.tar.gz xine-lib-e0dafdff5dc592fb47151894a6db3ce0ae045e26.tar.bz2 |
mpg123 decoder plugin, 4/5-channel surround, ac3 pass-through (untested) and minor bugfixes
CVS patchset: 86
CVS date: 2001/05/27 23:48:12
Diffstat (limited to 'src/audio_out')
-rw-r--r-- | src/audio_out/audio_oss_out.c | 164 | ||||
-rw-r--r-- | src/audio_out/resample.c | 149 |
2 files changed, 288 insertions, 25 deletions
diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c index 0bb47ffbb..e8a9eacca 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.6 2001/05/08 11:31:39 f1rmb Exp $ + * $Id: audio_oss_out.c,v 1.7 2001/05/27 23:48:12 guenter Exp $ */ #ifdef HAVE_CONFIG_H @@ -60,6 +60,10 @@ # 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 @@ -82,6 +86,8 @@ typedef struct oss_functions_s { char audio_dev[20]; int audio_fd; + int capabilities; + int mode; int32_t output_sample_rate, input_sample_rate; int32_t output_rate_correction; @@ -111,23 +117,23 @@ static int ao_open(ao_functions_t *this_gen, { oss_functions_t *this = (oss_functions_t *) this_gen; int tmp; - int fsize; printf ("audio_oss_out: ao_open rate=%d, mode=%d\n", rate, mode); - if (((mode & AO_CAP_MODE_STEREO) == 0) && ((mode & AO_CAP_MODE_MONO) == 0)) { - printf ("OSS Driver only supports mono/stereo output modes at the moment\n"); + if ( (mode & this->capabilities) == 0 ) { + printf ("audio_oss_out: unsupported mode %08x\n", mode); return -1; } if (this->audio_fd > -1) { - if (rate == this->input_sample_rate) + if ( (mode == this->mode) && (rate == this->input_sample_rate) ) return 1; close (this->audio_fd); } - + + this->mode = mode; this->input_sample_rate = rate; this->bytes_in_buffer = 0; this->last_vpts = 0; @@ -157,8 +163,6 @@ static int ao_open(ao_functions_t *this_gen, tmp = (mode & AO_CAP_MODE_STEREO) ? 1 : 0; ioctl(this->audio_fd,SNDCTL_DSP_STEREO,&tmp); - this->num_channels = tmp+1; - xprintf (VERBOSE|AUDIO, "audio_oss_out: %d channels\n",this->num_channels); tmp = bits; ioctl(this->audio_fd,SNDCTL_DSP_SAMPLESIZE,&tmp); @@ -170,12 +174,47 @@ static int ao_open(ao_functions_t *this_gen, 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 + */ + + switch (mode) { + case AO_CAP_MODE_MONO: + tmp = 1; + ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); + this->num_channels = tmp; + break; + case AO_CAP_MODE_STEREO: + tmp = 2; + ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); + this->num_channels = tmp; + break; + case AO_CAP_MODE_4CHANNEL: + tmp = 4; + ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); + this->num_channels = tmp; + break; + case AO_CAP_MODE_5CHANNEL: + tmp = 5; + ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp); + this->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 ? */ + 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); @@ -183,6 +222,7 @@ static int ao_open(ao_functions_t *this_gen, * audio buffer size handling */ + /* WARNING: let's hope for good defaults here... tmp=0 ; fsize = AUDIO_FRAGMENT_SIZE; while (fsize>0) { @@ -196,7 +236,7 @@ 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); - + */ return 1; } @@ -231,7 +271,7 @@ static void ao_fill_gap (oss_functions_t *this, uint32_t pts_len) { int num_bytes = pts_len * this->bytes_per_kpts / 1024; - num_bytes = (num_bytes / 4) * 4; + num_bytes = (num_bytes / (2*this->num_channels)) * (2*this->num_channels); printf ("audio_oss_out: inserting %d 0-bytes to fill a gap of %d pts\n",num_bytes, pts_len); @@ -263,11 +303,11 @@ static void ao_write_audio_data(ao_functions_t *this_gen, int bDropPackage; uint16_t sample_buffer[8192]; - + if (this->audio_fd<0) return; - vpts = this->metronom->got_audio_samples (this->metronom, pts_, num_samples); + vpts = this->metronom->got_audio_samples (this->metronom, pts_, num_samples); xprintf (VERBOSE|AUDIO, "audio_oss_out: got %d samples, vpts=%d, last_vpts=%d\n", num_samples, vpts, this->last_vpts); @@ -306,6 +346,7 @@ static void ao_write_audio_data(ao_functions_t *this_gen, printf ("audio_oss_out: audio_vpts=%d <=> master_vpts=%d (diff=%d)\n", audio_vpts, master_vpts, diff); */ + /* * method 1 : resampling */ @@ -349,11 +390,34 @@ static void ao_write_audio_data(ao_functions_t *this_gen, if (!bDropPackage) { int num_output_samples = num_samples * (this->output_sample_rate + this->output_rate_correction) / this->input_sample_rate; - - audio_out_resample_stereo (output_samples, num_samples, + switch (this->mode) { + case AO_CAP_MODE_MONO: + audio_out_resample_mono (output_samples, num_samples, sample_buffer, num_output_samples); - - write(this->audio_fd, sample_buffer, num_output_samples * 2 * this->num_channels); + write(this->audio_fd, sample_buffer, num_output_samples * 2); + break; + case AO_CAP_MODE_STEREO: + audio_out_resample_stereo (output_samples, num_samples, + sample_buffer, num_output_samples); + write(this->audio_fd, sample_buffer, num_output_samples * 4); + break; + case AO_CAP_MODE_4CHANNEL: + audio_out_resample_4channel (output_samples, num_samples, + sample_buffer, num_output_samples); + write(this->audio_fd, sample_buffer, num_output_samples * 8); + break; + case AO_CAP_MODE_5CHANNEL: + audio_out_resample_5channel (output_samples, num_samples, + sample_buffer, num_output_samples); + write(this->audio_fd, sample_buffer, num_output_samples * 10); + break; + case AO_CAP_MODE_AC3: + + write(this->audio_fd, sample_buffer, num_output_samples * 2); + num_output_samples = num_samples; + + break; + } xprintf (AUDIO|VERBOSE, "audio_oss_out :audio package written\n"); @@ -386,8 +450,9 @@ static void ao_close(ao_functions_t *this_gen) this->audio_fd = -1; } -static uint32_t ao_get_capabilities (ao_functions_t *this) { - return AO_CAP_MODE_STEREO | AO_CAP_MODE_MONO; +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_connect (ao_functions_t *this_gen, metronom_t *metronom) { @@ -457,6 +522,7 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { int rate ; int devnum; int audio_fd; + int num_channels, status, arg; this = (oss_functions_t *) malloc (sizeof (oss_functions_t)); @@ -505,6 +571,19 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { } else xprintf (VERBOSE|AUDIO, " %s\n", this->audio_dev); + /* + * set up driver to reasonable values for capabilities tests + */ + + arg = AFMT_S16_NE; + status = ioctl(audio_fd, SOUND_PCM_SETFMT, &arg); + arg = 44100; + status = ioctl(audio_fd, SOUND_PCM_WRITE_RATE, &arg); + + /* + * get capabilities + */ + ioctl (audio_fd, SNDCTL_DSP_GETCAPS, &caps); if ((caps & DSP_CAP_REALTIME) > 0) { @@ -513,13 +592,50 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) { xprintf (VERBOSE|AUDIO, "audio_oss_out : realtime check: *FAILED* :-(((((\n\n"); } - /* - if ((caps & DSP_CAP_TRIGGER) > 0) { - xprintf (VERBOSE|AUDIO, "audio_out : trigger check : passed :-)\n"); - } else { - xprintf (VERBOSE|AUDIO, "audio_out : trigger check : *FAILED* :-(((((\n"); + this->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; + 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; + 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; + printf ("4-channel "); + } else + printf ("(4-channel not enabled in .xinerc) " ); + } + num_channels = 5; + 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; + printf ("5-channel "); + } else + printf ("(5-channel not enabled in .xinerc) " ); + } + + 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; + printf ("ac3-pass-through "); + } else + printf ("(ac3-pass-through not enabled in .xinerc)"); + } + + printf ("\n"); close (audio_fd); diff --git a/src/audio_out/resample.c b/src/audio_out/resample.c index 9f464b276..158b17c59 100644 --- a/src/audio_out/resample.c +++ b/src/audio_out/resample.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: resample.c,v 1.1 2001/04/24 20:53:00 f1rmb Exp $ + * $Id: resample.c,v 1.2 2001/05/27 23:48:12 guenter Exp $ */ #ifdef HAVE_CONFIG_H @@ -28,6 +28,37 @@ /* contributed by paul flinders */ +void audio_out_resample_mono(int16_t* input_samples, uint32_t in_samples, + int16_t* output_samples, uint32_t out_samples) +{ + int osample; + /* 16+16 fixed point math */ + uint32_t isample = 0; + uint32_t istep = (in_samples << 16)/out_samples; + +#ifdef VERBOSE + printf ("Audio : resample %d samples to %d\n", + in_samples, out_samples); +#endif + + for (osample = 0; osample < out_samples - 1; osample++) { + int s1; + int s2; + int16_t os; + uint32_t t = isample&0xffff; + + /* don't "optimize" the (isample >> 16)*2 to (isample >> 15) */ + s1 = input_samples[(isample >> 16)]; + s2 = input_samples[(isample >> 16)+1]; + + os = (s1 * (0x10000-t)+ s2 * t) >> 16; + output_samples[osample] = os; + + isample += istep; + } + output_samples[out_samples-1] = input_samples[in_samples-1]; +} + void audio_out_resample_stereo(int16_t* input_samples, uint32_t in_samples, int16_t* output_samples, uint32_t out_samples) { @@ -65,3 +96,119 @@ void audio_out_resample_stereo(int16_t* input_samples, uint32_t in_samples, output_samples[out_samples*2-1] = input_samples[in_samples*2-1]; } + +void audio_out_resample_4channel(int16_t* input_samples, uint32_t in_samples, + int16_t* output_samples, uint32_t out_samples) +{ + int osample; + /* 16+16 fixed point math */ + uint32_t isample = 0; + uint32_t istep = (in_samples << 16)/out_samples; + +#ifdef VERBOSE + printf ("Audio : resample %d samples to %d\n", + in_samples, out_samples); +#endif + + for (osample = 0; osample < out_samples - 1; osample++) { + int s1; + int s2; + int16_t os; + uint32_t t = isample&0xffff; + + /* don't "optimize" the (isample >> 16)*2 to (isample >> 15) */ + s1 = input_samples[(isample >> 16)*4]; + s2 = input_samples[(isample >> 16)*4+4]; + + os = (s1 * (0x10000-t)+ s2 * t) >> 16; + output_samples[osample * 4] = os; + + s1 = input_samples[(isample >> 16)*4+1]; + s2 = input_samples[(isample >> 16)*4+5]; + + os = (s1 * (0x10000-t)+ s2 * t) >> 16; + output_samples[(osample * 4 )+1] = os; + + s1 = input_samples[(isample >> 16)*4+2]; + s2 = input_samples[(isample >> 16)*4+6]; + + os = (s1 * (0x10000-t)+ s2 * t) >> 16; + output_samples[(osample * 4 )+2] = os; + + s1 = input_samples[(isample >> 16)*4+3]; + s2 = input_samples[(isample >> 16)*4+7]; + + os = (s1 * (0x10000-t)+ s2 * t) >> 16; + output_samples[(osample * 4 )+3] = os; + + isample += istep; + } + output_samples[out_samples*4-4] = input_samples[in_samples*4-4]; + output_samples[out_samples*4-3] = input_samples[in_samples*4-3]; + output_samples[out_samples*4-2] = input_samples[in_samples*4-2]; + output_samples[out_samples*4-1] = input_samples[in_samples*4-1]; + +} + + +void audio_out_resample_5channel(int16_t* input_samples, uint32_t in_samples, + int16_t* output_samples, uint32_t out_samples) +{ + int osample; + /* 16+16 fixed point math */ + uint32_t isample = 0; + uint32_t istep = (in_samples << 16)/out_samples; + +#ifdef VERBOSE + printf ("Audio : resample %d samples to %d\n", + in_samples, out_samples); +#endif + + for (osample = 0; osample < out_samples - 1; osample++) { + int s1; + int s2; + int16_t os; + uint32_t t = isample&0xffff; + + /* don't "optimize" the (isample >> 16)*2 to (isample >> 15) */ + s1 = input_samples[(isample >> 16)*5]; + s2 = input_samples[(isample >> 16)*5+5]; + + os = (s1 * (0x10000-t)+ s2 * t) >> 16; + output_samples[osample * 5] = os; + + s1 = input_samples[(isample >> 16)*5+1]; + s2 = input_samples[(isample >> 16)*5+6]; + + os = (s1 * (0x10000-t)+ s2 * t) >> 16; + output_samples[(osample * 5 )+1] = os; + + s1 = input_samples[(isample >> 16)*5+2]; + s2 = input_samples[(isample >> 16)*5+7]; + + os = (s1 * (0x10000-t)+ s2 * t) >> 16; + output_samples[(osample * 5 )+2] = os; + + s1 = input_samples[(isample >> 16)*5+3]; + s2 = input_samples[(isample >> 16)*5+8]; + + os = (s1 * (0x10000-t)+ s2 * t) >> 16; + output_samples[(osample * 5 )+3] = os; + + s1 = input_samples[(isample >> 16)*5+4]; + s2 = input_samples[(isample >> 16)*5+9]; + + os = (s1 * (0x10000-t)+ s2 * t) >> 16; + output_samples[(osample * 5 )+4] = os; + + isample += istep; + } + + output_samples[out_samples*5-5] = input_samples[in_samples*5-5]; + output_samples[out_samples*5-4] = input_samples[in_samples*5-4]; + output_samples[out_samples*5-3] = input_samples[in_samples*5-3]; + output_samples[out_samples*5-2] = input_samples[in_samples*5-2]; + output_samples[out_samples*5-1] = input_samples[in_samples*5-1]; +} + + |