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 HAVE_RADIO_BSDBT848
38 #include <sys/param.h>
39 #ifdef IOCTL_BT848_H_NAME
40 #include IOCTL_BT848_H_NAME
43 #else // HAVE_RADIO_BSDBT848
45 #include <linux/types.h>
47 #ifdef HAVE_RADIO_V4L2
48 #include <linux/videodev2.h>
52 #include <linux/videodev.h>
53 #warning "V4L is deprecated and will be removed in future"
56 #endif // !IOCTL_BT848_H_NAME
60 #include "libmpdemux/demuxer.h"
65 #include "stream_radio.h"
66 #include "libavutil/avstring.h"
68 #ifdef USE_RADIO_CAPTURE
71 #ifdef HAVE_SYS_SOUNDCARD_H
72 #include <sys/soundcard.h>
74 #ifdef HAVE_SOUNDCARD_H
75 #include <soundcard.h>
77 #include <linux/soundcard.h>
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
;
91 /// default values for options
92 radio_param_t stream_radio_defaults
={
93 #ifdef HAVE_RADIO_BSDBT848
94 "/dev/tuner0", //device
98 "/dev/radio0", //device;
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
;
119 #ifdef USE_RADIO_CAPTURE
120 volatile int do_capture
; ///< is capture enabled
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
;
130 radio_param_t
*radio_param
;
133 typedef struct radio_driver_s
{
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
);
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
= {
152 sizeof(radio_param_t
),
153 &stream_radio_defaults
,
157 static void close_s(struct stream
*stream
);
158 #ifdef USE_RADIO_CAPTURE
159 static int clear_buffer(radio_priv_t
* priv
);
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
){
181 if (priv
->radio_param
->channels
){
182 /*parsing channels string*/
183 channels
=priv
->radio_param
->channels
;
185 mp_msg(MSGT_RADIO
, MSGL_INFO
, MSGTR_RADIO_ChannelNamesDetected
);
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
;
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);
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_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_WrongFreqForChannel
,
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
);
219 channel
= freq_channel
;
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_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_WrongChannelNumberFloat
,freq_channel
);
231 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_WrongChannelNumberInt
,(int)freq_channel
);
234 mp_msg(MSGT_RADIO
, MSGL_INFO
, MSGTR_RADIO_SelectedChannel
, priv
->radio_channel_current
->index
,
235 priv
->radio_channel_current
->name
, priv
->radio_channel_current
->freq
);
236 *pfreq
=priv
->radio_channel_current
->freq
;
239 mp_msg(MSGT_RADIO
, MSGL_INFO
, MSGTR_RADIO_FreqParameterDetected
);
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
;
250 mp_msg(MSGT_RADIO
, MSGL_DBG2
, MSGTR_RADIO_DoneParsingChannels
);
254 #ifdef HAVE_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:
261 * frac= 1MHz/unit=1000000/62.5 =16000
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
));
272 if (ioctl(priv
->radio_fd
, VIDIOC_G_TUNER
, &tuner
)<0){
273 mp_msg(MSGT_RADIO
,MSGL_WARN
,MSGTR_RADIO_GetTunerFailed
,strerror(errno
),priv
->frac
);
276 if(tuner
.type
!=V4L2_TUNER_RADIO
){
277 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_NotRadioDevice
,priv
->radio_param
->device
);
280 if(tuner
.capability
& V4L2_TUNER_CAP_LOW
){
282 mp_msg(MSGT_RADIO
,MSGL_DBG2
,MSGTR_RADIO_TunerCapLowYes
,priv
->frac
);
286 mp_msg(MSGT_RADIO
,MSGL_DBG2
,MSGTR_RADIO_TunerCapLowNo
,priv
->frac
);
289 priv
->rangelow
=((float)tuner
.rangelow
)/priv
->frac
;
290 priv
->rangehigh
=((float)tuner
.rangehigh
)/priv
->frac
;
291 mp_msg(MSGT_RADIO
,MSGL_V
,MSGTR_RADIO_FreqRange
,priv
->rangelow
,priv
->rangehigh
);
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
));
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_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_SetFreqFailed
,freq
.frequency
,
309 frequency
,strerror(errno
));
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_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_GetFreqFailed
,strerror(errno
));
327 *frequency
=((float)freq
.frequency
)/priv
->frac
;
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_msg(MSGT_RADIO
,MSGL_WARN
,MSGTR_RADIO_SetMuteFailed
,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_msg(MSGT_RADIO
, MSGL_WARN
, MSGTR_RADIO_QueryControlFailed
,strerror(errno
));
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_msg(MSGT_RADIO
, MSGL_WARN
,MSGTR_RADIO_SetVolumeFailed
,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_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_QueryControlFailed
,strerror(errno
));
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_msg(MSGT_RADIO
, MSGL_ERR
,MSGTR_RADIO_GetVolumeFailed
,strerror(errno
));
389 if (qctrl
.maximum
==qctrl
.minimum
)
390 *volume
=qctrl
.minimum
;
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;
401 /* v4l2 driver info structure */
402 static const radio_driver_t radio_driver_v4l2
={
404 MSGTR_RADIO_DriverV4L2
,
411 #endif //HAVE_RADIO_V4L2
412 #ifdef HAVE_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:
419 * frac= 1MHz/unit=1000000/62.5 =16000
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_msg(MSGT_RADIO
,MSGL_WARN
,MSGTR_RADIO_GetTunerFailed
,strerror(errno
),priv
->frac
);
433 if(tuner
.flags
& VIDEO_TUNER_LOW
){
435 mp_msg(MSGT_RADIO
,MSGL_DBG2
,MSGTR_RADIO_TunerCapLowYes
,priv
->frac
);
438 mp_msg(MSGT_RADIO
,MSGL_DBG2
,MSGTR_RADIO_TunerCapLowNo
,priv
->frac
);
441 priv
->rangelow
=((float)tuner
.rangelow
)/priv
->frac
;
442 priv
->rangehigh
=((float)tuner
.rangehigh
)/priv
->frac
;
443 mp_msg(MSGT_RADIO
,MSGL_V
,MSGTR_RADIO_FreqRange
,priv
->rangelow
,priv
->rangehigh
);
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
){
455 freq
=frequency
*priv
->frac
;
456 if (ioctl(priv
->radio_fd
, VIDIOCSFREQ
, &freq
) < 0) {
457 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_SetFreqFailed
,freq
,frequency
,strerror(errno
));
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
){
469 if (ioctl(priv
->radio_fd
, VIDIOCGFREQ
, &freq
) < 0) {
470 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_GetFreqFailed
,strerror(errno
));
473 *frequency
=((float)freq
)/priv
->frac
;
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_msg(MSGT_RADIO
,MSGL_WARN
,MSGTR_RADIO_SetMuteFailed
,strerror(errno
));
495 memset(&audio
,0,sizeof(audio
));
496 audio
.flags
= VIDEO_AUDIO_VOLUME
;
497 audio
.mode
= VIDEO_SOUND_STEREO
;
499 audio
.volume
= volume
* (65535 / 100);
501 if (ioctl(priv
->radio_fd
, VIDIOCSAUDIO
, &audio
) < 0){
502 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_SetVolumeFailed
,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
));
516 if (ioctl(priv
->radio_fd
, VIDIOCGAUDIO
, &audio
) < 0){
517 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_GetVolumeFailed
,strerror(errno
));
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;
532 /* v4l driver info structure */
533 static const radio_driver_t radio_driver_v4l
={
535 MSGTR_RADIO_DriverV4L
,
542 #endif //HAVE_RADIO_V4L
543 #ifdef HAVE_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:
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
){
564 priv
->rangelow
=priv
->radio_param
->freq_min
;
565 priv
->rangehigh
=priv
->radio_param
->freq_max
;
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
){
576 freq
=frequency
*priv
->frac
;
577 if(ioctl(priv
->radio_fd
,RADIO_SETFREQ
,&freq
)<0){
578 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_SetFreqFailed
,freq
, frequency
, strerror(errno
));
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
){
591 if (ioctl(priv
->radio_fd
, RADIO_GETFREQ
, &freq
) < 0) {
592 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_GetFreqFailed
,strerror(errno
));
595 *frequency
=((float)freq
)/priv
->frac
;
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
){
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_msg(MSGT_RADIO
,MSGL_WARN
,MSGTR_RADIO_SetMuteFailed
,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
){
631 if (ioctl(priv
->radio_fd
, BT848_GAUDIO
, &audio_flags
)<0){
632 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_GetVolumeFailed
,strerror(errno
));
636 if (audio_flags
& AUDIO_MUTE
)
644 /* bsdbt848 driver info structure */
645 static const radio_driver_t radio_driver_bsdbt848
={
647 MSGTR_RADIO_DriverBSDBT848
,
651 set_frequency_bsdbt848
,
652 get_frequency_bsdbt848
654 #endif //HAVE_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_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_WrongFreq
,frequency
);
664 if(priv
->driver
->set_frequency(priv
,frequency
)!=STREAM_OK
)
667 #ifdef USE_RADIO_CAPTURE
668 if(clear_buffer(priv
)!=STREAM_OK
){
669 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_ClearBufferFailed
,strerror(errno
));
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 USE_RADIO_CAPTURE
687 /*****************************************************************
688 * \brief stub, if capture disabled at compile-time
691 static inline int init_audio(radio_priv_t
*priv
){ return STREAM_OK
;}
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;
704 memset(priv
->audio_ringbuffer
,0,priv
->audio_in
.blocksize
);
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
)
717 #if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X)
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
) {
723 if (ret
==-EAGAIN
) return -1;
724 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio
, snd_strerror(ret
));
726 if (ai_alsa_xrun(ai
) == 0) {
727 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_MPDEMUX_AUDIOIN_XRUNSomeFramesMayBeLeftOut
);
729 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_MPDEMUX_AUDIOIN_ErrFatalCannotRecover
);
733 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_MPDEMUX_AUDIOIN_NotEnoughSamples
);
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
;
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_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_MPDEMUX_AUDIOIN_ErrReadingAudio
, strerror(errno
));
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
)
787 mp_msg(MSGT_RADIO
, MSGL_DBG3
, MSGTR_RADIO_BufferString
,"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
){
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
)
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
;
816 /*****************************************************************
817 * \brief init audio device
818 * \return STREAM_OK if success, STREAM_ERROR otherwise
820 static int init_audio(radio_priv_t
*priv
)
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
)
831 if (!priv
->radio_param
->adevice
){
837 mp_msg(MSGT_RADIO
,MSGL_V
,MSGTR_RADIO_CaptureStarting
);
838 #if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X)
839 while ((tmp
= strrchr(priv
->radio_param
->adevice
, '='))){
841 //adevice option looks like ALSA device name. Switching to ALSA
844 while ((tmp
= strrchr(priv
->radio_param
->adevice
, '.')))
848 if(audio_in_init(&priv
->audio_in
, is_oss
?AUDIO_IN_OSS
:AUDIO_IN_ALSA
)<0){
849 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_AudioInInitFailed
);
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_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_AudioInSetupFailed
, strerror(errno
));
862 ioctl(priv
->audio_in
.oss
.audio_fd
, SNDCTL_DSP_NONBLOCK
, 0);
864 #if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X)
866 snd_pcm_nonblock(priv
->audio_in
.alsa
.handle
,1);
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_msg(MSGT_RADIO
, MSGL_V
, MSGTR_RADIO_AudioBuffer
,
874 priv
->audio_buffer_size
,priv
->audio_in
.blocksize
);
876 priv
->audio_ringbuffer
= calloc(1, priv
->audio_buffer_size
);
877 if (!priv
->audio_ringbuffer
) {
878 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_AllocateBufferFailed
,priv
->audio_in
.blocksize
, priv
->audio_buffer_size
, strerror(errno
));
881 priv
->audio_head
= 0;
882 priv
->audio_tail
= 0;
884 priv
->audio_drop
= 0;
886 audio_in_start_capture(&priv
->audio_in
);
888 priv
->audio_initialized
= 1;
892 #endif //USE_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
;
907 if (get_frequency(priv
,frequency
)!=STREAM_OK
){
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
){
923 if (get_frequency(priv
,&frequency
)!=STREAM_OK
){
926 mp_msg(MSGT_RADIO
, MSGL_INFO
, MSGTR_RADIO_CurrentFreq
,frequency
);
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
){
938 radio_priv_t
* priv
=(radio_priv_t
*)stream
->priv
;
940 if (get_frequency(priv
,&frequency
)!=STREAM_OK
)
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
) {
964 case RADIO_CHANNEL_HIGHER
:
965 if (priv
->radio_channel_current
->next
)
966 priv
->radio_channel_current
= priv
->radio_channel_current
->next
;
968 priv
->radio_channel_current
= priv
->radio_channel_list
;
969 if(!radio_set_freq(stream
,priv
->radio_channel_current
->freq
))
971 mp_msg(MSGT_RADIO
, MSGL_V
, MSGTR_RADIO_SelectedChannel
,
972 priv
->radio_channel_current
->index
, priv
->radio_channel_current
->name
,
973 priv
->radio_channel_current
->freq
);
975 case RADIO_CHANNEL_LOWER
:
976 if (priv
->radio_channel_current
->prev
)
977 priv
->radio_channel_current
= priv
->radio_channel_current
->prev
;
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
))
983 mp_msg(MSGT_RADIO
, MSGL_V
, MSGTR_RADIO_SelectedChannel
,
984 priv
->radio_channel_current
->index
, priv
->radio_channel_current
->name
,
985 priv
->radio_channel_current
->freq
);
989 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_ChangeChannelNoChannelList
);
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
;
1004 radio_channels_t
* tmp
;
1008 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_WrongChannelName
,channel
);
1010 if (priv
->radio_channel_list
) {
1011 channel_int
= strtol(channel
,&endptr
,10);
1012 tmp
= priv
->radio_channel_list
;
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))
1019 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_WrongChannelName
,channel
);
1023 for (i
= 1; i
< channel_int
; i
++)
1028 if (tmp
->index
!=channel_int
){
1029 mp_msg(MSGT_RADIO
,MSGL_ERR
,MSGTR_RADIO_WrongChannelNumberInt
,channel_int
);
1033 priv
->radio_channel_current
=tmp
;
1034 mp_msg(MSGT_RADIO
, MSGL_V
, MSGTR_RADIO_SelectedChannel
, 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
))
1039 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_ChangeChannelNoChannelList
);
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
;
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
){
1064 #ifdef USE_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
);
1072 memset(buffer
,0,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 HAVE_RADIO_BSDBT848
1083 &radio_driver_bsdbt848
,
1085 #ifdef HAVE_RADIO_V4L2
1088 #ifdef HAVE_RADIO_V4L
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
) {
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
));
1112 return STREAM_ERROR
;
1115 priv
->radio_param
=opts
;
1117 #ifdef USE_RADIO_CAPTURE
1118 if (priv
->radio_param
->capture
&& strncmp("capture",priv
->radio_param
->capture
,7)==0)
1126 if (strncmp(priv
->radio_param
->driver
,"default",7)==0)
1127 priv
->driver
=radio_drivers
[0];
1131 mp_msg(MSGT_RADIO
,MSGL_V
,MSGTR_RADIO_AvailableDrivers
);
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");
1140 mp_msg(MSGT_RADIO
, MSGL_INFO
, priv
->driver
->info
);
1142 mp_msg(MSGT_RADIO
, MSGL_INFO
, MSGTR_RADIO_DriverUnknownStr
,priv
->radio_param
->driver
);
1144 return STREAM_ERROR
;
1147 stream
->type
= STREAMTYPE_RADIO
;
1148 /* using rawaudio demuxer */
1149 *file_format
= DEMUXER_TYPE_RAWAUDIO
;
1150 stream
->flags
= STREAM_READ
;
1154 stream
->start_pos
=0;
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_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_UnableOpenDevice
,
1163 priv
->radio_param
->device
, strerror(errno
));
1165 return STREAM_ERROR
;
1167 mp_msg(MSGT_RADIO
, MSGL_V
, MSGTR_RADIO_RadioDevice
, priv
->radio_fd
,priv
->radio_param
->device
);
1168 fcntl(priv
->radio_fd
, F_SETFD
, FD_CLOEXEC
);
1170 get_volume(priv
, &priv
->old_snd_volume
);
1173 if (init_frac(priv
)!=STREAM_OK
){
1175 return STREAM_ERROR
;
1178 if (parse_channels(priv
,priv
->radio_param
->freq_channel
,&frequency
)!=STREAM_OK
){
1180 return STREAM_ERROR
;
1183 if ((frequency
<priv
->rangelow
)||(frequency
>priv
->rangehigh
)){
1184 mp_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_WrongFreq
,frequency
);
1186 return STREAM_ERROR
;
1188 mp_msg(MSGT_RADIO
, MSGL_INFO
, MSGTR_RADIO_UsingFreq
,frequency
);
1190 if(set_frequency(priv
,frequency
)!=STREAM_OK
){
1192 return STREAM_ERROR
;
1196 if (init_audio(priv
)!=STREAM_OK
){
1198 return STREAM_ERROR
;
1201 #if defined(USE_RADIO_CAPTURE) && defined(USE_STREAM_CACHE)
1202 if(priv
->do_capture
){
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_msg(MSGT_RADIO
, MSGL_ERR
, MSGTR_RADIO_StreamEnableCacheFailed
,strerror(errno
));
1209 return STREAM_ERROR
;
1214 set_volume(priv
,priv
->radio_param
->volume
);
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
;
1227 #ifdef USE_RADIO_CAPTURE
1228 if(priv
->audio_ringbuffer
){
1229 free(priv
->audio_ringbuffer
);
1230 priv
->audio_ringbuffer
=NULL
;
1236 while (priv
->radio_channel_list
) {
1237 tmp
=priv
->radio_channel_list
;
1238 priv
->radio_channel_list
=priv
->radio_channel_list
->next
;
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
);
1255 const stream_info_t stream_info_radio
= {
1258 "Vladimir Voroshilov",
1263 1 // Urls are an option string