📄 ao_sun.c
字号:
if ((sun_mixer_device = mixer_device) == NULL || !sun_mixer_device[0]) { sun_mixer_device = malloc(strlen(audio_dev) + 4); strcpy(sun_mixer_device, audio_dev); strcat(sun_mixer_device, "ctl"); } } if (ao_subdevice) audio_dev = ao_subdevice;}// to set/get/query special features/parametersstatic int control(int cmd,void *arg){ switch(cmd){ case AOCONTROL_SET_DEVICE: audio_dev=(char*)arg; return CONTROL_OK; case AOCONTROL_QUERY_FORMAT: return CONTROL_TRUE; case AOCONTROL_GET_VOLUME: { int fd; if ( !sun_mixer_device ) /* control function is used before init? */ setup_device_paths(); fd=open( sun_mixer_device,O_RDONLY ); if ( fd != -1 ) { ao_control_vol_t *vol = (ao_control_vol_t *)arg; float volume; struct audio_info info; ioctl( fd,AUDIO_GETINFO,&info); volume = info.play.gain * 100. / AUDIO_MAX_GAIN; if ( info.play.balance == AUDIO_MID_BALANCE ) { vol->right = vol->left = volume; } else if ( info.play.balance < AUDIO_MID_BALANCE ) { vol->left = volume; vol->right = volume * info.play.balance / AUDIO_MID_BALANCE; } else { vol->left = volume * (AUDIO_RIGHT_BALANCE-info.play.balance) / AUDIO_MID_BALANCE; vol->right = volume; } close( fd ); return CONTROL_OK; } return CONTROL_ERROR; } case AOCONTROL_SET_VOLUME: { ao_control_vol_t *vol = (ao_control_vol_t *)arg; int fd; if ( !sun_mixer_device ) /* control function is used before init? */ setup_device_paths(); fd=open( sun_mixer_device,O_RDONLY ); if ( fd != -1 ) { struct audio_info info; float volume; AUDIO_INITINFO(&info); volume = vol->right > vol->left ? vol->right : vol->left; if ( volume != 0 ) { info.play.gain = volume * AUDIO_MAX_GAIN / 100; if ( vol->right == vol->left ) info.play.balance = AUDIO_MID_BALANCE; else info.play.balance = (vol->right - vol->left + volume) * AUDIO_RIGHT_BALANCE / (2*volume); }#if !defined (__OpenBSD__) && !defined (__NetBSD__) info.output_muted = (volume == 0);#endif ioctl( fd,AUDIO_SETINFO,&info ); close( fd ); return CONTROL_OK; } return CONTROL_ERROR; } } return CONTROL_UNKNOWN;}// open & setup audio device// return: 1=success 0=failstatic 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); } printf("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; } ioctl(audio_fd, AUDIO_DRAIN, 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;#ifdef __not_used__ /* * hmm, ao_data.buffersize is currently not used in this driver, do there's * no need to measure it */ if(ao_data.buffersize==-1){ // Measuring buffer size: void* data; ao_data.buffersize=0;#ifdef HAVE_AUDIO_SELECT data = malloc(ao_data.outburst); memset(data, format==AF_FORMAT_U8 ? 0x80 : 0, ao_data.outburst); while(ao_data.buffersize<0x40000){ fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(audio_fd,&rfds); tv.tv_sec=0; tv.tv_usec = 0; if(!select(audio_fd+1, NULL, &rfds, NULL, &tv)) break; write(audio_fd,data,ao_data.outburst); ao_data.buffersize+=ao_data.outburst; } free(data); if(ao_data.buffersize==0){ mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SUN_CantUseSelect); return 0; }#ifdef __svr4__ // remove the 0 bytes from the above ao_data.buffersize measurement from the // audio driver's STREAMS queue ioctl(audio_fd, I_FLUSH, FLUSHW);#endif ioctl(audio_fd, AUDIO_DRAIN, 0);#endif }#endif /* __not_used__ */ AUDIO_INITINFO(&info); info.play.samples = 0; info.play.eof = 0; info.play.error = 0; ioctl (audio_fd, AUDIO_SETINFO, &info); queued_bursts = 0; queued_samples = 0; return 1;}// close audio devicestatic void uninit(int immed){#ifdef __svr4__ // throw away buffered data in the audio driver's STREAMS queue if (immed) ioctl(audio_fd, I_FLUSH, FLUSHW);#endif close(audio_fd);}// stop playing and empty buffers (for seeking/pause)static void reset(){ audio_info_t info; uninit(1); audio_fd=open(audio_dev, O_WRONLY); if(audio_fd<0){ mp_msg(MSGT_AO, MSGL_FATAL, MSGTR_AO_SUN_CantReopenReset, strerror(errno)); return; } ioctl(audio_fd, AUDIO_DRAIN, 0); AUDIO_INITINFO(&info); info.play.encoding = af2sunfmt(ao_data.format); info.play.precision = (ao_data.format==AF_FORMAT_S16_NE ? AUDIO_PRECISION_16 : AUDIO_PRECISION_8); info.play.channels = ao_data.channels; info.play.sample_rate = ao_data.samplerate; info.play.samples = 0; info.play.eof = 0; info.play.error = 0; ioctl (audio_fd, AUDIO_SETINFO, &info); queued_bursts = 0; queued_samples = 0;}// stop playing, keep buffers (for pause)static void audio_pause(){ struct audio_info info; AUDIO_INITINFO(&info); info.play.pause = 1; ioctl(audio_fd, AUDIO_SETINFO, &info);}// resume playing, after audio_pause()static void audio_resume(){ struct audio_info info; AUDIO_INITINFO(&info); info.play.pause = 0; ioctl(audio_fd, AUDIO_SETINFO, &info);}// return: how many bytes can be played without blockingstatic int get_space(){ audio_info_t info; // check buffer#ifdef HAVE_AUDIO_SELECT { fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(audio_fd, &rfds); tv.tv_sec = 0; tv.tv_usec = 0; if(!select(audio_fd+1, NULL, &rfds, NULL, &tv)) return 0; // not block! }#endif#if !defined (__OpenBSD__) && !defined(__NetBSD__) ioctl(audio_fd, AUDIO_GETINFO, &info); if (queued_bursts - info.play.eof > 2) return 0;#endif#if defined(__NetBSD__) || defined(__OpenBSD__) ioctl(audio_fd, AUDIO_GETINFO, &info); return info.hiwat * info.blocksize - info.play.seek;#else return ao_data.outburst;#endif}// plays 'len' bytes of 'data'// it should round it down to outburst*n// return: number of bytes playedstatic int play(void* data,int len,int flags){ if (len < ao_data.outburst) return 0; len /= ao_data.outburst; len *= ao_data.outburst; len = write(audio_fd, data, len); if(len > 0) { queued_samples += len / bytes_per_sample; if (write(audio_fd,data,0) < 0) perror("ao_sun: send EOF audio record"); else queued_bursts ++; } return len;}// return: delay in seconds between first and last sample in bufferstatic float get_delay(){ audio_info_t info; ioctl(audio_fd, AUDIO_GETINFO, &info);#if defined (__OpenBSD__) || defined(__NetBSD__) return (float) info.play.seek/ (float)byte_per_sec ;#else if (info.play.samples && enable_sample_timing == RTSC_ENABLED) return (float)(queued_samples - info.play.samples) / (float)ao_data.samplerate; else return (float)((queued_bursts - info.play.eof) * ao_data.outburst) / (float)byte_per_sec;#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -