osd: add changes missing from recent 393988c274 (exit crash)
[mplayer.git] / stream / stream_radio.c
blob245f889bbe688d637fa0098d1eac67e4cc058607
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 #endif // !IOCTL_BT848_H_NAME
55 #include "stream.h"
56 #include "libmpdemux/demuxer.h"
57 #include "m_struct.h"
58 #include "m_option.h"
59 #include "mp_msg.h"
60 #include "stream_radio.h"
61 #include "libavutil/avstring.h"
63 #ifdef CONFIG_RADIO_CAPTURE
64 #include "audio_in.h"
66 #ifdef HAVE_SYS_SOUNDCARD_H
67 #include <sys/soundcard.h>
68 #else
69 #ifdef HAVE_SOUNDCARD_H
70 #include <soundcard.h>
71 #else
72 #include <linux/soundcard.h>
73 #endif
74 #endif
76 #endif
78 typedef struct radio_channels_s {
79 int index; ///< channel index in channels list
80 float freq; ///< frequency in MHz
81 char name[20]; ///< channel name
82 struct radio_channels_s * next;
83 struct radio_channels_s * prev;
84 } radio_channels_t;
86 /// default values for options
87 radio_param_t stream_radio_defaults={
88 #ifdef CONFIG_RADIO_BSDBT848
89 "/dev/tuner0", //device
90 87.50, //freq_min
91 108.00, //freq_max
92 #else
93 "/dev/radio0", //device;
94 #endif
95 "default", //driver
96 NULL, //channels
97 100, //volume
98 NULL, //adevice
99 44100, //arate
100 2, //achannels
101 0, //freq_channel
102 NULL, //capture
105 typedef struct radio_priv_s {
106 int radio_fd; ///< radio device descriptor
107 int frac; ///< fraction value (see comment to init_frac)
108 radio_channels_t* radio_channel_list;
109 radio_channels_t* radio_channel_current;
110 float rangelow; ///< lowest tunable frequency in MHz
111 float rangehigh; ///< highest tunable frequency in MHz
112 const struct radio_driver_s* driver;
113 int old_snd_volume;
114 #ifdef CONFIG_RADIO_CAPTURE
115 volatile int do_capture; ///< is capture enabled
116 audio_in_t audio_in;
117 unsigned char* audio_ringbuffer;
118 int audio_head; ///< start of meanfull data in ringbuffer
119 int audio_tail; ///< end of meanfull data in ringbuffer
120 int audio_buffer_size; ///< size of ringbuffer
121 int audio_cnt; ///< size of meanfull data inringbuffer
122 int audio_drop; ///< number of dropped bytes
123 int audio_initialized;
124 #endif
125 radio_param_t *radio_param;
126 } radio_priv_t;
128 typedef struct radio_driver_s {
129 char* name;
130 char* info;
131 int (*init_frac)(radio_priv_t* priv);
132 void (*set_volume)(radio_priv_t* priv,int volume);
133 int (*get_volume)(radio_priv_t* priv,int* volume);
134 int (*set_frequency)(radio_priv_t* priv,float frequency);
135 int (*get_frequency)(radio_priv_t* priv,float* frequency);
136 } radio_driver_t;
138 #define ST_OFF(f) M_ST_OFF(radio_param_t,f)
139 static const m_option_t stream_opts_fields[] = {
140 {"hostname", ST_OFF(freq_channel), CONF_TYPE_FLOAT, 0, 0 ,0, NULL},
141 {"filename", ST_OFF(capture), CONF_TYPE_STRING, 0, 0 ,0, NULL},
142 { NULL, NULL, 0, 0, 0, 0, NULL }
145 static const struct m_struct_st stream_opts = {
146 "radio",
147 sizeof(radio_param_t),
148 &stream_radio_defaults,
149 stream_opts_fields
152 static void close_s(struct stream *stream);
153 #ifdef CONFIG_RADIO_CAPTURE
154 static int clear_buffer(radio_priv_t* priv);
155 #endif
158 /*****************************************************************
159 * \brief parse channels parameter and store result into list
160 * \param freq_channel if channels!=NULL this mean channel number, otherwise - frequency
161 * \param pfreq selected frequency (from selected channel or from URL)
162 * \result STREAM_OK if success, STREAM_ERROR otherwise
164 * channels option must be in the following format
165 * <frequency>-<name>,<frequency>-<name>,...
167 * '_' will be replaced with spaces.
169 * If channels option is not null, number in movie URL will be treated as
170 * channel position in channel list.
172 static int parse_channels(radio_priv_t* priv,float freq_channel,float* pfreq){
173 char** channels;
174 int i;
175 int channel = 0;
176 if (priv->radio_param->channels){
177 /*parsing channels string*/
178 channels=priv->radio_param->channels;
180 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Radio channel names detected.\n");
181 priv->radio_channel_list = malloc(sizeof(radio_channels_t));
182 priv->radio_channel_list->index=1;
183 priv->radio_channel_list->next=NULL;
184 priv->radio_channel_list->prev=NULL;
185 priv->radio_channel_current = priv->radio_channel_list;
187 while (*channels) {
188 char* tmp = *(channels++);
189 char* sep = strchr(tmp,'-');
190 if (!sep) continue; // Wrong syntax, but mplayer should not crash
191 av_strlcpy(priv->radio_channel_current->name, sep + 1,sizeof(priv->radio_channel_current->name)-1);
193 sep[0] = '\0';
195 priv->radio_channel_current->freq=atof(tmp);
197 if ((priv->radio_channel_current->freq>priv->rangehigh)||(priv->radio_channel_current->freq<priv->rangelow))
198 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Wrong frequency for channel %s\n",
199 priv->radio_channel_current->name);
201 while ((sep=strchr(priv->radio_channel_current->name, '_'))) sep[0] = ' ';
203 priv->radio_channel_current->next = malloc(sizeof(radio_channels_t));
204 priv->radio_channel_current->next->index = priv->radio_channel_current->index + 1;
205 priv->radio_channel_current->next->prev = priv->radio_channel_current;
206 priv->radio_channel_current->next->next = NULL;
207 priv->radio_channel_current = priv->radio_channel_current->next;
209 if (priv->radio_channel_current->prev)
210 priv->radio_channel_current->prev->next = NULL;
211 free(priv->radio_channel_current);
213 if (freq_channel)
214 channel = freq_channel;
215 else
216 channel = 1;
218 priv->radio_channel_current = priv->radio_channel_list;
219 for (i = 1; i < channel; i++)
220 if (priv->radio_channel_current->next)
221 priv->radio_channel_current = priv->radio_channel_current->next;
222 if (priv->radio_channel_current->index!=channel){
223 if (((float)((int)freq_channel))!=freq_channel)
224 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Wrong channel number: %.2f\n",freq_channel);
225 else
226 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Wrong channel number: %d\n",(int)freq_channel);
227 return STREAM_ERROR;
229 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Selected channel: %d - %s (freq: %.2f)\n", priv->radio_channel_current->index,
230 priv->radio_channel_current->name, priv->radio_channel_current->freq);
231 *pfreq=priv->radio_channel_current->freq;
232 }else{
233 if (freq_channel){
234 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Radio frequency parameter detected.\n");
235 priv->radio_channel_list=malloc(sizeof(radio_channels_t));
236 priv->radio_channel_list->next=NULL;
237 priv->radio_channel_list->prev=NULL;
238 priv->radio_channel_list->index=1;
239 snprintf(priv->radio_channel_list->name,sizeof(priv->radio_channel_current->name)-1,"Freq: %.2f",freq_channel);
241 priv->radio_channel_current=priv->radio_channel_list;
242 *pfreq=freq_channel;
245 mp_tmsg(MSGT_RADIO, MSGL_DBG2, "[radio] Done parsing channels.\n");
246 return STREAM_OK;
249 #ifdef CONFIG_RADIO_V4L2
250 /*****************************************************************
251 * \brief get fraction value for using in set_frequency and get_frequency
252 * \return STREAM_OK if success, STREAM_ERROR otherwise
254 * V4L2_TUNER_CAP_LOW:
255 * unit=62.5Hz
256 * frac= 1MHz/unit=1000000/62.5 =16000
258 * otherwise:
259 * unit=62500Hz
260 * frac= 1MHz/unit=1000000/62500 =16
262 static int init_frac_v4l2(radio_priv_t* priv){
263 struct v4l2_tuner tuner;
265 memset(&tuner,0,sizeof(tuner));
266 tuner.index=0;
267 if (ioctl(priv->radio_fd, VIDIOC_G_TUNER, &tuner)<0){
268 mp_tmsg(MSGT_RADIO,MSGL_WARN,"[radio] Warning: ioctl get tuner failed: %s. Setting frac to %d.\n",strerror(errno),priv->frac);
269 return STREAM_ERROR;
271 if(tuner.type!=V4L2_TUNER_RADIO){
272 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] %s is no radio device!\n",priv->radio_param->device);
273 return STREAM_ERROR;
275 if(tuner.capability & V4L2_TUNER_CAP_LOW){
276 priv->frac=16000;
277 mp_tmsg(MSGT_RADIO,MSGL_DBG2,"[radio] tuner is low:yes frac=%d\n",priv->frac);
279 else{
280 priv->frac=16;
281 mp_tmsg(MSGT_RADIO,MSGL_DBG2,"[radio] tuner is low:no frac=%d\n",priv->frac);
284 priv->rangelow=((float)tuner.rangelow)/priv->frac;
285 priv->rangehigh=((float)tuner.rangehigh)/priv->frac;
286 mp_tmsg(MSGT_RADIO,MSGL_V,"[radio] Allowed frequency range is %.2f-%.2f MHz.\n",priv->rangelow,priv->rangehigh);
287 return STREAM_OK;
290 /*****************************************************************
291 * \brief tune card to given frequency
292 * \param frequency frequency in MHz
293 * \return STREAM_OK if success, STREAM_ERROR otherwise
295 static int set_frequency_v4l2(radio_priv_t* priv,float frequency){
296 struct v4l2_frequency freq;
298 memset(&freq,0,sizeof(freq));
299 freq.tuner=0;
300 freq.type=V4L2_TUNER_RADIO;
301 freq.frequency=frequency*priv->frac;
302 if(ioctl(priv->radio_fd,VIDIOC_S_FREQUENCY,&freq)<0){
303 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl set frequency 0x%x (%.2f) failed: %s\n",freq.frequency,
304 frequency,strerror(errno));
305 return STREAM_ERROR;
307 return STREAM_OK;
310 /*****************************************************************
311 * \brief get current tuned frequency from card
312 * \param frequency where to store frequency in MHz
313 * \return STREAM_OK if success, STREAM_ERROR otherwise
315 static int get_frequency_v4l2(radio_priv_t* priv,float* frequency){
316 struct v4l2_frequency freq;
317 memset(&freq,0,sizeof(freq));
318 if (ioctl(priv->radio_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
319 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl get frequency failed: %s\n",strerror(errno));
320 return STREAM_ERROR;
322 *frequency=((float)freq.frequency)/priv->frac;
323 return STREAM_OK;
326 /*****************************************************************
327 * \brief set volume on radio card
328 * \param volume volume level (0..100)
329 * \return STREAM_OK if success, STREAM_ERROR otherwise
331 static void set_volume_v4l2(radio_priv_t* priv,int volume){
332 struct v4l2_queryctrl qctrl;
333 struct v4l2_control control;
335 /*arg must be between 0 and 100*/
336 if (volume > 100) volume = 100;
337 if (volume < 0) volume = 0;
339 memset(&control,0,sizeof(control));
340 control.id=V4L2_CID_AUDIO_MUTE;
341 control.value = (volume==0?1:0);
342 if (ioctl(priv->radio_fd, VIDIOC_S_CTRL, &control)<0){
343 mp_tmsg(MSGT_RADIO,MSGL_WARN,"[radio] ioctl set mute failed: %s\n",strerror(errno));
346 memset(&qctrl,0,sizeof(qctrl));
347 qctrl.id = V4L2_CID_AUDIO_VOLUME;
348 if (ioctl(priv->radio_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
349 mp_tmsg(MSGT_RADIO, MSGL_WARN, "[radio] ioctl query control failed: %s\n",strerror(errno));
350 return;
353 memset(&control,0,sizeof(control));
354 control.id=V4L2_CID_AUDIO_VOLUME;
355 control.value=qctrl.minimum+volume*(qctrl.maximum-qctrl.minimum)/100;
356 if (ioctl(priv->radio_fd, VIDIOC_S_CTRL, &control) < 0) {
357 mp_tmsg(MSGT_RADIO, MSGL_WARN,"[radio] ioctl set volume failed: %s\n",strerror(errno));
361 /*****************************************************************
362 * \brief get current volume from radio card
363 * \param volume where to store volume level (0..100)
364 * \return STREAM_OK if success, STREAM_ERROR otherwise
366 static int get_volume_v4l2(radio_priv_t* priv,int* volume){
367 struct v4l2_queryctrl qctrl;
368 struct v4l2_control control;
370 memset(&qctrl,0,sizeof(qctrl));
371 qctrl.id = V4L2_CID_AUDIO_VOLUME;
372 if (ioctl(priv->radio_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
373 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] ioctl query control failed: %s\n",strerror(errno));
374 return STREAM_ERROR;
377 memset(&control,0,sizeof(control));
378 control.id=V4L2_CID_AUDIO_VOLUME;
379 if (ioctl(priv->radio_fd, VIDIOC_G_CTRL, &control) < 0) {
380 mp_tmsg(MSGT_RADIO, MSGL_ERR,"[radio] ioctl get volume failed: %s\n",strerror(errno));
381 return STREAM_ERROR;
384 if (qctrl.maximum==qctrl.minimum)
385 *volume=qctrl.minimum;
386 else
387 *volume=100*(control.value-qctrl.minimum)/(qctrl.maximum-qctrl.minimum);
389 /*arg must be between 0 and 100*/
390 if (*volume > 100) *volume = 100;
391 if (*volume < 0) *volume = 0;
393 return STREAM_OK;
396 /* v4l2 driver info structure */
397 static const radio_driver_t radio_driver_v4l2={
398 "v4l2",
399 _("[radio] Using V4Lv2 radio interface.\n"),
400 init_frac_v4l2,
401 set_volume_v4l2,
402 get_volume_v4l2,
403 set_frequency_v4l2,
404 get_frequency_v4l2
406 #endif /* CONFIG_RADIO_V4L2 */
407 #ifdef CONFIG_RADIO_BSDBT848
409 /*****************************************************************
410 * \brief get fraction value for using in set_frequency and get_frequency
411 * \return STREAM_OK if success, STREAM_ERROR otherwise
413 * For *BSD BT848 frac=100
415 * Here is a coment from FreeBSD 5.2-RELEASE source code:
417 * * Tuner Notes:
418 * * Programming the tuner properly is quite complicated.
419 * * Here are some notes, based on a FM1246 data sheet for a PAL-I tuner.
420 * * The tuner (front end) covers 45.75 MHz - 855.25 MHz and an FM band of
421 * * 87.5 MHz to 108.0 MHz.
423 * Thus, frequency range is limited to 87.5-108.0, but you can change
424 * it, using freq_min and freq_max options
426 static int init_frac_bsdbt848(radio_priv_t* priv){
427 priv->frac=100;
428 priv->rangelow=priv->radio_param->freq_min;
429 priv->rangehigh=priv->radio_param->freq_max;
430 return STREAM_OK;
433 /*****************************************************************
434 * \brief tune card to given frequency
435 * \param frequency frequency in MHz
436 * \return STREAM_OK if success, STREAM_ERROR otherwise
438 static int set_frequency_bsdbt848(radio_priv_t* priv,float frequency){
439 unsigned int freq;
440 freq=frequency*priv->frac;
441 if(ioctl(priv->radio_fd,RADIO_SETFREQ,&freq)<0){
442 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl set frequency 0x%x (%.2f) failed: %s\n",freq, frequency, strerror(errno));
443 return STREAM_ERROR;
445 return STREAM_OK;
448 /*****************************************************************
449 * \brief get current tuned frequency from card
450 * \param frequency where to store frequency in MHz
451 * \return STREAM_OK if success, STREAM_ERROR otherwise
453 static int get_frequency_bsdbt848(radio_priv_t* priv,float* frequency){
454 unsigned int freq;
455 if (ioctl(priv->radio_fd, RADIO_GETFREQ, &freq) < 0) {
456 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl get frequency failed: %s\n",strerror(errno));
457 return STREAM_ERROR;
459 *frequency=((float)freq)/priv->frac;
460 return STREAM_OK;
463 /*****************************************************************
464 * \brief set volume on radio card
465 * \param volume volume level (0..100)
466 * \return STREAM_OK if success, STREAM_ERROR otherwise
468 * *BSD BT848 does not have volume changing abilities, so
469 * we will just mute sound if volume=0 and unmute it otherwise.
471 static void set_volume_bsdbt848(radio_priv_t* priv,int volume){
472 int audio_flags;
474 /*arg must be between 0 and 100*/
475 if (volume > 100) volume = 100;
476 if (volume < 0) volume = 0;
478 audio_flags = (volume==0?AUDIO_MUTE:AUDIO_UNMUTE);
479 if (ioctl(priv->radio_fd, BT848_SAUDIO, &audio_flags)<0){
480 mp_tmsg(MSGT_RADIO,MSGL_WARN,"[radio] ioctl set mute failed: %s\n",strerror(errno));
484 /*****************************************************************
485 * \brief get current volume from radio card
486 * \param volume where to store volume level (0..100)
487 * \return previous STREAM_OK if success, STREAM_ERROR otherwise
489 * *BSD BT848 does not have volume changing abilities, so
490 * we will return 0 if sound is muted and 100 otherwise.
492 static int get_volume_bsdbt848(radio_priv_t* priv,int* volume){
493 int audio_flags;
495 if (ioctl(priv->radio_fd, BT848_GAUDIO, &audio_flags)<0){
496 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] ioctl get volume failed: %s\n",strerror(errno));
497 return STREAM_ERROR;
500 if (audio_flags & AUDIO_MUTE)
501 *volume=0;
502 else
503 *volume=100;
505 return STREAM_OK;
508 /* bsdbt848 driver info structure */
509 static const radio_driver_t radio_driver_bsdbt848={
510 "bsdbt848",
511 _("[radio] Using *BSD BT848 radio interface.\n"),
512 init_frac_bsdbt848,
513 set_volume_bsdbt848,
514 get_volume_bsdbt848,
515 set_frequency_bsdbt848,
516 get_frequency_bsdbt848
518 #endif /* CONFIG_RADIO_BSDBT848 */
520 static inline int init_frac(radio_priv_t* priv){
521 return priv->driver->init_frac(priv);
523 static inline int set_frequency(radio_priv_t* priv,float frequency){
524 if ((frequency<priv->rangelow)||(frequency>priv->rangehigh)){
525 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] Wrong frequency: %.2f\n",frequency);
526 return STREAM_ERROR;
528 if(priv->driver->set_frequency(priv,frequency)!=STREAM_OK)
529 return STREAM_ERROR;
531 #ifdef CONFIG_RADIO_CAPTURE
532 if(clear_buffer(priv)!=STREAM_OK){
533 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] Clearing buffer failed: %s\n",strerror(errno));
534 return STREAM_ERROR;
536 #endif
537 return STREAM_OK;
539 static inline int get_frequency(radio_priv_t* priv,float* frequency){
540 return priv->driver->get_frequency(priv,frequency);
542 static inline void set_volume(radio_priv_t* priv,int volume){
543 priv->driver->set_volume(priv,volume);
545 static inline int get_volume(radio_priv_t* priv,int* volume){
546 return priv->driver->get_volume(priv,volume);
550 #ifndef CONFIG_RADIO_CAPTURE
551 /*****************************************************************
552 * \brief stub, if capture disabled at compile-time
553 * \return STREAM_OK
555 static inline int init_audio(radio_priv_t *priv){ return STREAM_OK;}
556 #else
557 /*****************************************************************
558 * \brief making buffer empty
559 * \return STREAM_OK if success, STREAM_ERROR otherwise
561 * when changing channel we must clear buffer to avoid large switching delay
563 static int clear_buffer(radio_priv_t* priv){
564 if (!priv->do_capture) return STREAM_OK;
565 priv->audio_tail = 0;
566 priv->audio_head = 0;
567 priv->audio_cnt=0;
568 memset(priv->audio_ringbuffer,0,priv->audio_in.blocksize);
569 return STREAM_OK;
571 /*****************************************************************
572 * \brief read next part of data into buffer
573 * \return -1 if error occured or no data available yet, otherwise - bytes read
574 * NOTE: audio device works in non-blocking mode
576 static int read_chunk(audio_in_t *ai, unsigned char *buffer)
578 int ret;
580 switch (ai->type) {
581 #ifdef CONFIG_ALSA
582 case AUDIO_IN_ALSA:
583 //device opened in non-blocking mode
584 ret = snd_pcm_readi(ai->alsa.handle, buffer, ai->alsa.chunk_size);
585 if (ret != ai->alsa.chunk_size) {
586 if (ret < 0) {
587 if (ret==-EAGAIN) return -1;
588 mp_tmsg(MSGT_RADIO, MSGL_ERR, "\nError reading audio: %s\n", snd_strerror(ret));
589 if (ret == -EPIPE) {
590 if (ai_alsa_xrun(ai) == 0) {
591 mp_tmsg(MSGT_RADIO, MSGL_ERR, "Recovered from cross-run, some frames may be left out!\n");
592 } else {
593 mp_tmsg(MSGT_RADIO, MSGL_ERR, "Fatal error, cannot recover!\n");
596 } else {
597 mp_tmsg(MSGT_RADIO, MSGL_ERR, "\nNot enough audio samples!\n");
599 return -1;
601 return ret;
602 #endif
603 #ifdef CONFIG_OSS_AUDIO
604 case AUDIO_IN_OSS:
606 int bt=0;
608 we must return exactly blocksize bytes, so if we have got any bytes
609 at first call to read, we will loop untils get all blocksize bytes
610 otherwise we will return -1
612 while(bt<ai->blocksize){
613 //device opened in non-blocking mode
614 ret = read(ai->oss.audio_fd, buffer+bt, ai->blocksize-bt);
615 if (ret==ai->blocksize) return ret;
616 if (ret<0){
617 if (errno==EAGAIN && bt==0) return -1; //no data avail yet
618 if (errno==EAGAIN) { usleep(1000); continue;} //nilling buffer to blocksize size
619 mp_tmsg(MSGT_RADIO, MSGL_ERR, "\nError reading audio: %s\n", strerror(errno));
620 return -1;
622 bt+=ret;
624 return bt;
626 #endif
627 default:
628 return -1;
631 /*****************************************************************
632 * \brief grab next frame from audio device
633 * \parameter buffer - store buffer
634 * \parameter len - store buffer size in bytes
635 * \return number of bytes written into buffer
637 * grabs len (or less) bytes from ringbuffer into buffer
638 * if ringbuffer is empty waits until len bytes of data will be available
640 * priv->audio_cnt - size (in bytes) of ringbuffer's filled part
641 * priv->audio_drop - size (in bytes) of dropped data (if no space in ringbuffer)
642 * priv->audio_head - index of first byte in filled part
643 * priv->audio_tail - index of last byte in filled part
645 * NOTE: audio_tail always aligned by priv->audio_in.blocksize
646 * audio_head may NOT.
648 static int grab_audio_frame(radio_priv_t *priv, char *buffer, int len)
650 int i;
651 mp_tmsg(MSGT_RADIO, MSGL_DBG3, "[radio] %s: in buffer=%d dropped=%d\n","grab_audio_frame",priv->audio_cnt,priv->audio_drop);
652 /* Cache buffer must be filled by some audio packets when playing starts.
653 Otherwise MPlayer will quit with EOF error.
654 Probably, there is need more carefull checking rather than simple 'for' loop
655 (something like timer or similar).
657 1000ms delay will happen only at first buffer filling. At next call function
658 just fills buffer until either buffer full or no data from driver available.
660 for (i=0;i<1000 && !priv->audio_cnt; i++){
661 //read_chunk fills exact priv->blocksize bytes
662 if(read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail) < 0){
663 //sleppeing only when waiting first block to fill empty buffer
664 if (!priv->audio_cnt){
665 usleep(1000);
666 continue;
667 }else
668 break;
670 priv->audio_cnt+=priv->audio_in.blocksize;
671 priv->audio_tail = (priv->audio_tail+priv->audio_in.blocksize) % priv->audio_buffer_size;
673 if(priv->audio_cnt<len)
674 len=priv->audio_cnt;
675 memcpy(buffer, priv->audio_ringbuffer+priv->audio_head,len);
676 priv->audio_head = (priv->audio_head+len) % priv->audio_buffer_size;
677 priv->audio_cnt-=len;
678 return len;
680 /*****************************************************************
681 * \brief init audio device
682 * \return STREAM_OK if success, STREAM_ERROR otherwise
684 static int init_audio(radio_priv_t *priv)
686 int is_oss=1;
687 int seconds=2;
688 char* tmp;
689 if (priv->audio_initialized) return 1;
691 /* do_capture==0 mplayer was not started with capture keyword, so disabling capture*/
692 if(!priv->do_capture)
693 return STREAM_OK;
695 if (!priv->radio_param->adevice){
696 priv->do_capture=0;
697 return STREAM_OK;
700 priv->do_capture=1;
701 mp_tmsg(MSGT_RADIO,MSGL_V,"[radio] Starting capture stuff.\n");
702 #ifdef CONFIG_ALSA
703 while ((tmp = strrchr(priv->radio_param->adevice, '='))){
704 tmp[0] = ':';
705 //adevice option looks like ALSA device name. Switching to ALSA
706 is_oss=0;
708 while ((tmp = strrchr(priv->radio_param->adevice, '.')))
709 tmp[0] = ',';
710 #endif
712 if(audio_in_init(&priv->audio_in, is_oss?AUDIO_IN_OSS:AUDIO_IN_ALSA)<0){
713 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] audio_in_init failed.\n");
716 audio_in_set_device(&priv->audio_in, priv->radio_param->adevice);
717 audio_in_set_channels(&priv->audio_in, priv->radio_param->achannels);
718 audio_in_set_samplerate(&priv->audio_in, priv->radio_param->arate);
720 if (audio_in_setup(&priv->audio_in) < 0) {
721 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] audio_in_setup call failed: %s\n", strerror(errno));
722 return STREAM_ERROR;
724 #ifdef CONFIG_OSS_AUDIO
725 if(is_oss)
726 ioctl(priv->audio_in.oss.audio_fd, SNDCTL_DSP_NONBLOCK, 0);
727 #endif
728 #ifdef CONFIG_ALSA
729 if(!is_oss)
730 snd_pcm_nonblock(priv->audio_in.alsa.handle,1);
731 #endif
733 priv->audio_buffer_size = seconds*priv->audio_in.samplerate*priv->audio_in.channels*
734 priv->audio_in.bytes_per_sample+priv->audio_in.blocksize;
735 if (priv->audio_buffer_size < 256*priv->audio_in.blocksize)
736 priv->audio_buffer_size = 256*priv->audio_in.blocksize;
737 mp_tmsg(MSGT_RADIO, MSGL_V, "[radio] Audio capture - buffer=%d bytes (block=%d bytes).\n",
738 priv->audio_buffer_size,priv->audio_in.blocksize);
739 /* start capture */
740 priv->audio_ringbuffer = calloc(1, priv->audio_buffer_size);
741 if (!priv->audio_ringbuffer) {
742 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));
743 return STREAM_ERROR;
745 priv->audio_head = 0;
746 priv->audio_tail = 0;
747 priv->audio_cnt = 0;
748 priv->audio_drop = 0;
750 audio_in_start_capture(&priv->audio_in);
752 priv->audio_initialized = 1;
754 return STREAM_OK;
756 #endif /* CONFIG_RADIO_CAPTURE */
758 /*-------------------------------------------------------------------------
759 for call from mplayer.c
760 --------------------------------------------------------------------------*/
761 /*****************************************************************
762 * \brief public wrapper for get_frequency
763 * \parameter frequency pointer to float, which will contain frequency in MHz
764 * \return 1 if success,0 - otherwise
766 int radio_get_freq(struct stream *stream, float *frequency){
767 radio_priv_t* priv=(radio_priv_t*)stream->priv;
769 if (!frequency)
770 return 0;
771 if (get_frequency(priv,frequency)!=STREAM_OK){
772 return 0;
774 return 1;
776 /*****************************************************************
777 * \brief public wrapper for set_frequency
778 * \parameter frequency frequency in MHz
779 * \return 1 if success,0 - otherwise
781 int radio_set_freq(struct stream *stream, float frequency){
782 radio_priv_t* priv=(radio_priv_t*)stream->priv;
784 if (set_frequency(priv,frequency)!=STREAM_OK){
785 return 0;
787 if (get_frequency(priv,&frequency)!=STREAM_OK){
788 return 0;
790 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Current frequency: %.2f\n",frequency);
791 return 1;
794 /*****************************************************************
795 * \brief tune current frequency by step_interval value
796 * \parameter step_interval increment value
797 * \return 1 if success,0 - otherwise
800 int radio_step_freq(struct stream *stream, float step_interval){
801 float frequency;
802 radio_priv_t* priv=(radio_priv_t*)stream->priv;
804 if (get_frequency(priv,&frequency)!=STREAM_OK)
805 return 0;
807 frequency+=step_interval;
808 if (frequency>priv->rangehigh)
809 frequency=priv->rangehigh;
810 if (frequency<priv->rangelow)
811 frequency=priv->rangelow;
813 return radio_set_freq(stream,frequency);
815 /*****************************************************************
816 * \brief step channel up or down
817 * \parameter direction RADIO_CHANNEL_LOWER - go to prev channel,RADIO_CHANNEL_HIGHER - to next
818 * \return 1 if success,0 - otherwise
820 * if channel parameter is NULL function prints error message and does nothing, otherwise
821 * changes channel to prev or next in list
823 int radio_step_channel(struct stream *stream, int direction) {
824 radio_priv_t* priv=(radio_priv_t*)stream->priv;
826 if (priv->radio_channel_list) {
827 switch (direction){
828 case RADIO_CHANNEL_HIGHER:
829 if (priv->radio_channel_current->next)
830 priv->radio_channel_current = priv->radio_channel_current->next;
831 else
832 priv->radio_channel_current = priv->radio_channel_list;
833 if(!radio_set_freq(stream,priv->radio_channel_current->freq))
834 return 0;
835 mp_tmsg(MSGT_RADIO, MSGL_V, "[radio] Selected channel: %d - %s (freq: %.2f)\n",
836 priv->radio_channel_current->index, priv->radio_channel_current->name,
837 priv->radio_channel_current->freq);
838 break;
839 case RADIO_CHANNEL_LOWER:
840 if (priv->radio_channel_current->prev)
841 priv->radio_channel_current = priv->radio_channel_current->prev;
842 else
843 while (priv->radio_channel_current->next)
844 priv->radio_channel_current = priv->radio_channel_current->next;
845 if(!radio_set_freq(stream,priv->radio_channel_current->freq))
846 return 0;
847 mp_tmsg(MSGT_RADIO, MSGL_V, "[radio] Selected channel: %d - %s (freq: %.2f)\n",
848 priv->radio_channel_current->index, priv->radio_channel_current->name,
849 priv->radio_channel_current->freq);
850 break;
852 }else
853 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Can not change channel: no channel list given.\n");
854 return 1;
857 /*****************************************************************
858 * \brief change channel to one with given index
859 * \parameter channel string, containing channel number
860 * \return 1 if success,0 - otherwise
862 * if channel parameter is NULL function prints error message and does nothing, otherwise
863 * changes channel to given
865 int radio_set_channel(struct stream *stream, char *channel) {
866 radio_priv_t* priv=(radio_priv_t*)stream->priv;
867 int i, channel_int;
868 radio_channels_t* tmp;
869 char* endptr;
871 if (*channel=='\0')
872 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] Wrong channel name: %s\n",channel);
874 if (priv->radio_channel_list) {
875 channel_int = strtol(channel,&endptr,10);
876 tmp = priv->radio_channel_list;
877 if (*endptr!='\0'){
878 //channel is not a number, so it contains channel name
879 for ( ; tmp; tmp=tmp->next)
880 if (!strncmp(channel,tmp->name,sizeof(tmp->name)-1))
881 break;
882 if (!tmp){
883 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] Wrong channel name: %s\n",channel);
884 return 0;
886 }else{
887 for (i = 1; i < channel_int; i++)
888 if (tmp->next)
889 tmp = tmp->next;
890 else
891 break;
892 if (tmp->index!=channel_int){
893 mp_tmsg(MSGT_RADIO,MSGL_ERR,"[radio] Wrong channel number: %d\n",channel_int);
894 return 0;
897 priv->radio_channel_current=tmp;
898 mp_tmsg(MSGT_RADIO, MSGL_V, "[radio] Selected channel: %d - %s (freq: %.2f)\n", priv->radio_channel_current->index,
899 priv->radio_channel_current->name, priv->radio_channel_current->freq);
900 if(!radio_set_freq(stream, priv->radio_channel_current->freq))
901 return 0;
902 } else
903 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Can not change channel: no channel list given.\n");
904 return 1;
907 /*****************************************************************
908 * \brief get current channel's name
909 * \return pointer to string, containing current channel's name
911 * NOTE: return value may be NULL (e.g. when channel list not initialized)
913 char* radio_get_channel_name(struct stream *stream){
914 radio_priv_t* priv=(radio_priv_t*)stream->priv;
915 if (priv->radio_channel_current) {
916 return priv->radio_channel_current->name;
918 return NULL;
921 /*****************************************************************
922 * \brief fills given buffer with audio data
923 * \return number of bytes, written into buffer
925 static int fill_buffer_s(struct stream *s, char *buffer, int max_len){
926 int len=max_len;
928 #ifdef CONFIG_RADIO_CAPTURE
929 radio_priv_t* priv=(radio_priv_t*)s->priv;
931 if (priv->do_capture){
932 len=grab_audio_frame(priv, buffer,max_len);
934 else
935 #endif
936 memset(buffer,0,len);
937 return len;
942 order if significant!
943 when no driver explicitly specified first available will be used
945 static const radio_driver_t* radio_drivers[]={
946 #ifdef CONFIG_RADIO_BSDBT848
947 &radio_driver_bsdbt848,
948 #endif
949 #ifdef CONFIG_RADIO_V4L2
950 &radio_driver_v4l2,
951 #endif
955 /*****************************************************************
956 * Stream initialization
957 * \return STREAM_OK if success, STREAM_ERROR otherwise
959 static int open_s(stream_t *stream,int mode, void* opts, int* file_format) {
960 radio_priv_t* priv;
961 float frequency=0;
962 int i;
964 if (strncmp("radio://",stream->url,8) != 0)
965 return STREAM_UNSUPPORTED;
967 if(mode != STREAM_READ)
968 return STREAM_UNSUPPORTED;
970 priv=calloc(1,sizeof(radio_priv_t));
972 if (!priv)
973 return STREAM_ERROR;
976 priv->radio_param=opts;
978 #ifdef CONFIG_RADIO_CAPTURE
979 if (priv->radio_param->capture && strncmp("capture",priv->radio_param->capture,7)==0)
980 priv->do_capture=1;
981 else
982 priv->do_capture=0;
983 #endif
987 if (strncmp(priv->radio_param->driver,"default",7)==0)
988 priv->driver=radio_drivers[0];
989 else
990 priv->driver=NULL;
992 mp_tmsg(MSGT_RADIO,MSGL_V,"[radio] Available drivers: ");
993 for(i=0;radio_drivers[i];i++){
994 mp_msg(MSGT_RADIO,MSGL_V,"%s, ",radio_drivers[i]->name);
995 if(strcmp(priv->radio_param->driver,radio_drivers[i]->name)==0)
996 priv->driver=radio_drivers[i];
998 mp_msg(MSGT_RADIO,MSGL_V,"\n");
1000 if(priv->driver)
1001 mp_msg(MSGT_RADIO, MSGL_INFO, priv->driver->info);
1002 else{
1003 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Unknown driver name: %s\n",priv->radio_param->driver);
1004 close_s(stream);
1005 return STREAM_ERROR;
1008 stream->type = STREAMTYPE_RADIO;
1009 /* using rawaudio demuxer */
1010 *file_format = DEMUXER_TYPE_RAWAUDIO;
1011 stream->flags = STREAM_READ;
1013 priv->radio_fd=-1;
1015 stream->start_pos=0;
1016 stream->end_pos=0;
1017 stream->priv=priv;
1018 stream->close=close_s;
1019 stream->fill_buffer=fill_buffer_s;
1021 priv->radio_fd = open(priv->radio_param->device, O_RDONLY);
1022 if (priv->radio_fd < 0) {
1023 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Unable to open '%s': %s\n",
1024 priv->radio_param->device, strerror(errno));
1025 close_s(stream);
1026 return STREAM_ERROR;
1028 mp_tmsg(MSGT_RADIO, MSGL_V, "[radio] Radio fd: %d, %s\n", priv->radio_fd,priv->radio_param->device);
1029 fcntl(priv->radio_fd, F_SETFD, FD_CLOEXEC);
1031 get_volume(priv, &priv->old_snd_volume);
1032 set_volume(priv,0);
1034 if (init_frac(priv)!=STREAM_OK){
1035 close_s(stream);
1036 return STREAM_ERROR;
1039 if (parse_channels(priv,priv->radio_param->freq_channel,&frequency)!=STREAM_OK){
1040 close_s(stream);
1041 return STREAM_ERROR;
1044 if ((frequency<priv->rangelow)||(frequency>priv->rangehigh)){
1045 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Wrong frequency: %.2f\n",frequency);
1046 close_s(stream);
1047 return STREAM_ERROR;
1048 }else
1049 mp_tmsg(MSGT_RADIO, MSGL_INFO, "[radio] Using frequency: %.2f.\n",frequency);
1051 if(set_frequency(priv,frequency)!=STREAM_OK){
1052 close_s(stream);
1053 return STREAM_ERROR;
1057 if (init_audio(priv)!=STREAM_OK){
1058 close_s(stream);
1059 return STREAM_ERROR;
1062 #if defined(CONFIG_RADIO_CAPTURE) && defined(CONFIG_STREAM_CACHE)
1063 if(priv->do_capture){
1064 //5 second cache
1065 if(!stream_enable_cache(stream,5*priv->audio_in.samplerate*priv->audio_in.channels*
1066 priv->audio_in.bytes_per_sample,2*priv->audio_in.samplerate*priv->audio_in.channels*
1067 priv->audio_in.bytes_per_sample,priv->audio_in.blocksize)) {
1068 mp_tmsg(MSGT_RADIO, MSGL_ERR, "[radio] Call to stream_enable_cache failed: %s\n",strerror(errno));
1069 close_s(stream);
1070 return STREAM_ERROR;
1073 #endif
1075 set_volume(priv,priv->radio_param->volume);
1077 return STREAM_OK;
1080 /*****************************************************************
1081 * Close stream. Clear structures.
1083 static void close_s(struct stream *stream){
1084 radio_priv_t* priv=(radio_priv_t*)stream->priv;
1085 radio_channels_t * tmp;
1086 if (!priv) return;
1088 #ifdef CONFIG_RADIO_CAPTURE
1089 free(priv->audio_ringbuffer);
1090 priv->audio_ringbuffer = NULL;
1092 priv->do_capture=0;
1093 #endif
1095 while (priv->radio_channel_list) {
1096 tmp=priv->radio_channel_list;
1097 priv->radio_channel_list=priv->radio_channel_list->next;
1098 free(tmp);
1100 priv->radio_channel_current=NULL;
1101 priv->radio_channel_list=NULL;
1103 if (priv->radio_fd>0){
1104 set_volume(priv, priv->old_snd_volume);
1105 close(priv->radio_fd);
1108 if(priv->radio_param)
1109 m_struct_free(&stream_opts,priv->radio_param);
1110 free(priv);
1111 stream->priv=NULL;
1114 const stream_info_t stream_info_radio = {
1115 "Radio stream",
1116 "Radio",
1117 "Vladimir Voroshilov",
1118 "In development",
1119 open_s,
1120 { "radio", NULL },
1121 &stream_opts,
1122 1 // Urls are an option string