diff options
Diffstat (limited to 'src/audio_out/audio_oss_out.c')
-rw-r--r-- | src/audio_out/audio_oss_out.c | 164 |
1 files changed, 140 insertions, 24 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); |