From 18f9e60c7e5e60657f416be2a0427ae8ee8267c8 Mon Sep 17 00:00:00 2001 From: Juergen Keil Date: Mon, 7 Oct 2002 14:14:30 +0000 Subject: - Sun audio output plugin is able to play 8-bit sound. Announce this in the driver's capabilities flag word. - Several samples from Mike Melanson's testlist didn't work with the sun audio plugin on Solaris SPARC using the "audiocs" driver, because the clips use sample rates not directly supported by the sun audio hardware (e.g. 22478 Hz or 22254 Hz; the Sun audio HW supports 22050 Hz) Sound from: FILM format/Cinepak video/PCM audio ftp://ftp.mplayerhq.hu/MPlayer/samples/FILM/ and VOC format/PCM audio http://dod.hpi.net/samples/10M1PB1.VOC.bz2 should work now. CVS patchset: 2799 CVS date: 2002/10/07 14:14:30 --- src/audio_out/audio_sun_out.c | 237 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 213 insertions(+), 24 deletions(-) diff --git a/src/audio_out/audio_sun_out.c b/src/audio_out/audio_sun_out.c index 797f91fa8..b481ced56 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.23 2002/09/11 18:19:53 jkeil Exp $ + * $Id: audio_sun_out.c,v 1.24 2002/10/07 14:14:30 jkeil Exp $ */ #ifdef HAVE_CONFIG_H @@ -32,6 +32,9 @@ #include #include #include +#if HAVE_SYS_MIXER_H +#include +#endif #include #include #include @@ -234,6 +237,149 @@ error: } +/* + * match the requested sample rate |sample_rate| against the + * sample rates supported by the audio device |dev|. Return + * a supported sample rate, it that sample rate is close to + * (< 1% difference) the requested rate; return 0 otherwise. + */ +static int +find_close_samplerate_match(int dev, int sample_rate) +{ +#if HAVE_SYS_MIXER_H + am_sample_rates_t *sr; + int i, num, err, best_err, best_rate; + + for (num = 16; num < 1024; num *= 2) { + sr = malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(num)); + if (!sr) + return 0; + sr->type = AUDIO_PLAY; + sr->flags = 0; + sr->num_samp_rates = num; + if (ioctl(dev, AUDIO_MIXER_GET_SAMPLE_RATES, sr)) { + free(sr); + return 0; + } + if (sr->num_samp_rates <= num) + break; + free(sr); + } + + if (sr->flags & MIXER_SR_LIMITS) { + /* + * HW can playback any rate between + * sr->samp_rates[0] .. sr->samp_rates[1] + */ + free(sr); + return 0; + } else { + /* HW supports fixed sample rates only */ + + best_err = 65535; + best_rate = 0; + + for (i = 0; i < sr->num_samp_rates; i++) { + err = abs(sr->samp_rates[i] - sample_rate); + if (err == 0) { + /* + * exact supported sample rate match, no need to + * retry something else + */ + best_rate = 0; + break; + } + if (err < best_err) { + best_err = err; + best_rate = sr->samp_rates[i]; + } + } + + free(sr); + + if (best_rate > 0 && 100*best_err < sample_rate) { + /* found a supported sample rate with <1% error? */ + return best_rate; + } + return 0; + } + +#else + int i, err; + int audiocs_rates[] = { + 5510, 6620, 8000, 9600, 11025, 16000, 18900, 22050, + 27420, 32000, 33075, 37800, 44100, 48000, 0 + }; + + for (i = 0; audiocs_rates[i]; i++) { + err = abs(audiocs_rates[i] - sample_rate); + if (err == 0) { + /* + * exact supported sample rate match, no need to + * retry something elise + */ + return 0; + } + if (100*err < audiocs_rates[i]) { + /* <1% error? */ + return audiocs_rates[i]; + } + } + + return 0; +#endif +} + + +/* + * return the highest sample rate supported by audio device |dev|. + */ +static int +find_highest_samplerate(int dev) +{ +#if HAVE_SYS_MIXER_H + am_sample_rates_t *sr; + int i, num, max_rate; + + for (num = 16; num < 1024; num *= 2) { + sr = malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(num)); + if (!sr) + return 0; + sr->type = AUDIO_PLAY; + sr->flags = 0; + sr->num_samp_rates = num; + if (ioctl(dev, AUDIO_MIXER_GET_SAMPLE_RATES, sr)) { + free(sr); + return 0; + } + if (sr->num_samp_rates <= num) + break; + free(sr); + } + + if (sr->flags & MIXER_SR_LIMITS) { + /* + * HW can playback any rate between + * sr->samp_rates[0] .. sr->samp_rates[1] + */ + max_rate = sr->samp_rates[1]; + } else { + /* HW supports fixed sample rates only */ + max_rate = 0; + for (i = 0; i < sr->num_samp_rates; i++) { + if (sr->samp_rates[i] > max_rate) + max_rate = sr->samp_rates[i]; + } + } + free(sr); + return max_rate; + +#else + return 44100; /* should be supported even on old ISA SB cards */ +#endif +} + + /* * open the audio device for writing to * @@ -251,6 +397,7 @@ static int ao_sun_open(xine_ao_driver_t *this_gen, { sun_driver_t *this = (sun_driver_t *) this_gen; audio_info_t info; + int pass; int ok; printf ("audio_sun_out: ao_sun_open rate=%d, mode=%d\n", rate, mode); @@ -278,7 +425,7 @@ static int ao_sun_open(xine_ao_driver_t *this_gen, this->audio_fd=open(this->audio_dev,O_WRONLY|O_NONBLOCK); if(this->audio_fd < 0) { - printf("audio_sun_out: Opening audio device %s: %s\n", + printf("audio_sun_out: Opening audio device %s failed: %s\n", this->audio_dev, strerror(errno)); return 0; } @@ -289,36 +436,75 @@ static int ao_sun_open(xine_ao_driver_t *this_gen, /* * configure audio device */ + for (ok = pass = 0; pass <= 5; pass++) { + + AUDIO_INITINFO(&info); + info.play.channels = (mode & AO_CAP_MODE_STEREO) + ? AUDIO_CHANNELS_STEREO + : AUDIO_CHANNELS_MONO; + info.play.precision = bits; + info.play.encoding = bits == 8 + ? AUDIO_ENCODING_LINEAR8 + : AUDIO_ENCODING_LINEAR; + info.play.sample_rate = this->input_sample_rate; + info.play.eof = 0; + info.play.samples = 0; + + this->convert_u8_s8 = 0; + + if (pass & 1) { + /* + * on some sun audio drivers, 8-bit unsigned LINEAR8 encoding is + * not supported, but 8-bit signed encoding is. + * + * Try S8, and if it works, use our own U8->S8 conversion before + * sending the samples to the sound driver. + */ + if (info.play.encoding != AUDIO_ENCODING_LINEAR8) + continue; + info.play.encoding = AUDIO_ENCODING_LINEAR; + this->convert_u8_s8 = 1; + } - AUDIO_INITINFO(&info); - info.play.channels = (mode & AO_CAP_MODE_STEREO) - ? AUDIO_CHANNELS_STEREO - : AUDIO_CHANNELS_MONO; - info.play.precision = bits; - info.play.encoding = bits == 8 - ? AUDIO_ENCODING_LINEAR8 - : AUDIO_ENCODING_LINEAR; - info.play.sample_rate = this->input_sample_rate; - info.play.eof = 0; - info.play.samples = 0; + if (pass & 2) { + /* + * on some sun audio drivers, only certain fixed sample rates are + * supported. + * + * In case the requested sample rate is very close to one of the + * supported rates, use the fixed supported rate instead. + * + * XXX: assuming the fixed supported rate works, should we + * lie with our return value and report the requested input + * sample rate, to avoid the software resample code? + */ + if (!(info.play.sample_rate = + find_close_samplerate_match(this->audio_fd, + this->input_sample_rate))) + continue; + } + + if (pass & 4) { + /* like "pass & 2", but use the highest supported sample rate */ + if (!(info.play.sample_rate = find_highest_samplerate(this->audio_fd))) + continue; + } + + if ((ok = ioctl(this->audio_fd, AUDIO_SETINFO, &info) >= 0)) { + /* audio format accepted by audio driver */ + break; + } - this->convert_u8_s8 = 0; - ok = ioctl(this->audio_fd, AUDIO_SETINFO, &info) >= 0; - if (!ok && info.play.encoding == AUDIO_ENCODING_LINEAR8) { /* - * Unsigned AUDIO_ENCODING_LINEAR8 not supported. - * Maybe signed AUDIO_ENCODING_LINEAR works? + * format not supported? + * retry with different encoding and/or sample rate */ - info.play.encoding = AUDIO_ENCODING_LINEAR; - ok = ioctl(this->audio_fd, AUDIO_SETINFO, &info) >= 0; - if (ok) this->convert_u8_s8 = 1; } if (!ok) { printf("audio_sun_out: Cannot configure audio device for " - "%dhz, %d channel, %d bits\n", - info.play.sample_rate, info.play.channels, - info.play.precision); + "%dhz, %d channel, %d bits: %s\n", + rate, info.play.channels, bits, strerror(errno)); close(this->audio_fd); this->audio_fd = -1; return 0; @@ -715,6 +901,9 @@ static void *init_audio_out_plugin (xine_t *xine, void *data) { this->capabilities |= AO_CAP_MODE_STEREO; printf ("stereo "); + this->capabilities |= AO_CAP_8BITS; + printf ("8bit "); + this->capabilities |= AO_CAP_PCM_VOL | AO_CAP_MUTE_VOL; printf ("\n"); -- cgit v1.2.3