📄 stream_radio.c
字号:
while ((tmp = strrchr(priv->radio_param->adevice, '.'))) tmp[0] = ',';#endif if(audio_in_init(&priv->audio_in, is_oss?AUDIO_IN_OSS:AUDIO_IN_ALSA)<0){ mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_AudioInInitFailed); } audio_in_set_device(&priv->audio_in, priv->radio_param->adevice); audio_in_set_channels(&priv->audio_in, priv->radio_param->achannels); audio_in_set_samplerate(&priv->audio_in, priv->radio_param->arate); if (audio_in_setup(&priv->audio_in) < 0) { mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_AudioInSetupFailed, strerror(errno)); return STREAM_ERROR; }#ifdef USE_OSS_AUDIO if(is_oss) ioctl(priv->audio_in.oss.audio_fd, SNDCTL_DSP_NONBLOCK, 0);#endif#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X) if(!is_oss) snd_pcm_nonblock(priv->audio_in.alsa.handle,1);#endif priv->audio_buffer_size = seconds*priv->audio_in.samplerate*priv->audio_in.channels* priv->audio_in.bytes_per_sample+priv->audio_in.blocksize; if (priv->audio_buffer_size < 256*priv->audio_in.blocksize) priv->audio_buffer_size = 256*priv->audio_in.blocksize; mp_msg(MSGT_RADIO, MSGL_V, MSGTR_RADIO_AudioBuffer, priv->audio_buffer_size,priv->audio_in.blocksize); /* start capture */ priv->audio_ringbuffer = calloc(1, priv->audio_buffer_size); if (!priv->audio_ringbuffer) { mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_AllocateBufferFailed,priv->audio_in.blocksize, priv->audio_buffer_size, strerror(errno)); return STREAM_ERROR; } priv->audio_head = 0; priv->audio_tail = 0; priv->audio_cnt = 0; priv->audio_drop = 0; priv->audio_inited = 1; return STREAM_OK;}#endif //USE_RADIO_CAPTURE/*------------------------------------------------------------------------- for call from mplayer.c--------------------------------------------------------------------------*//***************************************************************** * \brief public wrapper for get_frequency * \parameter frequency pointer to float, which will contain frequency in MHz * \return 1 if success,0 - otherwise */int radio_get_freq(struct stream_st *stream, float* frequency){ radio_priv_t* priv=(radio_priv_t*)stream->priv; if (!frequency) return 0; if (get_frequency(priv,frequency)!=STREAM_OK){ return 0; } return 1;}/***************************************************************** * \brief public wrapper for set_frequency * \parameter frequency frequency in MHz * \return 1 if success,0 - otherwise */int radio_set_freq(struct stream_st *stream, float frequency){ radio_priv_t* priv=(radio_priv_t*)stream->priv; if (set_frequency(priv,frequency)!=STREAM_OK){ return 0; } if (get_frequency(priv,&frequency)!=STREAM_OK){ return 0; } mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_CurrentFreq,frequency); return 1;}/***************************************************************** * \brief tune current frequency by step_interval value * \parameter step_interval increment value * \return 1 if success,0 - otherwise * */int radio_step_freq(struct stream_st *stream, float step_interval){ float frequency; radio_priv_t* priv=(radio_priv_t*)stream->priv; if (get_frequency(priv,&frequency)!=STREAM_OK) return 0; frequency+=step_interval; if (frequency>priv->rangehigh) frequency=priv->rangehigh; if (frequency<priv->rangelow) frequency=priv->rangelow; return radio_set_freq(stream,frequency);}/***************************************************************** * \brief step channel up or down * \parameter direction RADIO_CHANNEL_LOWER - go to prev channel,RADIO_CHANNEL_HIGHER - to next * \return 1 if success,0 - otherwise * * if channel parameter is NULL function prints error message and does nothing, otherwise * changes channel to prev or next in list */int radio_step_channel(struct stream_st *stream, int direction) { radio_priv_t* priv=(radio_priv_t*)stream->priv; if (priv->radio_channel_list) { switch (direction){ case RADIO_CHANNEL_HIGHER: if (priv->radio_channel_current->next) priv->radio_channel_current = priv->radio_channel_current->next; else priv->radio_channel_current = priv->radio_channel_list; if(!radio_set_freq(stream,priv->radio_channel_current->freq)) return 0; mp_msg(MSGT_RADIO, MSGL_V, MSGTR_RADIO_SelectedChannel, priv->radio_channel_current->index, priv->radio_channel_current->name, priv->radio_channel_current->freq); break; case RADIO_CHANNEL_LOWER: if (priv->radio_channel_current->prev) priv->radio_channel_current = priv->radio_channel_current->prev; else while (priv->radio_channel_current->next) priv->radio_channel_current = priv->radio_channel_current->next; if(!radio_set_freq(stream,priv->radio_channel_current->freq)) return 0; mp_msg(MSGT_RADIO, MSGL_V, MSGTR_RADIO_SelectedChannel, priv->radio_channel_current->index, priv->radio_channel_current->name, priv->radio_channel_current->freq); break; } }else mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_ChangeChannelNoChannelList); return 1;}/***************************************************************** * \brief change channel to one with given index * \parameter channel string, containing channel number * \return 1 if success,0 - otherwise * * if channel parameter is NULL function prints error message and does nothing, otherwise * changes channel to given */int radio_set_channel(struct stream_st *stream, char *channel) { radio_priv_t* priv=(radio_priv_t*)stream->priv; int i, channel_int; radio_channels_t* tmp; char* endptr; if (*channel=='\0') mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_WrongChannelName,channel); if (priv->radio_channel_list) { channel_int = strtol(channel,&endptr,10); tmp = priv->radio_channel_list; if (*endptr!='\0'){ //channel is not a number, so it contains channel name for ( ; tmp; tmp=tmp->next) if (!strncmp(channel,tmp->name,sizeof(tmp->name)-1)) break; if (!tmp){ mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_WrongChannelName,channel); return 0; } }else{ for (i = 1; i < channel_int; i++) if (tmp->next) tmp = tmp->next; else break; if (tmp->index!=channel_int){ mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_WrongChannelNumberInt,channel_int); return 0; } } priv->radio_channel_current=tmp; mp_msg(MSGT_RADIO, MSGL_V, MSGTR_RADIO_SelectedChannel, priv->radio_channel_current->index, priv->radio_channel_current->name, priv->radio_channel_current->freq); if(!radio_set_freq(stream, priv->radio_channel_current->freq)) return 0; } else mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_ChangeChannelNoChannelList); return 1;}/***************************************************************** * \brief get current channel's name * \return pointer to string, containing current channel's name * * NOTE: return value may be NULL (e.g. when channel list not initialized) */char* radio_get_channel_name(struct stream_st *stream){ radio_priv_t* priv=(radio_priv_t*)stream->priv; if (priv->radio_channel_current) { return priv->radio_channel_current->name; } return NULL;}/***************************************************************** * \brief fills given buffer with audio data * \return number of bytes, written into buffer */static int fill_buffer_s(struct stream_st *s, char* buffer, int max_len){ int len=max_len;#ifdef USE_RADIO_CAPTURE radio_priv_t* priv=(radio_priv_t*)s->priv; if (priv->do_capture){ len=grab_audio_frame(priv, buffer,max_len); } else#endif memset(buffer,0,len); return len;}/* order if significant! when no driver explicitly specified first available will be used */static const radio_driver_t* radio_drivers[]={#ifdef HAVE_RADIO_BSDBT848 &radio_driver_bsdbt848,#endif#ifdef HAVE_RADIO_V4L2 &radio_driver_v4l2,#endif#ifdef HAVE_RADIO_V4L &radio_driver_v4l,#endif 0};/***************************************************************** * Stream initialization * \return STREAM_OK if success, STREAM_ERROR otherwise */static int open_s(stream_t *stream,int mode, void* opts, int* file_format) { radio_priv_t* priv; float frequency=0; int i; if (strncmp("radio://",stream->url,8) != 0) return STREAM_UNSUPPORTED; if(mode != STREAM_READ) return STREAM_UNSUPPORTED; priv=calloc(1,sizeof(radio_priv_t)); if (!priv) return STREAM_ERROR; priv->radio_param=opts;#ifdef USE_RADIO_CAPTURE if (priv->radio_param->capture && strncmp("capture",priv->radio_param->capture,7)==0) priv->do_capture=1; else priv->do_capture=0;#endif if (strncmp(priv->radio_param->driver,"default",7)==0) priv->driver=radio_drivers[0]; else priv->driver=NULL; mp_msg(MSGT_RADIO,MSGL_V,MSGTR_RADIO_AvailableDrivers); for(i=0;radio_drivers[i];i++){ mp_msg(MSGT_RADIO,MSGL_V,"%s, ",radio_drivers[i]->name); if(strcmp(priv->radio_param->driver,radio_drivers[i]->name)==0) priv->driver=radio_drivers[i]; } mp_msg(MSGT_RADIO,MSGL_V,"\n"); if(priv->driver) mp_msg(MSGT_RADIO, MSGL_INFO, priv->driver->info); else{ mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_DriverUnknownStr,priv->radio_param->driver); close_s(stream); return STREAM_ERROR; } stream->type = STREAMTYPE_RADIO; /* using rawaudio demuxer */ *file_format = DEMUXER_TYPE_RAWAUDIO; stream->flags = STREAM_READ; priv->radio_fd=-1; stream->start_pos=0; stream->end_pos=0; stream->priv=priv; stream->close=close_s; stream->fill_buffer=fill_buffer_s; priv->radio_fd = open(priv->radio_param->device, O_RDONLY); if (priv->radio_fd < 0) { mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_UnableOpenDevice, priv->radio_param->device, strerror(errno)); close_s(stream); return STREAM_ERROR; } mp_msg(MSGT_RADIO, MSGL_V, MSGTR_RADIO_RadioDevice, priv->radio_fd,priv->radio_param->device); fcntl(priv->radio_fd, F_SETFD, FD_CLOEXEC); get_volume(priv, &priv->old_snd_volume); set_volume(priv,0); if (init_frac(priv)!=STREAM_OK){ close_s(stream); return STREAM_ERROR; }; if (parse_channels(priv,priv->radio_param->freq_channel,&frequency)!=STREAM_OK){ close_s(stream); return STREAM_ERROR; } if ((frequency<priv->rangelow)||(frequency>priv->rangehigh)){ mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_WrongFreq,frequency); close_s(stream); return STREAM_ERROR; }else mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_UsingFreq,frequency); if(set_frequency(priv,frequency)!=STREAM_OK){ close_s(stream); return STREAM_ERROR; } if (init_audio(priv)!=STREAM_OK){ close_s(stream); return STREAM_ERROR; }#if defined(USE_RADIO_CAPTURE) && defined(USE_STREAM_CACHE) if(priv->do_capture){ //5 second cache if(!stream_enable_cache(stream,5*priv->audio_in.samplerate*priv->audio_in.channels* priv->audio_in.bytes_per_sample,2*priv->audio_in.samplerate*priv->audio_in.channels* priv->audio_in.bytes_per_sample,priv->audio_in.blocksize)) { mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_StreamEnableCacheFailed,strerror(errno)); close_s(stream); return STREAM_ERROR; } }#endif set_volume(priv,priv->radio_param->volume); return STREAM_OK;}/***************************************************************** * Close stream. Clear structures. */static void close_s(struct stream_st * stream){ radio_priv_t* priv=(radio_priv_t*)stream->priv; radio_channels_t * tmp; if (!priv) return;#ifdef USE_RADIO_CAPTURE if(priv->audio_ringbuffer){ free(priv->audio_ringbuffer); priv->audio_ringbuffer=NULL; } priv->do_capture=0;#endif while (priv->radio_channel_list) { tmp=priv->radio_channel_list; priv->radio_channel_list=priv->radio_channel_list->next; free(tmp); } priv->radio_channel_current=NULL; priv->radio_channel_list=NULL; if (priv->radio_fd>0){ set_volume(priv, priv->old_snd_volume); close(priv->radio_fd); } if(priv->radio_param) m_struct_free(&stream_opts,priv->radio_param); free(priv); stream->priv=NULL;}stream_info_t stream_info_radio = { "Radio stream", "Radio", "Vladimir Voroshilov", "In development", open_s, { "radio", NULL }, &stream_opts, 1 // Urls are an option string};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -