[MPlayer-dev-eng] [PATCH] Adding Radio support to MPlayer
Vladimir Voroshilov
voroshil at univer.omsk.su
Sun Jun 25 16:05:56 CEST 2006
This patch adds ability of listening radio
from V4L compatible radio tuners.
It allows listening radio using line-in cable and recording
audio stream through either line-in cable or pci bus
from tuner's internal ADC.
--
Vladimir Voroshilov mailto:voroshli at univer.omsk.su
Omsk State University
JID: voroshil at jabber.ru
ICQ: 95587719
-------------- next part --------------
Index: input/input.c
===================================================================
--- input/input.c (revision 18810)
+++ input/input.c (working copy)
@@ -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}} } },
Index: input/input.h
===================================================================
--- input/input.h (revision 18810)
+++ input/input.h (working copy)
@@ -71,6 +71,10 @@
#define MP_CMD_GET_PROPERTY 69
#define MP_CMD_OSD_SHOW_PROPERTY_TEXT 70
+#define MP_CMD_RADIO_STEP_CHANNEL 71
+#define MP_CMD_RADIO_SET_CHANNEL 72
+#define MP_CMD_RADIO_SET_FREQ 73
+
#define MP_CMD_GUI_EVENTS 5000
#define MP_CMD_GUI_LOADFILE 5001
#define MP_CMD_GUI_LOADSUBTITLE 5002
Index: configure
===================================================================
--- configure (revision 18810)
+++ configure (working copy)
@@ -217,6 +217,8 @@
--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-tv disable TV Interface (tv/dvb grabbers) [enable]
--disable-tv-v4l disable Video4Linux TV Interface support [autodetect]
--disable-tv-v4l2 disable Video4Linux2 TV Interface support [autodetect]
@@ -1635,8 +1637,12 @@
_win32=auto
_select=yes
_tv=yes
+_radio=no
+_radio_capture=no
_tv_v4l=auto
_tv_v4l2=auto
+_radio_v4l=auto
+_radio_v4l2=auto
_tv_bsdbt848=auto
_network=yes
_winsock2=auto
@@ -1865,13 +1871,21 @@
--enable-alsa) _alsa=yes ;;
--disable-alsa) _alsa=no ;;
--enable-tv) _tv=yes ;;
+ --enable-radio) _radio=yes ;;
+ --enable-radio-capture) _radio_capture=yes ;;
+ --disable-radio-capture) _radio_capture=no ;;
--disable-tv) _tv=no ;;
+ --disable-radio) _radio=no ;;
--enable-tv-bsdbt848) _tv_bsdbt848=yes ;;
--disable-tv-bsdbt848) _tv_bsdbt848=no ;;
--enable-tv-v4l) _tv_v4l=yes ;;
--disable-tv-v4l) _tv_v4l=no ;;
--enable-tv-v4l2) _tv_v4l2=yes ;;
--disable-tv-v4l2) _tv_v4l2=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-fastmemcpy) _fastmemcpy=yes ;;
--disable-fastmemcpy) _fastmemcpy=no ;;
--enable-network) _network=yes ;;
@@ -6677,6 +6691,25 @@
echores "$_tv"
+echocheck "Radio interface"
+if test "$_radio" = yes ; then
+ _def_radio='#define USE_RADIO 1'
+ _inputmodules="radio $_inputmodules"
+ 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"
+
if bsd; then
echocheck "*BSD BrookTree 848 TV interface"
if test "$_tv_bsdbt848" = auto ; then
@@ -6750,6 +6783,51 @@
echores "$_tv_v4l2"
+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"
+
+if test "$_radio_v4l2" = yes ; then
+ _radio_v4l=no
+ _def_radio_v4l="#undef HAVE_RADIO_V4L"
+else
+ 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"
+fi
+
+
echocheck "audio select()"
if test "$_select" = no ; then
_def_select='#undef HAVE_AUDIO_SELECT'
@@ -7955,12 +8033,24 @@
/* Enable TV Interface support */
$_def_tv
+/* Enable Radio Interface support */
+$_def_radio
+
+/* Enable Capture for Radio Interface support */
+$_def_radio_capture
+
/* Enable Video 4 Linux TV interface support */
$_def_tv_v4l
/* Enable Video 4 Linux 2 TV interface support */
$_def_tv_v4l2
+/* Enable Video 4 Linux Radio interface support */
+$_def_radio_v4l
+
+/* Enable Video 4 Linux 2 Radio interface support */
+$_def_radio_v4l2
+
/* Enable *BSD BrookTree TV interface support */
$_def_tv_bsdbt848
Index: DOCS/xml/ru/radio.xml
===================================================================
--- DOCS/xml/ru/radio.xml (revision 0)
+++ DOCS/xml/ru/radio.xml (revision 0)
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="koi8-r"?>
+<!-- $Revision: 17322 $ -->
+<chapter id="tv">
+<title>Radio</title>
+
+<sect1 id="radio" xreflabel="Radio">
+<title>Radio</title>
+
+<para>
+? ???? ?????? ??????????? ??? ???????? <emphasis role="bold">?????????????
+????? ??? ?????? V4L ???????????? ????? ??????</emphasis>. ???????? man ???????? ???
+???????? ????? ? ?????? ??????????.
+</para>
+
+
+<sect2 id="radio-compilation">
+<title>??????????</title>
+
+<procedure>
+<step><para>
+ ??-??????, ??? ?????????? ????????????????? <application>MPlayer</application> ???
+ ?????? <filename>./configure</filename> ? ????????? ?????
+ --enable-radio ? (???? ?????? ???????? ????????? ??????) --enable-radio-capture.
+ </para></step>
+<step><para>
+ ?????????, ??? ??? ????? ???????? ? ??????? ???????????? ? Linux, ????????
+ <application>XawTV</application>.
+ </para></step>
+</procedure>
+</sect2>
+
+<sect2 id="radio-tips">
+<title>?????? ?? ?????????????</title>
+<para>
+?????? ?????? ????? ???????? ?? ????????? ??????????? (man).
+??? ????? ????????? ???????:
+</para>
+<itemizedlist>
+<listitem>
+<para>
+????????????? <option>channels</option> ?????. ?????:
+<screen>-radio channels=104.4-Sibir,103.9-Maximum</screen>
+??????????: ??? ???????? ???? ?????, ????? ???????? ?????? ????????????
+104.4 ? 103.9. ????? ????, ????? ???????? OSD ????? ??? ???????????? ????? ????????,
+???????????? ???????? ??????. ??????? ? ????????? ??????? ?????? ???? ????????
+???????? "_"
+</para>
+</listitem>
+
+<listitem>
+<para>
+???? ????????? ????? ??????? ?????. ?? ?????? ???????? ????, ???? ????????? ????
+???????? ????? ? ??????? ??????, ??????????? ????? ????? ? ???????? ????[line-in],
+???? ????????? ?????????? ADC ?? ? ???? saa7134. ? ???? ??????, ?? ??????
+????????? ??????? <emphasis role="bold">saa7134-alsa</emphasis> ???
+<emphasis role="bold">saa7134-oss</emphasis>.
+</para>
+</listitem>
+
+<listitem>
+<para>
+<application>MEncoder</application> ?? ????? ???? ??????????? ??? ??????? ?????,
+????????? ?? ??????? ????????????? ??????? ?????-??????.????? ???????, ?? ??????
+?????????? ?????? ???? ????????? ????????? arecord ?? ??????? ALSA ???? ?????????
+<option>-ao pcm:file=file.wav</option>. ?? ?????? ?????? ?? ?? ?????? ??????? ?????? ??
+????? ??????? (?? ?????????? ??????, ????? ?? ??????????? line-in ??????, ? ????????
+???? ??????????????? ? ????????? ?????.
+</para>
+</listitem>
+</itemizedlist>
+</sect2>
+
+<sect2 id="radio-examples">
+<title>???????</title>
+
+
+<informalexample>
+<para>
+???? ?? ???????????? V4L (????????? line-in ??????. ??????? ?????????.):
+<screen>
+mplayer radio://104.4<!--
+--></screen>
+</para>
+</informalexample>
+
+<informalexample>
+<para>
+????????????? ?????? ???????????? ?? ??????:
+<screen>
+mplayer -radio channels=104.4=Sibir,103.9=Maximm radio://2<!--
+--></screen>
+</para>
+</informalexample>
+
+<informalexample>
+<para>
+????????? ????? ????? ???? pci ? ??????????? ADC ????? ??????. ? ???? ???????
+????? ???????????? ??? ??????? ???????? ????? (ALSA ?????????? hw:1,0).
+??? ????, ?????????? ?? saa7134 ???? saa7134-alsa ???? saa7134-oss ?????? ?????? ????
+????????. ?????????: ??? ????????????? ???? ????????? ALSA, ????????? ?????????? ???????? ??
+?????????, ??????? - ?? ?????.
+<screen>
+mplayer -rawaudio rate=32000 -radio adevice=hw=1.0:arate=32000:channels=104.4=Sibir,103.9=Maximm radio://2<!--
+--></screen>
+</para>
+</informalexample>
+</sect2>
+</sect1>
+
+</chapter>
Index: DOCS/xml/ru/install.xml
===================================================================
--- DOCS/xml/ru/install.xml (revision 18810)
+++ DOCS/xml/ru/install.xml (working copy)
@@ -449,6 +449,15 @@
? ?????????? 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>
Index: DOCS/xml/ru/features.xml
===================================================================
--- DOCS/xml/ru/features.xml (revision 18810)
+++ DOCS/xml/ru/features.xml (working copy)
@@ -7,5 +7,6 @@
&codecs.xml;
&tvinput.xml;
+&radio.xml;
</chapter>
Index: DOCS/xml/en/radio.xml
===================================================================
--- DOCS/xml/en/radio.xml (revision 0)
+++ DOCS/xml/en/radio.xml (revision 0)
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- $Revision: 17322 $ -->
+<chapter id="tv">
+<title>Radio</title>
+
+<sect1 id="radio" xreflabel="Radio">
+<title>Radio</title>
+
+<para>
+This section is about how to enable <emphasis role="bold">listening
+from V4L compatible Radio tuner</emphasis>. See the man page for a description
+of Radio options and keyboard controls.
+</para>
+
+
+<sect2 id="radio-compilation">
+<title>Compilation</title>
+
+<procedure>
+<step><para>
+ First, you have to recompile MPlayer using <filename>./configure</filename> with
+ --enable-radio and (if you want capture support) --enable-radio-capture.
+ </para></step>
+<step><para>
+ Make sure your tuner works with another radio software in Linux, for
+ example <application>XawTV</application>.
+ </para></step>
+</procedure>
+</sect2>
+
+<sect2 id="radio-tips">
+<title>Usage tips</title>
+<para>
+The full listing of the options is available on the manual page.
+Here are just a few tips:
+</para>
+<itemizedlist>
+<listitem>
+<para>
+Use the <option>channels</option> option. An example:
+<screen>-radio channels=104.4-Sibir,103.9-Maximum</screen>
+Explanation: using this option, only the 104.4 and 103.9 radio stations
+will be usable, and there will be a nice OSD text upon channel switching, displaying the
+channel's name. Spaces in the channel name must be replaced by the
+"_" character.
+</para>
+</listitem>
+
+<listitem>
+<para>
+There are several ways of capturing audio. You can grab the sound either using
+your sound card via an external cable connection between video card and line-in,
+or using the built-in ADC in the saa7134 chip. In the latter case, you have to
+load the <emphasis role="bold">saa7134-alsa</emphasis> or
+<emphasis role="bold">saa7134-oss</emphasis> driver.
+</para>
+</listitem>
+
+<listitem>
+<para>
+<application>MEncoder</application> cannot be used for audio capture, because it
+requires video stream to work. So your can either use arecord from ALSA project or
+use <option>-ao pcm:file=file.wav</option>. In second case you will not hear any sound
+(except you using line-in cable and have switched line-in mute off)
+</para>
+</listitem>
+</itemizedlist>
+</sect2>
+
+
+<sect2 id="radio-examples">
+<title>Examples</title>
+
+
+<informalexample>
+<para>
+Input from standard V4L (using line-in cable. capture switched off):
+<screen>
+mplayer radio://104.4<!--
+--></screen>
+</para>
+</informalexample>
+
+<informalexample>
+<para>
+Playing second channel from channel list:
+<screen>
+mplayer -radio channels=104.4=Sibir,103.9=Maximm radio://2<!--
+--></screen>
+</para>
+</informalexample>
+
+<informalexample>
+<para>
+Using sound through pci bus from radio card's internal ADC. In this example tuner used as second sound card
+(ALSA device hw:1,0). For saa7134 based cards either saa7134-alsa or saa7134-oss module must be
+loaded . NOTE: when using ALSA device names colons must be replaced with equals, commas with dots.
+<screen>
+mplayer -rawaudio rate=32000 -radio adevice=hw=1.0:arate=32000:channels=104.4=Sibir,103.9=Maximm radio://2<!--
+--></screen>
+</para>
+</informalexample>
+</sect2>
+</sect1>
+
+</chapter>
Index: DOCS/xml/en/install.xml
===================================================================
--- DOCS/xml/en/install.xml (revision 18810)
+++ DOCS/xml/en/install.xml (working copy)
@@ -456,6 +456,11 @@
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>
Index: DOCS/xml/en/documentation.xml
===================================================================
--- DOCS/xml/en/documentation.xml (revision 18810)
+++ DOCS/xml/en/documentation.xml (working copy)
@@ -185,6 +185,7 @@
&video.xml;
&audio.xml;
&tvinput.xml;
+&radio.xml;
&ports.xml;
&mencoder.xml;
Index: DOCS/man/en/mplayer.1
===================================================================
--- DOCS/man/en/mplayer.1 (revision 18810)
+++ DOCS/man/en/mplayer.1 (working copy)
@@ -88,6 +88,13 @@
.in
.B mplayer
'in +\n[.k]u
+.I radio://[channel or frequency]
+[options]
+.
+.br
+.in
+.B mplayer
+'in +\n[.k]u
.I dvb://[card_number@]channel
[options]
.
@@ -1455,6 +1462,46 @@
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.
+.sp 1
+Available options are:
+.RSs
+.IPs device=<value>
+radio device to use (default /dev/radio0)
+.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. 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:
+If you have trouble with audio speed (too quickly) try to set also
+-rawaudio rate=<value> option with the same value as arate and 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 only)
This option tunes various properties of the TV capture module.
For watching TV with MPlayer, use 'tv://' or 'tv://<channel_number>'
Index: mplayer.c
===================================================================
--- mplayer.c (revision 18810)
+++ mplayer.c (working copy)
@@ -108,6 +108,9 @@
#ifdef USE_TV
#include "libmpdemux/tv.h"
#endif
+#ifdef USE_RADIO
+#include "libmpdemux/stream_radio.h"
+#endif
#ifdef HAS_DVBIN_SUPPORT
#include "libmpdemux/dvbin.h"
@@ -1060,6 +1063,7 @@
#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
@@ -4392,6 +4396,37 @@
}
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));
+ //vo_osd_changed(OSDTYPE_SUBTITLE);
+ }
+ }
+ } 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));
+ //vo_osd_changed(OSDTYPE_SUBTITLE);
+ }
+ }
+ } 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)
Index: cfg-common.h
===================================================================
--- cfg-common.h (revision 18810)
+++ cfg-common.h (working copy)
@@ -125,6 +125,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
@@ -353,9 +358,25 @@
#include "libmpdemux/tv.h"
+#ifdef USE_RADIO
+#include "libmpdemux/stream_radio.h"
+#endif
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},
+ {"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},
@@ -517,6 +538,7 @@
{ "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 },
Index: libmpdemux/ai_oss.c
===================================================================
--- libmpdemux/ai_oss.c (revision 18810)
+++ libmpdemux/ai_oss.c (working copy)
@@ -3,7 +3,7 @@
#include "config.h"
-#if defined(USE_TV) && (defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2)) && defined(USE_OSS_AUDIO)
+#if (defined(USE_RADIO) || defined(USE_TV)) && (defined(HAVE_RADIO_V4L) || defined(HAVE_RADIO_V4L2) || defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2))
#include <string.h> /* strerror */
#include <fcntl.h>
Index: libmpdemux/ai_alsa.c
===================================================================
--- libmpdemux/ai_alsa.c (revision 18810)
+++ libmpdemux/ai_alsa.c (working copy)
@@ -4,7 +4,7 @@
#include "config.h"
-#if defined(USE_TV) && (defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2)) && defined(HAVE_ALSA9)
+#if (defined(USE_RADIO) || defined(USE_TV)) && (defined(HAVE_RADIO_V4L) || defined(HAVE_RADIO_V4L2) || defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2)) && defined(HAVE_ALSA9)
#include <alsa/asoundlib.h>
#include "audio_in.h"
Index: libmpdemux/Makefile
===================================================================
--- libmpdemux/Makefile (revision 18810)
+++ libmpdemux/Makefile (working copy)
@@ -40,6 +40,9 @@
stream_vcd.c \
stream_vstream.c \
+# Radio in
+SRCS += stream_radio.c \
+
# TV in
SRCS += tv.c \
frequencies.c \
Index: libmpdemux/stream_radio.c
===================================================================
--- libmpdemux/stream_radio.c (revision 0)
+++ libmpdemux/stream_radio.c (revision 0)
@@ -0,0 +1,775 @@
+
+#include "config.h"
+
+/*
+ Radio support by Vladimir Voroshilov.
+
+ Based on tv.c and tvi_v4l2.c code.
+
+*/
+#ifdef USE_RADIO
+
+#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>
+#else
+#include <linux/videodev.h>
+#warning "V4L is deprecated and will be removed in future"
+#endif
+
+#include "stream.h"
+#include "demuxer.h"
+#include "m_struct.h"
+#include "m_option.h"
+#include "mp_msg.h"
+#include "stream_radio.h"
+
+#ifdef USE_RADIO_CAPTURE
+#include "audio_in.h"
+
+#endif
+
+
+typedef struct radio_channels_s {
+ int index;
+ float freq; //Frequency in MHz
+ char name[20];
+ struct radio_channels_s * next;
+ struct radio_channels_s * prev;
+} radio_channels_t;
+
+char* radio_param_device="/dev/radio0";
+char** radio_param_channels=NULL;
+int radio_param_volume=100;
+
+char* radio_param_adevice=NULL;
+int radio_param_arate=44100;
+int radio_param_achannels=2;
+
+static struct stream_priv_s {
+ float radio_param_freq_channel; //If channels exist here will be channel otherwise - frequency
+} stream_priv_dflts = {
+ 0
+};
+
+/*
+LOW: unit=62.5Hz
+ HI: unit=62500Hz
+
+LOW: frac= 1000000/62.5 =16000
+ HI: frac= 1000000/62500 =16
+*/
+typedef struct radio_priv_s {
+ int radio_fd;
+ int frac;
+ radio_channels_t *radio_channel_list;
+ radio_channels_t *radio_channel_current;
+#ifdef USE_RADIO_CAPTURE
+ volatile int do_capture;
+ audio_in_t audio_in;
+ pthread_t audio_grabber_thread;
+ pthread_mutex_t audio_mutex;
+ unsigned char *audio_ringbuffer;
+ int audio_head;
+ int audio_tail;
+ int audio_buffer_size;
+ int audio_cnt;
+ int audio_drop;
+ int shutdown;
+ int audio_inited;
+#endif
+} radio_priv_t;
+
+static int set_frequency(radio_priv_t* priv,float frequency);
+static int set_volume(radio_priv_t *priv,int volume);
+static int get_volume(radio_priv_t* priv,int* volume);
+static int get_frequency(radio_priv_t* priv,float* frequency);
+static int set_mute(radio_priv_t* priv,int mute);
+static int init_frac(radio_priv_t* priv);
+static int fill_buffer_s(struct stream_st *s, char* buffer, int max_len);
+#ifdef USE_RADIO_CAPTURE
+static void *audio_grabber(void *data);
+static int init_audio(radio_priv_t *priv);
+static void grab_audio_frame(radio_priv_t *priv, char *buffer, int len);
+#endif
+
+#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},
+ { 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
+};
+
+
+void close_s(struct stream_st * stream){
+ radio_priv_t* priv=(radio_priv_t*)stream->priv;
+ radio_channels_t * tmp;
+ if (!priv) return;
+
+#ifdef USE_RADIO_CAPTURE
+ priv->shutdown=1;
+ if (priv->audio_grabber_thread) {
+ pthread_join(priv->audio_grabber_thread, NULL);
+ pthread_mutex_destroy(&priv->audio_mutex);
+ }
+
+ if(priv->audio_ringbuffer){
+ free(priv->audio_ringbuffer);
+ priv->audio_ringbuffer=NULL;
+ }
+
+ priv->do_capture=0;
+#endif
+
+ while (priv->radio_channel_list) {
+ tmp=priv->radio_channel_list;
+ priv->radio_channel_list=priv->radio_channel_list->next;
+ free(tmp);
+ }
+ priv->radio_channel_current=NULL;
+ priv->radio_channel_list=NULL;
+
+ if (priv->radio_fd){
+ set_mute(priv,1);
+ close(priv->radio_fd);
+ }
+
+ free(priv);
+ stream->priv=NULL;
+}
+
+
+static int open_s(stream_t *stream,int mode, void* opts, int* file_format) {
+ struct stream_priv_s* p=(struct stream_priv_s*)opts;
+ char** channels;
+ float frequency=0;
+ int i;
+ int channel = 0;
+
+ if (strncmp("radio://",stream->url,5) != 0)
+ return STREAM_UNSUPORTED;
+
+ if(mode != STREAM_READ)
+ return STREAM_UNSUPORTED;
+
+ radio_priv_t* priv=(radio_priv_t*)malloc(sizeof(radio_priv_t));
+
+ if (!priv)
+ return STREAM_ERROR;
+
+#ifdef HAVE_RADIO_V4L2
+ mp_msg(MSGT_RADIO, MSGL_INFO, "Using V4Lv2 radio interface\n");
+#else
+ mp_msg(MSGT_RADIO, MSGL_INFO, "Using V4Lv1 radio interface\n");
+#endif
+
+ memset(priv,0,sizeof(radio_priv_t));
+
+ stream->type = STREAMTYPE_RADIO;
+ *file_format = DEMUXER_TYPE_RAWAUDIO;
+ stream->flags = STREAM_READ;
+ /* diable caching */
+ stream->fd=-1;
+
+#ifdef USE_RADIO_CAPTURE
+ if (!init_audio(priv)){
+ mp_msg(MSGT_RADIO, MSGL_ERR, "Audio init failed\n");
+ close_s(stream);
+ return STREAM_ERROR;
+ }
+#endif
+
+ stream->start_pos=0;
+ stream->end_pos=0;
+ stream->priv=priv;
+ stream->close=close_s;
+ stream->fill_buffer=fill_buffer_s;
+
+ priv->radio_fd = open(radio_param_device, O_RDWR);
+ if (priv->radio_fd < 0) {
+ mp_msg(MSGT_RADIO, MSGL_ERR, "unable to open '%s': %s\n",
+ radio_param_device, strerror(errno));
+ return STREAM_ERROR;
+ }
+ mp_msg(MSGT_RADIO, MSGL_V, "Radio fd: %d, %s\n", priv->radio_fd,radio_param_device);
+ fcntl(priv->radio_fd, F_SETFD, FD_CLOEXEC);
+
+ if (init_frac(priv)!=STREAM_OK){
+ mp_msg(MSGT_RADIO, MSGL_ERR, "Init_frac failed\n");
+ close_s(stream);
+ return STREAM_ERROR;
+ };
+
+ set_mute(priv,1);
+
+ if (radio_param_channels){
+ /*parsing channels string*/
+ channels =radio_param_channels;
+
+ mp_msg(MSGT_RADIO, MSGL_INFO, "Radio channel names detected.\n");
+ priv->radio_channel_list = 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, "Wrong frequency for channel %s\n",
+ priv->radio_channel_current->name);
+
+ while ((sep=strchr(priv->radio_channel_current->name, '_'))) sep[0] = ' ';
+
+ priv->radio_channel_current->next = 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 (p->radio_param_freq_channel)
+ channel = p->radio_param_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)p->radio_param_freq_channel))!=p->radio_param_freq_channel)
+ mp_msg(MSGT_RADIO, MSGL_ERR, "Wrong channel number: %.2f\n",p->radio_param_freq_channel);
+ else
+ mp_msg(MSGT_RADIO, MSGL_ERR, "Wrong channel number: %.0f\n",p->radio_param_freq_channel);
+ close_s(stream);
+ return STREAM_ERROR;
+ }
+ mp_msg(MSGT_RADIO, MSGL_INFO, "Selected channel: %d - %s (freq: %.2f)\n", priv->radio_channel_current->index,
+ priv->radio_channel_current->name, priv->radio_channel_current->freq);
+ frequency=priv->radio_channel_current->freq;
+ }else{
+ if (p->radio_param_freq_channel){
+ mp_msg(MSGT_RADIO, MSGL_INFO, "Radio frequency parameter detected.\n");
+ priv->radio_channel_list=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",p->radio_param_freq_channel);
+
+ priv->radio_channel_current=priv->radio_channel_list;
+ frequency=p->radio_param_freq_channel;
+ }
+ }
+ mp_msg(MSGT_RADIO, MSGL_DBG2, "Done parsing channels\n");
+
+ if (frequency==0){
+ mp_msg(MSGT_RADIO, MSGL_ERR, "Wrong frequency: 0.00\n");
+ close_s(stream);
+ return STREAM_ERROR;
+ }else
+ mp_msg(MSGT_RADIO, MSGL_INFO, "Using frequency: %.2f.\n",frequency);
+
+ if(set_frequency(priv,frequency)!=STREAM_OK){
+ close_s(stream);
+ return STREAM_ERROR;
+ }
+ if (set_volume(priv,radio_param_volume)!=STREAM_OK){
+ close_s(stream);
+ return STREAM_ERROR;
+ }
+ set_mute(priv,0);
+
+
+#ifdef USE_RADIO_CAPTURE
+ if (priv->do_capture){
+ /* start capture */
+ priv->audio_ringbuffer = (unsigned char*)calloc(1, priv->audio_buffer_size);
+ if (!priv->audio_ringbuffer) {
+ mp_msg(MSGT_RADIO, MSGL_ERR, "cannot allocate audio buffer (block=%d,buf=%d): %s\n",priv->audio_in.blocksize, priv->audio_buffer_size, strerror(errno));
+ close_s(stream);
+ return STREAM_ERROR;
+ }
+ priv->audio_head = 0;
+ priv->audio_tail = 0;
+ priv->audio_cnt = 0;
+ priv->audio_drop = 0;
+ pthread_mutex_init(&priv->audio_mutex, NULL);
+
+ priv->shutdown=0;
+ pthread_create(&priv->audio_grabber_thread, NULL, audio_grabber, priv);
+ }
+#endif
+
+ return STREAM_OK;
+}
+
+static int fill_buffer_s(struct stream_st *s, char* buffer, int max_len){
+ radio_priv_t* priv=(radio_priv_t*)s->priv;
+ int len=max_len;
+
+#ifdef USE_RADIO_CAPTURE
+ if (priv->do_capture){
+ len=priv->audio_in.blocksize>max_len?max_len:priv->audio_in.blocksize;
+ grab_audio_frame(priv, buffer,len);
+ }
+ else
+#endif
+ memset(buffer,0,len);
+ return len;
+}
+
+/* for call from mplayer.c */
+int radio_set_freq(struct stream_st *stream, float frequency){
+ radio_priv_t* priv=(radio_priv_t*)stream->priv;
+
+ if (set_frequency(priv,frequency)!=STREAM_OK){
+ return 0;
+ }
+ if (get_frequency(priv,&frequency)!=STREAM_OK){
+ return 0;
+ }
+ mp_msg(MSGT_RADIO, MSGL_V, "Current frequency: %.2f\n",frequency);
+ return(1);
+}
+
+/* for call from mplayer.c */
+int radio_step_channel(struct stream_st *stream, int direction) {
+ radio_priv_t* priv=(radio_priv_t*)stream->priv;
+
+ if (priv->radio_channel_list) {
+ switch (direction){
+ case RADIO_CHANNEL_HIGHER:
+ if (priv->radio_channel_current->next)
+ priv->radio_channel_current = priv->radio_channel_current->next;
+ else
+ priv->radio_channel_current = priv->radio_channel_list;
+ radio_set_freq(stream,priv->radio_channel_current->freq);
+ mp_msg(MSGT_RADIO, MSGL_V, "Selected channel: %d - %s (freq: %.2f)\n",
+ priv->radio_channel_current->index, priv->radio_channel_current->name,
+ priv->radio_channel_current->freq);
+ break;
+ case RADIO_CHANNEL_LOWER:
+ if (priv->radio_channel_current->prev)
+ priv->radio_channel_current = priv->radio_channel_current->prev;
+ else
+ while (priv->radio_channel_current->next)
+ priv->radio_channel_current = priv->radio_channel_current->next;
+ radio_set_freq(stream,priv->radio_channel_current->freq);
+ mp_msg(MSGT_RADIO, MSGL_V, "Selected channel: %d - %s (freq: %.2f)\n",
+ priv->radio_channel_current->index, priv->radio_channel_current->name,
+ priv->radio_channel_current->freq);
+ break;
+ }
+ }else
+ mp_msg(MSGT_RADIO, MSGL_ERR, "Can not step channel: no channel list given\n");
+ return(1);
+}
+
+/* for call from mplayer.c */
+int radio_set_channel(struct stream_st *stream, char *channel) {
+ radio_priv_t* priv=(radio_priv_t*)stream->priv;
+ int i, channel_int;
+
+ if (priv->radio_channel_list) {
+ channel_int = atoi(channel);
+ priv->radio_channel_current = priv->radio_channel_list;
+ for (i = 1; i < channel_int; i++)
+ if (priv->radio_channel_current->next)
+ priv->radio_channel_current = priv->radio_channel_current->next;
+ mp_msg(MSGT_RADIO, MSGL_V, "Selected channel: %d - %s (freq: %.2f)\n", priv->radio_channel_current->index,
+ priv->radio_channel_current->name, priv->radio_channel_current->freq);
+ radio_set_freq(stream, priv->radio_channel_current->freq);
+ } else
+ mp_msg(MSGT_RADIO, MSGL_ERR, "Can not set channel: no channel list given\n");
+ return 1;
+}
+
+/* for call from mplayer.c */
+char* radio_get_channel_name(struct stream_st *stream){
+ radio_priv_t* priv=(radio_priv_t*)stream->priv;
+ if (priv->radio_channel_list) {
+ return priv->radio_channel_current->name;
+ }
+ return NULL;
+}
+
+/*
+ radio device control staff
+*/
+#ifdef HAVE_RADIO_V4L2
+/*
+V4L2_TUNER_CAP_LOW: unit=62.5Hz
+otherwise: unit=62500Hz
+
+V4L2_TUNER_CAP_LOW: frac= 1000000/62.5 =16000
+otherwise: frac= 1000000/62500 =16
+*/
+static int init_frac(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){
+ priv->frac=16;
+ mp_msg(MSGT_RADIO,MSGL_WARN,"Warning:ioctl get tuner failed: %s\n",strerror(errno));
+ return STREAM_OK;
+ }
+ if(tuner.type!=V4L2_TUNER_RADIO){
+ mp_msg(MSGT_RADIO,MSGL_ERR,"%s is not radio device!\n",radio_param_device);
+ return STREAM_ERROR;
+ }
+ if(tuner.capability & V4L2_TUNER_CAP_LOW){
+ priv->frac=16000;
+ mp_msg(MSGT_RADIO,MSGL_DBG2,"ioctl return V4L2_TUNER_CAP_LOW. frac=%d\n",priv->frac);
+ }
+ else{
+ priv->frac=16;
+ mp_msg(MSGT_RADIO,MSGL_DBG2,"ioctl return no V4L2_TUNER_CAP_LOW. frac=%d\n",priv->frac);
+ }
+ mp_msg(MSGT_RADIO,MSGL_DBG2,"Frac: %d\n",priv->frac);
+ return STREAM_OK;
+}
+//frequency in MHz
+static int set_frequency(radio_priv_t* priv,float frequency){
+ struct v4l2_frequency freq;
+
+ memset(&freq,0,sizeof(freq));
+ freq.tuner=0;
+ freq.type=V4L2_TUNER_RADIO;
+ freq.frequency=frequency*priv->frac;
+ if(ioctl(priv->radio_fd,VIDIOC_S_FREQUENCY,&freq)<0){
+ mp_msg(MSGT_RADIO,MSGL_ERR,"ioctl set frequency 0x%x (%.2f) failed: %s\n",freq.frequency,
+ frequency,strerror(errno));
+ return STREAM_ERROR;
+ }
+ return STREAM_OK;
+}
+
+//frequency in MHz
+static int get_frequency(radio_priv_t* priv,float* frequency){
+ struct v4l2_frequency freq;
+ memset(&freq,0,sizeof(freq));
+ if (ioctl(priv->radio_fd, VIDIOC_G_FREQUENCY, &freq) < 0) {
+ mp_msg(MSGT_RADIO,MSGL_ERR,"ioctl get frequency failed: %s\n",strerror(errno));
+ return STREAM_ERROR;
+ }
+ *frequency=((float)freq.frequency)/priv->frac;
+ return STREAM_OK;
+}
+
+static int set_mute(radio_priv_t* priv,int mute){
+ struct v4l2_control control;
+
+ memset(&control,0,sizeof(control));
+ control.id=V4L2_CID_AUDIO_MUTE;
+ control.value = (mute?1:0);
+ if (ioctl(priv->radio_fd, VIDIOC_S_CTRL, &control)<0){
+ mp_msg(MSGT_RADIO,MSGL_ERR,"ioctl set mute failed: %s\n",strerror(errno));
+ return STREAM_ERROR;
+ }
+ return STREAM_OK;
+}
+
+static int set_volume(radio_priv_t* priv,int volume){
+ struct v4l2_queryctrl qctrl;
+ struct v4l2_control control;
+
+ /*arg must be between 0 and 100*/
+ if (volume > 100) volume = 100;
+ if (volume < 0) volume = 0;
+
+ memset(&qctrl,0,sizeof(qctrl));
+ qctrl.id = V4L2_CID_AUDIO_VOLUME;
+ if (ioctl(priv->radio_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
+ mp_msg(MSGT_RADIO, MSGL_ERR, "ioctl query control failed %s\n",strerror(errno));
+ return STREAM_ERROR;
+ }
+
+ memset(&control,0,sizeof(control));
+ control.id=V4L2_CID_AUDIO_VOLUME;
+ control.value=qctrl.minimum+volume*(qctrl.maximum-qctrl.minimum)/100;
+ if (ioctl(priv->radio_fd, VIDIOC_S_CTRL, &control) < 0) {
+ mp_msg(MSGT_RADIO, MSGL_ERR,"volume: ioctl set %s %d failed: %s\n",
+ qctrl.name, control.value, strerror(errno));
+ return STREAM_ERROR;
+ }
+ mp_msg(MSGT_RADIO, MSGL_V, "volume: set %s: %d [%d, %d]\n",
+ qctrl.name,control.value, qctrl.minimum, qctrl.maximum);
+ return STREAM_OK;
+}
+
+static int get_volume(radio_priv_t* priv,int* volume){
+ struct v4l2_queryctrl qctrl;
+ struct v4l2_control control;
+
+ memset(&qctrl,0,sizeof(qctrl));
+ qctrl.id = V4L2_CID_AUDIO_VOLUME;
+ if (ioctl(priv->radio_fd, VIDIOC_QUERYCTRL, &qctrl) < 0) {
+ mp_msg(MSGT_RADIO, MSGL_ERR, "ioctl query control failed %s\n",strerror(errno));
+ return STREAM_ERROR;
+ }
+
+ memset(&control,0,sizeof(control));
+ control.id=V4L2_CID_AUDIO_VOLUME;
+ if (ioctl(priv->radio_fd, VIDIOC_G_CTRL, &control) < 0) {
+ mp_msg(MSGT_RADIO, MSGL_ERR,"ioctl get %s %d failed: %s\n",
+ qctrl.name, control.value, strerror(errno));
+ return STREAM_ERROR;
+ }
+ mp_msg(MSGT_RADIO, MSGL_V, "get %s: %d [%d, %d]\n",
+ qctrl.name,control.value, qctrl.minimum, qctrl.maximum);
+
+ if (qctrl.maximum==qctrl.minimum)
+ *volume=qctrl.minimum;
+ else
+ *volume=100*(control.value-qctrl.minimum)/(qctrl.maximum-qctrl.minimum);
+
+ /*arg must be between 0 and 100*/
+ if (*volume > 100) *volume = 100;
+ if (*volume < 0) *volume = 0;
+
+ return STREAM_OK;
+}
+
+#else
+/*
+VIDEO_TUNER_LOW: unit=62.5Hz
+otherwise: unit=62500Hz
+
+VIDEO_TUNER_LOW: frac= 1000000/62.5 =16000
+otherwise: frac= 1000000/62500 =16
+*/
+static int init_frac(radio_priv_t* priv){
+ struct video_tuner tuner;
+ memset(&tuner,0,sizeof(tuner));
+ if (ioctl(priv->radio_fd, VIDIOCGTUNER, &tuner) <0){
+ priv->frac=16;
+ mp_msg(MSGT_RADIO,MSGL_WARN,"Warning: ioctl get tuner failed: %s\n",strerror(errno));
+ return STREAM_OK;
+ }
+ if(tuner.flags & VIDEO_TUNER_LOW){
+ priv->frac=16000;
+ mp_msg(MSGT_RADIO,MSGL_DBG2,"ioctl return VIDEO_TUNER_LOW. frac=%d: %s\n",priv->frac);
+ }else{
+ priv->frac=16;
+ mp_msg(MSGT_RADIO,MSGL_DBG2,"ioctl return no VIDEO_TUNER_LOW. frac=%d: %s\n",priv->frac);
+ }
+ mp_msg(MSGT_RADIO,MSGL_DBG2,"Frac: %d\n",priv->frac);
+ return STREAM_OK;
+}
+
+//frequency in MHz
+static int set_frequency(radio_priv_t* priv,float frequency){
+ __u32 freq;
+ freq=frequency*priv->frac;
+ if (ioctl(priv->radio_fd, VIDIOCSFREQ, &freq) < 0) {
+ mp_msg(MSGT_RADIO,MSGL_ERR,"ioctl set frequency failed: %s\n",strerror(errno));
+ return STREAM_ERROR;
+ }
+ return STREAM_OK;
+}
+//frequency in MHz
+static int get_frequency(radio_priv_t* priv,float* frequency){
+ __u32 freq;
+ if (ioctl(priv->radio_fd, VIDIOCGFREQ, &freq) < 0) {
+ mp_msg(MSGT_RADIO,MSGL_ERR,"ioctl get frequency failed: %s\n",strerror(errno));
+ return STREAM_ERROR;
+ }
+ *frequency=((float)freq)/priv->frac;
+ return STREAM_OK;
+}
+
+static int set_mute(radio_priv_t* priv,int mute){
+ struct video_audio audio;
+ memset(&audio,0,sizeof(audio));
+ audio.flags = (mute?VIDEO_AUDIO_MUTE:0);
+ if (ioctl(priv->radio_fd, VIDIOCSAUDIO, &audio)<0){
+ mp_msg(MSGT_RADIO,MSGL_ERR,"ioctl set mute failed: %s\n",strerror(errno));
+ return STREAM_ERROR;
+ }
+ return STREAM_OK;
+}
+
+static int set_volume(radio_priv_t* priv,int volume){
+ struct video_audio audio;
+
+ /*arg must be between 0 and 100*/
+ if (volume > 100) volume = 100;
+ if (volume < 0) volume = 0;
+
+ memset(&audio,0,sizeof(audio));
+ audio.flags = VIDEO_AUDIO_VOLUME;
+ audio.mode = VIDEO_SOUND_STEREO;
+ audio.audio = 0;
+ audio.volume = volume* (65535 / 100);
+
+ if (ioctl(priv->radio_fd, VIDIOCSAUDIO, &audio) < 0){
+ mp_msg(MSGT_RADIO,MSGL_ERR,"ioctl set volume failed: %s\n",strerror(errno));
+ return STREAM_ERROR;
+ }
+ return STREAM_OK;
+}
+
+static int get_volume(radio_priv_t* priv,int* volume){
+ struct video_audio audio;
+
+ memset(&audio,0,sizeof(audio));
+ audio.audio=0;
+ if (ioctl(priv->radio_fd, VIDIOCGAUDIO, &audio) < 0){
+ mp_msg(MSGT_RADIO,MSGL_ERR,"ioctl get volume failed: %s\n",strerror(errno));
+ return STREAM_ERROR;
+ }
+
+ if (audio.flags & VIDEO_AUDIO_VOLUME){
+ *volume=100*audio.volume/65535;
+ /*arg must be between 0 and 100*/
+ if (*volume > 100) *volume = 100;
+ if (*volume < 0) *volume = 0;
+ return STREAM_OK;
+ }
+
+ return STREAM_ERROR;
+}
+#endif
+
+#ifdef USE_RADIO_CAPTURE
+/*
+ capture staff
+*/
+static int init_audio(radio_priv_t *priv)
+{
+ int is_oss=1;
+ if (priv->audio_inited) return 1;
+ priv->do_capture=0;
+
+ if (radio_param_adevice){
+ char* tmp;
+
+ priv->do_capture=1;
+ while ((tmp = strrchr(radio_param_adevice, '=')))
+ { tmp[0] = ':'; is_oss=0;}
+ while ((tmp = strrchr(radio_param_adevice, '.')))
+ tmp[0] = ',';
+ }
+ else
+ return;
+
+#if defined(HAVE_ALSA9) || defined(HAVE_ALSA1X)
+
+ if(audio_in_init(&priv->audio_in, is_oss?AUDIO_IN_OSS:AUDIO_IN_ALSA)<0){
+#else
+ if(audio_in_init(&priv->audio_in, AUDIO_IN_OSS)<0){
+#endif
+ mp_msg(MSGT_RADIO, MSGL_ERR, "audio_in_init failed: %s\n",strerror(errno));
+ }
+
+ audio_in_set_device(&priv->audio_in, radio_param_adevice);
+ audio_in_set_channels(&priv->audio_in, radio_param_achannels);
+ audio_in_set_samplerate(&priv->audio_in, radio_param_arate);
+ if (audio_in_setup(&priv->audio_in) < 0) return;
+
+ priv->audio_buffer_size = priv->audio_in.samplerate*priv->audio_in.channels*
+ priv->audio_in.bytes_per_sample+priv->audio_in.blocksize;
+ if (priv->audio_buffer_size < 256*priv->audio_in.blocksize)
+ priv->audio_buffer_size = 256*priv->audio_in.blocksize;
+
+ mp_msg(MSGT_RADIO, MSGL_V, "Audio capture - buffer=%d bytes (block=%d bytes).\n",
+ priv->audio_buffer_size,priv->audio_in.blocksize);
+ priv->audio_inited = 1;
+
+ return 1;
+}
+
+static void *audio_grabber(void *data)
+{
+ radio_priv_t *priv = (radio_priv_t*)data;
+
+ audio_in_start_capture(&priv->audio_in);
+
+ for (; !priv->shutdown;)
+ {
+ /* There is no enough place in ringbuffer to store chunk
+ audio_tail always aligned in audio_in.blocksize (audio_head may not)
+ Thus if audio_buffer_size-audio_cnt>blocksize we can write at least blocksize
+ bytes to position pointed by audio_tail.
+ */
+ if (priv->audio_buffer_size-priv->audio_cnt<priv->audio_in.blocksize) {
+ /* priv->audio_drop used only here, so mutex is not needed*/
+ priv->audio_drop+=priv->audio_in.blocksize;
+ mp_msg(MSGT_RADIO, MSGL_ERR, "\ntoo bad - dropping audio frame (bytes %d blocks %d)!\n",
+ priv->audio_drop,priv->audio_drop / priv->audio_in.blocksize);
+ continue;
+ }
+ if (audio_in_read_chunk(&priv->audio_in, priv->audio_ringbuffer+priv->audio_tail) < 0)
+ continue;
+
+ pthread_mutex_lock(&priv->audio_mutex);
+ priv->audio_tail = (priv->audio_tail+priv->audio_in.blocksize) % priv->audio_buffer_size;
+ priv->audio_cnt+=priv->audio_in.blocksize;
+ pthread_mutex_unlock(&priv->audio_mutex);
+
+ mp_msg(MSGT_RADIO, MSGL_DBG3, "grabber: capt=%d drop=%d block=%d head=0x%x tail=0x%x\n",priv->audio_cnt,priv->audio_drop,priv->audio_in.blocksize,priv->audio_head,priv->audio_tail);
+ }
+ return NULL;
+}
+static void grab_audio_frame(radio_priv_t *priv, char *buffer, int len)
+{
+ mp_msg(MSGT_RADIO, MSGL_DBG3, "grab_audio_frame: capt=%d drop=%d bufsize=%d head=0x%x tail=0x%x\n",priv->audio_cnt,priv->audio_drop,len,priv->audio_head,priv->audio_tail);
+ if (!priv->audio_cnt){
+ mp_msg(MSGT_RADIO, MSGL_WARN, "grab_audio_frame: buffer empty, wating fo %d data bytes\n",len);
+ while (priv->audio_cnt<len) usleep(10000);
+ }
+ if(priv->audio_cnt<len)
+ len=priv->audio_cnt;
+
+ pthread_mutex_lock(&priv->audio_mutex);
+ memcpy(buffer, priv->audio_ringbuffer+priv->audio_head,len);
+ priv->audio_head = (priv->audio_head+len) % priv->audio_buffer_size;
+ priv->audio_cnt-=len;
+ pthread_mutex_unlock(&priv->audio_mutex);
+}
+#endif
+
+
+stream_info_t stream_info_radio = {
+ "Radio stream",
+ "Radio",
+ "Vladimir Voroshilov",
+ "In development",
+ open_s,
+ { "radio", NULL },
+ &stream_opts,
+ 1 // Urls are an option string
+};
+
+#endif
+
Index: libmpdemux/stream_radio.h
===================================================================
--- libmpdemux/stream_radio.h (revision 0)
+++ libmpdemux/stream_radio.h (revision 0)
@@ -0,0 +1,20 @@
+#ifndef _H_STREAM_RADIO_
+#define _H_STREAM_RADIO_
+
+#define RADIO_CHANNEL_LOWER 1
+#define RADIO_CHANNEL_HIGHER 2
+
+
+extern char *radio_param_device;
+extern char **radio_param_channels;
+extern int radio_param_volume;
+char* radio_param_adevice;
+int radio_param_arate;
+int radio_param_achannels;
+
+char* radio_get_channel_name(struct stream_st *stream);
+int radio_set_channel(struct stream_st *stream, char *channel);
+int radio_step_channel(struct stream_st *stream, int direction);
+int radio_set_freq(struct stream_st *stream, float freq);
+
+#endif
Index: libmpdemux/audio_in.c
===================================================================
--- libmpdemux/audio_in.c (revision 18810)
+++ libmpdemux/audio_in.c (working copy)
@@ -4,8 +4,9 @@
#include "config.h"
-#if defined(USE_TV) && (defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2))
+#if (defined(USE_RADIO) || defined(USE_TV)) && (defined(HAVE_RADIO_V4L) || defined(HAVE_RADIO_V4L2) || defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2))
+
#include "audio_in.h"
#include "mp_msg.h"
#include "help_mp.h"
Index: libmpdemux/ai_alsa1x.c
===================================================================
--- libmpdemux/ai_alsa1x.c (revision 18810)
+++ libmpdemux/ai_alsa1x.c (working copy)
@@ -4,7 +4,7 @@
#include "config.h"
-#if defined(USE_TV) && (defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2)) && defined(HAVE_ALSA1X)
+#if (defined(USE_RADIO) || defined(USE_TV)) && (defined(HAVE_RADIO_V4L) || defined(HAVE_RADIO_V4L2) || defined(HAVE_TV_V4L) || defined(HAVE_TV_V4L2)) && defined(HAVE_ALSA1X)
#include <alsa/asoundlib.h>
#include "audio_in.h"
Index: libmpdemux/stream.c
===================================================================
--- libmpdemux/stream.c (revision 18810)
+++ libmpdemux/stream.c (working copy)
@@ -73,6 +73,7 @@
extern stream_info_t stream_info_cue;
extern stream_info_t stream_info_null;
+extern stream_info_t stream_info_radio;
extern stream_info_t stream_info_file;
#ifdef HAVE_DVD
extern stream_info_t stream_info_dvd;
@@ -111,6 +112,9 @@
&stream_info_smb,
#endif
&stream_info_cue,
+#ifdef USE_RADIO
+ &stream_info_radio,
+#endif
#ifdef HAVE_DVD
&stream_info_dvd,
#endif
Index: libmpdemux/stream.h
===================================================================
--- libmpdemux/stream.h (revision 18810)
+++ libmpdemux/stream.h (working copy)
@@ -21,6 +21,7 @@
#define STREAMTYPE_DVB 13
#define STREAMTYPE_VSTREAM 14
#define STREAMTYPE_SDP 15
+#define STREAMTYPE_RADIO 16
#define STREAM_BUFFER_SIZE 2048
Index: mp_msg.h
===================================================================
--- mp_msg.h (revision 18810)
+++ mp_msg.h (working copy)
@@ -97,6 +97,8 @@
#define MSGT_IDENTIFY 41 // -identify output
+#define MSGT_RADIO 42
+
#define MSGT_MAX 64
void mp_msg_init(void);
More information about the MPlayer-dev-eng
mailing list