summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS3
-rw-r--r--ChangeLog1
-rw-r--r--DOCS/man/en/mplayer.156
-rw-r--r--DOCS/xml/en/documentation.xml1
-rw-r--r--DOCS/xml/en/install.xml5
-rw-r--r--DOCS/xml/ru/features.xml1
-rw-r--r--DOCS/xml/ru/install.xml9
-rw-r--r--cfg-common.h21
-rwxr-xr-xconfigure91
-rw-r--r--help/help_mp-en.h43
-rw-r--r--input/input.c5
-rw-r--r--input/input.h3
-rw-r--r--mp_msg.h2
-rw-r--r--mplayer.c32
-rw-r--r--stream/Makefile17
-rw-r--r--stream/stream.c6
-rw-r--r--stream/stream.h1
-rw-r--r--stream/stream_radio.c1108
-rw-r--r--stream/stream_radio.h23
19 files changed, 1428 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
index 4b1eaca106..f387f7e2d7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1046,6 +1046,9 @@ Vesko, Radic <rvesko@EUnet.yu>
Vigvary, Balasz (Toky)
* avifile
+Voroshilov, Vladimir <voroshil@gmail.com>
+ * Radio support
+
Weber, Andrew (Webby) <webbypssht@gmail.com>
* webby, smoothwebby
diff --git a/ChangeLog b/ChangeLog
index a42e42c219..9fb0caa214 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -24,6 +24,7 @@ MPlayer (1.0)
* PVR input for IVTV based cards (Hauppauge WinTV PVR-150/250/350/500)
* native RTSP input (handles MPEG-TS over RTP) for generic RTSP servers.
* support for chapters seeking in dvd:// and dvdnav:// streams
+ * Radio support (radio://)
FFmpeg/libavcodec:
* VC-1/WMV3/WMV9 video decoder
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1
index 92fbcfe732..6dee23d5d7 100644
--- a/DOCS/man/en/mplayer.1
+++ b/DOCS/man/en/mplayer.1
@@ -88,6 +88,13 @@ mencoder \- movie encoder
.in
.B mplayer
'in +\n[.k]u
+.I radio://[channel or frequency][/capture]
+[options]
+.
+.br
+.in
+.B mplayer
+'in +\n[.k]u
.I pvr://
[options]
.
@@ -1542,6 +1549,55 @@ program (if present) you want to play.
Can be used with \-vid and \-aid.
.
.TP
+.B \-radio <option1:option2:...> (Radio only)
+This options set variaous parameters of radio capture module
+For listening radio with MPlayer use 'radio://<frequency>'
+(if channels option is not given) or
+'radio://<channel_number>' (if channels option is given) as
+a movie URL. To start grabbing subsystem, please use
+radio://<frequency or channel>/capture. If capture keyword is not given
+your can listen radio using line-in cable only. Using capture
+to listening is not recommended due to synchronization problems, which
+makes this process uncomfortable.
+.sp 1
+Available options are:
+.RSs
+.IPs device=<value>
+radio device to use (default /dev/radio0)
+.IPs driver=<value>
+radio driver to use (default v4l2 if available, otherwise v4l). Currently supported
+v4l and v4l2 drivers.
+.IPs volume=<0..100>
+sound volume for radio device (default 100)
+.IPs channels=<frequency>\-<name>,<frequency>\-<name>,...
+Set channel list.
+Use _ for spaces in names (or play with quoting ;-).
+The channel names will then be written using OSD, and the slave commands
+radio_step_channel and radio_set_channel will be usable for
+a remote control (see LIRC).
+If given, number in movie URL will be treated as channel position in
+channel list.
+.br
+.I EXAMPLE:
+radio://1, radio://104.4, radio_set_channel 1
+.IPs adevice=<value> (with radio capture enabled)
+Name of device to capture sound from. If not given capture will be
+disabled, even if capture keyword in URL used. For alsa devices use it
+in form hw=<card>.<device>. If device
+name contain '=' module will use ALSA to capture, otherwise - OSS.
+.IPs arate=<value> (with radio capture enabled)
+Rate in samples per second (default 44100).
+.br
+.I NOTE:
+When using audio capture set also
+-rawaudio rate=<value> option with the same value as arate. If
+you have problems with sound speed (too quickl) try to play with
+different values of rate (e.g. 48000,44100,32000,...).
+.IPs achannels=<value> (with radio capture enabled)
+number of audio channels to capture
+.RE
+.
+.TP
.B \-tv <option1:option2:...> (TV/PVR only)
This option tunes various properties of the TV capture module.
For watching TV with MPlayer, use 'tv://' or 'tv://<channel_number>'
diff --git a/DOCS/xml/en/documentation.xml b/DOCS/xml/en/documentation.xml
index e2a1f90eac..6ddd105c34 100644
--- a/DOCS/xml/en/documentation.xml
+++ b/DOCS/xml/en/documentation.xml
@@ -185,6 +185,7 @@ can be distributed under the terms of the GNU General Public License Version 2.
&video.xml;
&audio.xml;
&tvinput.xml;
+&radio.xml;
&ports.xml;
&mencoder.xml;
diff --git a/DOCS/xml/en/install.xml b/DOCS/xml/en/install.xml
index 3ea2f15e4d..ba8d1c9d77 100644
--- a/DOCS/xml/en/install.xml
+++ b/DOCS/xml/en/install.xml
@@ -434,6 +434,11 @@ it works with the following drivers:
read the <link linkend="tv-input">TV input</link> section.
</para></listitem>
<listitem><para>
+ If you have a V4L compatible <emphasis role="bold">Radio tuner</emphasis> card,
+ and wish to listen and capture sound with <application>MPlayer</application>,
+ read the <link linkend="radio">Radio</link> section.
+ </para></listitem>
+<listitem><para>
There is a neat <emphasis role="bold">OSD Menu</emphasis> support ready to be
used. Check the <link linkend="subosd">OSD menu</link> section.
</para></listitem>
diff --git a/DOCS/xml/ru/features.xml b/DOCS/xml/ru/features.xml
index 65b51e4b99..1de8d296d1 100644
--- a/DOCS/xml/ru/features.xml
+++ b/DOCS/xml/ru/features.xml
@@ -7,5 +7,6 @@
&codecs.xml;
&tvinput.xml;
+&radio.xml;
</chapter>
diff --git a/DOCS/xml/ru/install.xml b/DOCS/xml/ru/install.xml
index 87f2799b60..a0839a0868 100644
--- a/DOCS/xml/ru/install.xml
+++ b/DOCS/xml/ru/install.xml
@@ -449,6 +449,15 @@ nVidia TV-выход</link>, если Вы хотите использовать TV.
и кодировать MPlayer'ом фильмы, читайте секцию <link linkend="tv-input">TV вход</link>.
</para></listitem>
<listitem><para>
+ Если у вас есть V4L совместимый <emphasis role="bold">Radio тюнер</emphasis>,
+ и вы хотите слушать/записывать MPlayer'ом радиопередачи, читайте секцию
+ <link linkend="radio">Радио</link>.
+ </para></listitem>
+<listitem><para>
+ There is a neat <emphasis role="bold">OSD Menu</emphasis> support ready to be
+ used. Check the <link linkend="subosd">OSD menu</link> section.
+ </para></listitem>
+<listitem><para>
Существует изящное <emphasis role="bold">OSD Меню</emphasis> готовое для использования. Проверьте секцию
<link linkend="subosd">OSD Меню</link>.
</para></listitem>
diff --git a/cfg-common.h b/cfg-common.h
index 8d2291b2fa..ad69e5cb1d 100644
--- a/cfg-common.h
+++ b/cfg-common.h
@@ -133,6 +133,11 @@
{ "noextbased", &extension_parsing, CONF_TYPE_FLAG, 0, 1, 0, NULL },
{"mf", mfopts_conf, CONF_TYPE_SUBCONFIG, 0,0,0, NULL},
+#ifdef USE_RADIO
+ {"radio", radioopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
+#else
+ {"radio", "MPlayer was compiled without Radio interface support.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL},
+#endif
#ifdef USE_TV
{"tv", tvopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
#else
@@ -370,10 +375,25 @@ extern int ts_keep_broken;
extern off_t ts_probe;
#include "stream/tv.h"
+#include "stream/stream_radio.h"
extern char* edl_filename;
extern char* edl_output_filename;
+
+#ifdef USE_RADIO
+m_option_t radioopts_conf[]={
+ {"device", &radio_param_device, CONF_TYPE_STRING, 0, 0 ,0, NULL},
+ {"driver", &radio_param_driver, CONF_TYPE_STRING, 0, 0 ,0, NULL},
+ {"channels", &radio_param_channels, CONF_TYPE_STRING_LIST, 0, 0 ,0, NULL},
+ {"volume", &radio_param_volume, CONF_TYPE_INT, CONF_RANGE, 0 ,100, NULL},
+ {"adevice", &radio_param_adevice, CONF_TYPE_STRING, 0, 0 ,0, NULL},
+ {"arate", &radio_param_arate, CONF_TYPE_INT, CONF_MIN, 0 ,0, NULL},
+ {"achannels", &radio_param_achannels, CONF_TYPE_INT, CONF_MIN, 0 ,0, NULL},
+ {NULL, NULL, 0, 0, 0, 0, NULL}
+};
+#endif
+
#ifdef USE_TV
m_option_t tvopts_conf[]={
{"on", "-tv on is deprecated, use tv:// instead.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL},
@@ -561,6 +581,7 @@ m_option_t msgl_config[]={
{ "mencoder", &mp_msg_levels[MSGT_MENCODER], CONF_TYPE_INT, CONF_RANGE, -1, 9, NULL },
{ "xacodec", &mp_msg_levels[MSGT_XACODEC], CONF_TYPE_INT, CONF_RANGE, -1, 9, NULL },
{ "tv", &mp_msg_levels[MSGT_TV], CONF_TYPE_INT, CONF_RANGE, -1, 9, NULL },
+ { "radio", &mp_msg_levels[MSGT_RADIO], CONF_TYPE_INT, CONF_RANGE, -1, 9, NULL },
{ "osdep", &mp_msg_levels[MSGT_OSDEP], CONF_TYPE_INT, CONF_RANGE, -1, 9, NULL },
{ "spudec", &mp_msg_levels[MSGT_SPUDEC], CONF_TYPE_INT, CONF_RANGE, -1, 9, NULL },
{ "playtree", &mp_msg_levels[MSGT_PLAYTREE], CONF_TYPE_INT, CONF_RANGE, -1, 9, NULL },
diff --git a/configure b/configure
index 419630805a..b3be97ab8e 100755
--- a/configure
+++ b/configure
@@ -215,6 +215,9 @@ Optional features:
--enable-joystick enable joystick support [disable]
--disable-vm disable support X video mode extensions [autodetect]
--disable-xf86keysym disable support for 'multimedia' keys [autodetect]
+ --enable-radio enable Radio Interface [disable]
+ --enable-radio-capture enable Capture for Radio Interface (through pci/line-in) [disable]
+ --disable-radio-v4l2 disable Video4Linux2 Radio Interface support [autodetect]
--disable-tv disable TV Interface (tv/dvb grabbers) [enable]
--disable-tv-v4l1 disable Video4Linux TV Interface support [autodetect]
--disable-tv-v4l2 disable Video4Linux2 TV Interface support [autodetect]
@@ -1647,6 +1650,10 @@ _fastmemcpy=yes
_unrarlib=yes
_win32=auto
_select=yes
+_radio=no
+_radio_capture=no
+_radio_v4l=auto
+_radio_v4l2=auto
_tv=yes
_tv_v4l1=auto
_tv_v4l2=auto
@@ -1890,6 +1897,14 @@ for ac_option do
--disable-tv-v4l1) _tv_v4l1=no ;;
--enable-tv-v4l2) _tv_v4l2=yes ;;
--disable-tv-v4l2) _tv_v4l2=no ;;
+ --enable-radio) _radio=yes ;;
+ --enable-radio-capture) _radio_capture=yes ;;
+ --disable-radio-capture) _radio_capture=no ;;
+ --disable-radio) _radio=no ;;
+ --enable-radio-v4l) _radio_v4l=yes ;;
+ --disable-radio-v4l) _radio_v4l=no ;;
+ --enable-radio-v4l2) _radio_v4l2=yes ;;
+ --disable-radio-v4l2) _radio_v4l2=no ;;
--enable-pvr) _pvr=yes ;;
--disable-pvr) _pvr=no ;;
--enable-fastmemcpy) _fastmemcpy=yes ;;
@@ -6641,6 +6656,68 @@ fi
echores "$_tv_v4l2"
+echocheck "Radio interface"
+if test "$_radio" = yes ; then
+ _def_radio='#define USE_RADIO 1'
+ _inputmodules="radio $_inputmodules"
+ if test "$_alsa9" != yes -a "$_alsa1x" != yes -a "$_ossaudio" != yes ; then
+ _radio_capture=no
+ fi
+ if test "$_radio_capture" = yes ; then
+ _def_radio_capture="#define USE_RADIO_CAPTURE 1"
+ else
+ _def_radio_capture="#undef USE_RADIO_CAPTURE"
+ fi
+else
+ _noinputmodules="radio $_noinputmodules"
+ _def_radio='#undef USE_RADIO'
+ _def_radio_capture="#undef USE_RADIO_CAPTURE"
+ _radio_capture=no
+fi
+echores "$_radio"
+echocheck "Capture for Radio interface"
+echores "$_radio_capture"
+
+echocheck "Video 4 Linux 2 Radio interface"
+if test "$_radio_v4l2" = auto ; then
+ _radio_v4l2=no
+ if test "$_radio" = yes && linux ; then
+ cat > $TMPC <<EOF
+#include <stdlib.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+int main(void) { return 0; }
+EOF
+ cc_check && _radio_v4l2=yes
+ fi
+fi
+if test "$_radio_v4l2" = yes ; then
+ _def_radio_v4l2='#define HAVE_RADIO_V4L2 1'
+else
+ _def_radio_v4l2='#undef HAVE_RADIO_V4L2'
+fi
+echores "$_radio_v4l2"
+
+echocheck "Video 4 Linux Radio interface"
+if test "$_radio_v4l" = auto ; then
+ _radio_v4l=no
+ if test "$_radio" = yes && linux ; then
+ cat > $TMPC <<EOF
+#include <stdlib.h>
+#include <linux/videodev.h>
+int main(void) { return 0; }
+EOF
+ cc_check && _radio_v4l=yes
+ fi
+fi
+if test "$_radio_v4l" = yes ; then
+ _def_radio_v4l='#define HAVE_RADIO_V4L 1'
+else
+ _def_radio_v4l='#undef HAVE_RADIO_V4L'
+fi
+echores "$_radio_v4l"
+
+
echocheck "Video 4 Linux 2/IVTV PVR interface"
if test "$_pvr" = auto ; then
_pvr=no
@@ -7437,6 +7514,8 @@ CONFIG_X264=$_x264
CONFIG_GPL=yes
CONFIG_ENCODERS=$_mencoder
CONFIG_MUXERS=$_mencoder
+RADIO=$_radio
+RADIO_CAPTURE=$_radio_capture
# --- Some stuff for autoconfigure ----
$_target_arch
@@ -7873,6 +7952,18 @@ $_def_tv_v4l2
/* Enable *BSD BrookTree TV interface support */
$_def_tv_bsdbt848
+/* Enable Radio Interface support */
+$_def_radio
+
+/* Enable Capture for Radio Interface support */
+$_def_radio_capture
+
+/* Enable Video 4 Linux Radio interface support */
+$_def_radio_v4l
+
+/* Enable Video 4 Linux 2 Radio interface support */
+$_def_radio_v4l2
+
/* Enable Video 4 Linux 2/IVTV PVR support */
$_def_pvr
diff --git a/help/help_mp-en.h b/help/help_mp-en.h
index 8cdfc212bc..1187e817b3 100644
--- a/help/help_mp-en.h
+++ b/help/help_mp-en.h
@@ -1814,3 +1814,46 @@ static char help_text[]=
// libvo/vo_xv.c
#define MSGTR_LIBVO_XV_DrawFrameCalled "[VO_XV] draw_frame() called!!!!!!\n"
+
+// stream/stream_radio.c
+
+#define MSGTR_RADIO_ChannelNamesDetected "[radio] Radio channel names detected.\n"
+#define MSGTR_RADIO_WrongFreqForChannel "[radio] Wrong frequency for channel %s\n"
+#define MSGTR_RADIO_WrongChannelNumberFloat "[radio] Wrong channel number: %.2f\n"
+#define MSGTR_RADIO_WrongChannelNumberInt "[radio] Wrong channel number: %d\n"
+#define MSGTR_RADIO_FreqParameterDetected "[radio] Radio frequency parameter detected.\n"
+#define MSGTR_RADIO_DoneParsingChannels "[radio] Done parsing channels\n"
+#define MSGTR_RADIO_GetTunerFailed "[radio] Warning:ioctl get tuner failed: %s. Setting frac to %d\n"
+#define MSGTR_RADIO_NotRadioDevice "[radio] %s is not radio device!\n"
+#define MSGTR_RADIO_TunerCapLowYes "[radio] tuner is low:yes frac=%d\n"
+#define MSGTR_RADIO_TunerCapLowNo "[radio] tuner is low:no frac=%d\n"
+#define MSGTR_RADIO_SetFreqFailed "[radio] ioctl set frequency 0x%x (%.2f) failed: %s\n"
+#define MSGTR_RADIO_GetFreqFailed "[radio] ioctl get frequency failed: %s\n"
+#define MSGTR_RADIO_SetMuteFailed "[radio] ioctl set mute failed: %s\n"
+#define MSGTR_RADIO_QueryControlFailed "[radio] ioctl query control failed %s\n"
+#define MSGTR_RADIO_GetVolumeFailed "[radio] ioctl get volume failed: %s\n"
+#define MSGTR_RADIO_SetVolumeFailed "[radio] ioctl set volume failed: %s\n"
+#define MSGTR_RADIO_DroppingFrame "\n[radio] too bad - dropping audio frame (%d bytes)!\n"
+#define MSGTR_RADIO_BufferEmpty "[radio] grab_audio_frame: buffer empty, wating fo %d data bytes\n"
+#define MSGTR_RADIO_AudioInitFailed "[radio] audio_in_init failed: %s\n"
+#define MSGTR_RADIO_AudioBuffer "[radio] Audio capture - buffer=%d bytes (block=%d bytes).\n"
+#define MSGTR_RADIO_AllocateBufferFailed "[radio] cannot allocate audio buffer (block=%d,buf=%d): %s\n"
+#define MSGTR_RADIO_CurrentFreq "[radio] Current frequency: %.2f\n"
+#define MSGTR_RADIO_SelectedChannel "[radio] Selected channel: %d - %s (freq: %.2f)\n"
+#define MSGTR_RADIO_ChangeChannelNoChannelList "[radio] Can not change channel: no channel list given\n"
+#define MSGTR_RADIO_UnableOpenDevice "[radio] Unable to open '%s': %s\n"
+#define MSGTR_RADIO_RadioDevice "[radio] Radio fd: %d, %s\n"
+#define MSGTR_RADIO_InitFracFailed "[radio] init_frac failed\n"
+#define MSGTR_RADIO_WrongFreq "[radio] Wrong frequency: %.2f\n"
+#define MSGTR_RADIO_UsingFreq "[radio] Using frequency: %.2f.\n"
+#define MSGTR_RADIO_AudioInInitFailed "[radio] audio_in_init failed\n"
+#define MSGTR_RADIO_BufferString "[radio] %s: in buffer=%d dropped=%d\n"
+#define MSGTR_RADIO_AudioInSetupFailed "[radio] audio_in_setup call failed: %s\n"
+#define MSGTR_RADIO_CaptureStarting "[radio] Starting capture staff\n"
+#define MSGTR_RADIO_ClearBufferFailed "[radio] Clearing buffer failed: %s\n"
+#define MSGTR_RADIO_StreamEnableCacheFailed "[radio] Call to stream_enable_cache failed: %s\n"
+#define MSGTR_RADIO_DriverUnknownId "[radio] Unknown driver id: %d\n"
+#define MSGTR_RADIO_DriverUnknownStr "[radio] Unknown driver name: %s\n"
+#define MSGTR_RADIO_DriverV4L2 "[radio] Using V4Lv2 radio interface\n"
+#define MSGTR_RADIO_DriverV4L "[radio] Using V4Lv1 radio interface\n"
+
diff --git a/input/input.c b/input/input.c
index 931526d993..5e824d147b 100644
--- a/input/input.c
+++ b/input/input.c
@@ -47,6 +47,11 @@
/// is the default value wich is used for optional arguments
static mp_cmd_t mp_cmds[] = {
+#ifdef USE_RADIO
+ { MP_CMD_RADIO_STEP_CHANNEL, "radio_step_channel", 1, { { MP_CMD_ARG_INT ,{0}}, {-1,{0}} }},
+ { MP_CMD_RADIO_SET_CHANNEL, "radio_set_channel", 1, { { MP_CMD_ARG_STRING, {0}}, {-1,{0}} }},
+ { MP_CMD_RADIO_SET_FREQ, "radio_set_freq", 1, { {MP_CMD_ARG_FLOAT,{0}}, {-1,{0}} } },
+#endif
{ MP_CMD_SEEK, "seek", 1, { {MP_CMD_ARG_FLOAT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } },
{ MP_CMD_EDL_MARK, "edl_mark", 0, { {-1,{0}} } },
{ MP_CMD_AUDIO_DELAY, "audio_delay", 1, { {MP_CMD_ARG_FLOAT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } },
diff --git a/input/input.h b/input/input.h
index 53072ceff7..df1c964287 100644
--- a/input/input.h
+++ b/input/input.h
@@ -86,6 +86,9 @@
#define MP_CMD_GET_META_COMMENT 84
#define MP_CMD_GET_META_TRACK 85
#define MP_CMD_GET_META_GENRE 86
+#define MP_CMD_RADIO_STEP_CHANNEL 87
+#define MP_CMD_RADIO_SET_CHANNEL 88
+#define MP_CMD_RADIO_SET_FREQ 89
#define MP_CMD_GUI_EVENTS 5000
#define MP_CMD_GUI_LOADFILE 5001
diff --git a/mp_msg.h b/mp_msg.h
index 371a6df957..1003b27edb 100644
--- a/mp_msg.h
+++ b/mp_msg.h
@@ -97,6 +97,8 @@ extern int verbose;
#define MSGT_IDENTIFY 41 // -identify output
+#define MSGT_RADIO 42
+
#define MSGT_MAX 64
void mp_msg_init(void);
diff --git a/mplayer.c b/mplayer.c
index 72c85ccc97..8172c4ba98 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -108,6 +108,9 @@ char * proc_priority=NULL;
#ifdef USE_TV
#include "stream/tv.h"
#endif
+#ifdef USE_RADIO
+#include "stream/stream_radio.h"
+#endif
#ifdef HAS_DVBIN_SUPPORT
#include "stream/dvbin.h"
@@ -1251,6 +1254,7 @@ static void log_sub(void){
#define OSD_MSG_OSD_STATUS 4
#define OSD_MSG_BAR 5
#define OSD_MSG_PAUSE 6
+#define OSD_MSG_RADIO_CHANNEL 7
/// Base id for messages generated from the commmand to property bridge.
#define OSD_MSG_PROPERTY 0x100
@@ -4760,6 +4764,34 @@ if(step_sec>0) {
}
brk_cmd = 1;
} break;
+#ifdef USE_RADIO
+ case MP_CMD_RADIO_STEP_CHANNEL : {
+ if (demuxer->stream->type==STREAMTYPE_RADIO) {
+ int v = cmd->args[0].v.i;
+ if(v > 0)
+ radio_step_channel(demuxer->stream, RADIO_CHANNEL_HIGHER);
+ else
+ radio_step_channel(demuxer->stream, RADIO_CHANNEL_LOWER);
+ if (radio_get_channel_name(demuxer->stream)) {
+ set_osd_msg(OSD_MSG_RADIO_CHANNEL,1,osd_duration,
+ MSGTR_OSDChannel, radio_get_channel_name(demuxer->stream));
+ }
+ }
+ } break;
+ case MP_CMD_RADIO_SET_CHANNEL : {
+ if (demuxer->stream->type== STREAMTYPE_RADIO) {
+ radio_set_channel(demuxer->stream, cmd->args[0].v.s);
+ if (radio_get_channel_name(demuxer->stream)) {
+ set_osd_msg(OSD_MSG_RADIO_CHANNEL,1,osd_duration,
+ MSGTR_OSDChannel, radio_get_channel_name(demuxer->stream));
+ }
+ }
+ } break;
+ case MP_CMD_RADIO_SET_FREQ : {
+ if (demuxer->stream->type== STREAMTYPE_RADIO)
+ radio_set_freq(demuxer->stream, cmd->args[0].v.f);
+ } break;
+#endif
#ifdef USE_TV
case MP_CMD_TV_SET_FREQ : {
if (file_format == DEMUXER_TYPE_TV)
diff --git a/stream/Makefile b/stream/Makefile
index 2c03000fb6..144f3488fd 100644
--- a/stream/Makefile
+++ b/stream/Makefile
@@ -78,6 +78,23 @@ SRCS += stream_tv.c tv.c frequencies.c tvi_dummy.c
endif
endif
+# Radio in
+ifeq ($(RADIO),yes)
+SRCS += stream_radio.c
+ ifeq ($(RADIO_CAPTURE),yes)
+ SRCS += audio_in.c
+ ifeq ($(ALSA1X),yes)
+ SRCS += ai_alsa1x.c
+ endif
+ ifeq ($(ALSA9),yes)
+ SRCS += ai_alsa.c
+ endif
+ ifeq ($(OSS),yes)
+ SRCS += ai_oss.c
+ endif
+ endif
+endif
+
ifeq ($(MPLAYER_NETWORK),yes)
SRCS += asf_streaming.c \
http.c \
diff --git a/stream/stream.c b/stream/stream.c
index 5deb6daa4a..a25b1a1f37 100644
--- a/stream/stream.c
+++ b/stream/stream.c
@@ -58,6 +58,9 @@ extern stream_info_t stream_info_dvb;
#ifdef USE_TV
extern stream_info_t stream_info_tv;
#endif
+#ifdef USE_RADIO
+extern stream_info_t stream_info_radio;
+#endif
#ifdef HAVE_PVR
extern stream_info_t stream_info_pvr;
#endif
@@ -113,6 +116,9 @@ stream_info_t* auto_open_streams[] = {
#ifdef USE_TV
&stream_info_tv,
#endif
+#ifdef USE_RADIO
+ &stream_info_radio,
+#endif
#ifdef HAVE_PVR
&stream_info_pvr,
#endif
diff --git a/stream/stream.h b/stream/stream.h
index 24a587a110..b85db830f7 100644
--- a/stream/stream.h
+++ b/stream/stream.h
@@ -24,6 +24,7 @@
#define STREAMTYPE_PVR 16
#define STREAMTYPE_TV 17
#define STREAMTYPE_MF 18
+#define STREAMTYPE_RADIO 19
#define STREAM_BUFFER_SIZE 2048
diff --git a/stream/stream_radio.c b/stream/stream_radio.c
new file mode 100644
index 0000000000..15f9b08071
--- /dev/null
+++ b/stream/stream_radio.c
@@ -0,0 +1,1108 @@
+
+#include "config.h"
+/*
+ * Radio support
+ *
+ * Initially wrote by Vladimir Voroshilov <voroshil@univer.omsk.su>.
+ * Based on tv.c and tvi_v4l2.c code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ *
+ * Abilities:
+ * * Listening v4l compatible radio cards using line-in or
+ * similar cable
+ * * Grabbing audio data using -ao pcm or -dumpaudio
+ * (must be compiled with --enable-radio-capture).
+ */
+#if !defined(HAVE_ALSA9) && !defined(HAVE_ALSA1X) && !defined(USE_OSS_AUDIO) && defined(USE_RADIO_CAPTURE)
+#warning "Neither alsa1x, alsa9 nor oss found. Radio capture disabled"
+#undef USE_RADIO_CAPTURE
+#endif
+
+#if !defined(HAVE_RADIO_V4L) && !defined(HAVE_RADIO_V4L2)
+#error "This driver requires V4L1 or V4L2!"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <linux/types.h>
+
+#ifdef HAVE_RADIO_V4L2
+#include <linux/videodev2.h>
+#endif
+
+#ifdef HAVE_RADIO_V4L
+#include <linux/videodev.h>
+#warning "V4L is deprecated and will be removed in future"
+#endif
+
+
+
+#include "stream.h"
+#include "libmpdemux/demuxer.h"
+#include "m_struct.h"
+#include "m_option.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+#include "stream_radio.h"
+
+#ifdef USE_RADIO_CAPTURE
+#include "audio_in.h"
+
+#ifdef HAVE_SYS_SOUNDCARD_H
+#include <sys/soundcard.h>
+#else
+#ifdef HAVE_SOUNDCARD_H
+#include <soundcard.h>
+#else
+#include <linux/soundcard.h>
+#endif
+#endif
+
+#endif
+
+#define RADIO_DRIVER_UNKNOWN 0
+#define RADIO_DRIVER_V4L 1
+#define RADIO_DRIVER_V4L2 2
+
+typedef struct radio_channels_s {
+ int index; ///< channel index in channels list
+ float freq; ///< frequency in MHz
+ char name[20]; ///< channel name
+ struct radio_channels_s * next;
+ struct radio_channels_s * prev;
+} radio_channels_t;
+
+/** (device,string, "/dev/radio0") name of radio device file */
+char* radio_param_device="/dev/radio0";
+/** (driver,string, "v4l2") radio driver (v4l,v4l2) */
+char* radio_param_driver="default";
+/** radio_param_channels (channels,string,NULL) channels list (see man page) */
+char** radio_param_channels;
+/** radio_param_volume (volume,number,100) initial volume for radio device */
+int radio_param_volume=100;
+/** radio_param_adevice (adevice,string,NULL) name of audio device file to grab data from */
+char* radio_param_adevice;
+/** radio_param_arate (arate,number,44100) audio framerate
+(please also set -rawaudio rate parameter to the same value) */
+int radio_param_arate=44100;
+/** radio_param_achannels (achannels,number,2) number of audio channels */
+int radio_param_achannels=2;
+extern int demux_rawaudio_packs_per_sec;
+
+static struct stream_priv_s {
+ /* if channels parameter exist here will be channel number otherwise - frequency */
+ float radio_param_freq_channel;
+ char* capture;
+} stream_priv_dflts = {
+ 0,
+ NULL
+};
+
+typedef struct radio_priv_s {
+ int radio_fd; ///< radio device descriptor
+ int frac; ///< fraction value (see comment to init_frac)
+ radio_channels_t* radio_channel_list;
+ radio_channels_t* radio_channel_current;
+ int driver;
+#ifdef USE_RADIO_CAPTURE
+ volatile int do_capture; ///< is capture enabled
+ audio_in_t audio_in;
+ unsigned char* audio_ringbuffer;
+ int audio_head; ///< start of meanfull data in ringbuffer
+ int audio_tail; ///< end of meanfull data in ringbuffer
+ int audio_buffer_size; ///< size of ringbuffer
+ int audio_cnt; ///< size of meanfull data inringbuffer
+ int audio_drop; ///< number of dropped bytes
+ int audio_inited;
+#endif
+} radio_priv_t;
+
+#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
+static m_option_t stream_opts_fields[] = {
+ {"hostname", ST_OFF(radio_param_freq_channel), CONF_TYPE_FLOAT, 0, 0 ,0, NULL},
+ {"filename", ST_OFF(capture), CONF_TYPE_STRING, 0, 0 ,0, NULL},
+ { NULL, NULL, 0, 0, 0, 0, NULL }
+};
+
+static struct m_struct_st stream_opts = {
+ "radio",
+ sizeof(struct stream_priv_s),
+ &stream_priv_dflts,
+ stream_opts_fields
+};
+
+static void close_s(struct stream_st * stream);
+#ifdef USE_RADIO_CAPTURE
+static int clear_buffer(radio_priv_t* priv);
+#endif
+
+
+/*****************************************************************
+ * \brief parse radio_param_channels parameter and store result into list
+ * \param freq_channel if radio_param_channels!=NULL this mean channel number, otherwise - frequency
+ * \param pfreq selected frequency (from selected channel or from URL)
+ * \result STREAM_OK if success, STREAM_ERROR otherwise
+ *
+ * radio_param_channels (channels options) must be in the following format
+ * <frequency>-<name>,<frequency>-<name>,...
+ *
+ * '_' will be replaced with spaces.
+ *
+ * If radio_param_channels is not null, number in movie URL will be treated as
+ * channel position in channel list.
+ */
+static int parse_channels(radio_priv_t* priv,float freq_channel,float* pfreq){
+ char** channels;
+ int i;
+ int channel = 0;
+ if (radio_param_channels){
+ /*parsing channels string*/
+ channels =radio_param_channels;
+
+ mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_ChannelNamesDetected);
+ priv->radio_channel_list = (radio_channels_t*)malloc(sizeof(radio_channels_t));
+ priv->radio_channel_list->index=1;
+ priv->radio_channel_list->next=NULL;
+ priv->radio_channel_list->prev=NULL;
+ priv->radio_channel_current = priv->radio_channel_list;
+
+ while (*channels) {
+ char* tmp = *(channels++);
+ char* sep = strchr(tmp,'-');
+ if (!sep) continue; // Wrong syntax, but mplayer should not crash
+ strlcpy(priv->radio_channel_current->name, sep + 1,sizeof(priv->radio_channel_current->name)-1);
+
+ sep[0] = '\0';
+
+ priv->radio_channel_current->freq=atof(tmp);
+
+ if (priv->radio_channel_current->freq == 0)
+ mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_WrongFreqForChannel,
+ priv->radio_channel_current->name);
+
+ while ((sep=strchr(priv->radio_channel_current->name, '_'))) sep[0] = ' ';
+
+ priv->radio_channel_current->next = (radio_channels_t*)malloc(sizeof(radio_channels_t));
+ priv->radio_channel_current->next->index = priv->radio_channel_current->index + 1;
+ priv->radio_channel_current->next->prev = priv->radio_channel_current;
+ priv->radio_channel_current->next->next = NULL;
+ priv->radio_channel_current = priv->radio_channel_current->next;
+ }
+ if (priv->radio_channel_current->prev)
+ priv->radio_channel_current->prev->next = NULL;
+ free(priv->radio_channel_current);
+
+ if (freq_channel)
+ channel = freq_channel;
+ else
+ channel = 1;
+
+ priv->radio_channel_current = priv->radio_channel_list;
+ for (i = 1; i < channel; i++)
+ if (priv->radio_channel_current->next)
+ priv->radio_channel_current = priv->radio_channel_current->next;
+ if (priv->radio_channel_current->index!=channel){
+ if (((float)((int)freq_channel))!=freq_channel)
+ mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_WrongChannelNumberFloat,freq_channel);
+ else
+ mp_msg(MSGT_RADIO, MSGL_ERR, MSGTR_RADIO_WrongChannelNumberInt,(int)freq_channel);
+ return STREAM_ERROR;
+ }
+ mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_SelectedChannel, priv->radio_channel_current->index,
+ priv->radio_channel_current->name, priv->radio_channel_current->freq);
+ *pfreq=priv->radio_channel_current->freq;
+ }else{
+ if (freq_channel){
+ mp_msg(MSGT_RADIO, MSGL_INFO, MSGTR_RADIO_FreqParameterDetected);
+ priv->radio_channel_list=(radio_channels_t*)malloc(sizeof(radio_channels_t));
+ priv->radio_channel_list->next=NULL;
+ priv->radio_channel_list->prev=NULL;
+ priv->radio_channel_list->index=1;
+ snprintf(priv->radio_channel_list->name,sizeof(priv->radio_channel_current->name)-1,"Freq: %.2f",freq_channel);
+
+ priv->radio_channel_current=priv->radio_channel_list;
+ *pfreq=freq_channel;
+ }
+ }
+ mp_msg(MSGT_RADIO, MSGL_DBG2, MSGTR_RADIO_DoneParsingChannels);
+ return STREAM_OK;
+}
+
+#ifdef HAVE_RADIO_V4L2
+/*****************************************************************
+ * \brief get fraction value for using in set_frequency and get_frequency
+ * \return STREAM_OK if success, STREAM_ERROR otherwise
+ *
+ * V4L2_TUNER_CAP_LOW:
+ * unit=62.5Hz
+ * frac= 1MHz/unit=1000000/62.5 =16000
+ *
+ * otherwise:
+ * unit=62500Hz
+ * frac= 1MHz/unit=1000000/62500 =16
+ */
+static int init_frac_v4l2(radio_priv_t* priv){
+ struct v4l2_tuner tuner;
+
+ memset(&tuner,0,sizeof(tuner));
+ tuner.index=0;
+ if (ioctl(priv->radio_fd, VIDIOC_G_TUNER, &tuner)<0){
+ mp_msg(MSGT_RADIO,MSGL_WARN,MSGTR_RADIO_GetTunerFailed,strerror(errno),priv->frac);
+ return STREAM_ERROR;
+ }
+ if(tuner.type!=V4L