diff options
author | reimar <reimar@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2006-08-28 17:05:18 +0000 |
---|---|---|
committer | reimar <reimar@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2006-08-28 17:05:18 +0000 |
commit | acf654cf8ff5d7a2693067116347ce568b0455d6 (patch) | |
tree | 55aa4861d6411c4f81e0f08c4be4e44233af23b9 | |
parent | 0decebcb05de3b3f4774567524f32d9013c4c6ee (diff) | |
download | mpv-acf654cf8ff5d7a2693067116347ce568b0455d6.tar.bz2 mpv-acf654cf8ff5d7a2693067116347ce568b0455d6.tar.xz |
Radio support, patch by Vladimir Voroshilov (voroshil gmail com)
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@19574 b3059339-0415-0410-9bf9-f77b7e298cf2
-rw-r--r-- | AUTHORS | 3 | ||||
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | DOCS/man/en/mplayer.1 | 56 | ||||
-rw-r--r-- | DOCS/xml/en/documentation.xml | 1 | ||||
-rw-r--r-- | DOCS/xml/en/install.xml | 5 | ||||
-rw-r--r-- | DOCS/xml/ru/features.xml | 1 | ||||
-rw-r--r-- | DOCS/xml/ru/install.xml | 9 | ||||
-rw-r--r-- | cfg-common.h | 21 | ||||
-rwxr-xr-x | configure | 91 | ||||
-rw-r--r-- | help/help_mp-en.h | 43 | ||||
-rw-r--r-- | input/input.c | 5 | ||||
-rw-r--r-- | input/input.h | 3 | ||||
-rw-r--r-- | mp_msg.h | 2 | ||||
-rw-r--r-- | mplayer.c | 32 | ||||
-rw-r--r-- | stream/Makefile | 17 | ||||
-rw-r--r-- | stream/stream.c | 6 | ||||
-rw-r--r-- | stream/stream.h | 1 | ||||
-rw-r--r-- | stream/stream_radio.c | 1108 | ||||
-rw-r--r-- | stream/stream_radio.h | 23 |
19 files changed, 1428 insertions, 0 deletions
@@ -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 @@ -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 }, @@ -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 @@ -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); @@ -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 |