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
23 * * Listening v4l compatible radio cards using line-in or
25 * * Grabbing audio data using -ao pcm or -dumpaudio
26 * (must be compiled with --enable-radio-capture).
33 #include <sys/ioctl.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>
50 #include <linux/videodev.h>
51 #warning "V4L is deprecated and will be removed in future"
54 #endif // !RADIO_BSDBT848_HDR
58 #include "libmpdemux/demuxer.h"
63 #include "stream_radio.h"
65 #ifdef USE_RADIO_CAPTURE
68 #ifdef HAVE_SYS_SOUNDCARD_H
69 #include <sys/soundcard.h>
71 #ifdef HAVE_SOUNDCARD_H
72 #include <soundcard.h>
74 #include <linux/soundcard.h>
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
;
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;
101 /** (device,string, "/dev/radio0") name of radio device file */
102 char* radio_param_device
="/dev/radio0";
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
;
123 } stream_priv_dflts
= {
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
137 #ifdef USE_RADIO_CAPTURE
138 volatile int do_capture
; ///< is capture enabled
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
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
= {
159 sizeof(struct stream_priv_s
),
164 static void close_s(struct stream_st
* stream
);
165 #ifdef USE_RADIO_CAPTURE
166 static int clear_buffer(radio_priv_t
* priv
);
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
){
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
;
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);
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
);
226 channel
= freq_channel
;
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
);
238 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_WrongChannelNumberInt
,(int)freq_channel
);
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
;
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
;
257 mp_msg(MSGT_RADIO
, MSGL_DBG2
, MSGTR_RADIO_DoneParsingChannels
);
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:
268 * frac= 1MHz/unit=1000000/62.5 =16000
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
));
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
);
283 if(tuner
.type
!=V4L2_TUNER_RADIO
){
284 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_NotRadioDevice
,radio_param_device
);
287 if(tuner
.capability
& V4L2_TUNER_CAP_LOW
){
289 mp_msg(MSGT_RADIO
,MSGL_DBG2
,MSGTR_RADIO_TunerCapLowYes
,priv
->frac
);
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
);
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
));
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
));
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
));
334 *frequency
=((float)freq
.frequency
)/priv
->frac
;
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
));
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
));
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
));
396 if (qctrl
.maximum
==qctrl
.minimum
)
397 *volume
=qctrl
.minimum
;
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;
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:
415 * frac= 1MHz/unit=1000000/62.5 =16000
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
);
429 if(tuner
.flags
& VIDEO_TUNER_LOW
){
431 mp_msg(MSGT_RADIO
,MSGL_DBG2
,MSGTR_RADIO_TunerCapLowYes
,priv
->frac
);
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
);
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
){
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
));
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
){
465 if (ioctl(priv
->radio_fd
, VIDIOCGFREQ
, &freq
) < 0) {
466 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_GetFreqFailed
,strerror(errno
));
469 *frequency
=((float)freq
)/priv
->frac
;
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
;
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
));
512 if (ioctl(priv
->radio_fd
, VIDIOCGAUDIO
, &audio
) < 0){
513 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_GetVolumeFailed
,strerror(errno
));
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;
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:
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
){
548 priv
->rangelow
=radio_param_freq_min
;
549 priv
->rangehigh
=radio_param_freq_max
;
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
){
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
));
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
){
575 if (ioctl(priv
->radio_fd
, RADIO_GETFREQ
, &freq
) < 0) {
576 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_GetFreqFailed
,strerror(errno
));
579 *frequency
=((float)freq
)/priv
->frac
;
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
){
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
){
615 if (ioctl(priv
->radio_fd
, BT848_GAUDIO
, &audio_flags
)<0){
616 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_GetVolumeFailed
,strerror(errno
));
620 if (audio_flags
& AUDIO_MUTE
)
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
);
635 #ifdef HAVE_RADIO_V4L2
636 case RADIO_DRIVER_V4L2
:
637 return init_frac_v4l2(priv
);
639 #ifdef RADIO_BSDBT848_HDR
640 case RADIO_DRIVER_BSDBT848
:
641 return init_frac_bsdbt848(priv
);
644 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_DriverUnknownId
,priv
->driver
);
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
);
652 switch(priv
->driver
){
653 #ifdef HAVE_RADIO_V4L
654 case RADIO_DRIVER_V4L
:
655 if(set_frequency_v4l(priv
,frequency
)!=STREAM_OK
)
659 #ifdef HAVE_RADIO_V4L2
660 case RADIO_DRIVER_V4L2
:
661 if(set_frequency_v4l2(priv
,frequency
)!=STREAM_OK
)
665 #ifdef RADIO_BSDBT848_HDR
666 case RADIO_DRIVER_BSDBT848
:
667 if(set_frequency_bsdbt848(priv
,frequency
)!=STREAM_OK
)
672 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_DriverUnknownId
,priv
->driver
);
675 #ifdef USE_RADIO_CAPTURE
676 if(clear_buffer(priv
)!=STREAM_OK
){
677 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_ClearBufferFailed
,strerror(errno
));
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
);
689 #ifdef HAVE_RADIO_V4L2
690 case RADIO_DRIVER_V4L2
:
691 return get_frequency_v4l2(priv
,frequency
);
693 #ifdef RADIO_BSDBT848_HDR
694 case RADIO_DRIVER_BSDBT848
:
695 return get_frequency_bsdbt848(priv
,frequency
);
698 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_DriverUnknownId
,priv
->driver
);
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
);
708 #ifdef HAVE_RADIO_V4L2
709 case RADIO_DRIVER_V4L2
:
710 set_volume_v4l2(priv
,volume
);
713 #ifdef RADIO_BSDBT848_HDR
714 case RADIO_DRIVER_BSDBT848
:
715 set_volume_bsdbt848(priv
,volume
);
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
);
727 #ifdef HAVE_RADIO_V4L2
728 case RADIO_DRIVER_V4L2
:
729 return get_volume_v4l2(priv
,volume
);
731 #ifdef RADIO_BSDBT848_HDR
732 case RADIO_DRIVER_BSDBT848
:
733 return get_volume_bsdbt848(priv
,volume
);
736 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_DriverUnknownId
,priv
->driver
);
741 #ifndef USE_RADIO_CAPTURE
742 /*****************************************************************
743 * \brief stub, if capture disabled at compile-time
746 static inline int init_audio(radio_priv_t
*priv
){ return STREAM_OK
;}
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;
759 memset(priv
->audio_ringbuffer
,0,priv
->audio_in
.blocksize
);
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
)
772 #if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X)
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
) {
778 if (ret
==-EAGAIN
) return -1;
779 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio
, snd_strerror(ret
));
781 if (ai_alsa_xrun(ai
) == 0) {
782 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_MPDEMUX_AUDIOIN_XRUNSomeFramesMayBeLeftOut
);
784 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_MPDEMUX_AUDIOIN_ErrFatalCannotRecover
);
788 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_MPDEMUX_AUDIOIN_NotEnoughSamples
);
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
;
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
));
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
)
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
){
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
)
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
;
871 /*****************************************************************
872 * \brief init audio device
873 * \return STREAM_OK if success, STREAM_ERROR otherwise
875 static int init_audio(radio_priv_t
*priv
)
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
)
886 if (!radio_param_adevice
){
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
, '='))){
896 //radio_param_adevice looks like ALSA device name. Switching to ALSA
899 while ((tmp
= strrchr(radio_param_adevice
, '.')))
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
));
916 ioctl(priv
->audio_in
.oss
.audio_fd
, SNDCTL_DSP_NONBLOCK
, 0);
917 #if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X)
919 snd_pcm_nonblock(priv
->audio_in
.alsa
.handle
,1);
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
);
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
));
935 priv
->audio_head
= 0;
936 priv
->audio_tail
= 0;
938 priv
->audio_drop
= 0;
941 priv
->audio_inited
= 1;
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
;
960 if (get_frequency(priv
,frequency
)!=STREAM_OK
){
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
){
976 if (get_frequency(priv
,&frequency
)!=STREAM_OK
){
979 mp_msg(MSGT_RADIO
, MSGL_INFO
, MSGTR_RADIO_CurrentFreq
,frequency
);
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
){
991 radio_priv_t
* priv
=(radio_priv_t
*)stream
->priv
;
993 if (get_frequency(priv
,&frequency
)!=STREAM_OK
)
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
) {
1017 case RADIO_CHANNEL_HIGHER
:
1018 if (priv
->radio_channel_current
->next
)
1019 priv
->radio_channel_current
= priv
->radio_channel_current
->next
;
1021 priv
->radio_channel_current
= priv
->radio_channel_list
;
1022 if(!radio_set_freq(stream
,priv
->radio_channel_current
->freq
))
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
);
1028 case RADIO_CHANNEL_LOWER
:
1029 if (priv
->radio_channel_current
->prev
)
1030 priv
->radio_channel_current
= priv
->radio_channel_current
->prev
;
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
))
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
);
1042 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_ChangeChannelNoChannelList
);
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
;
1057 radio_channels_t
* tmp
;
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
;
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))
1072 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_WrongChannelName
,channel
);
1076 for (i
= 1; i
< channel_int
; i
++)
1081 if (tmp
->index
!=channel_int
){
1082 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_WrongChannelNumberInt
,channel_int
);
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
))
1092 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_ChangeChannelNoChannelList
);
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
;
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
;
1118 #ifdef USE_RADIO_CAPTURE
1119 if (priv
->do_capture
){
1120 len
=grab_audio_frame(priv
, buffer
,max_len
);
1124 memset(buffer
,0,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
;
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
));
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)
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
;
1166 priv
->driver
=RADIO_DRIVER_V4L
;
1169 #ifdef HAVE_RADIO_V4L2
1170 if (strncmp(radio_param_driver
,"v4l2",4)==0)
1171 priv
->driver
=RADIO_DRIVER_V4L2
;
1174 #ifdef HAVE_RADIO_V4L
1175 if (strncmp(radio_param_driver
,"v4l",3)==0)
1176 priv
->driver
=RADIO_DRIVER_V4L
;
1179 #ifdef RADIO_BSDBT848_HDR
1180 if (strncmp(radio_param_driver
,"bsdbt848",8)==0)
1181 priv
->driver
=RADIO_DRIVER_BSDBT848
;
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
);
1191 case RADIO_DRIVER_V4L2
:
1192 mp_msg(MSGT_RADIO
, MSGL_INFO
, MSGTR_RADIO_DriverV4L2
);
1194 case RADIO_DRIVER_BSDBT848
:
1195 mp_msg(MSGT_RADIO
, MSGL_INFO
, MSGTR_RADIO_DriverBSDBT848
);
1198 mp_msg(MSGT_RADIO
, MSGL_INFO
, MSGTR_RADIO_DriverUnknownStr
,radio_param_driver
);
1200 return STREAM_ERROR
;
1203 stream
->type
= STREAMTYPE_RADIO
;
1204 /* using rawaudio demuxer */
1205 *file_format
= DEMUXER_TYPE_RAWAUDIO
;
1206 stream
->flags
= STREAM_READ
;
1210 stream
->start_pos
=0;
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
));
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
);
1229 if (init_frac(priv
)!=STREAM_OK
){
1231 return STREAM_ERROR
;
1234 if (parse_channels(priv
,p
->radio_param_freq_channel
,&frequency
)!=STREAM_OK
){
1236 return STREAM_ERROR
;
1239 if ((frequency
<priv
->rangelow
)||(frequency
>priv
->rangehigh
)){
1240 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_WrongFreq
,frequency
);
1242 return STREAM_ERROR
;
1244 mp_msg(MSGT_RADIO
, MSGL_INFO
, MSGTR_RADIO_UsingFreq
,frequency
);
1246 if(set_frequency(priv
,frequency
)!=STREAM_OK
){
1248 return STREAM_ERROR
;
1252 if (init_audio(priv
)!=STREAM_OK
){
1254 return STREAM_ERROR
;
1257 #if defined(USE_RADIO_CAPTURE) && defined(USE_STREAM_CACHE)
1258 if(priv
->do_capture
){
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
));
1265 return STREAM_ERROR
;
1270 set_volume(priv
,radio_param_volume
);
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
;
1283 #ifdef USE_RADIO_CAPTURE
1284 if(priv
->audio_ringbuffer
){
1285 free(priv
->audio_ringbuffer
);
1286 priv
->audio_ringbuffer
=NULL
;
1292 while (priv
->radio_channel_list
) {
1293 tmp
=priv
->radio_channel_list
;
1294 priv
->radio_channel_list
=priv
->radio_channel_list
->next
;
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
);
1309 stream_info_t stream_info_radio
= {
1312 "Vladimir Voroshilov",
1317 1 // Urls are an option string