mirror of
				https://github.com/rofafor/vdr-plugin-iptv.git
				synced 2023-10-10 11:37:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			468 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			468 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * setup.c: IPTV plugin for the Video Disk Recorder
 | |
|  *
 | |
|  * See the README file for copyright information and how to reach the author.
 | |
|  *
 | |
|  * $Id: setup.c,v 1.11 2007/09/28 16:44:59 rahrenbe Exp $
 | |
|  */
 | |
| 
 | |
| #include <string.h>
 | |
| 
 | |
| #include <vdr/device.h>
 | |
| #include <vdr/interface.h>
 | |
| 
 | |
| #include "common.h"
 | |
| #include "config.h"
 | |
| #include "setup.h"
 | |
| 
 | |
| #ifndef trVDR
 | |
| #define trVDR(s) tr(s)
 | |
| #endif
 | |
| 
 | |
| // --- cIptvMenuEditChannel --------------------------------------------------
 | |
| 
 | |
| class cIptvMenuEditChannel : public cOsdMenu
 | |
| {
 | |
| private:
 | |
|   enum {
 | |
|     eProtocolUDP,
 | |
|     eProtocolHTTP,
 | |
|     eProtocolFILE,
 | |
|     eProtocolCount
 | |
|   };
 | |
|   struct tIptvChannel {
 | |
|     int frequency, source, protocol, port, vpid, ppid, tpid, sid, nid, tid, rid;
 | |
|     int apid[MAXAPIDS + 1], dpid[MAXDPIDS + 1], spid[MAXSPIDS + 1], caids[MAXCAIDS + 1];
 | |
|     char name[256], location[256];
 | |
|   } data;
 | |
|   cChannel *channel;
 | |
|   const char *protocols[eProtocolCount];
 | |
|   void Setup(void);
 | |
|   cString GetIptvSettings(const char *Param, int *Port, int *Protocol);
 | |
|   void GetChannelData(cChannel *Channel);
 | |
|   void SetChannelData(cChannel *Channel);
 | |
| 
 | |
| public:
 | |
|   cIptvMenuEditChannel(cChannel *Channel, bool New = false);
 | |
|   virtual eOSState ProcessKey(eKeys Key);
 | |
| };
 | |
| 
 | |
| cIptvMenuEditChannel::cIptvMenuEditChannel(cChannel *Channel, bool New)
 | |
| :cOsdMenu(trVDR("Edit channel"), 16)
 | |
| {
 | |
|   protocols[eProtocolUDP]  = tr("UDP");
 | |
|   protocols[eProtocolHTTP] = tr("HTTP");
 | |
|   protocols[eProtocolFILE] = tr("FILE");
 | |
|   channel = Channel;
 | |
|   GetChannelData(channel);
 | |
|   if (New) {
 | |
|      channel = NULL;
 | |
|      data.nid = 0;
 | |
|      data.tid = 0;
 | |
|      data.rid = 0;
 | |
|      }
 | |
|   Setup();
 | |
| }
 | |
| 
 | |
| cString cIptvMenuEditChannel::GetIptvSettings(const char *Param, int *Port, int *Protocol)
 | |
| {
 | |
|   char *loc = NULL;
 | |
|   if (sscanf(Param, "IPTV|UDP|%a[^|]|%u", &loc, Port) == 2) {
 | |
|      cString addr(loc, true);
 | |
|      *Protocol = eProtocolUDP;
 | |
|      return addr;
 | |
|      }
 | |
|   else if (sscanf(Param, "IPTV|HTTP|%a[^|]|%u", &loc, Port) == 2) {
 | |
|      cString addr(loc, true);
 | |
|      *Protocol = eProtocolHTTP;
 | |
|      return addr;
 | |
|      }
 | |
|   else if (sscanf(Param, "IPTV|FILE|%a[^|]|%u", &loc, Port) == 2) {
 | |
|      cString addr(loc, true);
 | |
|      *Protocol = eProtocolFILE;
 | |
|      return addr;
 | |
|      }
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| void cIptvMenuEditChannel::GetChannelData(cChannel *Channel)
 | |
| {
 | |
|   if (Channel) {
 | |
|      int port, protocol;
 | |
|      data.frequency = Channel->Frequency();
 | |
|      data.source = Channel->Source();
 | |
|      data.vpid = Channel->Vpid();
 | |
|      data.ppid = Channel->Ppid();
 | |
|      data.tpid = Channel->Tpid();
 | |
|      for (unsigned int i = 0; i < sizeof(data.apid); ++i)
 | |
|          data.apid[i] = Channel->Apid(i);
 | |
|      for (unsigned int i = 0; i < sizeof(data.dpid); ++i)
 | |
|          data.dpid[i] = Channel->Dpid(i);
 | |
|      for (unsigned int i = 0; i < sizeof(data.spid); ++i)
 | |
|          data.spid[i] = Channel->Spid(i);
 | |
|      for (unsigned int i = 0; i < sizeof(data.caids); ++i)
 | |
|          data.caids[i] = Channel->Ca(i);
 | |
|      data.sid = Channel->Sid();
 | |
|      data.nid = Channel->Nid();
 | |
|      data.tid = Channel->Tid();
 | |
|      data.rid = Channel->Rid();
 | |
|      strn0cpy(data.name, Channel->Name(), sizeof(data.name));
 | |
|      strn0cpy(data.location, *GetIptvSettings(Channel->PluginParam(), &port, &protocol), sizeof(data.location));
 | |
|      data.protocol = protocol;
 | |
|      data.port = port;
 | |
|      }
 | |
|   else {
 | |
|      data.frequency = 1;
 | |
|      data.source = cSource::FromData(cSource::stPlug);
 | |
|      data.vpid = 0;
 | |
|      data.ppid = 0;
 | |
|      data.tpid = 0;
 | |
|      for (unsigned int i = 0; i < sizeof(data.apid); ++i)
 | |
|          data.apid[i] = 0;
 | |
|      for (unsigned int i = 0; i < sizeof(data.dpid); ++i)
 | |
|          data.dpid[i] = 0;
 | |
|      for (unsigned int i = 0; i < sizeof(data.spid); ++i)
 | |
|          data.spid[i] = 0;
 | |
|      for (unsigned int i = 0; i < sizeof(data.caids); ++i)
 | |
|          data.caids[i] = 0;
 | |
|      data.sid = 1;
 | |
|      data.nid = 0;
 | |
|      data.tid = 0;
 | |
|      data.rid = 0;
 | |
|      strn0cpy(data.name, "IPTV", sizeof(data.name));
 | |
|      strn0cpy(data.location, "127.0.0.1", sizeof(data.location));
 | |
|      data.protocol = eProtocolUDP;
 | |
|      data.port = 1234;
 | |
|      }
 | |
| }
 | |
| 
 | |
| void cIptvMenuEditChannel::SetChannelData(cChannel *Channel)
 | |
| {
 | |
|   if (Channel) {
 | |
|      cString param;
 | |
|      char alangs[MAXAPIDS][MAXLANGCODE2] = { "" };
 | |
|      char dlangs[MAXDPIDS][MAXLANGCODE2] = { "" };
 | |
|      switch (data.protocol) {
 | |
|        case eProtocolFILE:
 | |
|             param = cString::sprintf("IPTV|FILE|%s|0", data.location);
 | |
|             break;
 | |
|        case eProtocolHTTP:
 | |
|             param = cString::sprintf("IPTV|HTTP|%s|%d", data.location, data.port);
 | |
|             break;
 | |
|        default:
 | |
|        case eProtocolUDP:
 | |
|             param = cString::sprintf("IPTV|UDP|%s|%d", data.location, data.port);
 | |
|             break;
 | |
|        }
 | |
|      Channel->SetPids(data.vpid, data.ppid, data.apid, alangs, data.dpid, dlangs, data.tpid);
 | |
|      Channel->SetCaIds(data.caids);
 | |
|      Channel->SetId(data.nid, data.tid, data.sid, data.rid);
 | |
|      Channel->SetName(data.name, "", "IPTV");
 | |
|      Channel->SetPlugTransponderData(cSource::stPlug, data.frequency, param);
 | |
|      }
 | |
| }
 | |
| 
 | |
| void cIptvMenuEditChannel::Setup(void)
 | |
| {
 | |
|   int current = Current();
 | |
|   Clear();
 | |
|   // IPTV specific settings
 | |
|   Add(new cMenuEditStraItem(tr("Protocol"),    &data.protocol, 3, protocols));
 | |
|   switch (data.protocol) {
 | |
|     case eProtocolFILE:
 | |
|          Add(new cMenuEditStrItem(trVDR("File"), data.location, sizeof(data.location), trVDR(FileNameChars)));
 | |
|          break;
 | |
|     case eProtocolHTTP:
 | |
|     case eProtocolUDP:
 | |
|     default:
 | |
|          Add(new cMenuEditStrItem(tr("Address"),data.location, sizeof(data.location), trVDR(FileNameChars)));
 | |
|          Add(new cMenuEditIntItem(tr("Port"),  &data.port,  0, 0xFFFF));
 | |
|          break;
 | |
|     }
 | |
|   // Normal settings
 | |
|   Add(new cMenuEditStrItem(trVDR("Name"),       data.name,     sizeof(data.name), trVDR(FileNameChars)));
 | |
|   Add(new cMenuEditIntItem(trVDR("Frequency"), &data.frequency));
 | |
|   Add(new cMenuEditIntItem(trVDR("Vpid"),      &data.vpid,     0, 0x1FFF));
 | |
|   Add(new cMenuEditIntItem(trVDR("Ppid"),      &data.ppid,     0, 0x1FFF));
 | |
|   Add(new cMenuEditIntItem(trVDR("Apid1"),     &data.apid[0],  0, 0x1FFF));
 | |
|   Add(new cMenuEditIntItem(trVDR("Apid2"),     &data.apid[1],  0, 0x1FFF));
 | |
|   Add(new cMenuEditIntItem(trVDR("Dpid1"),     &data.dpid[0],  0, 0x1FFF));
 | |
|   Add(new cMenuEditIntItem(trVDR("Dpid2"),     &data.dpid[1],  0, 0x1FFF));
 | |
|   Add(new cMenuEditIntItem(trVDR("Tpid"),      &data.tpid,     0, 0x1FFF));
 | |
|   Add(new cMenuEditIntItem(trVDR("CA"),        &data.caids[0], 0, 0xFFFF));
 | |
|   Add(new cMenuEditIntItem(trVDR("Sid"),       &data.sid,      1, 0xFFFF));
 | |
|   SetCurrent(Get(current));
 | |
|   Display();
 | |
| }
 | |
| 
 | |
| eOSState cIptvMenuEditChannel::ProcessKey(eKeys Key)
 | |
| {
 | |
|   int oldProtocol = data.protocol;
 | |
|   eOSState state = cOsdMenu::ProcessKey(Key);
 | |
|   if (state == osUnknown) {
 | |
|      if (Key == kOk) {
 | |
|         cChannel newchannel;
 | |
|         SetChannelData(&newchannel);
 | |
|         if (Channels.HasUniqueChannelID(&newchannel, channel)) {
 | |
|            if (channel) {
 | |
|               SetChannelData(channel);
 | |
|               isyslog("edited channel %d %s", channel->Number(), *channel->ToText());
 | |
|               state = osBack;
 | |
|               }
 | |
|            else {
 | |
|               channel = new cChannel;
 | |
|               SetChannelData(channel);
 | |
|               Channels.Add(channel);
 | |
|               Channels.ReNumber();
 | |
|               isyslog("added channel %d %s", channel->Number(), *channel->ToText());
 | |
|               state = osUser1;
 | |
|               }
 | |
|            Channels.SetModified(true);
 | |
|            }
 | |
|         else {
 | |
|            Skins.Message(mtError, trVDR("Channel settings are not unique!"));
 | |
|            state = osContinue;
 | |
|            }
 | |
|         }
 | |
|      }
 | |
|   if ((Key != kNone) && (data.protocol != oldProtocol)) {
 | |
|      switch (data.protocol) {
 | |
|        case eProtocolFILE:
 | |
|             strn0cpy(data.location, "/tmp/video.ts", sizeof(data.location));
 | |
|             data.port = 0;
 | |
|             break;
 | |
|        case eProtocolHTTP:
 | |
|             strn0cpy(data.location, "127.0.0.1/TS/1", sizeof(data.location));
 | |
|             data.port = 3000;
 | |
|             break;
 | |
|        default:
 | |
|        case eProtocolUDP:
 | |
|             strn0cpy(data.location, "127.0.0.1", sizeof(data.location));
 | |
|             data.port = 1234;
 | |
|             break;
 | |
|        }
 | |
|      Setup();
 | |
|      }
 | |
|   return state;
 | |
| }
 | |
| 
 | |
| // --- cIptvMenuChannelItem --------------------------------------------------
 | |
| 
 | |
| class cIptvMenuChannelItem : public cOsdItem
 | |
| {
 | |
| private:
 | |
|   cChannel *channel;
 | |
| 
 | |
| public:
 | |
|   cIptvMenuChannelItem(cChannel *Channel);
 | |
|   virtual void Set(void);
 | |
|   cChannel *Channel(void) { return channel; }
 | |
| };
 | |
| 
 | |
| cIptvMenuChannelItem::cIptvMenuChannelItem(cChannel *Channel)
 | |
| {
 | |
|   channel = Channel;
 | |
|   Set();
 | |
| }
 | |
| 
 | |
| void cIptvMenuChannelItem::Set(void)
 | |
| {
 | |
|   char *buffer = NULL;
 | |
|   asprintf(&buffer, "%d\t%s", channel->Number(), channel->Name());
 | |
|   SetText(buffer, false);
 | |
| }
 | |
| 
 | |
| // --- cIptvMenuChannels -----------------------------------------------------
 | |
| 
 | |
| class cIptvMenuChannels : public cOsdMenu
 | |
| {
 | |
| private:
 | |
|   void Setup(void);
 | |
|   cChannel *GetChannel(int Index);
 | |
|   void Propagate(void);
 | |
| 
 | |
| protected:
 | |
|   eOSState Edit(void);
 | |
|   eOSState New(void);
 | |
|   eOSState Delete(void);
 | |
| 
 | |
| public:
 | |
|   cIptvMenuChannels();
 | |
|   ~cIptvMenuChannels();
 | |
|   virtual eOSState ProcessKey(eKeys Key);
 | |
| };
 | |
| 
 | |
| cIptvMenuChannels::cIptvMenuChannels(void)
 | |
| :cOsdMenu(tr("IPTV Channels"), numdigits(Channels.MaxNumber()) + 1)
 | |
| {
 | |
|   Setup();
 | |
|   Channels.IncBeingEdited();
 | |
| }
 | |
| 
 | |
| cIptvMenuChannels::~cIptvMenuChannels()
 | |
| {
 | |
|   Channels.DecBeingEdited();
 | |
| }
 | |
| 
 | |
| void cIptvMenuChannels::Setup(void)
 | |
| {
 | |
|   Clear();
 | |
|   for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) {
 | |
|       if (!channel->GroupSep() && channel->IsPlug() && !strncmp(channel->PluginParam(), "IPTV", 4)) {
 | |
|          cIptvMenuChannelItem *item = new cIptvMenuChannelItem(channel);
 | |
|          Add(item);
 | |
|          }
 | |
|       }
 | |
|   SetHelp(trVDR("Button$Edit"), trVDR("Button$New"), trVDR("Button$Delete"), NULL);
 | |
|   Display();
 | |
| }
 | |
| 
 | |
| cChannel *cIptvMenuChannels::GetChannel(int Index)
 | |
| {
 | |
|   cIptvMenuChannelItem *p = (cIptvMenuChannelItem *)Get(Index);
 | |
|   return p ? (cChannel *)p->Channel() : NULL;
 | |
| }
 | |
| 
 | |
| void cIptvMenuChannels::Propagate(void)
 | |
| {
 | |
|   Channels.ReNumber();
 | |
|   for (cIptvMenuChannelItem *ci = (cIptvMenuChannelItem *)First(); ci; ci = (cIptvMenuChannelItem *)ci->Next())
 | |
|       ci->Set();
 | |
|   Display();
 | |
|   Channels.SetModified(true);
 | |
| }
 | |
| 
 | |
| eOSState cIptvMenuChannels::Edit(void)
 | |
| {
 | |
|   if (HasSubMenu() || Count() == 0)
 | |
|      return osContinue;
 | |
|   cChannel *ch = GetChannel(Current());
 | |
|   if (ch)
 | |
|      return AddSubMenu(new cIptvMenuEditChannel(ch));
 | |
|   return osContinue;
 | |
| }
 | |
| 
 | |
| eOSState cIptvMenuChannels::New(void)
 | |
| {
 | |
|   if (HasSubMenu())
 | |
|      return osContinue;
 | |
|   return AddSubMenu(new cIptvMenuEditChannel(GetChannel(Current()), true));
 | |
| }
 | |
| 
 | |
| eOSState cIptvMenuChannels::Delete(void)
 | |
| {
 | |
|   if (!HasSubMenu() && Count() > 0) {
 | |
|      int CurrentChannelNr = cDevice::CurrentChannel();
 | |
|      cChannel *CurrentChannel = Channels.GetByNumber(CurrentChannelNr);
 | |
|      int Index = Current();
 | |
|      cChannel *channel = GetChannel(Current());
 | |
|      int DeletedChannel = channel->Number();
 | |
|      // Check if there is a timer using this channel:
 | |
|      if (channel->HasTimer()) {
 | |
|         Skins.Message(mtError, trVDR("Channel is being used by a timer!"));
 | |
|         return osContinue;
 | |
|         }
 | |
|      if (Interface->Confirm(trVDR("Delete channel?"))) {
 | |
|         if (CurrentChannel && channel == CurrentChannel) {
 | |
|            int n = Channels.GetNextNormal(CurrentChannel->Index());
 | |
|            if (n < 0)
 | |
|               n = Channels.GetPrevNormal(CurrentChannel->Index());
 | |
|            CurrentChannel = Channels.Get(n);
 | |
|            CurrentChannelNr = 0; // triggers channel switch below
 | |
|            }
 | |
|         Channels.Del(channel);
 | |
|         cOsdMenu::Del(Index);
 | |
|         Propagate();
 | |
|         isyslog("channel %d deleted", DeletedChannel);
 | |
|         if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) {
 | |
|            if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring())
 | |
|               Channels.SwitchTo(CurrentChannel->Number());
 | |
|            else
 | |
|               cDevice::SetCurrentChannel(CurrentChannel);
 | |
|            }
 | |
|         }
 | |
|      }
 | |
|   return osContinue;
 | |
| }
 | |
| 
 | |
| eOSState cIptvMenuChannels::ProcessKey(eKeys Key)
 | |
| {
 | |
|   eOSState state = cOsdMenu::ProcessKey(Key);
 | |
| 
 | |
|   switch (state) {
 | |
|     case osUser1: {
 | |
|          cChannel *channel = Channels.Last();
 | |
|          if (channel) {
 | |
|             Add(new cIptvMenuChannelItem(channel), true);
 | |
|             return CloseSubMenu();
 | |
|             }
 | |
|          }
 | |
|          break;
 | |
|     default:
 | |
|          if (state == osUnknown) {
 | |
|             switch (Key) {
 | |
|               case kOk:
 | |
|               case kRed:    return Edit();
 | |
|               case kGreen:  return New();
 | |
|               case kYellow: return Delete();
 | |
|               default: break;
 | |
|               }
 | |
|             }
 | |
|     }
 | |
|   return state;
 | |
| }
 | |
| 
 | |
| // --- cIptvPluginSetup ------------------------------------------------------
 | |
| 
 | |
| cIptvPluginSetup::cIptvPluginSetup()
 | |
| {
 | |
|   tsBufferSize = IptvConfig.GetTsBufferSize();
 | |
|   tsBufferPrefill = IptvConfig.GetTsBufferPrefillRatio();
 | |
|   fileIdleTimeMs = IptvConfig.GetFileIdleTimeMs();
 | |
|   Setup();
 | |
|   SetHelp(trVDR("Channels"), NULL, NULL, NULL);
 | |
| }
 | |
| 
 | |
| void cIptvPluginSetup::Setup(void)
 | |
| {
 | |
|   int current = Current();
 | |
|   Clear();
 | |
|   Add(new cMenuEditIntItem(tr("TS buffer size [MB]"),          &tsBufferSize,     2, 16));
 | |
|   Add(new cMenuEditIntItem(tr("TS buffer prefill ratio [%]"),  &tsBufferPrefill,  0, 40));
 | |
|   Add(new cMenuEditIntItem(tr("FILE protocol idle time [ms]"), &fileIdleTimeMs,   1, 100));
 | |
|   SetCurrent(Get(current));
 | |
|   Display();
 | |
| }
 | |
| 
 | |
| eOSState cIptvPluginSetup::EditChannel(void)
 | |
| {
 | |
|   if (HasSubMenu())
 | |
|      return osContinue;
 | |
|   return AddSubMenu(new cIptvMenuChannels());
 | |
| }
 | |
| 
 | |
| eOSState cIptvPluginSetup::ProcessKey(eKeys Key)
 | |
| {
 | |
|   eOSState state = cMenuSetupPage::ProcessKey(Key);
 | |
|   if (state == osUnknown) {
 | |
|      switch (Key) {
 | |
|        case kRed: return EditChannel();
 | |
|        default:   break;
 | |
|        }
 | |
|      }
 | |
|   return state;
 | |
| }
 | |
| 
 | |
| void cIptvPluginSetup::Store(void)
 | |
| {
 | |
|   // Store values into setup.conf
 | |
|   SetupStore("TsBufferSize", tsBufferSize);
 | |
|   SetupStore("TsBufferPrefill", tsBufferPrefill);
 | |
|   SetupStore("FileIdleTimeMs", fileIdleTimeMs);
 | |
|   // Update global config
 | |
|   IptvConfig.SetTsBufferSize(tsBufferSize);
 | |
|   IptvConfig.SetTsBufferPrefillRatio(tsBufferPrefill);
 | |
|   IptvConfig.SetFileIdleTimeMs(fileIdleTimeMs);
 | |
| }
 | |
| 
 |