/* * open the audio device for writing to * * Implicit assumptions about audio format (bits/rate/mode): * * bits == 16: We always get 16-bit samples in native endian format, * using signed linear encoding * * bits == 8: 8-bit samples use unsigned linear encoding, * other 8-bit formats (uLaw, aLaw, etc) are currently not supported * by xine */ static int ao_sun_open(ao_driver_t *this_gen, uint32_t bits, uint32_t rate, int mode) { sun_driver_t *this = (sun_driver_t *) this_gen; audio_info_t info; int pass; int ok; if (this->xine->verbosity >= XINE_VERBOSITY_LOG) printf ("audio_sun_out: ao_sun_open rate=%d, mode=%d\n", rate, mode); if ( (mode & this->capabilities) == 0 ) { if (this->xine->verbosity >= XINE_VERBOSITY_LOG) printf ("audio_sun_out: unsupported mode %08x\n", mode); return 0; } if (this->audio_fd >= 0) { if ( (mode == this->mode) && (rate == this->input_sample_rate) ) return this->output_sample_rate; close (this->audio_fd); } this->mode = mode; this->input_sample_rate = rate; this->frames_in_buffer = 0; /* * open audio device */ this->audio_fd = open(this->audio_dev, O_WRONLY|O_NONBLOCK); if(this->audio_fd < 0) { fprintf(stderr, "audio_sun_out: Opening audio device %s failed: %s\n", this->audio_dev, strerror(errno)); return 0; } /* We wanted non blocking open but now put it back to normal */ fcntl(this->audio_fd, F_SETFL, fcntl(this->audio_fd, F_GETFL) & ~O_NONBLOCK); /* * 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; } 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; } /* * format not supported? * retry with different encoding and/or sample rate */ } if (!ok) { fprintf(stderr, "audio_sun_out: Cannot configure audio device for " "%dhz, %d channel, %d bits: %s\n", rate, info.play.channels, bits, strerror(errno)); close(this->audio_fd); this->audio_fd = -1; return 0; } this->last_samplecnt = 0; this->output_sample_rate = info.play.sample_rate; this->num_channels = info.play.channels; this->bytes_per_frame = 1; if (info.play.channels == AUDIO_CHANNELS_STEREO) this->bytes_per_frame *= 2; if (info.play.precision == 16) this->bytes_per_frame *= 2; #if CS4231_WORKAROUND this->buf_len = 0; #endif /* printf ("audio_sun_out: audio rate : %d requested, %d provided by device/sec\n", this->input_sample_rate, this->output_sample_rate); */ if (this->xine->verbosity >= XINE_VERBOSITY_LOG) printf ("audio_sun_out: %d channels output\n",this->num_channels); return this->output_sample_rate; }
// open & setup audio device // return: 1=success 0=fail static int init(int rate,int channels,int format,int flags){ audio_info_t info; int pass; int ok; int convert_u8_s8; setup_device_paths(); if (enable_sample_timing == RTSC_UNKNOWN && !getenv("AO_SUN_DISABLE_SAMPLE_TIMING")) { enable_sample_timing = realtime_samplecounter_available(audio_dev); } mp_msg(MSGT_AO,MSGL_STATUS,"ao2: %d Hz %d chans %s [0x%X]\n", rate,channels,af_fmt2str_short(format),format); audio_fd=open(audio_dev, O_WRONLY); if(audio_fd<0){ mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SUN_CantOpenAudioDev, audio_dev, strerror(errno)); return 0; } if (af2sunfmt(format) == AUDIO_ENCODING_NONE) format = AF_FORMAT_S16_NE; for (ok = pass = 0; pass <= 5; pass++) { /* pass 6&7 not useful */ AUDIO_INITINFO(&info); info.play.encoding = af2sunfmt(ao_data.format = format); info.play.precision = (format==AF_FORMAT_S16_NE ? AUDIO_PRECISION_16 : AUDIO_PRECISION_8); info.play.channels = ao_data.channels = channels; info.play.sample_rate = ao_data.samplerate = rate; 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. */ #ifdef AUDIO_ENCODING_LINEAR8 if (info.play.encoding != AUDIO_ENCODING_LINEAR8) #endif continue; info.play.encoding = AUDIO_ENCODING_LINEAR; convert_u8_s8 = 1; } 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. */ if (!(info.play.sample_rate = find_close_samplerate_match(audio_fd, rate))) continue; /* * I'm not returning the correct sample rate in * |ao_data.samplerate|, to avoid software resampling. * * ao_data.samplerate = info.play.sample_rate; */ } if (pass & 4) { /* like "pass & 2", but use the highest supported sample rate */ if (!(info.play.sample_rate = ao_data.samplerate = find_highest_samplerate(audio_fd))) continue; } ok = ioctl(audio_fd, AUDIO_SETINFO, &info) >= 0; if (ok) { /* audio format accepted by audio driver */ break; } /* * format not supported? * retry with different encoding and/or sample rate */ } if (!ok) { char buf[128]; mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SUN_UnsupSampleRate, channels, af_fmt2str(format, buf, 128), rate); return 0; } if (convert_u8_s8) ao_data.format = AF_FORMAT_S8; bytes_per_sample = channels * info.play.precision / 8; ao_data.bps = byte_per_sec = bytes_per_sample * ao_data.samplerate; ao_data.outburst = byte_per_sec > 100000 ? 16384 : 8192; reset(); return 1; }