📄 stream_radio.c
字号:
* unit=62500Hz * frac= 1MHz/unit=1000000/62500 =16 * */static int init_frac_v4l(radio_priv_t* priv){ struct video_tuner tuner; memset(&tuner,0,sizeof(tuner)); if (ioctl(priv->radio_fd, VIDIOCGTUNER, &tuner) <0){ mp_msg(MSGT_RADIO,MSGL_WARN,MSGTR_RADIO_GetTunerFailed,strerror(errno),priv->frac); return STREAM_ERROR; } if(tuner.flags & VIDEO_TUNER_LOW){ priv->frac=16000; mp_msg(MSGT_RADIO,MSGL_DBG2,MSGTR_RADIO_TunerCapLowYes,priv->frac); }else{ priv->frac=16; mp_msg(MSGT_RADIO,MSGL_DBG2,MSGTR_RADIO_TunerCapLowNo,priv->frac); } priv->rangelow=((float)tuner.rangelow)/priv->frac; priv->rangehigh=((float)tuner.rangehigh)/priv->frac; mp_msg(MSGT_RADIO,MSGL_V,MSGTR_RADIO_FreqRange,priv->rangelow,priv->rangehigh); return STREAM_OK;}/***************************************************************** * \brief tune card to given frequency * \param frequency frequency in MHz * \return STREAM_OK if success, STREAM_ERROR otherwise */static int set_frequency_v4l(radio_priv_t* priv,float frequency){ __u32 freq; freq=frequency*priv->frac; if (ioctl(priv->radio_fd, VIDIOCSFREQ, &freq) < 0) { mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_SetFreqFailed,freq,frequency,strerror(errno)); return STREAM_ERROR; } return STREAM_OK;}/***************************************************************** * \brief get current tuned frequency from card * \param frequency where to store frequency in MHz * \return STREAM_OK if success, STREAM_ERROR otherwise */static int get_frequency_v4l(radio_priv_t* priv,float* frequency){ __u32 freq; if (ioctl(priv->radio_fd, VIDIOCGFREQ, &freq) < 0) { mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_GetFreqFailed,strerror(errno)); return STREAM_ERROR; } *frequency=((float)freq)/priv->frac; return STREAM_OK;}/***************************************************************** * \brief set volume on radio card * \param volume volume level (0..100) * \return STREAM_OK if success, STREAM_ERROR otherwise */static void set_volume_v4l(radio_priv_t* priv,int volume){ struct video_audio audio; /*arg must be between 0 and 100*/ if (volume > 100) volume = 100; if (volume < 0) volume = 0; memset(&audio,0,sizeof(audio)); audio.flags = (volume==0?VIDEO_AUDIO_MUTE:0); if (ioctl(priv->radio_fd, VIDIOCSAUDIO, &audio)<0){ mp_msg(MSGT_RADIO,MSGL_WARN,MSGTR_RADIO_SetMuteFailed,strerror(errno)); } memset(&audio,0,sizeof(audio)); audio.flags = VIDEO_AUDIO_VOLUME; audio.mode = VIDEO_SOUND_STEREO; audio.audio = 0; audio.volume = volume* (65535 / 100); if (ioctl(priv->radio_fd, VIDIOCSAUDIO, &audio) < 0){ mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_SetVolumeFailed,strerror(errno)); }}/***************************************************************** * \brief get current volume from radio card * \param volume where to store volume level (0..100) * \return STREAM_OK if success, STREAM_ERROR otherwise */static int get_volume_v4l(radio_priv_t* priv,int* volume){ struct video_audio audio; memset(&audio,0,sizeof(audio)); audio.audio=0; if (ioctl(priv->radio_fd, VIDIOCGAUDIO, &audio) < 0){ mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_GetVolumeFailed,strerror(errno)); return STREAM_ERROR; } if (audio.flags & VIDEO_AUDIO_VOLUME){ *volume=100*audio.volume/65535; /*arg must be between 0 and 100*/ if (*volume > 100) *volume = 100; if (*volume < 0) *volume = 0; return STREAM_OK; } return STREAM_ERROR;}/* v4l driver info structure */static const radio_driver_t radio_driver_v4l={ "v4l", MSGTR_RADIO_DriverV4L, init_frac_v4l, set_volume_v4l, get_volume_v4l, set_frequency_v4l, get_frequency_v4l};#endif //HAVE_RADIO_V4L#ifdef HAVE_RADIO_BSDBT848/***************************************************************** * \brief get fraction value for using in set_frequency and get_frequency * \return STREAM_OK if success, STREAM_ERROR otherwise * * For *BSD BT848 frac=100 * * Here is a coment from FreeBSD 5.2-RELEASE source code: * * * Tuner Notes: * * Programming the tuner properly is quite complicated. * * Here are some notes, based on a FM1246 data sheet for a PAL-I tuner. * * The tuner (front end) covers 45.75 MHz - 855.25 MHz and an FM band of * * 87.5 MHz to 108.0 MHz. * * Thus, frequency range is limited to 87.5-108.0, but you can change * it, using freq_min and freq_max options*/static int init_frac_bsdbt848(radio_priv_t* priv){ priv->frac=100; priv->rangelow=priv->radio_param->freq_min; priv->rangehigh=priv->radio_param->freq_max; return STREAM_OK;}/***************************************************************** * \brief tune card to given frequency * \param frequency frequency in MHz * \return STREAM_OK if success, STREAM_ERROR otherwise */static int set_frequency_bsdbt848(radio_priv_t* priv,float frequency){ unsigned int freq; freq=frequency*priv->frac; if(ioctl(priv->radio_fd,RADIO_SETFREQ,&freq)<0){ mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_SetFreqFailed,freq, frequency, strerror(errno)); return STREAM_ERROR; } return STREAM_OK;}/***************************************************************** * \brief get current tuned frequency from card * \param frequency where to store frequency in MHz * \return STREAM_OK if success, STREAM_ERROR otherwise */static int get_frequency_bsdbt848(radio_priv_t* priv,float* frequency){ unsigned int freq; if (ioctl(priv->radio_fd, RADIO_GETFREQ, &freq) < 0) { mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_GetFreqFailed,strerror(errno)); return STREAM_ERROR; } *frequency=((float)freq)/priv->frac; return STREAM_OK;}/***************************************************************** * \brief set volume on radio card * \param volume volume level (0..100) * \return STREAM_OK if success, STREAM_ERROR otherwise * * *BSD BT848 does not have volume changing abilities, so * we will just mute sound if volume=0 and unmute it otherwise. */static void set_volume_bsdbt848(radio_priv_t* priv,int volume){ int audio_flags; /*arg must be between 0 and 100*/ if (volume > 100) volume = 100; if (volume < 0) volume = 0; audio_flags = (volume==0?AUDIO_MUTE:AUDIO_UNMUTE); if (ioctl(priv->radio_fd, BT848_SAUDIO, &audio_flags)<0){ mp_msg(MSGT_RADIO,MSGL_WARN,MSGTR_RADIO_SetMuteFailed,strerror(errno)); }}/***************************************************************** * \brief get current volume from radio card * \param volume where to store volume level (0..100) * \return previous STREAM_OK if success, STREAM_ERROR otherwise * * *BSD BT848 does not have volume changing abilities, so * we will return 0 if sound is muted and 100 otherwise. */static int get_volume_bsdbt848(radio_priv_t* priv,int* volume){ int audio_flags; if (ioctl(priv->radio_fd, BT848_GAUDIO, &audio_flags)<0){ mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_GetVolumeFailed,strerror(errno)); return STREAM_ERROR; } if (audio_flags & AUDIO_MUTE) *volume=0; else *volume=100; return STREAM_OK;}/* bsdbt848 driver info structure */static const radio_driver_t radio_driver_bsdbt848={ "bsdbt848", MSGTR_RADIO_DriverBSDBT848, init_frac_bsdbt848, set_volume_bsdbt848, get_volume_bsdbt848, set_frequency_bsdbt848, get_frequency_bsdbt848};#endif //HAVE_RADIO_BSDBT848static inline int init_frac(radio_priv_t* priv){ return priv->driver->init_frac(priv);}static inline int set_frequency(radio_priv_t* priv,float frequency){ if ((frequency<priv->rangelow)||(frequency>priv->rangehigh)){ mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_WrongFreq,frequency); return STREAM_ERROR; } if(priv->driver->set_frequency(priv,frequency)!=STREAM_OK) return STREAM_ERROR; #ifdef USE_RADIO_CAPTURE if(clear_buffer(priv)!=STREAM_OK){ mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_ClearBufferFailed,strerror(errno)); return STREAM_ERROR; }#endif return STREAM_OK;}static inline int get_frequency(radio_priv_t* priv,float* frequency){ return priv->driver->get_frequency(priv,frequency);}static inline void set_volume(radio_priv_t* priv,int volume){ priv->driver->set_volume(priv,volume);}static inline int get_volume(radio_priv_t* priv,int* volume){ return priv->driver->get_volume(priv,volume);}#ifndef USE_RADIO_CAPTURE/***************************************************************** * \brief stub, if capture disabled at compile-time * \return STREAM_OK */static inline int init_audio(radio_priv_t *priv){ return STREAM_OK;}#else/***************************************************************** * \brief making buffer empty * \return STREAM_OK if success, STREAM_ERROR otherwise * * when changing channel we must clear buffer to avoid large switching delay */static int clear_buffer(radio_priv_t* priv){ if (!priv->do_capture) return STREAM_OK; priv->audio_tail = 0; priv->audio_head = 0; priv->audio_cnt=0; memset(priv->audio_ringbuffer,0,priv->audio_in.blocksize); return STREAM_OK;}/***************************************************************** * \brief read next part of data into buffer * \return -1 if error occured or no data available yet, otherwise - bytes read * NOTE: audio device works in non-blocking mode */static int read_chunk(audio_in_t *ai, unsigned char *buffer){ int ret; switch (ai->type) {#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) case AUDIO_IN_ALSA: //device opened in non-blocking mode ret = snd_pcm_readi(ai->alsa.handle, buffer, ai->alsa.chunk_size); if (ret != ai->alsa.chunk_size) { if (ret < 0) { if (ret==-EAGAIN) return -1; mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio, snd_strerror(ret)); if (ret == -EPIPE) { if (ai_alsa_xrun(ai) == 0) { mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_XRUNSomeFramesMayBeLeftOut); } else { mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrFatalCannotRecover); } } } else { mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_NotEnoughSamples); } return -1; } return ret;#endif#ifdef USE_OSS_AUDIO case AUDIO_IN_OSS: { int bt=0; /* we must return exactly blocksize bytes, so if we have got any bytes at first call to read, we will loop untils get all blocksize bytes otherwise we will return -1 */ while(bt<ai->blocksize){ //device opened in non-blocking mode ret = read(ai->oss.audio_fd, buffer+bt, ai->blocksize-bt); if (ret==ai->blocksize) return ret; if (ret<0){ if (errno==EAGAIN && bt==0) return -1; //no data avail yet if (errno==EAGAIN) { usleep(1000); continue;} //nilling buffer to blocksize size mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio, strerror(errno)); return -1; } bt+=ret; } return bt; }#endif default: return -1; }}/***************************************************************** * \brief grab next frame from audio device * \parameter buffer - store buffer * \parameter len - store buffer size in bytes * \return number of bytes written into buffer * * grabs len (or less) bytes from ringbuffer into buffer * if ringbuffer is empty waits until len bytes of data will be available * * priv->audio_cnt - size (in bytes) of ringbuffer's filled part * priv->audio_drop - size (in bytes) of dropped data (if no space in ringbuffer) * priv->audio_head - index of first byte in filled part * priv->audio_tail - index of last byte in filled part * * NOTE: audio_tail always aligned by priv->audio_in.blocksize * audio_head may NOT. */static int grab_audio_frame(radio_priv_t *priv, char *buffer, int len){ int i; mp_msg(MSGT_RADIO, MSGL_DBG3, MSGTR_RADIO_BufferString,"grab_audio_frame",priv->audio_cnt,priv->audio_drop); /* Cache buffer must be filled by some audio packets when playing starts. Otherwise MPlayer will quit with EOF error. Probably, there is need more carefull checking rather than simple 'for' loop (something like timer or similar). 1000ms delay will happen only at first buffer filling. At next call function just fills buffer until either buffer full or no data from driver available. */ for (i=0;i<1000 && priv->audio_cnt<priv->audio_buffer_size; i++){ //read_chunk fills exact priv->blocksize bytes if(read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail) < 0){ //sleppeing only when waiting first block to fill empty buffer if (!priv->audio_cnt){ usleep(1000); continue; }else break; } priv->audio_cnt+=priv->audio_in.blocksize; priv->audio_tail = (priv->audio_tail+priv->audio_in.blocksize) % priv->audio_buffer_size; } if(priv->audio_cnt<len) len=priv->audio_cnt; memcpy(buffer, priv->audio_ringbuffer+priv->audio_head,len); priv->audio_head = (priv->audio_head+len) % priv->audio_buffer_size; priv->audio_cnt-=len; return len;}/***************************************************************** * \brief init audio device * \return STREAM_OK if success, STREAM_ERROR otherwise */static int init_audio(radio_priv_t *priv){ int is_oss=1; int seconds=2; char* tmp; if (priv->audio_inited) return 1; /* do_capture==0 mplayer was not started with capture keyword, so disabling capture*/ if(!priv->do_capture) return STREAM_OK; if (!priv->radio_param->adevice){ priv->do_capture=0; return STREAM_OK; } priv->do_capture=1; mp_msg(MSGT_RADIO,MSGL_V,MSGTR_RADIO_CaptureStarting);#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) while ((tmp = strrchr(priv->radio_param->adevice, '='))){ tmp[0] = ':'; //adevice option looks like ALSA device name. Switching to ALSA is_oss=0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -