/* * radio.c: A plugin for the Video Disk Recorder * * See the README file for copyright information and how to reach the author. * */ #include #include #include #include #include #include #include "getopt.h" #include "radioaudio.h" #include "radiotools.h" #include "radioepg.h" #include "inforx.h" #include "service.h" #if VDRVERSNUM < 10737 #error This version of radio-plugin requires vdr >= 1.7.37 #endif #ifndef GIT_REV static const char *VERSION = "1.1.0"; #else static const char *VERSION = GIT_REV; #endif static const char *DESCRIPTION = trNOOP("Radio Background-Image/RDS-Text"); static const char *MAINMENUENTRY = trNOOP("Show RDS-Radiotext"); char *ConfigDir; char *DataDir; char *LiveFile; char *ReplayFile; // Setup-Params int S_Activate = false; int S_StillPic = 1; int S_HMEntry = false; int S_RtFunc = 1; int S_RtOsdTitle = 1; int S_RtOsdTags = 2; int S_RtOsdPos = 1; int S_RtOsdRows = 2; int S_RtOsdLoop = 0; int S_RtOsdTO = 60; int S_RtSkinColor = 1; int S_RtBgCol = 0; int S_RtBgTra = 0xA0; int S_RtFgCol = 1; int S_RtDispl = 1; int S_RtMsgItems = 0; //int S_RtpMemNo = 25; int S_RassText = 1; int S_ExtInfo = 0; uint32_t rt_color[9]; int S_Verbose = 1; int S_Encrypted = 0; // Radiotext char RT_Text[5][RT_MEL]; char RTP_Artist[RT_MEL], RTP_Title[RT_MEL]; int RT_Info, RT_Index, RT_PTY; time_t RTP_Starttime; bool RT_OsdTO = false, RTplus_Osd = false, RT_ReOpen = false; int RT_OsdTOTemp = 0, Radio_CA = 0; int RT_Charset = 0; // 0= ISO-8859-1, 1= UTF8, 2= .. // RadioCheck const cChannel *chan; int IsRadioOrReplay; // Info bool DoInfoReq = false, InfoRequest = false; int InfoTimeout = 3; // --- cRadioCheck ------------------------------------------------------- class cRadioCheck: public cThread { private: static cRadioCheck *RadioCheck; protected: virtual void Action(void); void Stop(void); public: cRadioCheck(void); virtual ~cRadioCheck(); static void Init(void); static void Exit(void); }; cRadioCheck *cRadioCheck::RadioCheck = NULL; cRadioCheck::cRadioCheck(void) : cThread("radiocheck") { IsRadioOrReplay = 0; } cRadioCheck::~cRadioCheck() { if (Running()) { Stop(); } } void cRadioCheck::Init(void) { if (RadioCheck == NULL) { RadioCheck = new cRadioCheck; RadioCheck->Start(); } } void cRadioCheck::Exit(void) { if (RadioCheck != NULL) { RadioCheck->Stop(); DELETENULL(RadioCheck); } } void cRadioCheck::Stop(void) { Cancel(10); } void cRadioCheck::Action(void) { if ((S_Verbose & 0x0f) >= 2) { printf("vdr-radio: background-checking starts\n"); } while (Running()) { cCondWait::SleepMs(2000); // check Live-Radio if ((IsRadioOrReplay == 1) && (chan != NULL)) { if (chan->Vpid()) { isyslog("radio: channnel '%s' got Vpid= %d", chan->Name(), chan->Vpid()); IsRadioOrReplay = 0; #if VDRVERSNUM >= 20300 LOCK_CHANNELS_READ Channels->SwitchTo(cDevice::CurrentChannel()); #else Channels.SwitchTo(cDevice::CurrentChannel()); #endif //cDevice::PrimaryDevice()->SwitchChannel(chan, true); } else { if ((InfoTimeout -= 2) <= 0) { InfoTimeout = 20; int chtid = chan->Tid(); // Kanal-EPG PresentEvent if (chan->Apid(0) > 0 && (chtid == PREMIERERADIO_TID || chtid == KDRADIO_TID || chtid == UMRADIO_TID1 || chtid == UMRADIO_TID2 || chtid == UMRADIO_TID3 || chtid == UMRADIO_TID4 || chtid == UMRADIO_TID5)) { #if VDRVERSNUM >= 20300 LOCK_SCHEDULES_READ static cStateKey SchedulesStateKey; const cSchedules *scheds = cSchedules::GetSchedulesRead( SchedulesStateKey); #else cSchedulesLock schedLock; const cSchedules *scheds = cSchedules::Schedules(schedLock); #endif if (scheds != NULL) { const cSchedule *sched = scheds->GetSchedule( chan->GetChannelID()); if (sched != NULL) { const cEvent *present = sched->GetPresentEvent(); if (present != NULL) { if (chtid == PREMIERERADIO_TID) { // Premiere InfoTimeout = epg_premiere( present->Title(), present->Description(), present->StartTime(), present->EndTime()); } else if (chtid == KDRADIO_TID) {// Kabel Deutschland InfoTimeout = epg_kdg( present->Description(), present->StartTime(), present->EndTime()); } else { // Unity Media Kabel InfoTimeout = epg_unitymedia( present->Description(), present->StartTime(), present->EndTime()); } InfoRequest = true; } else { dsyslog("radio: no event.present (Tid= %d, Apid= %d)", chtid, chan->Apid(0)); } } else { dsyslog("radio: no schedule (Tid= %d, Apid= %d)", chtid, chan->Apid(0)); } } } // Artist/Title with external script? else if (chan->Apid(0) > 0 && DoInfoReq) { InfoTimeout = info_request(chtid, chan->Apid(0)); InfoRequest = (InfoTimeout > 0); } } } } // temp. OSD-CloseTimeout (RT_OsdTOTemp > 0) ? RT_OsdTOTemp -= 2 : RT_OsdTOTemp = 0; // in sec like this cycletime // Radiotext-Autodisplay if ((S_RtDispl == 2) && (RT_Info >= 0) && !RT_OsdTO && (RT_OsdTOTemp == 0) && RT_ReOpen && !Skins.IsOpen() && !cOsd::IsOpen()) { cRemote::CallPlugin("radio"); } } if ((S_Verbose & 0x0f) >= 2) { printf("vdr-radio: background-checking ends\n"); } } // --- cMenuSetupRadio ------------------------------------------------------- class cMenuSetupRadio : public cMenuSetupPage { private: int newS_Activate; int newS_StillPic; int newS_HMEntry; int newS_RtFunc; int newS_RtOsdTitle; int newS_RtOsdTags; int newS_RtOsdPos; int newS_RtOsdRows; int newS_RtOsdLoop; int newS_RtOsdTO; int newS_RtSkinColor; int newS_RtBgCol; int newS_RtBgTra; int newS_RtFgCol; int newS_RtDispl; int newS_RtMsgItems; //int newS_RtpMemNo; int newS_RassText; int newS_ExtInfo; const char *T_RtFunc[3]; const char *T_RtOsdTags[3]; const char *T_RtOsdPos[2]; const char *T_RtOsdLoop[2]; const char *T_RtBgColor[9]; const char *T_RtFgColor[9]; const char *T_RtDisplay[3]; const char *T_RtMsgItems[4]; const char *T_RassText[3]; protected: virtual void Store(void); public: cMenuSetupRadio(void); }; cMenuSetupRadio::cMenuSetupRadio(void) { T_RtFunc[0] = tr("Off"); T_RtFunc[1] = tr("only Text"); T_RtFunc[2] = tr("Text+TagInfo"); T_RtOsdTags[0] = tr("Off"); T_RtOsdTags[1] = tr("only, if some"); T_RtOsdTags[2] = tr("always"); T_RtOsdPos[0] = tr("Top"); T_RtOsdPos[1] = tr("Bottom"); T_RtOsdLoop[0] = tr("latest at Top"); T_RtOsdLoop[1] = tr("latest at Bottom"); T_RtBgColor[0] = T_RtFgColor[0] = tr ("Black"); T_RtBgColor[1] = T_RtFgColor[1] = tr ("White"); T_RtBgColor[2] = T_RtFgColor[2] = tr ("Red"); T_RtBgColor[3] = T_RtFgColor[3] = tr ("Green"); T_RtBgColor[4] = T_RtFgColor[4] = tr ("Yellow"); T_RtBgColor[5] = T_RtFgColor[5] = tr ("Magenta"); T_RtBgColor[6] = T_RtFgColor[6] = tr ("Blue"); T_RtBgColor[7] = T_RtFgColor[7] = tr ("Cyan"); T_RtBgColor[8] = T_RtFgColor[8] = tr ("Transparent"); T_RtDisplay[0] = tr("Off"); T_RtDisplay[1] = tr("about MainMenu"); T_RtDisplay[2] = tr("Automatic"); T_RtMsgItems[0] = tr("Off"); T_RtMsgItems[1] = tr("only Taginfo"); T_RtMsgItems[2] = tr("only Text"); T_RtMsgItems[3] = tr("Text+TagInfo"); T_RassText[0] = tr("Off"); T_RassText[1] = tr("Rass only"); T_RassText[2] = tr("Rass+Text mixed"); newS_Activate = S_Activate; newS_StillPic = S_StillPic; newS_Activate = S_Activate; newS_RtFunc = S_RtFunc; newS_RtOsdTitle = S_RtOsdTitle; newS_RtOsdTags = S_RtOsdTags; newS_RtOsdPos = S_RtOsdPos; newS_RtOsdRows = S_RtOsdRows; newS_RtOsdLoop = S_RtOsdLoop; newS_RtOsdTO = S_RtOsdTO; newS_RtSkinColor = S_RtSkinColor; newS_RtBgCol = S_RtBgCol; newS_RtBgTra = S_RtBgTra; newS_RtFgCol = S_RtFgCol; newS_RtDispl = (S_RtDispl > 2 ? 2 : S_RtDispl); newS_RtMsgItems = S_RtMsgItems; //newS_RtpMemNo = S_RtpMemNo; newS_RassText = S_RassText; newS_ExtInfo = S_ExtInfo; Add(new cMenuEditBoolItem( tr("Activate"), &newS_Activate)); Add(new cMenuEditBoolItem( tr("Use StillPicture-Function"), &newS_StillPic)); Add(new cMenuEditBoolItem( tr("Hide MainMenuEntry"), &newS_HMEntry)); Add(new cMenuEditStraItem( tr("RDSText Function"), &newS_RtFunc, 3, T_RtFunc)); Add(new cMenuEditStraItem( tr("RDSText OSD-Position"), &newS_RtOsdPos, 2, T_RtOsdPos)); Add(new cMenuEditBoolItem( tr("RDSText OSD-Titlerow"), &newS_RtOsdTitle)); Add(new cMenuEditIntItem( tr("RDSText OSD-Rows (1-5)"), &newS_RtOsdRows, 1, 5)); Add(new cMenuEditStraItem( tr("RDSText OSD-Scrollmode"), &newS_RtOsdLoop, 2, T_RtOsdLoop)); Add(new cMenuEditStraItem( tr("RDSText OSD-Taginfo"), &newS_RtOsdTags, 3, T_RtOsdTags)); Add(new cMenuEditBoolItem( tr("RDSText OSD-Skincolors used"), &newS_RtSkinColor)); if (newS_RtSkinColor == 0) { Add(new cMenuEditStraItem( tr("RDSText OSD-Backgr.Color"), &newS_RtBgCol, 9, T_RtBgColor)); Add(new cMenuEditIntItem( tr("RDSText OSD-Backgr.Transp."), &newS_RtBgTra, 1, 255)); Add(new cMenuEditStraItem( tr("RDSText OSD-Foregr.Color"), &newS_RtFgCol, 8, T_RtFgColor)); } Add(new cMenuEditIntItem( tr("RDSText OSD-Timeout (0-1440 min)"), &newS_RtOsdTO, 0, 1440)); Add(new cMenuEditStraItem( tr("RDSText OSD-Display"), &newS_RtDispl, 3, T_RtDisplay)); Add(new cMenuEditStraItem( tr("RDSText StatusMsg (lcdproc & co)"), &newS_RtMsgItems, 4, T_RtMsgItems)); //Add(new cMenuEditIntItem( tr("RDSplus Memorynumber (10-99)"), &newS_RtpMemNo, 10, 99)); Add(new cMenuEditStraItem( tr("RDSText Rass-Function"), &newS_RassText, 3, T_RassText)); Add(new cMenuEditBoolItem( tr("External Info-Request"), &newS_ExtInfo)); } void cMenuSetupRadio::Store(void) { SetupStore("Activate", S_Activate = newS_Activate); SetupStore("UseStillPic", S_StillPic = newS_StillPic); SetupStore("HideMenuEntry", S_HMEntry = newS_HMEntry); SetupStore("RDSText-Function", S_RtFunc = newS_RtFunc); SetupStore("RDSText-OsdTitle", S_RtOsdTitle = newS_RtOsdTitle); SetupStore("RDSText-OsdTags", S_RtOsdTags = newS_RtOsdTags); SetupStore("RDSText-OsdPosition", S_RtOsdPos = newS_RtOsdPos); SetupStore("RDSText-OsdRows", S_RtOsdRows = newS_RtOsdRows); SetupStore("RDSText-OsdLooping", S_RtOsdLoop = newS_RtOsdLoop); SetupStore("RDSText-OsdSkinColor", S_RtSkinColor = newS_RtSkinColor); SetupStore("RDSText-OsdBackgrColor", S_RtBgCol = newS_RtBgCol); SetupStore("RDSText-OsdBackgrTrans", S_RtBgTra = newS_RtBgTra); SetupStore("RDSText-OsdForegrColor", S_RtFgCol = newS_RtFgCol); SetupStore("RDSText-OsdTimeout", S_RtOsdTO = newS_RtOsdTO); SetupStore("RDSText-Display", S_RtDispl = newS_RtDispl); SetupStore("RDSText-MsgItems", S_RtMsgItems = newS_RtMsgItems); //SetupStore("RDSplus-MemNumber", S_RtpMemNo = newS_RtpMemNo); SetupStore("RDSText-Rass", S_RassText = newS_RassText); SetupStore("ExtInfo-Req", S_ExtInfo = newS_ExtInfo); } // --- cPluginRadio ------------------------------------------------------- class cRadioImage; class cRadioAudio; class cPluginRadio : public cPlugin, cStatus { private: // Add any member variables or functions you may need here. bool ConfigDirParam; bool DataDirParam; bool LiveFileParam; bool ReplayFileParam; cRadioImage *radioImage; cRadioAudio *radioAudio; public: cPluginRadio(void); virtual ~cPluginRadio(); virtual const char *Version(void) { return VERSION; } virtual const char *Description(void) { return tr(DESCRIPTION); } virtual const char *CommandLineHelp(void); virtual bool ProcessArgs(int argc, char *argv[]); virtual bool Start(void); virtual void Stop(void); virtual void Housekeeping(void); virtual void MainThreadHook(void) { } virtual cString Active(void) { return NULL; } virtual const char *MainMenuEntry(void) { return (S_Activate==0 || S_RtFunc==0 || S_RtDispl==0 || S_HMEntry ? NULL : tr(MAINMENUENTRY)); } virtual cOsdObject *MainMenuAction(void); virtual cMenuSetupPage *SetupMenu(void); virtual bool SetupParse(const char *Name, const char *Value); virtual bool Service(const char *Id, void *Data); virtual const char **SVDRPHelpPages(void); virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); protected: virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber, bool LiveView); virtual void Replaying(const cControl *Control, const char *Name, const char *FileName, bool On); }; cPluginRadio::cPluginRadio(void) { // Initialize any member variables here. // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL // VDR OBJECTS TO EXIST OR PROADUCE ANY OUTPUT! radioImage = 0; radioAudio = 0; ConfigDirParam = false; DataDirParam = false; LiveFileParam = false; ReplayFileParam = false; rt_color[0] = 0xFF000000; //Black rt_color[1] = 0xFFFCFCFC; //White rt_color[2] = 0xFFFC1414; //Red rt_color[3] = 0xFF24FC24; //Green rt_color[4] = 0xFFFCC024; //Yellow rt_color[5] = 0xFFB000FC; //Magenta rt_color[6] = 0xFF0000FC; //Blue rt_color[7] = 0xFF00FCFC; //Cyan rt_color[8] = 0x00000000; //Transparent } cPluginRadio::~cPluginRadio() { // Clean up after yourself! if (ConfigDir) free(ConfigDir); if (DataDir) free(DataDir); if (LiveFile) free(LiveFile); if (ReplayFile) free(ReplayFile); cRadioCheck::Exit(); radioImage->Exit(); } const char *cPluginRadio::CommandLineHelp(void) { // Return a string that describes all known command line options. return " -f dir, --files=dir use dir as image directory (default: /plugins/radio)\n" " -d dir, --data=dir use dir as temp. data directory (default: /plugins/radio)\n" " -l file, --live=file use file as default mpegfile in livemode (default: /radio.mpg)\n" " -r file, --replay=file use file as default mpegfile in replaymode (default: /replay.mpg)\n" " -e 1, --encrypted=1 use transfermode/backgroundimage @ encrypted radiochannels \n" " -v level, --verbose=level set verbose level (default = 1, 0 = Off, 1 = RDS-Text+Tags, \n" " 2 = +RDS-Telegram/Debug, 3 = +RawData 0xfd, \n" " += 16 = Rass-Info, +=32 = TMC-Info) \n"; } bool cPluginRadio::ProcessArgs(int argc, char *argv[]) { // Implement command line argument processing here if applicable. static struct option long_options[] = { { "files", required_argument, NULL, 'f' }, { "data", required_argument, NULL, 'd' }, { "live", required_argument, NULL, 'l' }, { "replay", required_argument, NULL, 'r' }, { "encrypted", required_argument, NULL, 'e' }, { "verbose", required_argument, NULL, 'v' }, { NULL } }; int c; while ((c = getopt_long(argc, argv, "f:d:l:r:e:v:", long_options, NULL)) != -1) { switch (c) { case 'f': printf("vdr-radio: arg files-dir = %s\n", optarg); ConfigDir = strdup(optarg); ConfigDirParam = true; break; case 'd': printf("vdr-radio: arg data-dir = %s\n", optarg); DataDir = strdup(optarg); DataDirParam = true; break; case 'l': printf("vdr-radio: arg live-mpeg = %s\n", optarg); LiveFile = strdup(optarg); LiveFileParam = true; break; case 'r': printf("vdr-radio: arg replay-mpeg = %s\n", optarg); ReplayFile = strdup(optarg); ReplayFileParam = true; break; case 'v': printf("vdr-radio: arg verbose = %s\n", optarg); if (isnumber(optarg)) S_Verbose = atoi(optarg); break; case 'e': printf("vdr-radio: arg encrypted = %s\n", optarg); if (isnumber(optarg)) S_Encrypted = atoi(optarg); break; default: printf("vdr-radio: arg char = %c\n", c); return false; } } return true; } bool cPluginRadio::Start(void) { // Start any background activities the plugin shall perform. printf("vdr-radio: Radio-Plugin Backgr.Image/RDS-Text starts...\n"); radioImage = new cRadioImage; if (!radioImage) return false; radioImage->Init(); radioAudio = new cRadioAudio; if (!radioAudio) return false; if (!ConfigDirParam) ConfigDir = strdup(ConfigDirectory(Name())); if (!DataDirParam) { DataDir = strdup("/tmp/vdr-radio.XXXXXX"); mkdtemp(DataDir); } if (!LiveFileParam) { asprintf(&LiveFile, "%s/radio.mpg", ConfigDir); } if (!ReplayFileParam) { asprintf(&ReplayFile, "%s/replay.mpg", ConfigDir); } cRadioCheck::Init(); return true; } void cPluginRadio::Stop(void) { cRadioCheck::Exit(); if (IsRadioOrReplay > 0) { radioAudio->DisableRadioTextProcessing(); } radioImage->Exit(); } void cPluginRadio::Housekeeping(void) { // Perform any cleanup or other regular tasks. } cOsdObject *cPluginRadio::MainMenuAction(void) { // Perform the action when selected from the main VDR menu. /* if (!cDevice::PrimaryDevice()->Transferring() && !cDevice::PrimaryDevice()->Replaying()) { //cRemote::CallPlugin("radio"); // try again later <-- disabled, looping if activate over menu @ tv in dvb-livemode } */ if (S_Activate > 0 && S_RtFunc > 0 && S_RtDispl > 0 && IsRadioOrReplay > 0) { if (!RTplus_Osd) { cRadioTextOsd *rtosd = new cRadioTextOsd(); return rtosd; } else { cRTplusOsd *rtposd = new cRTplusOsd(); return rtposd; } } return NULL; } cMenuSetupPage *cPluginRadio::SetupMenu(void) { // Return a setup menu in case the plugin supports one. return new cMenuSetupRadio; } bool cPluginRadio::SetupParse(const char *Name, const char *Value) { // Parse your own setup parameters and store their values. if (!strcasecmp(Name, "Activate")) S_Activate = atoi(Value); else if (!strcasecmp(Name, "UseStillPic")) S_StillPic = atoi(Value); else if (!strcasecmp(Name, "HideMenuEntry")) S_HMEntry = atoi(Value); else if (!strcasecmp(Name, "RDSText-Function")) S_RtFunc = atoi(Value); else if (!strcasecmp(Name, "RDSText-OsdTitle")) S_RtOsdTitle = atoi(Value); else if (!strcasecmp(Name, "RDSText-OsdTags")) S_RtOsdTags = atoi(Value); else if (!strcasecmp(Name, "RDSText-OsdPosition")) S_RtOsdPos = atoi(Value); else if (!strcasecmp(Name, "RDSText-OsdRows")) { S_RtOsdRows = atoi(Value); if (S_RtOsdRows > 5) S_RtOsdRows = 5; } else if (!strcasecmp(Name, "RDSText-OsdLooping")) S_RtOsdLoop = atoi(Value); else if (!strcasecmp(Name, "RDSText-OsdSkinColor")) S_RtSkinColor = atoi(Value); else if (!strcasecmp(Name, "RDSText-OsdBackgrColor")) S_RtBgCol = atoi(Value); else if (!strcasecmp(Name, "RDSText-OsdBackgrTrans")) S_RtBgTra = atoi(Value); else if (!strcasecmp(Name, "RDSText-OsdForegrColor")) S_RtFgCol = atoi(Value); else if (!strcasecmp(Name, "RDSText-OsdTimeout")) { S_RtOsdTO = atoi(Value); if (S_RtOsdTO > 1440) S_RtOsdTO = 1440; } else if (!strcasecmp(Name, "RDSText-Display")) S_RtDispl = atoi(Value); else if (!strcasecmp(Name, "RDSText-MsgItems")) S_RtMsgItems = atoi(Value); //else if (!strcasecmp(Name, "RDSplus-MemNumber")) S_RtpMemNo = atoi(Value); else if (!strcasecmp(Name, "RDSText-Rass")) S_RassText = atoi(Value); else if (!strcasecmp(Name, "ExtInfo-Req")) S_ExtInfo = atoi(Value); else return false; return true; } bool cPluginRadio::Service(const char *Id, void *Data) { static struct tm tm_store; if ((strcmp(Id, RADIO_TEXT_SERVICE0) == 0) && (S_Activate > 0) && (S_RtFunc >= 1)) { if (Data) { RadioTextService_v1_0 *data = (RadioTextService_v1_0*)Data; data->rds_pty = RT_PTY; data->rds_info = (RT_Info < 0) ? 0 : RT_Info; int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1; data->rds_text = RT_Text[ind]; data->rds_title = RTP_Title; data->rds_artist = RTP_Artist; data->title_start = localtime_r(&RTP_Starttime, &tm_store); } return true; } else if ((strcmp(Id, RADIO_TEXT_SERVICE1) == 0) && (S_Activate > 0) && (S_RtFunc >= 1)) { if (Data) { cCharSetConv conf(RT_Charset == 0 ? "ISO-8859-1" : 0); RadioTextService_v1_1 *data = (RadioTextService_v1_1*)Data; int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1; data->rds_pty = RT_PTY; data->rds_info = RT_Info < 0 ? 0 : RT_Info; data->rds_pty_info = RT_PTY > 0 ? ptynr2string(RT_PTY) : ""; data->rds_text = conf.Convert(RT_Text[ind]); data->rds_title = conf.Convert(RTP_Title); data->rds_artist = conf.Convert(RTP_Artist); data->title_start = RTP_Starttime; data->bitrate = radioAudio->bitrate; } return true; } return false; } const char **cPluginRadio::SVDRPHelpPages(void) { static const char *HelpPages[] = { "RTINFO\n" " Print the radiotext information.", "RTCLOSE\n" " Close the radiotext-osd,\n" " Reopen can only be done over menu or channelswitch.", "RTTCLOSE\n" " Close the radiotext-osd temporarily,\n" " Reopen will be done after osd-messagetimeout.", NULL }; return HelpPages; } cString cPluginRadio::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) { if (strcasecmp(Command, "RTINFO") == 0) { // we use the default reply code here if (RT_Info == 2) { int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1; return cString::sprintf( " Radiotext: %s\n RT-Title : %s\n RT-Artist: %s\n", RT_Text[ind], RTP_Title, RTP_Artist); } else if (RT_Info == 1) { int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1; return cString::sprintf(" Radiotext: %s\n", RT_Text[ind]); } else return cString::sprintf(" Radiotext not available (yet)\n"); } else if (strcasecmp(Command, "RTCLOSE") == 0) { // we use the default reply code here if (RT_OsdTO) return cString::sprintf("RT-OSD already closed"); else { RT_OsdTO = true; return cString::sprintf("RT-OSD will be closed now"); } } else if (strcasecmp(Command, "RTTCLOSE") == 0) { // we use the default reply code here RT_OsdTOTemp = 2 * Setup.OSDMessageTime; return cString::sprintf("RT-OSD will be temporarily closed"); } return NULL; } void cPluginRadio::ChannelSwitch(const cDevice *Device, int ChannelNumber, bool LiveView) { if (Device != cDevice::PrimaryDevice()) { return; } IsRadioOrReplay = Radio_CA = 0; radioAudio->DisableRadioTextProcessing(); InfoTimeout = 3; if (S_Activate == false) { return; } char *image; if (cDevice::CurrentChannel() == ChannelNumber) { #if VDRVERSNUM >= 20300 LOCK_CHANNELS_READ chan = ChannelNumber ? Channels->GetByNumber(ChannelNumber) : NULL; #else chan = ChannelNumber ? Channels.GetByNumber(ChannelNumber) : NULL; #endif if (chan != NULL && chan->Vpid() == 0 && chan->Apid(0) > 0) { asprintf(&image, "%s/%s.mpg", ConfigDir, chan->Name()); if (!file_exists(image)) { dsyslog("radio: channel-image not found '%s' (Channelname= %s)", image, chan->Name()); free(image); asprintf(&image, "%s", LiveFile); if (!file_exists(image)) { dsyslog("radio: live-image not found '%s' (Channelname= %s)", image, chan->Name()); } } dsyslog("radio: [ChannelSwitch # Apid= %d, Ca= %d] channelname '%s', use image '%s'", chan->Apid(0), chan->Ca(0), chan->Name(), image); if ((Radio_CA = chan->Ca(0)) == 0 || S_Encrypted == 1) { cDevice::PrimaryDevice()->ForceTransferMode(); } radioImage->SetBackgroundImage(image); radioAudio->EnableRadioTextProcessing(chan->Name(), chan->Apid(0), false); free(image); IsRadioOrReplay = 1; DoInfoReq = (S_ExtInfo > 0); } } } void cPluginRadio::Replaying(const cControl *Control, const char *Name, const char *FileName, bool On) { IsRadioOrReplay = 0; radioAudio->DisableRadioTextProcessing(); if (S_Activate == false) { return; } bool isRadio = false; if (On && FileName != NULL) { char *vdrfile; // check VDR PES-Recordings asprintf(&vdrfile, "%s/001.vdr", FileName); if (file_exists(vdrfile)) { cFileName fn(FileName, false, true, true); cUnbufferedFile *f = fn.Open(); if (f) { uchar b[4] = { 0x00, 0x00, 0x00, 0x00 }; ReadFrame(f, b, sizeof(b), sizeof(b)); fn.Close(); isRadio = (b[0] == 0x00) && (b[1] == 0x00) && (b[2] == 0x01) && (0xc0 <= b[3] && b[3] <= 0xdf); } } // check VDR TS-Recordings asprintf(&vdrfile, "%s/info", FileName); if (file_exists(vdrfile)) { cRecordingInfo rfi(FileName); if (rfi.Read()) { if (rfi.FramesPerSecond() > 0 && rfi.FramesPerSecond() < 18) {// max. seen 13.88 @ ARD-RadioTP 320k isRadio = true; } } } free(vdrfile); } if (isRadio) { if (!file_exists(ReplayFile)) { dsyslog("radio: replay-image not found '%s'", ReplayFile); } else { radioImage->SetBackgroundImage(ReplayFile); } radioAudio->EnableRadioTextProcessing(Name, 0, true); IsRadioOrReplay = 2; } } VDRPLUGINCREATOR(cPluginRadio); // Don't touch this!