ao_sun.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 700 行 · 第 1/2 页
C
700 行
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 /* old audioio driver, cannot return list of supported rates */ return 44100; /* should be supported even on old ISA SB cards */#endif}static void setup_device_paths(void){ if (audio_dev == NULL) { if ((audio_dev = getenv("AUDIODEV")) == NULL) audio_dev = "/dev/audio"; } if (sun_mixer_device == NULL) { 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); } 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; } 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; 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){ // throw away buffered data in the audio driver's STREAMS queue if (immed) flush_audio(audio_fd); close(audio_fd);}// stop playing and empty buffers (for seeking/pause)static void reset(void){ 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(void){ 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(void){ 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(void){ 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 ioctl(audio_fd, AUDIO_GETINFO, &info);#if !defined (__OpenBSD__) && !defined(__NetBSD__) if (queued_bursts - info.play.eof > 2) return 0; return ao_data.outburst;#else return info.hiwat * info.blocksize - info.play.seek;#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(void){ 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 + =
减小字号Ctrl + -
显示快捷键?