Some typo fixes in svn-howto
[mplayer/glamo.git] / stream / stream_radio.c
blob2db3680d0fc9da92f189e3dd17a58ad95e899e36
1 /*
2 * Radio support
3 *
4 * Initially wrote by Vladimir Voroshilov <voroshil@univer.omsk.su>.
5 * Based on tv.c and tvi_v4l2.c code.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * Abilities:
23 * * Listening v4l compatible radio cards using line-in or
24 * similar cable
25 * * Grabbing audio data using -ao pcm or -dumpaudio
26 * (must be compiled with --enable-radio-capture).
28 #include "config.h"
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <sys/ioctl.h>
34 #include <errno.h>
35 #include <unistd.h>
37 #ifdef RADIO_BSDBT848_HDR
38 #include <sys/param.h>
39 #include RADIO_BSDBT848_HDR
41 #else // RADIO_BSDBT848_HDR
43 #include <linux/types.h>
45 #ifdef HAVE_RADIO_V4L2
46 #include <linux/videodev2.h>
47 #endif
49 #ifdef HAVE_RADIO_V4L
50 #include <linux/videodev.h>
51 #warning "V4L is deprecated and will be removed in future"
52 #endif
54 #endif // !RADIO_BSDBT848_HDR
57 #include "stream.h"
58 #include "libmpdemux/demuxer.h"
59 #include "m_struct.h"
60 #include "m_option.h"
61 #include "mp_msg.h"
62 #include "help_mp.h"
63 #include "stream_radio.h"
65 #ifdef USE_RADIO_CAPTURE
66 #include "audio_in.h"
68 #ifdef HAVE_SYS_SOUNDCARD_H
69 #include <sys/soundcard.h>
70 #else
71 #ifdef HAVE_SOUNDCARD_H
72 #include <soundcard.h>
73 #else
74 #include <linux/soundcard.h>
75 #endif
76 #endif
78 #endif
80 #define RADIO_DRIVER_UNKNOWN 0
81 #define RADIO_DRIVER_V4L 1
82 #define RADIO_DRIVER_V4L2 2
83 #define RADIO_DRIVER_BSDBT848 3
85 typedef struct radio_channels_s {
86 int index; ///< channel index in channels list
87 float freq; ///< frequency in MHz
88 char name[20]; ///< channel name
89 struct radio_channels_s * next;
90 struct radio_channels_s * prev;
91 } radio_channels_t;
93 #ifdef RADIO_BSDBT848_HDR
94 /** (device,string, "/dev/tuner0") name of radio device file */
95 char* radio_param_device="/dev/tuner0";
96 /** radio_param_freq_min (freq_min,float,87.5) minimal allowed frequency */
97 float radio_param_freq_min=87.50;
98 /** radio_param_freq_min (freq_min,float,108.0) maximal allowed frequency */
99 float radio_param_freq_max=108.00;
100 #else
101 /** (device,string, "/dev/radio0") name of radio device file */
102 char* radio_param_device="/dev/radio0";
103 #endif
104 /** (driver,string, "v4l2") radio driver (v4l,v4l2) */
105 char* radio_param_driver="default";
106 /** radio_param_channels (channels,string,NULL) channels list (see man page) */
107 char** radio_param_channels;
108 /** radio_param_volume (volume,number,100) initial volume for radio device */
109 int radio_param_volume=100;
110 /** radio_param_adevice (adevice,string,NULL) name of audio device file to grab data from */
111 char* radio_param_adevice;
112 /** radio_param_arate (arate,number,44100) audio framerate
113 (please also set -rawaudio rate parameter to the same value) */
114 int radio_param_arate=44100;
115 /** radio_param_achannels (achannels,number,2) number of audio channels */
116 int radio_param_achannels=2;
117 extern int demux_rawaudio_packs_per_sec;
119 static struct stream_priv_s {
120 /* if channels parameter exist here will be channel number otherwise - frequency */
121 float radio_param_freq_channel;
122 char* capture;
123 } stream_priv_dflts = {
125 NULL
128 typedef struct radio_priv_s {
129 int radio_fd; ///< radio device descriptor
130 int frac; ///< fraction value (see comment to init_frac)
131 radio_channels_t* radio_channel_list;
132 radio_channels_t* radio_channel_current;
133 float rangelow; ///< lowest tunable frequency in MHz
134 float rangehigh; ///< highest tunable frequency in MHz
135 int driver;
136 int old_snd_volume;
137 #ifdef USE_RADIO_CAPTURE
138 volatile int do_capture; ///< is capture enabled
139 audio_in_t audio_in;
140 unsigned char* audio_ringbuffer;
141 int audio_head; ///< start of meanfull data in ringbuffer
142 int audio_tail; ///< end of meanfull data in ringbuffer
143 int audio_buffer_size; ///< size of ringbuffer
144 int audio_cnt; ///< size of meanfull data inringbuffer
145 int audio_drop; ///< number of dropped bytes
146 int audio_inited;
147 #endif
148 } radio_priv_t;
150 #define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
151 static m_option_t stream_opts_fields[] = {
152 {"hostname", ST_OFF(radio_param_freq_channel), CONF_TYPE_FLOAT, 0, 0 ,0, NULL},
153 {"filename", ST_OFF(capture), CONF_TYPE_STRING, 0, 0 ,0, NULL},
154 { NULL, NULL, 0, 0, 0, 0, NULL }
157 static struct m_struct_st stream_opts = {
158 "radio",
159 sizeof(struct stream_priv_s),
160 &stream_priv_dflts,
161 stream_opts_fields
164 static void close_s(struct stream_st * stream);
165 #ifdef USE_RADIO_CAPTURE
166 static int clear_buffer(radio_priv_t* priv);
167 #endif
170 /*****************************************************************
171 * \brief parse radio_param_channels parameter and store result into list
172 * \param freq_channel if radio_param_channels!=NULL this mean channel number, otherwise - frequency
173 * \param pfreq selected frequency (from selected channel or from URL)
174 * \result STREAM_OK if success, STREAM_ERROR otherwise
176 * radio_param_channels (channels options) must be in the following format
177 * <frequency>-<name>,<frequency>-<name>,...
179 * '_' will be replaced with spaces.
181 * If radio_param_channels is not null, number in movie URL will be treated as
182 * channel position in channel list.
184 static int parse_channels(radio_priv_t* priv,float freq_channel,float* pfreq){
185 char** channels;
186 int i;
187 int channel = 0;
188 if (radio_param_channels){
189 /*parsing channels string*/
190 channels =radio_param_channels;
192 mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_ChannelNamesDetected);
193 priv->radio_channel_list = malloc(sizeof(radio_channels_t));
194 priv->radio_channel_list->index=1;
195 priv->radio_channel_list->next=NULL;
196 priv->radio_channel_list->prev=NULL;
197 priv->radio_channel_current = priv->radio_channel_list;
199 while (*channels) {
200 char* tmp = *(channels++);
201 char* sep = strchr(tmp,'-');
202 if (!sep) continue; // Wrong syntax, but mplayer should not crash
203 strlcpy(priv->radio_channel_current->name, sep + 1,sizeof(priv->radio_channel_current->name)-1);
205 sep[0] = '\0';
207 priv->radio_channel_current->freq=atof(tmp);
209 if ((priv->radio_channel_current->freq>priv->rangehigh)||(priv->radio_channel_current->freq<priv->rangelow))
210 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_WrongFreqForChannel,
211 priv->radio_channel_current->name);
213 while ((sep=strchr(priv->radio_channel_current->name, '_'))) sep[0] = ' ';
215 priv->radio_channel_current->next = malloc(sizeof(radio_channels_t));
216 priv->radio_channel_current->next->index = priv->radio_channel_current->index + 1;
217 priv->radio_channel_current->next->prev = priv->radio_channel_current;
218 priv->radio_channel_current->next->next = NULL;
219 priv->radio_channel_current = priv->radio_channel_current->next;
221 if (priv->radio_channel_current->prev)
222 priv->radio_channel_current->prev->next = NULL;
223 free(priv->radio_channel_current);
225 if (freq_channel)
226 channel = freq_channel;
227 else
228 channel = 1;
230 priv->radio_channel_current = priv->radio_channel_list;
231 for (i = 1; i < channel; i++)
232 if (priv->radio_channel_current->next)
233 priv->radio_channel_current = priv->radio_channel_current->next;
234 if (priv->radio_channel_current->index!=channel){
235 if (((float)((int)freq_channel))!=freq_channel)
236 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_WrongChannelNumberFloat,freq_channel);
237 else
238 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_WrongChannelNumberInt,(int)freq_channel);
239 return STREAM_ERROR;
241 mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_SelectedChannel, priv->radio_channel_current->index,
242 priv->radio_channel_current->name, priv->radio_channel_current->freq);
243 *pfreq=priv->radio_channel_current->freq;
244 }else{
245 if (freq_channel){
246 mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_FreqParameterDetected);
247 priv->radio_channel_list=malloc(sizeof(radio_channels_t));
248 priv->radio_channel_list->next=NULL;
249 priv->radio_channel_list->prev=NULL;
250 priv->radio_channel_list->index=1;
251 snprintf(priv->radio_channel_list->name,sizeof(priv->radio_channel_current->name)-1,"Freq: %.2f",freq_channel);
253 priv->radio_channel_current=priv->radio_channel_list;
254 *pfreq=freq_channel;
257 mp_msg(MSGT_RADIO, MSGL_DBG2, MSGTR_RADIO_DoneParsingChannels);
258 return STREAM_OK;
261 #ifdef HAVE_RADIO_V4L2
262 /*****************************************************************
263 * \brief get fraction value for using in set_frequency and get_frequency
264 * \return STREAM_OK if success, STREAM_ERROR otherwise
266 * V4L2_TUNER_CAP_LOW:
267 * unit=62.5Hz
268 * frac= 1MHz/unit=1000000/62.5 =16000
270 * otherwise:
271 * unit=62500Hz
272 * frac= 1MHz/unit=1000000/62500 =16
274 static int init_frac_v4l2(radio_priv_t* priv){
275 struct v4l2_tuner tuner;
277 memset(&tuner,0,sizeof(tuner));
278 tuner.index=0;
279 if (ioctl(priv->radio_fd, VIDIOC_G_TUNER, &tuner)<0){
280 mp_msg(MSGT_RADIO,MSGL_WARN,MSGTR_RADIO_GetTunerFailed,strerror(errno),priv->frac);
281 return STREAM_ERROR;
283 if(tuner.type!=V4L2_TUNER_RADIO){
284 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_NotRadioDevice,radio_param_device);
285 return STREAM_ERROR;
287 if(tuner.capability & V4L2_TUNER_CAP_LOW){
288 priv->frac=16000;
289 mp_msg(MSGT_RADIO,MSGL_DBG2,MSGTR_RADIO_TunerCapLowYes,priv->frac);
291 else{
292 priv->frac=16;
293 mp_msg(MSGT_RADIO,MSGL_DBG2,MSGTR_RADIO_TunerCapLowNo,priv->frac);
296 priv->rangelow=((float)tuner.rangelow)/priv->frac;
297 priv->rangehigh=((float)tuner.rangehigh)/priv->frac;
298 mp_msg(MSGT_RADIO,MSGL_V,MSGTR_RADIO_FreqRange,priv->rangelow,priv->rangehigh);
299 return STREAM_OK;
302 /*****************************************************************
303 * \brief tune card to given frequency
304 * \param frequency frequency in MHz
305 * \return STREAM_OK if success, STREAM_ERROR otherwise
307 static int set_frequency_v4l2(radio_priv_t* priv,float frequency){
308 struct v4l2_frequency freq;
310 memset(&freq,0,sizeof(freq));
311 freq.tuner=0;
312 freq.type=V4L2_TUNER_RADIO;
313 freq.frequency=frequency*priv->frac;
314 if(ioctl(priv->radio_fd,VIDIOC_S_FREQUENCY,&freq)<0){
315 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_SetFreqFailed,freq.frequency,
316 frequency,strerror(errno));
317 return STREAM_ERROR;
319 return STREAM_OK;
322 /*****************************************************************
323 * \brief get current tuned frequency from card
324 * \param frequency where to store frequency in MHz
325 * \return STREAM_OK if success, STREAM_ERROR otherwise
327 static int get_frequency_v4l2(radio_priv_t* priv,float* frequency){
328 struct v4l2_frequency freq;
329 memset(&freq,0,sizeof(freq));
330 if (ioctl(priv->radio_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
331 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_GetFreqFailed,strerror(errno));
332 return STREAM_ERROR;
334 *frequency=((float)freq.frequency)/priv->frac;
335 return STREAM_OK;
338 /*****************************************************************
339 * \brief set volume on radio card
340 * \param volume volume level (0..100)
341 * \return STREAM_OK if success, STREAM_ERROR otherwise
343 static void set_volume_v4l2(radio_priv_t* priv,int volume){
344 struct v4l2_queryctrl qctrl;
345 struct v4l2_control control;
347 /*arg must be between 0 and 100*/
348 if (volume > 100) volume = 100;
349 if (volume < 0) volume = 0;
351 memset(&control,0,sizeof(control));
352 control.id=V4L2_CID_AUDIO_MUTE;
353 control.value = (volume==0?1:0);
354 if (ioctl(priv->radio_fd, VIDIOC_S_CTRL, &control)<0){
355 mp_msg(MSGT_RADIO,MSGL_WARN,MSGTR_RADIO_SetMuteFailed,strerror(errno));
358 memset(&qctrl,0,sizeof(qctrl));
359 qctrl.id = V4L2_CID_AUDIO_VOLUME;
360 if (ioctl(priv->radio_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
361 mp_msg(MSGT_RADIO, MSGL_WARN, MSGTR_RADIO_QueryControlFailed,strerror(errno));
362 return;
365 memset(&control,0,sizeof(control));
366 control.id=V4L2_CID_AUDIO_VOLUME;
367 control.value=qctrl.minimum+volume*(qctrl.maximum-qctrl.minimum)/100;
368 if (ioctl(priv->radio_fd, VIDIOC_S_CTRL, &control) < 0) {
369 mp_msg(MSGT_RADIO, MSGL_WARN,MSGTR_RADIO_SetVolumeFailed,strerror(errno));
373 /*****************************************************************
374 * \brief get current volume from radio card
375 * \param volume where to store volume level (0..100)
376 * \return STREAM_OK if success, STREAM_ERROR otherwise
378 static int get_volume_v4l2(radio_priv_t* priv,int* volume){
379 struct v4l2_queryctrl qctrl;
380 struct v4l2_control control;
382 memset(&qctrl,0,sizeof(qctrl));
383 qctrl.id = V4L2_CID_AUDIO_VOLUME;
384 if (ioctl(priv->radio_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
385 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_QueryControlFailed,strerror(errno));
386 return STREAM_ERROR;
389 memset(&control,0,sizeof(control));
390 control.id=V4L2_CID_AUDIO_VOLUME;
391 if (ioctl(priv->radio_fd, VIDIOC_G_CTRL, &control) < 0) {
392 mp_msg(MSGT_RADIO, MSGL_ERR,MSGTR_RADIO_GetVolumeFailed,strerror(errno));
393 return STREAM_ERROR;
396 if (qctrl.maximum==qctrl.minimum)
397 *volume=qctrl.minimum;
398 else
399 *volume=100*(control.value-qctrl.minimum)/(qctrl.maximum-qctrl.minimum);
401 /*arg must be between 0 and 100*/
402 if (*volume > 100) *volume = 100;
403 if (*volume < 0) *volume = 0;
405 return STREAM_OK;
407 #endif //HAVE_RADIO_V4L2
408 #ifdef HAVE_RADIO_V4L
409 /*****************************************************************
410 * \brief get fraction value for using in set_frequency and get_frequency
411 * \return STREAM_OK if success, STREAM_ERROR otherwise
413 * V4L2_TUNER_CAP_LOW:
414 * unit=62.5Hz
415 * frac= 1MHz/unit=1000000/62.5 =16000
417 * otherwise:
418 * unit=62500Hz
419 * frac= 1MHz/unit=1000000/62500 =16
422 static int init_frac_v4l(radio_priv_t* priv){
423 struct video_tuner tuner;
424 memset(&tuner,0,sizeof(tuner));
425 if (ioctl(priv->radio_fd, VIDIOCGTUNER, &tuner) <0){
426 mp_msg(MSGT_RADIO,MSGL_WARN,MSGTR_RADIO_GetTunerFailed,strerror(errno),priv->frac);
427 return STREAM_ERROR;
429 if(tuner.flags & VIDEO_TUNER_LOW){
430 priv->frac=16000;
431 mp_msg(MSGT_RADIO,MSGL_DBG2,MSGTR_RADIO_TunerCapLowYes,priv->frac);
432 }else{
433 priv->frac=16;
434 mp_msg(MSGT_RADIO,MSGL_DBG2,MSGTR_RADIO_TunerCapLowNo,priv->frac);
437 priv->rangelow=((float)tuner.rangelow)/priv->frac;
438 priv->rangehigh=((float)tuner.rangehigh)/priv->frac;
439 mp_msg(MSGT_RADIO,MSGL_V,MSGTR_RADIO_FreqRange,priv->rangelow,priv->rangehigh);
441 return STREAM_OK;
444 /*****************************************************************
445 * \brief tune card to given frequency
446 * \param frequency frequency in MHz
447 * \return STREAM_OK if success, STREAM_ERROR otherwise
449 static int set_frequency_v4l(radio_priv_t* priv,float frequency){
450 __u32 freq;
451 freq=frequency*priv->frac;
452 if (ioctl(priv->radio_fd, VIDIOCSFREQ, &freq) < 0) {
453 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_SetFreqFailed,freq,frequency,strerror(errno));
454 return STREAM_ERROR;
456 return STREAM_OK;
458 /*****************************************************************
459 * \brief get current tuned frequency from card
460 * \param frequency where to store frequency in MHz
461 * \return STREAM_OK if success, STREAM_ERROR otherwise
463 static int get_frequency_v4l(radio_priv_t* priv,float* frequency){
464 __u32 freq;
465 if (ioctl(priv->radio_fd, VIDIOCGFREQ, &freq) < 0) {
466 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_GetFreqFailed,strerror(errno));
467 return STREAM_ERROR;
469 *frequency=((float)freq)/priv->frac;
470 return STREAM_OK;
473 /*****************************************************************
474 * \brief set volume on radio card
475 * \param volume volume level (0..100)
476 * \return STREAM_OK if success, STREAM_ERROR otherwise
478 static void set_volume_v4l(radio_priv_t* priv,int volume){
479 struct video_audio audio;
481 /*arg must be between 0 and 100*/
482 if (volume > 100) volume = 100;
483 if (volume < 0) volume = 0;
485 memset(&audio,0,sizeof(audio));
486 audio.flags = (volume==0?VIDEO_AUDIO_MUTE:0);
487 if (ioctl(priv->radio_fd, VIDIOCSAUDIO, &audio)<0){
488 mp_msg(MSGT_RADIO,MSGL_WARN,MSGTR_RADIO_SetMuteFailed,strerror(errno));
491 memset(&audio,0,sizeof(audio));
492 audio.flags = VIDEO_AUDIO_VOLUME;
493 audio.mode = VIDEO_SOUND_STEREO;
494 audio.audio = 0;
495 audio.volume = volume* (65535 / 100);
497 if (ioctl(priv->radio_fd, VIDIOCSAUDIO, &audio) < 0){
498 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_SetVolumeFailed,strerror(errno));
502 /*****************************************************************
503 * \brief get current volume from radio card
504 * \param volume where to store volume level (0..100)
505 * \return STREAM_OK if success, STREAM_ERROR otherwise
507 static int get_volume_v4l(radio_priv_t* priv,int* volume){
508 struct video_audio audio;
510 memset(&audio,0,sizeof(audio));
511 audio.audio=0;
512 if (ioctl(priv->radio_fd, VIDIOCGAUDIO, &audio) < 0){
513 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_GetVolumeFailed,strerror(errno));
514 return STREAM_ERROR;
517 if (audio.flags & VIDEO_AUDIO_VOLUME){
518 *volume=100*audio.volume/65535;
519 /*arg must be between 0 and 100*/
520 if (*volume > 100) *volume = 100;
521 if (*volume < 0) *volume = 0;
522 return STREAM_OK;
525 return STREAM_ERROR;
527 #endif //HAVE_RADIO_V4L
528 #ifdef RADIO_BSDBT848_HDR
529 /*****************************************************************
530 * \brief get fraction value for using in set_frequency and get_frequency
531 * \return STREAM_OK if success, STREAM_ERROR otherwise
533 * For *BSD BT848 frac=100
535 * Here is a coment from FreeBSD 5.2-RELEASE source code:
537 * * Tuner Notes:
538 * * Programming the tuner properly is quite complicated.
539 * * Here are some notes, based on a FM1246 data sheet for a PAL-I tuner.
540 * * The tuner (front end) covers 45.75 MHz - 855.25 MHz and an FM band of
541 * * 87.5 MHz to 108.0 MHz.
543 * Thus, frequency range is limited to 87.5-108.0, but you can change
544 * it, using freq_min and freq_max options
546 static int init_frac_bsdbt848(radio_priv_t* priv){
547 priv->frac=100;
548 priv->rangelow=radio_param_freq_min;
549 priv->rangehigh=radio_param_freq_max;
550 return STREAM_OK;
553 /*****************************************************************
554 * \brief tune card to given frequency
555 * \param frequency frequency in MHz
556 * \return STREAM_OK if success, STREAM_ERROR otherwise
558 static int set_frequency_bsdbt848(radio_priv_t* priv,float frequency){
559 unsigned int freq;
560 freq=frequency*priv->frac;
561 if(ioctl(priv->radio_fd,RADIO_SETFREQ,&freq)<0){
562 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_SetFreqFailed,freq, frequency, strerror(errno));
563 return STREAM_ERROR;
565 return STREAM_OK;
568 /*****************************************************************
569 * \brief get current tuned frequency from card
570 * \param frequency where to store frequency in MHz
571 * \return STREAM_OK if success, STREAM_ERROR otherwise
573 static int get_frequency_bsdbt848(radio_priv_t* priv,float* frequency){
574 unsigned int freq;
575 if (ioctl(priv->radio_fd, RADIO_GETFREQ, &freq) < 0) {
576 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_GetFreqFailed,strerror(errno));
577 return STREAM_ERROR;
579 *frequency=((float)freq)/priv->frac;
580 return STREAM_OK;
583 /*****************************************************************
584 * \brief set volume on radio card
585 * \param volume volume level (0..100)
586 * \return STREAM_OK if success, STREAM_ERROR otherwise
588 * *BSD BT848 does not have volume changing abilities, so
589 * we will just mute sound if volume=0 and unmute it otherwise.
591 static void set_volume_bsdbt848(radio_priv_t* priv,int volume){
592 int audio_flags;
594 /*arg must be between 0 and 100*/
595 if (volume > 100) volume = 100;
596 if (volume < 0) volume = 0;
598 audio_flags = (volume==0?AUDIO_MUTE:AUDIO_UNMUTE);
599 if (ioctl(priv->radio_fd, BT848_SAUDIO, &audio_flags)<0){
600 mp_msg(MSGT_RADIO,MSGL_WARN,MSGTR_RADIO_SetMuteFailed,strerror(errno));
604 /*****************************************************************
605 * \brief get current volume from radio card
606 * \param volume where to store volume level (0..100)
607 * \return previous STREAM_OK if success, STREAM_ERROR otherwise
609 * *BSD BT848 does not have volume changing abilities, so
610 * we will return 0 if sound is muted and 100 otherwise.
612 static int get_volume_bsdbt848(radio_priv_t* priv,int* volume){
613 int audio_flags;
615 if (ioctl(priv->radio_fd, BT848_GAUDIO, &audio_flags)<0){
616 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_GetVolumeFailed,strerror(errno));
617 return STREAM_ERROR;
620 if (audio_flags & AUDIO_MUTE)
621 *volume=0;
622 else
623 *volume=100;
625 return STREAM_OK;
627 #endif //RADIO_BSDBT848_HDR
629 static inline int init_frac(radio_priv_t* priv){
630 switch(priv->driver){
631 #ifdef HAVE_RADIO_V4L
632 case RADIO_DRIVER_V4L:
633 return init_frac_v4l(priv);
634 #endif
635 #ifdef HAVE_RADIO_V4L2
636 case RADIO_DRIVER_V4L2:
637 return init_frac_v4l2(priv);
638 #endif
639 #ifdef RADIO_BSDBT848_HDR
640 case RADIO_DRIVER_BSDBT848:
641 return init_frac_bsdbt848(priv);
642 #endif
644 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_DriverUnknownId,priv->driver);
645 return STREAM_ERROR;
647 static inline int set_frequency(radio_priv_t* priv,float frequency){
648 if ((frequency<priv->rangelow)||(frequency>priv->rangehigh)){
649 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_WrongFreq,frequency);
650 return STREAM_ERROR;
652 switch(priv->driver){
653 #ifdef HAVE_RADIO_V4L
654 case RADIO_DRIVER_V4L:
655 if(set_frequency_v4l(priv,frequency)!=STREAM_OK)
656 return STREAM_ERROR;
657 break;
658 #endif
659 #ifdef HAVE_RADIO_V4L2
660 case RADIO_DRIVER_V4L2:
661 if(set_frequency_v4l2(priv,frequency)!=STREAM_OK)
662 return STREAM_ERROR;
663 break;
664 #endif
665 #ifdef RADIO_BSDBT848_HDR
666 case RADIO_DRIVER_BSDBT848:
667 if(set_frequency_bsdbt848(priv,frequency)!=STREAM_OK)
668 return STREAM_ERROR;
669 break;
670 #endif
671 default:
672 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_DriverUnknownId,priv->driver);
673 return STREAM_ERROR;
675 #ifdef USE_RADIO_CAPTURE
676 if(clear_buffer(priv)!=STREAM_OK){
677 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_ClearBufferFailed,strerror(errno));
678 return STREAM_ERROR;
680 #endif
681 return STREAM_OK;
683 static inline int get_frequency(radio_priv_t* priv,float* frequency){
684 switch(priv->driver){
685 #ifdef HAVE_RADIO_V4L
686 case RADIO_DRIVER_V4L:
687 return get_frequency_v4l(priv,frequency);
688 #endif
689 #ifdef HAVE_RADIO_V4L2
690 case RADIO_DRIVER_V4L2:
691 return get_frequency_v4l2(priv,frequency);
692 #endif
693 #ifdef RADIO_BSDBT848_HDR
694 case RADIO_DRIVER_BSDBT848:
695 return get_frequency_bsdbt848(priv,frequency);
696 #endif
698 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_DriverUnknownId,priv->driver);
699 return STREAM_ERROR;
701 static inline void set_volume(radio_priv_t* priv,int volume){
702 switch(priv->driver){
703 #ifdef HAVE_RADIO_V4L
704 case RADIO_DRIVER_V4L:
705 set_volume_v4l(priv,volume);
706 return;
707 #endif
708 #ifdef HAVE_RADIO_V4L2
709 case RADIO_DRIVER_V4L2:
710 set_volume_v4l2(priv,volume);
711 return;
712 #endif
713 #ifdef RADIO_BSDBT848_HDR
714 case RADIO_DRIVER_BSDBT848:
715 set_volume_bsdbt848(priv,volume);
716 return;
717 #endif
719 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_DriverUnknownId,priv->driver);
721 static inline int get_volume(radio_priv_t* priv,int* volume){
722 switch(priv->driver){
723 #ifdef HAVE_RADIO_V4L
724 case RADIO_DRIVER_V4L:
725 return get_volume_v4l(priv,volume);
726 #endif
727 #ifdef HAVE_RADIO_V4L2
728 case RADIO_DRIVER_V4L2:
729 return get_volume_v4l2(priv,volume);
730 #endif
731 #ifdef RADIO_BSDBT848_HDR
732 case RADIO_DRIVER_BSDBT848:
733 return get_volume_bsdbt848(priv,volume);
734 #endif
736 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_DriverUnknownId,priv->driver);
737 return STREAM_ERROR;
741 #ifndef USE_RADIO_CAPTURE
742 /*****************************************************************
743 * \brief stub, if capture disabled at compile-time
744 * \return STREAM_OK
746 static inline int init_audio(radio_priv_t *priv){ return STREAM_OK;}
747 #else
748 /*****************************************************************
749 * \brief making buffer empty
750 * \return STREAM_OK if success, STREAM_ERROR otherwise
752 * when changing channel we must clear buffer to avoid large switching delay
754 static int clear_buffer(radio_priv_t* priv){
755 if (!priv->do_capture) return STREAM_OK;
756 priv->audio_tail = 0;
757 priv->audio_head = 0;
758 priv->audio_cnt=0;
759 memset(priv->audio_ringbuffer,0,priv->audio_in.blocksize);
760 return STREAM_OK;
762 /*****************************************************************
763 * \brief read next part of data into buffer
764 * \return -1 if error occured or no data available yet, otherwise - bytes read
765 * NOTE: audio device works in non-blocking mode
767 static int read_chunk(audio_in_t *ai, unsigned char *buffer)
769 int ret;
771 switch (ai->type) {
772 #if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X)
773 case AUDIO_IN_ALSA:
774 //device opened in non-blocking mode
775 ret = snd_pcm_readi(ai->alsa.handle, buffer, ai->alsa.chunk_size);
776 if (ret != ai->alsa.chunk_size) {
777 if (ret < 0) {
778 if (ret==-EAGAIN) return -1;
779 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio, snd_strerror(ret));
780 if (ret == -EPIPE) {
781 if (ai_alsa_xrun(ai) == 0) {
782 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_XRUNSomeFramesMayBeLeftOut);
783 } else {
784 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrFatalCannotRecover);
787 } else {
788 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_NotEnoughSamples);
790 return -1;
792 return ret;
793 #endif
794 #ifdef USE_OSS_AUDIO
795 case AUDIO_IN_OSS:
797 int bt=0;
799 we must return exactly blocksize bytes, so if we have got any bytes
800 at first call to read, we will loop untils get all blocksize bytes
801 otherwise we will return -1
803 while(bt<ai->blocksize){
804 //device opened in non-blocking mode
805 ret = read(ai->oss.audio_fd, buffer+bt, ai->blocksize-bt);
806 if (ret==ai->blocksize) return ret;
807 if (ret<0){
808 if (errno==EAGAIN && bt==0) return -1; //no data avail yet
809 if (errno==EAGAIN) { usleep(1000); continue;} //nilling buffer to blocksize size
810 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio, strerror(errno));
811 return -1;
813 bt+=ret;
815 return bt;
817 #endif
818 default:
819 return -1;
822 /*****************************************************************
823 * \brief grab next frame from audio device
824 * \parameter buffer - store buffer
825 * \parameter len - store buffer size in bytes
826 * \return number of bytes written into buffer
828 * grabs len (or less) bytes from ringbuffer into buffer
829 * if ringbuffer is empty waits until len bytes of data will be available
831 * priv->audio_cnt - size (in bytes) of ringbuffer's filled part
832 * priv->audio_drop - size (in bytes) of dropped data (if no space in ringbuffer)
833 * priv->audio_head - index of first byte in filled part
834 * priv->audio_tail - index of last byte in filled part
836 * NOTE: audio_tail always aligned by priv->audio_in.blocksize
837 * audio_head may NOT.
839 static int grab_audio_frame(radio_priv_t *priv, char *buffer, int len)
841 int i;
842 mp_msg(MSGT_RADIO, MSGL_DBG3, MSGTR_RADIO_BufferString,"grab_audio_frame",priv->audio_cnt,priv->audio_drop);
843 /* Cache buffer must be filled by some audio packets when playing starts.
844 Otherwise MPlayer will quit with EOF error.
845 Probably, there is need more carefull checking rather than simple 'for' loop
846 (something like timer or similar).
848 1000ms delay will happen only at first buffer filling. At next call function
849 just fills buffer until either buffer full or no data from driver available.
851 for (i=0;i<1000 && priv->audio_cnt<priv->audio_buffer_size; i++){
852 //read_chunk fills exact priv->blocksize bytes
853 if(read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail) < 0){
854 //sleppeing only when waiting first block to fill empty buffer
855 if (!priv->audio_cnt){
856 usleep(1000);
857 continue;
858 }else
859 break;
861 priv->audio_cnt+=priv->audio_in.blocksize;
862 priv->audio_tail = (priv->audio_tail+priv->audio_in.blocksize) % priv->audio_buffer_size;
864 if(priv->audio_cnt<len)
865 len=priv->audio_cnt;
866 memcpy(buffer, priv->audio_ringbuffer+priv->audio_head,len);
867 priv->audio_head = (priv->audio_head+len) % priv->audio_buffer_size;
868 priv->audio_cnt-=len;
869 return len;
871 /*****************************************************************
872 * \brief init audio device
873 * \return STREAM_OK if success, STREAM_ERROR otherwise
875 static int init_audio(radio_priv_t *priv)
877 int is_oss=1;
878 int seconds=2;
879 char* tmp;
880 if (priv->audio_inited) return 1;
882 /* do_capture==0 mplayer was not started with capture keyword, so disabling capture*/
883 if(!priv->do_capture)
884 return STREAM_OK;
886 if (!radio_param_adevice){
887 priv->do_capture=0;
888 return STREAM_OK;
891 priv->do_capture=1;
892 mp_msg(MSGT_RADIO,MSGL_V,MSGTR_RADIO_CaptureStarting);
893 #if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X)
894 while ((tmp = strrchr(radio_param_adevice, '='))){
895 tmp[0] = ':';
896 //radio_param_adevice looks like ALSA device name. Switching to ALSA
897 is_oss=0;
899 while ((tmp = strrchr(radio_param_adevice, '.')))
900 tmp[0] = ',';
901 #endif
903 if(audio_in_init(&priv->audio_in, is_oss?AUDIO_IN_OSS:AUDIO_IN_ALSA)<0){
904 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_AudioInInitFailed,strerror(errno));
907 audio_in_set_device(&priv->audio_in, radio_param_adevice);
908 audio_in_set_channels(&priv->audio_in, radio_param_achannels);
909 audio_in_set_samplerate(&priv->audio_in, radio_param_arate);
911 if (audio_in_setup(&priv->audio_in) < 0) {
912 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_AudioInSetupFailed, strerror(errno));
913 return STREAM_ERROR;
915 if(is_oss)
916 ioctl(priv->audio_in.oss.audio_fd, SNDCTL_DSP_NONBLOCK, 0);
917 #if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X)
918 else{
919 snd_pcm_nonblock(priv->audio_in.alsa.handle,1);
921 #endif
923 priv->audio_buffer_size = seconds*priv->audio_in.samplerate*priv->audio_in.channels*
924 priv->audio_in.bytes_per_sample+priv->audio_in.blocksize;
925 if (priv->audio_buffer_size < 256*priv->audio_in.blocksize)
926 priv->audio_buffer_size = 256*priv->audio_in.blocksize;
927 mp_msg(MSGT_RADIO, MSGL_V, MSGTR_RADIO_AudioBuffer,
928 priv->audio_buffer_size,priv->audio_in.blocksize);
929 /* start capture */
930 priv->audio_ringbuffer = calloc(1, priv->audio_buffer_size);
931 if (!priv->audio_ringbuffer) {
932 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_AllocateBufferFailed,priv->audio_in.blocksize, priv->audio_buffer_size, strerror(errno));
933 return STREAM_ERROR;
935 priv->audio_head = 0;
936 priv->audio_tail = 0;
937 priv->audio_cnt = 0;
938 priv->audio_drop = 0;
941 priv->audio_inited = 1;
943 return STREAM_OK;
945 #endif //USE_RADIO_CAPTURE
947 /*-------------------------------------------------------------------------
948 for call from mplayer.c
949 --------------------------------------------------------------------------*/
950 /*****************************************************************
951 * \brief public wrapper for get_frequency
952 * \parameter frequency pointer to float, which will contain frequency in MHz
953 * \return 1 if success,0 - otherwise
955 int radio_get_freq(struct stream_st *stream, float* frequency){
956 radio_priv_t* priv=(radio_priv_t*)stream->priv;
958 if (!frequency)
959 return 0;
960 if (get_frequency(priv,frequency)!=STREAM_OK){
961 return 0;
963 return 1;
965 /*****************************************************************
966 * \brief public wrapper for set_frequency
967 * \parameter frequency frequency in MHz
968 * \return 1 if success,0 - otherwise
970 int radio_set_freq(struct stream_st *stream, float frequency){
971 radio_priv_t* priv=(radio_priv_t*)stream->priv;
973 if (set_frequency(priv,frequency)!=STREAM_OK){
974 return 0;
976 if (get_frequency(priv,&frequency)!=STREAM_OK){
977 return 0;
979 mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_CurrentFreq,frequency);
980 return 1;
983 /*****************************************************************
984 * \brief tune current frequency by step_interval value
985 * \parameter step_interval increment value
986 * \return 1 if success,0 - otherwise
989 int radio_step_freq(struct stream_st *stream, float step_interval){
990 float frequency;
991 radio_priv_t* priv=(radio_priv_t*)stream->priv;
993 if (get_frequency(priv,&frequency)!=STREAM_OK)
994 return 0;
996 frequency+=step_interval;
997 if (frequency>priv->rangehigh)
998 frequency=priv->rangehigh;
999 if (frequency<priv->rangelow)
1000 frequency=priv->rangelow;
1002 return radio_set_freq(stream,frequency);
1004 /*****************************************************************
1005 * \brief step channel up or down
1006 * \parameter direction RADIO_CHANNEL_LOWER - go to prev channel,RADIO_CHANNEL_HIGHER - to next
1007 * \return 1 if success,0 - otherwise
1009 * if radio_param_channel is NULL function prints error message and does nothing, otherwise
1010 * changes channel to prev or next in list
1012 int radio_step_channel(struct stream_st *stream, int direction) {
1013 radio_priv_t* priv=(radio_priv_t*)stream->priv;
1015 if (priv->radio_channel_list) {
1016 switch (direction){
1017 case RADIO_CHANNEL_HIGHER:
1018 if (priv->radio_channel_current->next)
1019 priv->radio_channel_current = priv->radio_channel_current->next;
1020 else
1021 priv->radio_channel_current = priv->radio_channel_list;
1022 if(!radio_set_freq(stream,priv->radio_channel_current->freq))
1023 return 0;
1024 mp_msg(MSGT_RADIO, MSGL_V, MSGTR_RADIO_SelectedChannel,
1025 priv->radio_channel_current->index, priv->radio_channel_current->name,
1026 priv->radio_channel_current->freq);
1027 break;
1028 case RADIO_CHANNEL_LOWER:
1029 if (priv->radio_channel_current->prev)
1030 priv->radio_channel_current = priv->radio_channel_current->prev;
1031 else
1032 while (priv->radio_channel_current->next)
1033 priv->radio_channel_current = priv->radio_channel_current->next;
1034 if(!radio_set_freq(stream,priv->radio_channel_current->freq))
1035 return 0;
1036 mp_msg(MSGT_RADIO, MSGL_V, MSGTR_RADIO_SelectedChannel,
1037 priv->radio_channel_current->index, priv->radio_channel_current->name,
1038 priv->radio_channel_current->freq);
1039 break;
1041 }else
1042 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_ChangeChannelNoChannelList);
1043 return 1;
1046 /*****************************************************************
1047 * \brief change channel to one with given index
1048 * \parameter channel string, containing channel number
1049 * \return 1 if success,0 - otherwise
1051 * if radio_param_channel is NULL function prints error message and does nothing, otherwise
1052 * changes channel to given
1054 int radio_set_channel(struct stream_st *stream, char *channel) {
1055 radio_priv_t* priv=(radio_priv_t*)stream->priv;
1056 int i, channel_int;
1057 radio_channels_t* tmp;
1058 char* endptr;
1060 if (*channel=='\0')
1061 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_WrongChannelName,channel);
1063 if (priv->radio_channel_list) {
1064 channel_int = strtol(channel,&endptr,10);
1065 tmp = priv->radio_channel_list;
1066 if (*endptr!='\0'){
1067 //channel is not a number, so it contains channel name
1068 for ( ; tmp; tmp=tmp->next)
1069 if (!strncmp(channel,tmp->name,sizeof(tmp->name)-1))
1070 break;
1071 if (!tmp){
1072 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_WrongChannelName,channel);
1073 return 0;
1075 }else{
1076 for (i = 1; i < channel_int; i++)
1077 if (tmp->next)
1078 tmp = tmp->next;
1079 else
1080 break;
1081 if (tmp->index!=channel_int){
1082 mp_msg(MSGT_RADIO,MSGL_ERR,MSGTR_RADIO_WrongChannelNumberInt,channel_int);
1083 return 0;
1086 priv->radio_channel_current=tmp;
1087 mp_msg(MSGT_RADIO, MSGL_V, MSGTR_RADIO_SelectedChannel, priv->radio_channel_current->index,
1088 priv->radio_channel_current->name, priv->radio_channel_current->freq);
1089 if(!radio_set_freq(stream, priv->radio_channel_current->freq))
1090 return 0;
1091 } else
1092 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_ChangeChannelNoChannelList);
1093 return 1;
1096 /*****************************************************************
1097 * \brief get current channel's name
1098 * \return pointer to string, containing current channel's name
1100 * NOTE: return value may be NULL (e.g. when channel list not initialized)
1102 char* radio_get_channel_name(struct stream_st *stream){
1103 radio_priv_t* priv=(radio_priv_t*)stream->priv;
1104 if (priv->radio_channel_current) {
1105 return priv->radio_channel_current->name;
1107 return NULL;
1110 /*****************************************************************
1111 * \brief fills given buffer with audio data
1112 * \return number of bytes, written into buffer
1114 static int fill_buffer_s(struct stream_st *s, char* buffer, int max_len){
1115 radio_priv_t* priv=(radio_priv_t*)s->priv;
1116 int len=max_len;
1118 #ifdef USE_RADIO_CAPTURE
1119 if (priv->do_capture){
1120 len=grab_audio_frame(priv, buffer,max_len);
1122 else
1123 #endif
1124 memset(buffer,0,len);
1125 return len;
1128 /*****************************************************************
1129 * Stream initialization
1130 * \return STREAM_OK if success, STREAM_ERROR otherwise
1132 static int open_s(stream_t *stream,int mode, void* opts, int* file_format) {
1133 struct stream_priv_s* p=(struct stream_priv_s*)opts;
1134 radio_priv_t* priv;
1135 float frequency=0;
1137 if (strncmp("radio://",stream->url,8) != 0)
1138 return STREAM_UNSUPORTED;
1140 if(mode != STREAM_READ)
1141 return STREAM_UNSUPORTED;
1143 priv=malloc(sizeof(radio_priv_t));
1145 if (!priv)
1146 return STREAM_ERROR;
1149 memset(priv,0,sizeof(radio_priv_t));
1151 #ifdef USE_RADIO_CAPTURE
1152 if (p->capture && strncmp("capture",p->capture,7)==0)
1153 priv->do_capture=1;
1154 else
1155 priv->do_capture=0;
1156 #endif
1160 if (strncmp(radio_param_driver,"default",7)==0)
1161 #if defined(HAVE_RADIO_V4L2)
1162 priv->driver=RADIO_DRIVER_V4L2;
1163 #elif defined(RADIO_BSDBT848_HDR)
1164 priv->driver=RADIO_DRIVER_BSDBT848;
1165 #else
1166 priv->driver=RADIO_DRIVER_V4L;
1167 #endif
1168 else
1169 #ifdef HAVE_RADIO_V4L2
1170 if (strncmp(radio_param_driver,"v4l2",4)==0)
1171 priv->driver=RADIO_DRIVER_V4L2;
1172 else
1173 #endif
1174 #ifdef HAVE_RADIO_V4L
1175 if (strncmp(radio_param_driver,"v4l",3)==0)
1176 priv->driver=RADIO_DRIVER_V4L;
1177 else
1178 #endif
1179 #ifdef RADIO_BSDBT848_HDR
1180 if (strncmp(radio_param_driver,"bsdbt848",8)==0)
1181 priv->driver=RADIO_DRIVER_BSDBT848;
1182 else
1183 #endif
1184 priv->driver=RADIO_DRIVER_UNKNOWN;
1187 switch(priv->driver){
1188 case RADIO_DRIVER_V4L:
1189 mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_DriverV4L);
1190 break;
1191 case RADIO_DRIVER_V4L2:
1192 mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_DriverV4L2);
1193 break;
1194 case RADIO_DRIVER_BSDBT848:
1195 mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_DriverBSDBT848);
1196 break;
1197 default:
1198 mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_DriverUnknownStr,radio_param_driver);
1199 close_s(stream);
1200 return STREAM_ERROR;
1203 stream->type = STREAMTYPE_RADIO;
1204 /* using rawaudio demuxer */
1205 *file_format = DEMUXER_TYPE_RAWAUDIO;
1206 stream->flags = STREAM_READ;
1208 priv->radio_fd=-1;
1210 stream->start_pos=0;
1211 stream->end_pos=0;
1212 stream->priv=priv;
1213 stream->close=close_s;
1214 stream->fill_buffer=fill_buffer_s;
1216 priv->radio_fd = open(radio_param_device, O_RDONLY);
1217 if (priv->radio_fd < 0) {
1218 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_UnableOpenDevice,
1219 radio_param_device, strerror(errno));
1220 close_s(stream);
1221 return STREAM_ERROR;
1223 mp_msg(MSGT_RADIO, MSGL_V, MSGTR_RADIO_RadioDevice, priv->radio_fd,radio_param_device);
1224 fcntl(priv->radio_fd, F_SETFD, FD_CLOEXEC);
1226 get_volume(priv, &priv->old_snd_volume);
1227 set_volume(priv,0);
1229 if (init_frac(priv)!=STREAM_OK){
1230 close_s(stream);
1231 return STREAM_ERROR;
1234 if (parse_channels(priv,p->radio_param_freq_channel,&frequency)!=STREAM_OK){
1235 close_s(stream);
1236 return STREAM_ERROR;
1239 if ((frequency<priv->rangelow)||(frequency>priv->rangehigh)){
1240 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_WrongFreq,frequency);
1241 close_s(stream);
1242 return STREAM_ERROR;
1243 }else
1244 mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_UsingFreq,frequency);
1246 if(set_frequency(priv,frequency)!=STREAM_OK){
1247 close_s(stream);
1248 return STREAM_ERROR;
1252 if (init_audio(priv)!=STREAM_OK){
1253 close_s(stream);
1254 return STREAM_ERROR;
1257 #if defined(USE_RADIO_CAPTURE) && defined(USE_STREAM_CACHE)
1258 if(priv->do_capture){
1259 //5 second cache
1260 if(!stream_enable_cache(stream,5*priv->audio_in.samplerate*priv->audio_in.channels*
1261 priv->audio_in.bytes_per_sample,2*priv->audio_in.samplerate*priv->audio_in.channels*
1262 priv->audio_in.bytes_per_sample,priv->audio_in.blocksize)) {
1263 mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_StreamEnableCacheFailed,strerror(errno));
1264 close_s(stream);
1265 return STREAM_ERROR;
1268 #endif
1270 set_volume(priv,radio_param_volume);
1272 return STREAM_OK;
1275 /*****************************************************************
1276 * Close stream. Clear structures.
1278 static void close_s(struct stream_st * stream){
1279 radio_priv_t* priv=(radio_priv_t*)stream->priv;
1280 radio_channels_t * tmp;
1281 if (!priv) return;
1283 #ifdef USE_RADIO_CAPTURE
1284 if(priv->audio_ringbuffer){
1285 free(priv->audio_ringbuffer);
1286 priv->audio_ringbuffer=NULL;
1289 priv->do_capture=0;
1290 #endif
1292 while (priv->radio_channel_list) {
1293 tmp=priv->radio_channel_list;
1294 priv->radio_channel_list=priv->radio_channel_list->next;
1295 free(tmp);
1297 priv->radio_channel_current=NULL;
1298 priv->radio_channel_list=NULL;
1300 if (priv->radio_fd>0){
1301 set_volume(priv, priv->old_snd_volume);
1302 close(priv->radio_fd);
1305 free(priv);
1306 stream->priv=NULL;
1309 stream_info_t stream_info_radio = {
1310 "Radio stream",
1311 "Radio",
1312 "Vladimir Voroshilov",
1313 "In development",
1314 open_s,
1315 { "radio", NULL },
1316 &stream_opts,
1317 1 // Urls are an option string