stream_dvd: fix incorrect assumption about chapter count
[mplayer/glamo.git] / stream / stream_radio.c
blob7e53ccf38a379794b4e9f0bce77f1df2682bbfa8
1 /*
2 * radio support
4 * Abilities:
5 * * Listening v4l compatible radio cards using line-in or
6 * similar cable
7 * * Grabbing audio data using -ao pcm or -dumpaudio
8 * (must be compiled with --enable-radio-capture).
10 * Initially written by Vladimir Voroshilov <voroshil@univer.omsk.su>.
11 * Based on tv.c and tvi_v4l2.c code.
13 * This file is part of MPlayer.
15 * MPlayer is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * MPlayer is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include "config.h"
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <sys/ioctl.h>
35 #include <errno.h>
36 #include <unistd.h>
38 #ifdef CONFIG_RADIO_BSDBT848
39 #include <sys/param.h>
40 #ifdef IOCTL_BT848_H_NAME
41 #include IOCTL_BT848_H_NAME
42 #endif
44 #else /* CONFIG_RADIO_BSDBT848 */
46 #include <linux/types.h>
48 #ifdef CONFIG_RADIO_V4L2
49 #include <linux/videodev2.h>
50 #endif
52 #ifdef CONFIG_RADIO_V4L
53 #include <linux/videodev.h>
54 #warning "V4L is deprecated and will be removed in future"
55 #endif
57 #endif // !IOCTL_BT848_H_NAME
60 #include "stream.h"
61 #include "libmpdemux/demuxer.h"
62 #include "m_struct.h"
63 #include "m_option.h"
64 #include "mp_msg.h"
65 #include "stream_radio.h"
66 #include "libavutil/avstring.h"
68 #ifdef CONFIG_RADIO_CAPTURE
69 #include "audio_in.h"
71 #ifdef HAVE_SYS_SOUNDCARD_H
72 #include <sys/soundcard.h>
73 #else
74 #ifdef HAVE_SOUNDCARD_H
75 #include <soundcard.h>
76 #else
77 #include <linux/soundcard.h>
78 #endif
79 #endif
81 #endif
83 typedef struct radio_channels_s {
84 int index; ///< channel index in channels list
85 float freq; ///< frequency in MHz
86 char name[20]; ///< channel name
87 struct radio_channels_s * next;
88 struct radio_channels_s * prev;
89 } radio_channels_t;
91 /// default values for options
92 radio_param_t stream_radio_defaults={
93 #ifdef CONFIG_RADIO_BSDBT848
94 "/dev/tuner0", //device
95 87.50, //freq_min
96 108.00, //freq_max
97 #else
98 "/dev/radio0", //device;
99 #endif
100 "default", //driver
101 NULL, //channels
102 100, //volume
103 NULL, //adevice
104 44100, //arate
105 2, //achannels
106 0, //freq_channel
107 NULL, //capture
110 typedef struct radio_priv_s {
111 int radio_fd; ///< radio device descriptor
112 int frac; ///< fraction value (see comment to init_frac)
113 radio_channels_t* radio_channel_list;
114 radio_channels_t* radio_channel_current;
115 float rangelow; ///< lowest tunable frequency in MHz
116 float rangehigh; ///< highest tunable frequency in MHz
117 const struct radio_driver_s* driver;
118 int old_snd_volume;
119 #ifdef CONFIG_RADIO_CAPTURE
120 volatile int do_capture; ///< is capture enabled
121 audio_in_t audio_in;
122 unsigned char* audio_ringbuffer;
123 int audio_head; ///< start of meanfull data in ringbuffer
124 int audio_tail; ///< end of meanfull data in ringbuffer
125 int audio_buffer_size; ///< size of ringbuffer
126 int audio_cnt; ///< size of meanfull data inringbuffer
127 int audio_drop; ///< number of dropped bytes
128 int audio_initialized;
129 #endif
130 radio_param_t *radio_param;
131 } radio_priv_t;
133 typedef struct radio_driver_s {
134 char* name;
135 char* info;
136 int (*init_frac)(radio_priv_t* priv);
137 void (*set_volume)(radio_priv_t* priv,int volume);
138 int (*get_volume)(radio_priv_t* priv,int* volume);
139 int (*set_frequency)(radio_priv_t* priv,float frequency);
140 int (*get_frequency)(radio_priv_t* priv,float* frequency);
141 } radio_driver_t;
143 #define ST_OFF(f) M_ST_OFF(radio_param_t,f)
144 static const m_option_t stream_opts_fields[] = {
145 {"hostname", ST_OFF(freq_channel), CONF_TYPE_FLOAT, 0, 0 ,0, NULL},
146 {"filename", ST_OFF(capture), CONF_TYPE_STRING, 0, 0 ,0, NULL},
147 { NULL, NULL, 0, 0, 0, 0, NULL }
150 static const struct m_struct_st stream_opts = {
151 "radio",
152 sizeof(radio_param_t),
153 &stream_radio_defaults,
154 stream_opts_fields
157 static void close_s(struct stream *stream);
158 #ifdef CONFIG_RADIO_CAPTURE
159 static int clear_buffer(radio_priv_t* priv);
160 #endif
163 /*****************************************************************
164 * \brief parse channels parameter and store result into list
165 * \param freq_channel if channels!=NULL this mean channel number, otherwise - frequency
166 * \param pfreq selected frequency (from selected channel or from URL)
167 * \result STREAM_OK if success, STREAM_ERROR otherwise
169 * channels option must be in the following format
170 * <frequency>-<name>,<frequency>-<name>,...
172 * '_' will be replaced with spaces.
174 * If channels option is not null, number in movie URL will be treated as
175 * channel position in channel list.
177 static int parse_channels(radio_priv_t* priv,float freq_channel,float* pfreq){
178 char** channels;
179 int i;
180 int channel = 0;
181 if (priv->radio_param->channels){
182 /*parsing channels string*/
183 channels=priv->radio_param->channels;
185 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Radio channel names detected.\n");
186 priv->radio_channel_list = malloc(sizeof(radio_channels_t));
187 priv->radio_channel_list->index=1;
188 priv->radio_channel_list->next=NULL;
189 priv->radio_channel_list->prev=NULL;
190 priv->radio_channel_current = priv->radio_channel_list;
192 while (*channels) {
193 char* tmp = *(channels++);
194 char* sep = strchr(tmp,'-');
195 if (!sep) continue; // Wrong syntax, but mplayer should not crash
196 av_strlcpy(priv->radio_channel_current->name, sep + 1,sizeof(priv->radio_channel_current->name)-1);
198 sep[0] = '\0';
200 priv->radio_channel_current->freq=atof(tmp);
202 if ((priv->radio_channel_current->freq>priv->rangehigh)||(priv->radio_channel_current->freq<priv->rangelow))
203 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Wrong frequency for channel %s\n",
204 priv->radio_channel_current->name);
206 while ((sep=strchr(priv->radio_channel_current->name, '_'))) sep[0] = ' ';
208 priv->radio_channel_current->next = malloc(sizeof(radio_channels_t));
209 priv->radio_channel_current->next->index = priv->radio_channel_current->index + 1;
210 priv->radio_channel_current->next->prev = priv->radio_channel_current;
211 priv->radio_channel_current->next->next = NULL;
212 priv->radio_channel_current = priv->radio_channel_current->next;
214 if (priv->radio_channel_current->prev)
215 priv->radio_channel_current->prev->next = NULL;
216 free(priv->radio_channel_current);
218 if (freq_channel)
219 channel = freq_channel;
220 else
221 channel = 1;
223 priv->radio_channel_current = priv->radio_channel_list;
224 for (i = 1; i < channel; i++)
225 if (priv->radio_channel_current->next)
226 priv->radio_channel_current = priv->radio_channel_current->next;
227 if (priv->radio_channel_current->index!=channel){
228 if (((float)((int)freq_channel))!=freq_channel)
229 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Wrong channel number: %.2f\n",freq_channel);
230 else
231 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Wrong channel number: %d\n",(int)freq_channel);
232 return STREAM_ERROR;
234 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Selected channel: %d - %s (freq: %.2f)\n", priv->radio_channel_current->index,
235 priv->radio_channel_current->name, priv->radio_channel_current->freq);
236 *pfreq=priv->radio_channel_current->freq;
237 }else{
238 if (freq_channel){
239 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Radio frequency parameter detected.\n");
240 priv->radio_channel_list=malloc(sizeof(radio_channels_t));
241 priv->radio_channel_list->next=NULL;
242 priv->radio_channel_list->prev=NULL;
243 priv->radio_channel_list->index=1;
244 snprintf(priv->radio_channel_list->name,sizeof(priv->radio_channel_current->name)-1,"Freq: %.2f",freq_channel);
246 priv->radio_channel_current=priv->radio_channel_list;
247 *pfreq=freq_channel;
250 mp_tmsg(MSGT_RADIO, MSGL_DBG2, "[radio] Done parsing channels.\n");
251 return STREAM_OK;
254 #ifdef CONFIG_RADIO_V4L2
255 /*****************************************************************
256 * \brief get fraction value for using in set_frequency and get_frequency
257 * \return STREAM_OK if success, STREAM_ERROR otherwise
259 * V4L2_TUNER_CAP_LOW:
260 * unit=62.5Hz
261 * frac= 1MHz/unit=1000000/62.5 =16000
263 * otherwise:
264 * unit=62500Hz
265 * frac= 1MHz/unit=1000000/62500 =16
267 static int init_frac_v4l2(radio_priv_t* priv){
268 struct v4l2_tuner tuner;
270 memset(&tuner,0,sizeof(tuner));
271 tuner.index=0;
272 if (ioctl(priv->radio_fd, VIDIOC_G_TUNER, &tuner)<0){
273 mp_tmsg(MSGT_RADIO,MSGL_WARN,"[radio] Warning: ioctl get tuner failed: %s. Setting frac to %d.\n",strerror(errno),priv->frac);
274 return STREAM_ERROR;
276 if(tuner.type!=V4L2_TUNER_RADIO){
277 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] %s is no radio device!\n",priv->radio_param->device);
278 return STREAM_ERROR;
280 if(tuner.capability & V4L2_TUNER_CAP_LOW){
281 priv->frac=16000;
282 mp_tmsg(MSGT_RADIO,MSGL_DBG2,"[radio] tuner is low:yes frac=%d\n",priv->frac);
284 else{
285 priv->frac=16;
286 mp_tmsg(MSGT_RADIO,MSGL_DBG2,"[radio] tuner is low:no frac=%d\n",priv->frac);
289 priv->rangelow=((float)tuner.rangelow)/priv->frac;
290 priv->rangehigh=((float)tuner.rangehigh)/priv->frac;
291 mp_tmsg(MSGT_RADIO,MSGL_V,"[radio] Allowed frequency range is %.2f-%.2f MHz.\n",priv->rangelow,priv->rangehigh);
292 return STREAM_OK;
295 /*****************************************************************
296 * \brief tune card to given frequency
297 * \param frequency frequency in MHz
298 * \return STREAM_OK if success, STREAM_ERROR otherwise
300 static int set_frequency_v4l2(radio_priv_t* priv,float frequency){
301 struct v4l2_frequency freq;
303 memset(&freq,0,sizeof(freq));
304 freq.tuner=0;
305 freq.type=V4L2_TUNER_RADIO;
306 freq.frequency=frequency*priv->frac;
307 if(ioctl(priv->radio_fd,VIDIOC_S_FREQUENCY,&freq)<0){
308 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl set frequency 0x%x (%.2f) failed: %s\n",freq.frequency,
309 frequency,strerror(errno));
310 return STREAM_ERROR;
312 return STREAM_OK;
315 /*****************************************************************
316 * \brief get current tuned frequency from card
317 * \param frequency where to store frequency in MHz
318 * \return STREAM_OK if success, STREAM_ERROR otherwise
320 static int get_frequency_v4l2(radio_priv_t* priv,float* frequency){
321 struct v4l2_frequency freq;
322 memset(&freq,0,sizeof(freq));
323 if (ioctl(priv->radio_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
324 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl get frequency failed: %s\n",strerror(errno));
325 return STREAM_ERROR;
327 *frequency=((float)freq.frequency)/priv->frac;
328 return STREAM_OK;
331 /*****************************************************************
332 * \brief set volume on radio card
333 * \param volume volume level (0..100)
334 * \return STREAM_OK if success, STREAM_ERROR otherwise
336 static void set_volume_v4l2(radio_priv_t* priv,int volume){
337 struct v4l2_queryctrl qctrl;
338 struct v4l2_control control;
340 /*arg must be between 0 and 100*/
341 if (volume > 100) volume = 100;
342 if (volume < 0) volume = 0;
344 memset(&control,0,sizeof(control));
345 control.id=V4L2_CID_AUDIO_MUTE;
346 control.value = (volume==0?1:0);
347 if (ioctl(priv->radio_fd, VIDIOC_S_CTRL, &control)<0){
348 mp_tmsg(MSGT_RADIO,MSGL_WARN,"[radio] ioctl set mute failed: %s\n",strerror(errno));
351 memset(&qctrl,0,sizeof(qctrl));
352 qctrl.id = V4L2_CID_AUDIO_VOLUME;
353 if (ioctl(priv->radio_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
354 mp_tmsg(MSGT_RADIO, MSGL_WARN, "[radio] ioctl query control failed: %s\n",strerror(errno));
355 return;
358 memset(&control,0,sizeof(control));
359 control.id=V4L2_CID_AUDIO_VOLUME;
360 control.value=qctrl.minimum+volume*(qctrl.maximum-qctrl.minimum)/100;
361 if (ioctl(priv->radio_fd, VIDIOC_S_CTRL, &control) < 0) {
362 mp_tmsg(MSGT_RADIO, MSGL_WARN,"[radio] ioctl set volume failed: %s\n",strerror(errno));
366 /*****************************************************************
367 * \brief get current volume from radio card
368 * \param volume where to store volume level (0..100)
369 * \return STREAM_OK if success, STREAM_ERROR otherwise
371 static int get_volume_v4l2(radio_priv_t* priv,int* volume){
372 struct v4l2_queryctrl qctrl;
373 struct v4l2_control control;
375 memset(&qctrl,0,sizeof(qctrl));
376 qctrl.id = V4L2_CID_AUDIO_VOLUME;
377 if (ioctl(priv->radio_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
378 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] ioctl query control failed: %s\n",strerror(errno));
379 return STREAM_ERROR;
382 memset(&control,0,sizeof(control));
383 control.id=V4L2_CID_AUDIO_VOLUME;
384 if (ioctl(priv->radio_fd, VIDIOC_G_CTRL, &control) < 0) {
385 mp_tmsg(MSGT_RADIO, MSGL_ERR,"[radio] ioctl get volume failed: %s\n",strerror(errno));
386 return STREAM_ERROR;
389 if (qctrl.maximum==qctrl.minimum)
390 *volume=qctrl.minimum;
391 else
392 *volume=100*(control.value-qctrl.minimum)/(qctrl.maximum-qctrl.minimum);
394 /*arg must be between 0 and 100*/
395 if (*volume > 100) *volume = 100;
396 if (*volume < 0) *volume = 0;
398 return STREAM_OK;
401 /* v4l2 driver info structure */
402 static const radio_driver_t radio_driver_v4l2={
403 "v4l2",
404 _("[radio] Using V4Lv2 radio interface.\n"),
405 init_frac_v4l2,
406 set_volume_v4l2,
407 get_volume_v4l2,
408 set_frequency_v4l2,
409 get_frequency_v4l2
411 #endif /* CONFIG_RADIO_V4L2 */
412 #ifdef CONFIG_RADIO_V4L
413 /*****************************************************************
414 * \brief get fraction value for using in set_frequency and get_frequency
415 * \return STREAM_OK if success, STREAM_ERROR otherwise
417 * V4L2_TUNER_CAP_LOW:
418 * unit=62.5Hz
419 * frac= 1MHz/unit=1000000/62.5 =16000
421 * otherwise:
422 * unit=62500Hz
423 * frac= 1MHz/unit=1000000/62500 =16
426 static int init_frac_v4l(radio_priv_t* priv){
427 struct video_tuner tuner;
428 memset(&tuner,0,sizeof(tuner));
429 if (ioctl(priv->radio_fd, VIDIOCGTUNER, &tuner) <0){
430 mp_tmsg(MSGT_RADIO,MSGL_WARN,"[radio] Warning: ioctl get tuner failed: %s. Setting frac to %d.\n",strerror(errno),priv->frac);
431 return STREAM_ERROR;
433 if(tuner.flags & VIDEO_TUNER_LOW){
434 priv->frac=16000;
435 mp_tmsg(MSGT_RADIO,MSGL_DBG2,"[radio] tuner is low:yes frac=%d\n",priv->frac);
436 }else{
437 priv->frac=16;
438 mp_tmsg(MSGT_RADIO,MSGL_DBG2,"[radio] tuner is low:no frac=%d\n",priv->frac);
441 priv->rangelow=((float)tuner.rangelow)/priv->frac;
442 priv->rangehigh=((float)tuner.rangehigh)/priv->frac;
443 mp_tmsg(MSGT_RADIO,MSGL_V,"[radio] Allowed frequency range is %.2f-%.2f MHz.\n",priv->rangelow,priv->rangehigh);
445 return STREAM_OK;
448 /*****************************************************************
449 * \brief tune card to given frequency
450 * \param frequency frequency in MHz
451 * \return STREAM_OK if success, STREAM_ERROR otherwise
453 static int set_frequency_v4l(radio_priv_t* priv,float frequency){
454 __u32 freq;
455 freq=frequency*priv->frac;
456 if (ioctl(priv->radio_fd, VIDIOCSFREQ, &freq) < 0) {
457 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl set frequency 0x%x (%.2f) failed: %s\n",freq,frequency,strerror(errno));
458 return STREAM_ERROR;
460 return STREAM_OK;
462 /*****************************************************************
463 * \brief get current tuned frequency from card
464 * \param frequency where to store frequency in MHz
465 * \return STREAM_OK if success, STREAM_ERROR otherwise
467 static int get_frequency_v4l(radio_priv_t* priv,float* frequency){
468 __u32 freq;
469 if (ioctl(priv->radio_fd, VIDIOCGFREQ, &freq) < 0) {
470 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl get frequency failed: %s\n",strerror(errno));
471 return STREAM_ERROR;
473 *frequency=((float)freq)/priv->frac;
474 return STREAM_OK;
477 /*****************************************************************
478 * \brief set volume on radio card
479 * \param volume volume level (0..100)
480 * \return STREAM_OK if success, STREAM_ERROR otherwise
482 static void set_volume_v4l(radio_priv_t* priv,int volume){
483 struct video_audio audio;
485 /*arg must be between 0 and 100*/
486 if (volume > 100) volume = 100;
487 if (volume < 0) volume = 0;
489 memset(&audio,0,sizeof(audio));
490 audio.flags = (volume==0?VIDEO_AUDIO_MUTE:0);
491 if (ioctl(priv->radio_fd, VIDIOCSAUDIO, &audio)<0){
492 mp_tmsg(MSGT_RADIO,MSGL_WARN,"[radio] ioctl set mute failed: %s\n",strerror(errno));
495 memset(&audio,0,sizeof(audio));
496 audio.flags = VIDEO_AUDIO_VOLUME;
497 audio.mode = VIDEO_SOUND_STEREO;
498 audio.audio = 0;
499 audio.volume = volume* (65535 / 100);
501 if (ioctl(priv->radio_fd, VIDIOCSAUDIO, &audio) < 0){
502 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl set volume failed: %s\n",strerror(errno));
506 /*****************************************************************
507 * \brief get current volume from radio card
508 * \param volume where to store volume level (0..100)
509 * \return STREAM_OK if success, STREAM_ERROR otherwise
511 static int get_volume_v4l(radio_priv_t* priv,int* volume){
512 struct video_audio audio;
514 memset(&audio,0,sizeof(audio));
515 audio.audio=0;
516 if (ioctl(priv->radio_fd, VIDIOCGAUDIO, &audio) < 0){
517 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl get volume failed: %s\n",strerror(errno));
518 return STREAM_ERROR;
521 if (audio.flags & VIDEO_AUDIO_VOLUME){
522 *volume=100*audio.volume/65535;
523 /*arg must be between 0 and 100*/
524 if (*volume > 100) *volume = 100;
525 if (*volume < 0) *volume = 0;
526 return STREAM_OK;
529 return STREAM_ERROR;
532 /* v4l driver info structure */
533 static const radio_driver_t radio_driver_v4l={
534 "v4l",
535 _("[radio] Using V4Lv1 radio interface.\n"),
536 init_frac_v4l,
537 set_volume_v4l,
538 get_volume_v4l,
539 set_frequency_v4l,
540 get_frequency_v4l
542 #endif /* CONFIG_RADIO_V4L */
543 #ifdef CONFIG_RADIO_BSDBT848
545 /*****************************************************************
546 * \brief get fraction value for using in set_frequency and get_frequency
547 * \return STREAM_OK if success, STREAM_ERROR otherwise
549 * For *BSD BT848 frac=100
551 * Here is a coment from FreeBSD 5.2-RELEASE source code:
553 * * Tuner Notes:
554 * * Programming the tuner properly is quite complicated.
555 * * Here are some notes, based on a FM1246 data sheet for a PAL-I tuner.
556 * * The tuner (front end) covers 45.75 MHz - 855.25 MHz and an FM band of
557 * * 87.5 MHz to 108.0 MHz.
559 * Thus, frequency range is limited to 87.5-108.0, but you can change
560 * it, using freq_min and freq_max options
562 static int init_frac_bsdbt848(radio_priv_t* priv){
563 priv->frac=100;
564 priv->rangelow=priv->radio_param->freq_min;
565 priv->rangehigh=priv->radio_param->freq_max;
566 return STREAM_OK;
569 /*****************************************************************
570 * \brief tune card to given frequency
571 * \param frequency frequency in MHz
572 * \return STREAM_OK if success, STREAM_ERROR otherwise
574 static int set_frequency_bsdbt848(radio_priv_t* priv,float frequency){
575 unsigned int freq;
576 freq=frequency*priv->frac;
577 if(ioctl(priv->radio_fd,RADIO_SETFREQ,&freq)<0){
578 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl set frequency 0x%x (%.2f) failed: %s\n",freq, frequency, strerror(errno));
579 return STREAM_ERROR;
581 return STREAM_OK;
584 /*****************************************************************
585 * \brief get current tuned frequency from card
586 * \param frequency where to store frequency in MHz
587 * \return STREAM_OK if success, STREAM_ERROR otherwise
589 static int get_frequency_bsdbt848(radio_priv_t* priv,float* frequency){
590 unsigned int freq;
591 if (ioctl(priv->radio_fd, RADIO_GETFREQ, &freq) < 0) {
592 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl get frequency failed: %s\n",strerror(errno));
593 return STREAM_ERROR;
595 *frequency=((float)freq)/priv->frac;
596 return STREAM_OK;
599 /*****************************************************************
600 * \brief set volume on radio card
601 * \param volume volume level (0..100)
602 * \return STREAM_OK if success, STREAM_ERROR otherwise
604 * *BSD BT848 does not have volume changing abilities, so
605 * we will just mute sound if volume=0 and unmute it otherwise.
607 static void set_volume_bsdbt848(radio_priv_t* priv,int volume){
608 int audio_flags;
610 /*arg must be between 0 and 100*/
611 if (volume > 100) volume = 100;
612 if (volume < 0) volume = 0;
614 audio_flags = (volume==0?AUDIO_MUTE:AUDIO_UNMUTE);
615 if (ioctl(priv->radio_fd, BT848_SAUDIO, &audio_flags)<0){
616 mp_tmsg(MSGT_RADIO,MSGL_WARN,"[radio] ioctl set mute failed: %s\n",strerror(errno));
620 /*****************************************************************
621 * \brief get current volume from radio card
622 * \param volume where to store volume level (0..100)
623 * \return previous STREAM_OK if success, STREAM_ERROR otherwise
625 * *BSD BT848 does not have volume changing abilities, so
626 * we will return 0 if sound is muted and 100 otherwise.
628 static int get_volume_bsdbt848(radio_priv_t* priv,int* volume){
629 int audio_flags;
631 if (ioctl(priv->radio_fd, BT848_GAUDIO, &audio_flags)<0){
632 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl get volume failed: %s\n",strerror(errno));
633 return STREAM_ERROR;
636 if (audio_flags & AUDIO_MUTE)
637 *volume=0;
638 else
639 *volume=100;
641 return STREAM_OK;
644 /* bsdbt848 driver info structure */
645 static const radio_driver_t radio_driver_bsdbt848={
646 "bsdbt848",
647 _("[radio] Using *BSD BT848 radio interface.\n"),
648 init_frac_bsdbt848,
649 set_volume_bsdbt848,
650 get_volume_bsdbt848,
651 set_frequency_bsdbt848,
652 get_frequency_bsdbt848
654 #endif /* CONFIG_RADIO_BSDBT848 */
656 static inline int init_frac(radio_priv_t* priv){
657 return priv->driver->init_frac(priv);
659 static inline int set_frequency(radio_priv_t* priv,float frequency){
660 if ((frequency<priv->rangelow)||(frequency>priv->rangehigh)){
661 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] Wrong frequency: %.2f\n",frequency);
662 return STREAM_ERROR;
664 if(priv->driver->set_frequency(priv,frequency)!=STREAM_OK)
665 return STREAM_ERROR;
667 #ifdef CONFIG_RADIO_CAPTURE
668 if(clear_buffer(priv)!=STREAM_OK){
669 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] Clearing buffer failed: %s\n",strerror(errno));
670 return STREAM_ERROR;
672 #endif
673 return STREAM_OK;
675 static inline int get_frequency(radio_priv_t* priv,float* frequency){
676 return priv->driver->get_frequency(priv,frequency);
678 static inline void set_volume(radio_priv_t* priv,int volume){
679 priv->driver->set_volume(priv,volume);
681 static inline int get_volume(radio_priv_t* priv,int* volume){
682 return priv->driver->get_volume(priv,volume);
686 #ifndef CONFIG_RADIO_CAPTURE
687 /*****************************************************************
688 * \brief stub, if capture disabled at compile-time
689 * \return STREAM_OK
691 static inline int init_audio(radio_priv_t *priv){ return STREAM_OK;}
692 #else
693 /*****************************************************************
694 * \brief making buffer empty
695 * \return STREAM_OK if success, STREAM_ERROR otherwise
697 * when changing channel we must clear buffer to avoid large switching delay
699 static int clear_buffer(radio_priv_t* priv){
700 if (!priv->do_capture) return STREAM_OK;
701 priv->audio_tail = 0;
702 priv->audio_head = 0;
703 priv->audio_cnt=0;
704 memset(priv->audio_ringbuffer,0,priv->audio_in.blocksize);
705 return STREAM_OK;
707 /*****************************************************************
708 * \brief read next part of data into buffer
709 * \return -1 if error occured or no data available yet, otherwise - bytes read
710 * NOTE: audio device works in non-blocking mode
712 static int read_chunk(audio_in_t *ai, unsigned char *buffer)
714 int ret;
716 switch (ai->type) {
717 #ifdef CONFIG_ALSA
718 case AUDIO_IN_ALSA:
719 //device opened in non-blocking mode
720 ret = snd_pcm_readi(ai->alsa.handle, buffer, ai->alsa.chunk_size);
721 if (ret != ai->alsa.chunk_size) {
722 if (ret < 0) {
723 if (ret==-EAGAIN) return -1;
724 mp_tmsg(MSGT_RADIO, MSGL_ERR, "\nError reading audio: %s\n", snd_strerror(ret));
725 if (ret == -EPIPE) {
726 if (ai_alsa_xrun(ai) == 0) {
727 mp_tmsg(MSGT_RADIO, MSGL_ERR, "Recovered from cross-run, some frames may be left out!\n");
728 } else {
729 mp_tmsg(MSGT_RADIO, MSGL_ERR, "Fatal error, cannot recover!\n");
732 } else {
733 mp_tmsg(MSGT_RADIO, MSGL_ERR, "\nNot enough audio samples!\n");
735 return -1;
737 return ret;
738 #endif
739 #ifdef CONFIG_OSS_AUDIO
740 case AUDIO_IN_OSS:
742 int bt=0;
744 we must return exactly blocksize bytes, so if we have got any bytes
745 at first call to read, we will loop untils get all blocksize bytes
746 otherwise we will return -1
748 while(bt<ai->blocksize){
749 //device opened in non-blocking mode
750 ret = read(ai->oss.audio_fd, buffer+bt, ai->blocksize-bt);
751 if (ret==ai->blocksize) return ret;
752 if (ret<0){
753 if (errno==EAGAIN && bt==0) return -1; //no data avail yet
754 if (errno==EAGAIN) { usleep(1000); continue;} //nilling buffer to blocksize size
755 mp_tmsg(MSGT_RADIO, MSGL_ERR, "\nError reading audio: %s\n", strerror(errno));
756 return -1;
758 bt+=ret;
760 return bt;
762 #endif
763 default:
764 return -1;
767 /*****************************************************************
768 * \brief grab next frame from audio device
769 * \parameter buffer - store buffer
770 * \parameter len - store buffer size in bytes
771 * \return number of bytes written into buffer
773 * grabs len (or less) bytes from ringbuffer into buffer
774 * if ringbuffer is empty waits until len bytes of data will be available
776 * priv->audio_cnt - size (in bytes) of ringbuffer's filled part
777 * priv->audio_drop - size (in bytes) of dropped data (if no space in ringbuffer)
778 * priv->audio_head - index of first byte in filled part
779 * priv->audio_tail - index of last byte in filled part
781 * NOTE: audio_tail always aligned by priv->audio_in.blocksize
782 * audio_head may NOT.
784 static int grab_audio_frame(radio_priv_t *priv, char *buffer, int len)
786 int i;
787 mp_tmsg(MSGT_RADIO, MSGL_DBG3, "[radio] %s: in buffer=%d dropped=%d\n","grab_audio_frame",priv->audio_cnt,priv->audio_drop);
788 /* Cache buffer must be filled by some audio packets when playing starts.
789 Otherwise MPlayer will quit with EOF error.
790 Probably, there is need more carefull checking rather than simple 'for' loop
791 (something like timer or similar).
793 1000ms delay will happen only at first buffer filling. At next call function
794 just fills buffer until either buffer full or no data from driver available.
796 for (i=0;i<1000 && !priv->audio_cnt; i++){
797 //read_chunk fills exact priv->blocksize bytes
798 if(read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail) < 0){
799 //sleppeing only when waiting first block to fill empty buffer
800 if (!priv->audio_cnt){
801 usleep(1000);
802 continue;
803 }else
804 break;
806 priv->audio_cnt+=priv->audio_in.blocksize;
807 priv->audio_tail = (priv->audio_tail+priv->audio_in.blocksize) % priv->audio_buffer_size;
809 if(priv->audio_cnt<len)
810 len=priv->audio_cnt;
811 memcpy(buffer, priv->audio_ringbuffer+priv->audio_head,len);
812 priv->audio_head = (priv->audio_head+len) % priv->audio_buffer_size;
813 priv->audio_cnt-=len;
814 return len;
816 /*****************************************************************
817 * \brief init audio device
818 * \return STREAM_OK if success, STREAM_ERROR otherwise
820 static int init_audio(radio_priv_t *priv)
822 int is_oss=1;
823 int seconds=2;
824 char* tmp;
825 if (priv->audio_initialized) return 1;
827 /* do_capture==0 mplayer was not started with capture keyword, so disabling capture*/
828 if(!priv->do_capture)
829 return STREAM_OK;
831 if (!priv->radio_param->adevice){
832 priv->do_capture=0;
833 return STREAM_OK;
836 priv->do_capture=1;
837 mp_tmsg(MSGT_RADIO,MSGL_V,"[radio] Starting capture stuff.\n");
838 #ifdef CONFIG_ALSA
839 while ((tmp = strrchr(priv->radio_param->adevice, '='))){
840 tmp[0] = ':';
841 //adevice option looks like ALSA device name. Switching to ALSA
842 is_oss=0;
844 while ((tmp = strrchr(priv->radio_param->adevice, '.')))
845 tmp[0] = ',';
846 #endif
848 if(audio_in_init(&priv->audio_in, is_oss?AUDIO_IN_OSS:AUDIO_IN_ALSA)<0){
849 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] audio_in_init failed.\n");
852 audio_in_set_device(&priv->audio_in, priv->radio_param->adevice);
853 audio_in_set_channels(&priv->audio_in, priv->radio_param->achannels);
854 audio_in_set_samplerate(&priv->audio_in, priv->radio_param->arate);
856 if (audio_in_setup(&priv->audio_in) < 0) {
857 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] audio_in_setup call failed: %s\n", strerror(errno));
858 return STREAM_ERROR;
860 #ifdef CONFIG_OSS_AUDIO
861 if(is_oss)
862 ioctl(priv->audio_in.oss.audio_fd, SNDCTL_DSP_NONBLOCK, 0);
863 #endif
864 #ifdef CONFIG_ALSA
865 if(!is_oss)
866 snd_pcm_nonblock(priv->audio_in.alsa.handle,1);
867 #endif
869 priv->audio_buffer_size = seconds*priv->audio_in.samplerate*priv->audio_in.channels*
870 priv->audio_in.bytes_per_sample+priv->audio_in.blocksize;
871 if (priv->audio_buffer_size < 256*priv->audio_in.blocksize)
872 priv->audio_buffer_size = 256*priv->audio_in.blocksize;
873 mp_tmsg(MSGT_RADIO, MSGL_V, "[radio] Audio capture - buffer=%d bytes (block=%d bytes).\n",
874 priv->audio_buffer_size,priv->audio_in.blocksize);
875 /* start capture */
876 priv->audio_ringbuffer = calloc(1, priv->audio_buffer_size);
877 if (!priv->audio_ringbuffer) {
878 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] cannot allocate audio buffer (block=%d,buf=%d): %s\n",priv->audio_in.blocksize, priv->audio_buffer_size, strerror(errno));
879 return STREAM_ERROR;
881 priv->audio_head = 0;
882 priv->audio_tail = 0;
883 priv->audio_cnt = 0;
884 priv->audio_drop = 0;
886 audio_in_start_capture(&priv->audio_in);
888 priv->audio_initialized = 1;
890 return STREAM_OK;
892 #endif /* CONFIG_RADIO_CAPTURE */
894 /*-------------------------------------------------------------------------
895 for call from mplayer.c
896 --------------------------------------------------------------------------*/
897 /*****************************************************************
898 * \brief public wrapper for get_frequency
899 * \parameter frequency pointer to float, which will contain frequency in MHz
900 * \return 1 if success,0 - otherwise
902 int radio_get_freq(struct stream *stream, float *frequency){
903 radio_priv_t* priv=(radio_priv_t*)stream->priv;
905 if (!frequency)
906 return 0;
907 if (get_frequency(priv,frequency)!=STREAM_OK){
908 return 0;
910 return 1;
912 /*****************************************************************
913 * \brief public wrapper for set_frequency
914 * \parameter frequency frequency in MHz
915 * \return 1 if success,0 - otherwise
917 int radio_set_freq(struct stream *stream, float frequency){
918 radio_priv_t* priv=(radio_priv_t*)stream->priv;
920 if (set_frequency(priv,frequency)!=STREAM_OK){
921 return 0;
923 if (get_frequency(priv,&frequency)!=STREAM_OK){
924 return 0;
926 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Current frequency: %.2f\n",frequency);
927 return 1;
930 /*****************************************************************
931 * \brief tune current frequency by step_interval value
932 * \parameter step_interval increment value
933 * \return 1 if success,0 - otherwise
936 int radio_step_freq(struct stream *stream, float step_interval){
937 float frequency;
938 radio_priv_t* priv=(radio_priv_t*)stream->priv;
940 if (get_frequency(priv,&frequency)!=STREAM_OK)
941 return 0;
943 frequency+=step_interval;
944 if (frequency>priv->rangehigh)
945 frequency=priv->rangehigh;
946 if (frequency<priv->rangelow)
947 frequency=priv->rangelow;
949 return radio_set_freq(stream,frequency);
951 /*****************************************************************
952 * \brief step channel up or down
953 * \parameter direction RADIO_CHANNEL_LOWER - go to prev channel,RADIO_CHANNEL_HIGHER - to next
954 * \return 1 if success,0 - otherwise
956 * if channel parameter is NULL function prints error message and does nothing, otherwise
957 * changes channel to prev or next in list
959 int radio_step_channel(struct stream *stream, int direction) {
960 radio_priv_t* priv=(radio_priv_t*)stream->priv;
962 if (priv->radio_channel_list) {
963 switch (direction){
964 case RADIO_CHANNEL_HIGHER:
965 if (priv->radio_channel_current->next)
966 priv->radio_channel_current = priv->radio_channel_current->next;
967 else
968 priv->radio_channel_current = priv->radio_channel_list;
969 if(!radio_set_freq(stream,priv->radio_channel_current->freq))
970 return 0;
971 mp_tmsg(MSGT_RADIO, MSGL_V, "[radio] Selected channel: %d - %s (freq: %.2f)\n",
972 priv->radio_channel_current->index, priv->radio_channel_current->name,
973 priv->radio_channel_current->freq);
974 break;
975 case RADIO_CHANNEL_LOWER:
976 if (priv->radio_channel_current->prev)
977 priv->radio_channel_current = priv->radio_channel_current->prev;
978 else
979 while (priv->radio_channel_current->next)
980 priv->radio_channel_current = priv->radio_channel_current->next;
981 if(!radio_set_freq(stream,priv->radio_channel_current->freq))
982 return 0;
983 mp_tmsg(MSGT_RADIO, MSGL_V, "[radio] Selected channel: %d - %s (freq: %.2f)\n",
984 priv->radio_channel_current->index, priv->radio_channel_current->name,
985 priv->radio_channel_current->freq);
986 break;
988 }else
989 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Can not change channel: no channel list given.\n");
990 return 1;
993 /*****************************************************************
994 * \brief change channel to one with given index
995 * \parameter channel string, containing channel number
996 * \return 1 if success,0 - otherwise
998 * if channel parameter is NULL function prints error message and does nothing, otherwise
999 * changes channel to given
1001 int radio_set_channel(struct stream *stream, char *channel) {
1002 radio_priv_t* priv=(radio_priv_t*)stream->priv;
1003 int i, channel_int;
1004 radio_channels_t* tmp;
1005 char* endptr;
1007 if (*channel=='\0')
1008 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] Wrong channel name: %s\n",channel);
1010 if (priv->radio_channel_list) {
1011 channel_int = strtol(channel,&endptr,10);
1012 tmp = priv->radio_channel_list;
1013 if (*endptr!='\0'){
1014 //channel is not a number, so it contains channel name
1015 for ( ; tmp; tmp=tmp->next)
1016 if (!strncmp(channel,tmp->name,sizeof(tmp->name)-1))
1017 break;
1018 if (!tmp){
1019 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] Wrong channel name: %s\n",channel);
1020 return 0;
1022 }else{
1023 for (i = 1; i < channel_int; i++)
1024 if (tmp->next)
1025 tmp = tmp->next;
1026 else
1027 break;
1028 if (tmp->index!=channel_int){
1029 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] Wrong channel number: %d\n",channel_int);
1030 return 0;
1033 priv->radio_channel_current=tmp;
1034 mp_tmsg(MSGT_RADIO, MSGL_V, "[radio] Selected channel: %d - %s (freq: %.2f)\n", priv->radio_channel_current->index,
1035 priv->radio_channel_current->name, priv->radio_channel_current->freq);
1036 if(!radio_set_freq(stream, priv->radio_channel_current->freq))
1037 return 0;
1038 } else
1039 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Can not change channel: no channel list given.\n");
1040 return 1;
1043 /*****************************************************************
1044 * \brief get current channel's name
1045 * \return pointer to string, containing current channel's name
1047 * NOTE: return value may be NULL (e.g. when channel list not initialized)
1049 char* radio_get_channel_name(struct stream *stream){
1050 radio_priv_t* priv=(radio_priv_t*)stream->priv;
1051 if (priv->radio_channel_current) {
1052 return priv->radio_channel_current->name;
1054 return NULL;
1057 /*****************************************************************
1058 * \brief fills given buffer with audio data
1059 * \return number of bytes, written into buffer
1061 static int fill_buffer_s(struct stream *s, char *buffer, int max_len){
1062 int len=max_len;
1064 #ifdef CONFIG_RADIO_CAPTURE
1065 radio_priv_t* priv=(radio_priv_t*)s->priv;
1067 if (priv->do_capture){
1068 len=grab_audio_frame(priv, buffer,max_len);
1070 else
1071 #endif
1072 memset(buffer,0,len);
1073 return len;
1078 order if significant!
1079 when no driver explicitly specified first available will be used
1081 static const radio_driver_t* radio_drivers[]={
1082 #ifdef CONFIG_RADIO_BSDBT848
1083 &radio_driver_bsdbt848,
1084 #endif
1085 #ifdef CONFIG_RADIO_V4L2
1086 &radio_driver_v4l2,
1087 #endif
1088 #ifdef CONFIG_RADIO_V4L
1089 &radio_driver_v4l,
1090 #endif
1094 /*****************************************************************
1095 * Stream initialization
1096 * \return STREAM_OK if success, STREAM_ERROR otherwise
1098 static int open_s(stream_t *stream,int mode, void* opts, int* file_format) {
1099 radio_priv_t* priv;
1100 float frequency=0;
1101 int i;
1103 if (strncmp("radio://",stream->url,8) != 0)
1104 return STREAM_UNSUPPORTED;
1106 if(mode != STREAM_READ)
1107 return STREAM_UNSUPPORTED;
1109 priv=calloc(1,sizeof(radio_priv_t));
1111 if (!priv)
1112 return STREAM_ERROR;
1115 priv->radio_param=opts;
1117 #ifdef CONFIG_RADIO_CAPTURE
1118 if (priv->radio_param->capture && strncmp("capture",priv->radio_param->capture,7)==0)
1119 priv->do_capture=1;
1120 else
1121 priv->do_capture=0;
1122 #endif
1126 if (strncmp(priv->radio_param->driver,"default",7)==0)
1127 priv->driver=radio_drivers[0];
1128 else
1129 priv->driver=NULL;
1131 mp_tmsg(MSGT_RADIO,MSGL_V,"[radio] Available drivers: ");
1132 for(i=0;radio_drivers[i];i++){
1133 mp_msg(MSGT_RADIO,MSGL_V,"%s, ",radio_drivers[i]->name);
1134 if(strcmp(priv->radio_param->driver,radio_drivers[i]->name)==0)
1135 priv->driver=radio_drivers[i];
1137 mp_msg(MSGT_RADIO,MSGL_V,"\n");
1139 if(priv->driver)
1140 mp_msg(MSGT_RADIO, MSGL_INFO, priv->driver->info);
1141 else{
1142 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Unknown driver name: %s\n",priv->radio_param->driver);
1143 close_s(stream);
1144 return STREAM_ERROR;
1147 stream->type = STREAMTYPE_RADIO;
1148 /* using rawaudio demuxer */
1149 *file_format = DEMUXER_TYPE_RAWAUDIO;
1150 stream->flags = STREAM_READ;
1152 priv->radio_fd=-1;
1154 stream->start_pos=0;
1155 stream->end_pos=0;
1156 stream->priv=priv;
1157 stream->close=close_s;
1158 stream->fill_buffer=fill_buffer_s;
1160 priv->radio_fd = open(priv->radio_param->device, O_RDONLY);
1161 if (priv->radio_fd < 0) {
1162 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Unable to open '%s': %s\n",
1163 priv->radio_param->device, strerror(errno));
1164 close_s(stream);
1165 return STREAM_ERROR;
1167 mp_tmsg(MSGT_RADIO, MSGL_V, "[radio] Radio fd: %d, %s\n", priv->radio_fd,priv->radio_param->device);
1168 fcntl(priv->radio_fd, F_SETFD, FD_CLOEXEC);
1170 get_volume(priv, &priv->old_snd_volume);
1171 set_volume(priv,0);
1173 if (init_frac(priv)!=STREAM_OK){
1174 close_s(stream);
1175 return STREAM_ERROR;
1178 if (parse_channels(priv,priv->radio_param->freq_channel,&frequency)!=STREAM_OK){
1179 close_s(stream);
1180 return STREAM_ERROR;
1183 if ((frequency<priv->rangelow)||(frequency>priv->rangehigh)){
1184 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Wrong frequency: %.2f\n",frequency);
1185 close_s(stream);
1186 return STREAM_ERROR;
1187 }else
1188 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Using frequency: %.2f.\n",frequency);
1190 if(set_frequency(priv,frequency)!=STREAM_OK){
1191 close_s(stream);
1192 return STREAM_ERROR;
1196 if (init_audio(priv)!=STREAM_OK){
1197 close_s(stream);
1198 return STREAM_ERROR;
1201 #if defined(CONFIG_RADIO_CAPTURE) && defined(CONFIG_STREAM_CACHE)
1202 if(priv->do_capture){
1203 //5 second cache
1204 if(!stream_enable_cache(stream,5*priv->audio_in.samplerate*priv->audio_in.channels*
1205 priv->audio_in.bytes_per_sample,2*priv->audio_in.samplerate*priv->audio_in.channels*
1206 priv->audio_in.bytes_per_sample,priv->audio_in.blocksize)) {
1207 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Call to stream_enable_cache failed: %s\n",strerror(errno));
1208 close_s(stream);
1209 return STREAM_ERROR;
1212 #endif
1214 set_volume(priv,priv->radio_param->volume);
1216 return STREAM_OK;
1219 /*****************************************************************
1220 * Close stream. Clear structures.
1222 static void close_s(struct stream *stream){
1223 radio_priv_t* priv=(radio_priv_t*)stream->priv;
1224 radio_channels_t * tmp;
1225 if (!priv) return;
1227 #ifdef CONFIG_RADIO_CAPTURE
1228 if(priv->audio_ringbuffer){
1229 free(priv->audio_ringbuffer);
1230 priv->audio_ringbuffer=NULL;
1233 priv->do_capture=0;
1234 #endif
1236 while (priv->radio_channel_list) {
1237 tmp=priv->radio_channel_list;
1238 priv->radio_channel_list=priv->radio_channel_list->next;
1239 free(tmp);
1241 priv->radio_channel_current=NULL;
1242 priv->radio_channel_list=NULL;
1244 if (priv->radio_fd>0){
1245 set_volume(priv, priv->old_snd_volume);
1246 close(priv->radio_fd);
1249 if(priv->radio_param)
1250 m_struct_free(&stream_opts,priv->radio_param);
1251 free(priv);
1252 stream->priv=NULL;
1255 const stream_info_t stream_info_radio = {
1256 "Radio stream",
1257 "Radio",
1258 "Vladimir Voroshilov",
1259 "In development",
1260 open_s,
1261 { "radio", NULL },
1262 &stream_opts,
1263 1 // Urls are an option string