diff --git a/CONTRIBUTORS b/CONTRIBUTORS index f057935..81adff9 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -245,3 +245,9 @@ Toerless Eckert Tomasz Maciej Nowak for providing Polish language texts + +Christopher Reimer + for providing an initial compatibility patch for VDR 2.3.1 + +Matthias Senzel + for refining the compatibility patch for VDR 2.3.1 diff --git a/HISTORY b/HISTORY index 3f394b8..15c89d2 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,8 @@ VDR Plugin 'streamdev' Revision History --------------------------------------- +- server compatibility with VDR 2.3.1 (thanks to Christopher Reimer and + Matthias Senzel) - client compatibility with VDR 2.3.1 - use cReceiver::SetPriority(...) in VDR 2.1.4+ - doubled size of client's filter buffer (suggested by Toerless Eckert) diff --git a/server/componentIGMP.c b/server/componentIGMP.c index 7398c67..52d2b5d 100644 --- a/server/componentIGMP.c +++ b/server/componentIGMP.c @@ -105,7 +105,11 @@ cComponentIGMP::~cComponentIGMP(void) { } +#if APIVERSNUM >= 20300 +cMulticastGroup* cComponentIGMP::FindGroup(in_addr_t Group) +#else cMulticastGroup* cComponentIGMP::FindGroup(in_addr_t Group) const +#endif { cMulticastGroup *group = m_Groups.First(); while (group && group->group != Group) @@ -117,7 +121,12 @@ bool cComponentIGMP::Initialize(void) { if (cServerComponent::Initialize() && IGMPMembership(IGMP_ALL_ROUTER)) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + for (const cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel)) +#else for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) +#endif { if (channel->GroupSep()) continue; @@ -146,7 +155,12 @@ void cComponentIGMP::Destruct(void) Cancel(-1); m_CondWait.Signal(); Cancel(2); +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + for (const cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel)) +#else for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) +#endif { if (channel->GroupSep()) continue; @@ -432,9 +446,18 @@ cServerConnection* cComponentIGMP::IGMPStartMulticast(cMulticastGroup* Group) in_addr_t g = ntohl(Group->group); if (g > MULTICAST_PRIV_MIN && g <= MULTICAST_PRIV_MAX) { cThreadLock lock; +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + const cChannel *channel = Channels->GetByNumber(g - MULTICAST_PRIV_MIN); +#else cChannel *channel = Channels.GetByNumber(g - MULTICAST_PRIV_MIN); +#endif const cList& clients = cStreamdevServer::Clients(lock); +#if APIVERSNUM >= 20300 + const cServerConnection *s = clients.First(); +#else cServerConnection *s = clients.First(); +#endif while (s) { if (s->RemoteIpAddr() == Group->group) break; @@ -453,7 +476,11 @@ cServerConnection* cComponentIGMP::IGMPStartMulticast(cMulticastGroup* Group) void cComponentIGMP::IGMPStopMulticast(cMulticastGroup* Group) { cThreadLock lock; +#if APIVERSNUM >= 20300 + cList& clients = cStreamdevServer::Clients(lock); +#else const cList& clients = cStreamdevServer::Clients(lock); +#endif for (cServerConnection *s = clients.First(); s; s = clients.Next(s)) { if (s->RemoteIpAddr() == Group->group) s->Close(); diff --git a/server/componentIGMP.h b/server/componentIGMP.h index 8f6c027..d870b64 100644 --- a/server/componentIGMP.h +++ b/server/componentIGMP.h @@ -9,6 +9,7 @@ #include #include #include "server/component.h" +#include "../common.h" class cMulticastGroup; @@ -23,7 +24,11 @@ private: bool m_Querier; cCondWait m_CondWait; +#if APIVERSNUM >= 20300 + cMulticastGroup* FindGroup(in_addr_t Group); +#else cMulticastGroup* FindGroup(in_addr_t Group) const; +#endif /* Add or remove local host to multicast group */ bool IGMPMembership(in_addr_t Group, bool Add = true); diff --git a/server/connection.c b/server/connection.c index 56be407..0db382e 100644 --- a/server/connection.c +++ b/server/connection.c @@ -46,14 +46,29 @@ const cChannel* cServerConnection::ChannelFromString(const char *String, int *Ap int temp = strtol(String, NULL, 10); if (temp == 0) temp = cDevice::CurrentChannel(); +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + if (temp >= 1 && temp <= Channels->MaxNumber()) + channel = Channels->GetByNumber(temp); +#else if (temp >= 1 && temp <= Channels.MaxNumber()) channel = Channels.GetByNumber(temp); +#endif } else { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + channel = Channels->GetByChannelID(tChannelID::FromString(string)); +#else channel = Channels.GetByChannelID(tChannelID::FromString(string)); +#endif if (channel == NULL) { int i = 1; +#if APIVERSNUM >= 20300 + while ((channel = Channels->GetByNumber(i, 1)) != NULL) { +#else while ((channel = Channels.GetByNumber(i, 1)) != NULL) { +#endif if (String == channel->Name()) break; diff --git a/server/connectionHTTP.c b/server/connectionHTTP.c index 922bd04..b139c9b 100644 --- a/server/connectionHTTP.c +++ b/server/connectionHTTP.c @@ -523,8 +523,13 @@ RecPlayer* cConnectionHTTP::RecPlayerFromString(const char *FileBase, const char ino_t inode = (ino_t) strtoull(p + 1, &p, 0); if (*p == 0 && inode > 0) { struct stat st; +#if APIVERSNUM >= 20300 + LOCK_RECORDINGS_READ; + for (const cRecording *rec = Recordings->First(); rec; rec = Recordings->Next(rec)) { +#else cThreadLock RecordingsLock(&Recordings); for (cRecording *rec = Recordings.First(); rec; rec = Recordings.Next(rec)) { +#endif if (stat(rec->FileName(), &st) == 0 && st.st_dev == (dev_t) l && st.st_ino == inode) recPlayer = new RecPlayer(rec->FileName()); } @@ -532,8 +537,13 @@ RecPlayer* cConnectionHTTP::RecPlayerFromString(const char *FileBase, const char } else if (*p == 0) { // get recording by index +#if APIVERSNUM >= 20300 + LOCK_RECORDINGS_READ; + const cRecording *rec = Recordings->Get((int) l - 1); +#else cThreadLock RecordingsLock(&Recordings); cRecording *rec = Recordings.Get((int) l - 1); +#endif if (rec) recPlayer = new RecPlayer(rec->FileName()); } diff --git a/server/connectionIGMP.c b/server/connectionIGMP.c index f2a34fc..53d2af4 100644 --- a/server/connectionIGMP.c +++ b/server/connectionIGMP.c @@ -21,7 +21,11 @@ cConnectionIGMP::~cConnectionIGMP() { } +#if APIVERSNUM >= 20300 +bool cConnectionIGMP::SetChannel(const cChannel *Channel, in_addr_t Dst) +#else bool cConnectionIGMP::SetChannel(cChannel *Channel, in_addr_t Dst) +#endif { if (Channel) { m_Channel = Channel; diff --git a/server/connectionIGMP.h b/server/connectionIGMP.h index 89292b2..ef9ea40 100644 --- a/server/connectionIGMP.h +++ b/server/connectionIGMP.h @@ -19,13 +19,21 @@ class cConnectionIGMP: public cServerConnection { private: int m_ClientPort; eStreamType m_StreamType; +#if APIVERSNUM >= 20300 + const cChannel *m_Channel; +#else cChannel *m_Channel; +#endif public: cConnectionIGMP(const char* Name, int ClientPort, eStreamType StreamType); virtual ~cConnectionIGMP(); +#if APIVERSNUM >= 20300 + bool SetChannel(const cChannel *Channel, in_addr_t Dst); +#else bool SetChannel(cChannel *Channel, in_addr_t Dst); +#endif virtual void Welcome(void); virtual cString ToText(char Delimiter = ' ') const; diff --git a/server/connectionVTP.c b/server/connectionVTP.c index 05c49ee..1b8dd96 100644 --- a/server/connectionVTP.c +++ b/server/connectionVTP.c @@ -58,8 +58,10 @@ public: cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option): m_Client(Client), +#if APIVERSNUM < 20300 m_SchedulesLock(new cSchedulesLock(false, 500)), m_Schedules(cSchedules::Schedules(*m_SchedulesLock)), +#endif m_Schedule(NULL), m_Event(NULL), m_Errno(0), @@ -131,11 +133,20 @@ cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option): break; } } else if (!m_Schedule) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + const cChannel* Channel = NULL; + if (isnumber(p)) + Channel = Channels->GetByNumber(strtol(Option, NULL, 10)); + else + Channel = Channels->GetByChannelID(tChannelID::FromString( +#else cChannel* Channel = NULL; if (isnumber(p)) Channel = Channels.GetByNumber(strtol(Option, NULL, 10)); else Channel = Channels.GetByChannelID(tChannelID::FromString( +#endif Option)); if (Channel) { m_Schedule = m_Schedules->GetSchedule(Channel->GetChannelID()); @@ -215,7 +226,12 @@ bool cLSTEHandler::Next(bool &Last) switch (m_State) { case Channel: if (m_Schedule != NULL) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + const cChannel *channel = Channels->GetByChannelID(m_Schedule->ChannelID(), +#else cChannel *channel = Channels.GetByChannelID(m_Schedule->ChannelID(), +#endif true); if (channel != NULL) { m_State = Event; @@ -371,12 +387,21 @@ cLSTCHandler::cLSTCHandler(cConnectionVTP *Client, const char *Option): m_Errno(0), m_Traverse(false) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + if (!Channels) { +#else if (!Channels.Lock(false, 500)) { +#endif m_Errno = 451; m_Error = "Channels are being modified - try again"; } else if (*Option) { if (isnumber(Option)) { +#if APIVERSNUM >= 20300 + m_Channel = Channels->GetByNumber(strtol(Option, NULL, 10)); +#else m_Channel = Channels.GetByNumber(strtol(Option, NULL, 10)); +#endif if (m_Channel == NULL) { m_Errno = 501; m_Error = cString::sprintf("Channel \"%s\" not defined", Option); @@ -386,21 +411,35 @@ cLSTCHandler::cLSTCHandler(cConnectionVTP *Client, const char *Option): int i = 1; m_Traverse = true; m_Option = strdup(Option); +#if APIVERSNUM >= 20300 + while (i <= Channels->MaxNumber()) { + m_Channel = Channels->GetByNumber(i, 1); +#else while (i <= Channels.MaxNumber()) { m_Channel = Channels.GetByNumber(i, 1); +#endif if (strcasestr(m_Channel->Name(), Option) != NULL) break; i = m_Channel->Number() + 1; } +#if APIVERSNUM >= 20300 + if (i > Channels->MaxNumber()) { +#else if (i > Channels.MaxNumber()) { +#endif m_Errno = 501; m_Error = cString::sprintf("Channel \"%s\" not defined", Option); return; } } +#if APIVERSNUM >= 20300 + } else if (Channels->MaxNumber() >= 1) { + m_Channel = Channels->GetByNumber(1, 1); +#else } else if (Channels.MaxNumber() >= 1) { m_Channel = Channels.GetByNumber(1, 1); +#endif m_Traverse = true; } else { m_Errno = 550; @@ -410,7 +449,9 @@ cLSTCHandler::cLSTCHandler(cConnectionVTP *Client, const char *Option): cLSTCHandler::~cLSTCHandler() { +#if APIVERSNUM < 20300 Channels.Unlock(); +#endif if (m_Option != NULL) free(m_Option); } @@ -435,8 +476,14 @@ bool cLSTCHandler::Next(bool &Last) Last = true; if (m_Traverse) { int i = m_Channel->Number() + 1; +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + while (i <= Channels->MaxNumber()) { + m_Channel = Channels->GetByNumber(i, 1); +#else while (i <= Channels.MaxNumber()) { m_Channel = Channels.GetByNumber(i, 1); +#endif if (m_Channel != NULL) { if (m_Option == NULL || strcasestr(m_Channel->Name(), m_Option) != NULL) @@ -448,7 +495,11 @@ bool cLSTCHandler::Next(bool &Last) } } +#if APIVERSNUM >= 20300 + if (i < Channels->MaxNumber() + 1) +#else if (i < Channels.MaxNumber() + 1) +#endif Last = false; } @@ -461,7 +512,11 @@ class cLSTTHandler { private: cConnectionVTP *m_Client; +#if APIVERSNUM >= 20300 + const cTimer *m_Timer; +#else cTimer *m_Timer; +#endif int m_Index; int m_Errno; cString m_Error; @@ -479,9 +534,16 @@ cLSTTHandler::cLSTTHandler(cConnectionVTP *Client, const char *Option): m_Errno(0), m_Traverse(false) { +#if APIVERSNUM >= 20300 + LOCK_TIMERS_READ; +#endif if (*Option) { if (isnumber(Option)) { +#if APIVERSNUM >= 20300 + m_Timer = Timers->Get(strtol(Option, NULL, 10) - 1); +#else m_Timer = Timers.Get(strtol(Option, NULL, 10) - 1); +#endif if (m_Timer == NULL) { m_Errno = 501; m_Error = cString::sprintf("Timer \"%s\" not defined", Option); @@ -490,10 +552,18 @@ cLSTTHandler::cLSTTHandler(cConnectionVTP *Client, const char *Option): m_Errno = 501; m_Error = cString::sprintf("Error in timer number \"%s\"", Option); } +#if APIVERSNUM >= 20300 + } else if (Timers->Count()) { +#else } else if (Timers.Count()) { +#endif m_Traverse = true; m_Index = 0; +#if APIVERSNUM >= 20300 + m_Timer = Timers->Get(m_Index); +#else m_Timer = Timers.Get(m_Index); +#endif if (m_Timer == NULL) { m_Errno = 501; m_Error = cString::sprintf("Timer \"%d\" not found", m_Index + 1); @@ -519,7 +589,12 @@ bool cLSTTHandler::Next(bool &Last) bool result; char *buffer; +#if APIVERSNUM >= 20300 + LOCK_TIMERS_READ; + Last = !m_Traverse || m_Index >= Timers->Count() - 1; +#else Last = !m_Traverse || m_Index >= Timers.Count() - 1; +#endif buffer = strdup(*m_Timer->ToText()); buffer[strlen(buffer) - 1] = '\0'; // strip \n result = m_Client->Respond(Last ? 250 : -250, "%d %s", m_Timer->Index() + 1, @@ -527,7 +602,11 @@ bool cLSTTHandler::Next(bool &Last) free(buffer); if (m_Traverse && !Last) { +#if APIVERSNUM >= 20300 + m_Timer = Timers->Get(++m_Index); +#else m_Timer = Timers.Get(++m_Index); +#endif if (m_Timer == NULL) { m_Errno = 501; m_Error = cString::sprintf("Timer \"%d\" not found", m_Index + 1); @@ -544,7 +623,11 @@ private: enum eStates { Recording, Event, Title, Subtitle, Description, Components, Vps, EndRecording }; cConnectionVTP *m_Client; +#if APIVERSNUM >= 20300 + const cRecording *m_Recording; +#else cRecording *m_Recording; +#endif const cEvent *m_Event; int m_Index; int m_Errno; @@ -570,9 +653,16 @@ cLSTRHandler::cLSTRHandler(cConnectionVTP *Client, const char *Option): m_State(Recording), m_CurrentComponent(0) { +#if APIVERSNUM >= 20300 + LOCK_RECORDINGS_READ; +#endif if (*Option) { if (isnumber(Option)) { +#if APIVERSNUM >= 20300 + m_Recording = Recordings->Get(strtol(Option, NULL, 10) - 1); +#else m_Recording = Recordings.Get(strtol(Option, NULL, 10) - 1); +#endif m_Event = m_Recording->Info()->GetEvent(); m_Info = true; if (m_Recording == NULL) { @@ -585,10 +675,18 @@ cLSTRHandler::cLSTRHandler(cConnectionVTP *Client, const char *Option): m_Error = cString::sprintf("Error in Recording number \"%s\"", Option); } } +#if APIVERSNUM >= 20300 + else if (Recordings->Count()) { +#else else if (Recordings.Count()) { +#endif m_Traverse = true; m_Index = 0; +#if APIVERSNUM >= 20300 + m_Recording = Recordings->Get(m_Index); +#else m_Recording = Recordings.Get(m_Index); +#endif if (m_Recording == NULL) { m_Errno = 501; m_Error = cString::sprintf("Recording \"%d\" not found", m_Index + 1); @@ -691,11 +789,20 @@ bool cLSTRHandler::Next(bool &Last) } else { bool result; +#if APIVERSNUM >= 20300 + LOCK_RECORDINGS_READ; + Last = !m_Traverse || m_Index >= Recordings->Count() - 1; +#else Last = !m_Traverse || m_Index >= Recordings.Count() - 1; +#endif result = m_Client->Respond(Last ? 250 : -250, "%d %s", m_Recording->Index() + 1, m_Recording->Title(' ', true)); if (m_Traverse && !Last) { +#if APIVERSNUM >= 20300 + m_Recording = Recordings->Get(++m_Index); +#else m_Recording = Recordings.Get(++m_Index); +#endif if (m_Recording == NULL) { m_Errno = 501; m_Error = cString::sprintf("Recording \"%d\" not found", m_Index + 1); @@ -1145,7 +1252,12 @@ bool cConnectionVTP::CmdPLAY(char *Opts) { if (*Opts) { if (isnumber(Opts)) { +#if APIVERSNUM >= 20300 + LOCK_RECORDINGS_READ; + const cRecording *recording = Recordings->Get(strtol(Opts, NULL, 10) - 1); +#else cRecording *recording = Recordings.Get(strtol(Opts, NULL, 10) - 1); +#endif if (recording) { if (m_RecPlayer) { delete m_RecPlayer; @@ -1391,10 +1503,17 @@ bool cConnectionVTP::CmdSTAT(const char *Option) Reply(250, "VDR: %s | Streamdev: %s", VDRVERSION, VERSION); } else if (strcasecmp(Option, "RECORDS") == 0) { +#if APIVERSNUM >= 20300 + LOCK_RECORDINGS_WRITE; + Recordings->Sort(); + if (Recordings) { + cRecording *recording = Recordings->Last(); +#else bool recordings = Recordings.Load(); Recordings.Sort(); if (recordings) { cRecording *recording = Recordings.Last(); +#endif Reply(250, "%d", recording->Index() + 1); } else { @@ -1402,10 +1521,20 @@ bool cConnectionVTP::CmdSTAT(const char *Option) } } else if (strcasecmp(Option, "CHANNELS") == 0) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + Reply(250, "%d", Channels->MaxNumber()); +#else Reply(250, "%d", Channels.MaxNumber()); +#endif } else if (strcasecmp(Option, "TIMERS") == 0) { +#if APIVERSNUM >= 20300 + LOCK_TIMERS_READ; + Reply(250, "%d", Timers->Count()); +#else Reply(250, "%d", Timers.Count()); +#endif } else if (strcasecmp(Option, "CHARSET") == 0) { Reply(250, "%s", cCharSetConv::SystemCharacterTable()); @@ -1433,7 +1562,12 @@ bool cConnectionVTP::CmdMODT(const char *Option) int n = strtol(Option, &tail, 10); if (tail && tail != Option) { tail = skipspace(tail); +#if APIVERSNUM >= 20300 + LOCK_TIMERS_WRITE; + cTimer *timer = Timers->Get(n - 1); +#else cTimer *timer = Timers.Get(n - 1); +#endif if (timer) { cTimer t = *timer; if (strcasecmp(tail, "ON") == 0) @@ -1445,7 +1579,11 @@ bool cConnectionVTP::CmdMODT(const char *Option) EXIT_WRAPPER(); } *timer = t; +#if APIVERSNUM >= 20300 + Timers->SetModified(); +#else Timers.SetModified(); +#endif isyslog("timer %s modified (%s)", *timer->ToDescr(), timer->HasFlags(tfActive) ? "active" : "inactive"); Reply(250, "%d %s", timer->Index() + 1, *timer->ToText()); @@ -1464,10 +1602,18 @@ bool cConnectionVTP::CmdNEWT(const char *Option) if (*Option) { cTimer *timer = new cTimer; if (timer->Parse(Option)) { +#if APIVERSNUM >= 20300 + LOCK_TIMERS_WRITE; + cTimer *t = Timers->GetTimer(timer); + if (!t) { + Timers->Add(timer); + Timers->SetModified(); +#else cTimer *t = Timers.GetTimer(timer); if (!t) { Timers.Add(timer); Timers.SetModified(); +#endif isyslog("timer %s added", *timer->ToDescr()); Reply(250, "%d %s", timer->Index() + 1, *timer->ToText()); EXIT_WRAPPER(); @@ -1512,21 +1658,39 @@ bool cConnectionVTP::CmdDELT(const char *Option) } } +#if APIVERSNUM >= 20300 + LOCK_TIMERS_WRITE; + cTimer *Timer = Timers->Get(number); + if (Timer) { + if (Timer->Recording()) { + if (force) { + if (!Timer->Remote()) { + Timer->Skip(); + cRecordControls::Process(Timers, time(NULL)); + } +#else cTimer *timer = Timers.Get(number); if (timer) { if (timer->Recording()) { if (force) { timer->Skip(); cRecordControls::Process(time(NULL)); +#endif } else { Reply(550, "Timer \"%i\" is recording", number); EXIT_WRAPPER(); } } +#if APIVERSNUM >= 20300 + isyslog("deleting timer %s", *Timer->ToDescr()); + Timers->Del(Timer); + Timers->SetModified(); +#else isyslog("deleting timer %s", *timer->ToDescr()); Timers.Del(timer); Timers.SetModified(); +#endif Reply(250, "Timer \"%i\" deleted", number); } else Reply(501, "Timer \"%i\" not defined", number); @@ -1538,7 +1702,12 @@ bool cConnectionVTP::CmdDELT(const char *Option) bool cConnectionVTP::CmdNEXT(const char *Option) { INIT_WRAPPER(); +#if APIVERSNUM >= 20300 + LOCK_TIMERS_READ; + const cTimer *t = Timers->GetNextActiveTimer(); +#else cTimer *t = Timers.GetNextActiveTimer(); +#endif if (t) { time_t Start = t->StartTime(); int Number = t->Index() + 1; @@ -1562,12 +1731,23 @@ bool cConnectionVTP::CmdNEWC(const char *Option) if (*Option) { cChannel ch; if (ch.Parse(Option)) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_WRITE; + if (Channels->HasUniqueChannelID(&ch)) { +#else if (Channels.HasUniqueChannelID(&ch)) { +#endif cChannel *channel = new cChannel; *channel = ch; +#if APIVERSNUM >= 20300 + Channels->Add(channel); + Channels->ReNumber(); + Channels->SetModified(); +#else Channels.Add(channel); Channels.ReNumber(); Channels.SetModified(true); +#endif isyslog("new channel %d %s", channel->Number(), *channel->ToText()); Reply(250, "%d %s", channel->Number(), *channel->ToText()); } @@ -1593,15 +1773,28 @@ bool cConnectionVTP::CmdMODC(const char *Option) int n = strtol(Option, &tail, 10); if (tail && tail != Option) { tail = skipspace(tail); +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_WRITE; + Channels->SetExplicitModify(); + cChannel *channel = Channels->GetByNumber(n); +#else if (!Channels.BeingEdited()) { cChannel *channel = Channels.GetByNumber(n); +#endif if (channel) { cChannel ch; if (ch.Parse(tail)) { +#if APIVERSNUM >= 20300 + if (Channels->HasUniqueChannelID(&ch, channel)) { + *channel = ch; + Channels->ReNumber(); + Channels->SetModified(); +#else if (Channels.HasUniqueChannelID(&ch, channel)) { *channel = ch; Channels.ReNumber(); Channels.SetModified(true); +#endif isyslog("modifed channel %d %s", channel->Number(), *channel->ToText()); Reply(250, "%d %s", channel->Number(), *channel->ToText()); } @@ -1616,10 +1809,12 @@ bool cConnectionVTP::CmdMODC(const char *Option) else { Reply(501, "Channel \"%d\" not defined", n); } +#if APIVERSNUM < 20300 } else { Reply(550, "Channels are being edited - try again later"); } +#endif } else { Reply(501, "Error in channel number"); @@ -1635,7 +1830,14 @@ bool cConnectionVTP::CmdMOVC(const char *Option) { INIT_WRAPPER(); if (*Option) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_WRITE; + Channels->SetExplicitModify(); +// LOCK_TIMERS_WRITE; +// Timers->SetExplicitModify(); +#else if (!Channels.BeingEdited() && !Timers.BeingEdited()) { +#endif char *tail; int From = strtol(Option, &tail, 10); if (tail && tail != Option) { @@ -1643,20 +1845,37 @@ bool cConnectionVTP::CmdMOVC(const char *Option) if (tail && tail != Option) { int To = strtol(tail, NULL, 10); int CurrentChannelNr = cDevice::CurrentChannel(); +#if APIVERSNUM >= 20300 + cChannel *CurrentChannel = Channels->GetByNumber(CurrentChannelNr); + cChannel *FromChannel = Channels->GetByNumber(From); + if (FromChannel) { + cChannel *ToChannel = Channels->GetByNumber(To); +#else cChannel *CurrentChannel = Channels.GetByNumber(CurrentChannelNr); cChannel *FromChannel = Channels.GetByNumber(From); if (FromChannel) { cChannel *ToChannel = Channels.GetByNumber(To); +#endif if (ToChannel) { int FromNumber = FromChannel->Number(); int ToNumber = ToChannel->Number(); if (FromNumber != ToNumber) { +#if APIVERSNUM >= 20300 + Channels->Move(FromChannel, ToChannel); + Channels->ReNumber(); + Channels->SetModified(); +#else Channels.Move(FromChannel, ToChannel); Channels.ReNumber(); Channels.SetModified(true); +#endif if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) { +#if APIVERSNUM >= 20300 + Channels->SwitchTo(CurrentChannel->Number()); +#else Channels.SwitchTo(CurrentChannel->Number()); +#endif } else { cDevice::SetCurrentChannel(CurrentChannel); @@ -1684,10 +1903,12 @@ bool cConnectionVTP::CmdMOVC(const char *Option) else { Reply(501, "Error in channel number"); } +#if APIVERSNUM < 20300 } else { Reply(550, "Channels or timers are being edited - try again later"); } +#endif } else { Reply(501, "Missing channel number"); @@ -1700,31 +1921,63 @@ bool cConnectionVTP::CmdDELC(const char *Option) INIT_WRAPPER(); if (*Option) { if (isnumber(Option)) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_WRITE; + Channels->SetExplicitModify(); + cChannel *channel = Channels->GetByNumber(strtol(Option, NULL, 10)); +#else if (!Channels.BeingEdited()) { cChannel *channel = Channels.GetByNumber(strtol(Option, NULL, 10)); +#endif if (channel) { +#if APIVERSNUM >= 20300 + LOCK_TIMERS_READ; + for (const cTimer *timer = Timers->First(); timer; timer = Timers->Next(timer)) { +#else for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) { +#endif if (timer->Channel() == channel) { Reply(550, "Channel \"%s\" is in use by timer %d", Option, timer->Index() + 1); return false; } } int CurrentChannelNr = cDevice::CurrentChannel(); +#if APIVERSNUM >= 20300 + cChannel *CurrentChannel = Channels->GetByNumber(CurrentChannelNr); +#else cChannel *CurrentChannel = Channels.GetByNumber(CurrentChannelNr); +#endif if (CurrentChannel && channel == CurrentChannel) { +#if APIVERSNUM >= 20300 + int n = Channels->GetNextNormal(CurrentChannel->Index()); + if (n < 0) + n = Channels->GetPrevNormal(CurrentChannel->Index()); + CurrentChannel = Channels->Get(n); +#else int n = Channels.GetNextNormal(CurrentChannel->Index()); if (n < 0) n = Channels.GetPrevNormal(CurrentChannel->Index()); CurrentChannel = Channels.Get(n); +#endif CurrentChannelNr = 0; // triggers channel switch below } +#if APIVERSNUM >= 20300 + Channels->Del(channel); + Channels->ReNumber(); + Channels->SetModified(); +#else Channels.Del(channel); Channels.ReNumber(); Channels.SetModified(true); +#endif isyslog("channel %s deleted", Option); if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) { if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) +#if APIVERSNUM >= 20300 + Channels->SwitchTo(CurrentChannel->Number()); +#else Channels.SwitchTo(CurrentChannel->Number()); +#endif else cDevice::SetCurrentChannel(CurrentChannel); } @@ -1733,9 +1986,11 @@ bool cConnectionVTP::CmdDELC(const char *Option) else Reply(501, "Channel \"%s\" not defined", Option); } +#if APIVERSNUM < 20300 else Reply(550, "Channels are being edited - try again later"); } +#endif else Reply(501, "Error in channel number \"%s\"", Option); } @@ -1750,13 +2005,22 @@ bool cConnectionVTP::CmdDELR(const char *Option) INIT_WRAPPER(); if (*Option) { if (isnumber(Option)) { +#if APIVERSNUM >= 20300 + LOCK_RECORDINGS_WRITE; + cRecording *recording = Recordings->Get(strtol(Option, NULL, 10) - 1); +#else cRecording *recording = Recordings.Get(strtol(Option, NULL, 10) - 1); +#endif if (recording) { cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName()); if (!rc) { if (recording->Delete()) { Reply(250, "Recording \"%s\" deleted", Option); +#if APIVERSNUM >= 20300 + Recordings->DelByName(recording->FileName()); +#else ::Recordings.DelByName(recording->FileName()); +#endif } else Reply(554, "Error while deleting recording!"); @@ -1765,7 +2029,11 @@ bool cConnectionVTP::CmdDELR(const char *Option) Reply(550, "Recording \"%s\" is in use by timer %d", Option, rc->Timer()->Index() + 1); } else +#if APIVERSNUM >= 20300 + Reply(550, "Recording \"%s\" not found%s", Option, Recordings->Count() ? "" : " (use LSTR before deleting)"); +#else Reply(550, "Recording \"%s\" not found%s", Option, Recordings.Count() ? "" : " (use LSTR before deleting)"); +#endif } else Reply(501, "Error in recording number \"%s\"", Option); diff --git a/server/livestreamer.c b/server/livestreamer.c index 78cbaab..41f7d2d 100644 --- a/server/livestreamer.c +++ b/server/livestreamer.c @@ -31,7 +31,11 @@ private: cStreamdevLiveStreamer *m_Streamer; protected: +#if APIVERSNUM >= 20300 + virtual void Receive(const uchar *Data, int Length); +#else virtual void Receive(uchar *Data, int Length); +#endif public: cStreamdevLiveReceiver(cStreamdevLiveStreamer *Streamer, const cChannel *Channel, int Priority, const int *Pids); @@ -53,7 +57,11 @@ cStreamdevLiveReceiver::~cStreamdevLiveReceiver() Detach(); } +#if APIVERSNUM >= 20300 +void cStreamdevLiveReceiver::Receive(const uchar *Data, int Length) { +#else void cStreamdevLiveReceiver::Receive(uchar *Data, int Length) { +#endif m_Streamer->Receive(Data, Length); } @@ -250,7 +258,12 @@ void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, i SI::PAT::Association assoc; for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) { if (!assoc.isNITPid()) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + const cChannel *Channel = Channels->GetByServiceID(Source(), Transponder(), assoc.getServiceId()); +#else const cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId()); +#endif if (Channel && (Channel == m_Channel)) { int prevPmtPid = pmtPid; if (0 != (pmtPid = assoc.getPid())) { @@ -547,7 +560,11 @@ bool cStreamdevLiveStreamer::SetChannel(eStreamType StreamType, const int* Apid, } } +#if APIVERSNUM >= 20300 +void cStreamdevLiveStreamer::Receive(const uchar *Data, int Length) +#else void cStreamdevLiveStreamer::Receive(uchar *Data, int Length) +#endif { int p = m_ReceiveBuffer->PutTS(Data, Length); if (p != Length) @@ -688,9 +705,16 @@ void cStreamdevLiveStreamer::MainThreadHook() } if (m_SwitchLive) { // switched away live TV. Try previous channel on other device first +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + if (!Channels->SwitchTo(cDevice::CurrentChannel())) { + // switch to streamdev channel otherwise + Channels->SwitchTo(m_Channel->Number()); +#else if (!Channels.SwitchTo(cDevice::CurrentChannel())) { // switch to streamdev channel otherwise Channels.SwitchTo(m_Channel->Number()); +#endif Skins.Message(mtInfo, tr("Streaming active")); } if (m_Device) diff --git a/server/livestreamer.h b/server/livestreamer.h index b525c7b..a671bd1 100644 --- a/server/livestreamer.h +++ b/server/livestreamer.h @@ -64,7 +64,11 @@ public: void GetSignal(int *DevNum, int *Strength, int *Quality) const; virtual cString ToText() const; +#if APIVERSNUM >= 20300 + void Receive(const uchar *Data, int Length); +#else void Receive(uchar *Data, int Length); +#endif virtual bool IsReceiving(void) const; virtual void Attach(void); diff --git a/server/menu.c b/server/menu.c index d5f0c7e..18c6764 100644 --- a/server/menu.c +++ b/server/menu.c @@ -13,7 +13,11 @@ cStreamdevServerMenu::cStreamdevServerMenu(): cOsdMenu(tr("Streamdev Connections"), 4, 20) { cThreadLock lock; +#if APIVERSNUM >= 20300 + cList& clients = cStreamdevServer::Clients(lock); +#else const cList& clients = cStreamdevServer::Clients(lock); +#endif for (cServerConnection *s = clients.First(); s; s = clients.Next(s)) Add(new cOsdItem(s->ToText('\t'))); SetHelpKeys(); @@ -31,7 +35,11 @@ eOSState cStreamdevServerMenu::Disconnect() { cOsdItem *item = Get(Current()); if (item) { cThreadLock lock; +#if APIVERSNUM >= 20300 + cList& clients = cStreamdevServer::Clients(lock); +#else const cList& clients = cStreamdevServer::Clients(lock); +#endif const char *text = item->Text(); for (cServerConnection *s = clients.First(); s; s = clients.Next(s)) { if (!strcmp(text, s->ToText('\t'))) { diff --git a/server/menuHTTP.c b/server/menuHTTP.c index 05315ea..e075d4d 100644 --- a/server/menuHTTP.c +++ b/server/menuHTTP.c @@ -6,10 +6,19 @@ #include "server/menuHTTP.h" //**************************** cRecordingIterator ************** +#if APIVERSNUM >= 20300 +cRecordingsIterator::cRecordingsIterator(eStreamType StreamType) +#else cRecordingsIterator::cRecordingsIterator(eStreamType StreamType): RecordingsLock(&Recordings) +#endif { streamType = StreamType; +#if APIVERSNUM >= 20300 + LOCK_RECORDINGS_READ; + first = NextSuitable(Recordings->First()); +#else first = NextSuitable(Recordings.First()); +#endif current = NULL; } @@ -20,20 +29,32 @@ const cRecording* cRecordingsIterator::NextSuitable(const cRecording *Recording) bool isPes = Recording->IsPesRecording(); if (!isPes || (isPes && streamType == stPES)) break; +#if APIVERSNUM >= 20300 + LOCK_RECORDINGS_READ; + Recording = Recordings->Next(Recording); +#else Recording = Recordings.Next(Recording); +#endif } return Recording; } bool cRecordingsIterator::Next() { +#if APIVERSNUM >= 20300 + LOCK_RECORDINGS_READ; +#endif if (first) { current = first; first = NULL; } else +#if APIVERSNUM >= 20300 + current = NextSuitable(Recordings->Next(current)); +#else current = NextSuitable(Recordings.Next(current)); +#endif return current; } @@ -71,9 +92,16 @@ const cString cChannelIterator::ItemId() const if (current->GroupSep()) { int index = 0; +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + for (int curr = Channels->GetNextGroup(-1); curr >= 0; curr = Channels->GetNextGroup(curr)) + { + if (Channels->Get(curr) == current) +#else for (int curr = Channels.GetNextGroup(-1); curr >= 0; curr = Channels.GetNextGroup(curr)) { if (Channels.Get(curr) == current) +#endif return itoa(index); index++; } @@ -89,47 +117,111 @@ const cString cChannelIterator::ItemId() const const cChannel* cChannelIterator::GetGroup(const char* GroupId) { int group = -1; +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; +#endif if (GroupId) { int Index = atoi(GroupId); +#if APIVERSNUM >= 20300 + group = Channels->GetNextGroup(-1); + while (Index-- && group >= 0) + group = Channels->GetNextGroup(group); + } + return group >= 0 ? Channels->Get(group) : NULL; +#else group = Channels.GetNextGroup(-1); while (Index-- && group >= 0) group = Channels.GetNextGroup(group); } return group >= 0 ? Channels.Get(group) : NULL; +#endif } +const cChannel* cChannelIterator::FirstChannel() +{ +const cChannel *Channel; +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + Channel = Channels->First(); +#else + Channel = Channels.First(); +#endif + return Channel; +} + +const cChannel* cChannelIterator::NextNormal() +{ +const cChannel *Channel; +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + Channel = Channels->Get(Channels->GetNextNormal(-1)); +#else + Channel = Channels.Get(Channels.GetNextNormal(-1)); +#endif + return Channel; +} + +const cChannel* cChannelIterator::NextGroup() +{ +const cChannel *Channel; +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + Channel = Channels->Get(Channels->GetNextGroup(-1)); +#else + Channel = Channels.Get(Channels.GetNextGroup(-1)); +#endif + return Channel; +} //**************************** cListAll ************** -cListAll::cListAll(): cChannelIterator(Channels.First()) +cListAll::cListAll(): cChannelIterator(FirstChannel()) {} const cChannel* cListAll::NextChannel(const cChannel *Channel) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + if (Channel) + Channel = SkipFakeGroups(Channels->Next(Channel)); +#else if (Channel) Channel = SkipFakeGroups(Channels.Next(Channel)); +#endif return Channel; } //**************************** cListChannels ************** -cListChannels::cListChannels(): cChannelIterator(Channels.Get(Channels.GetNextNormal(-1))) +cListChannels::cListChannels(): cChannelIterator(NextNormal()) {} const cChannel* cListChannels::NextChannel(const cChannel *Channel) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + if (Channel) + Channel = Channels->Get(Channels->GetNextNormal(Channel->Index())); +#else if (Channel) Channel = Channels.Get(Channels.GetNextNormal(Channel->Index())); +#endif return Channel; } // ********************* cListGroups **************** -cListGroups::cListGroups(): cChannelIterator(Channels.Get(Channels.GetNextGroup(-1))) +cListGroups::cListGroups(): cChannelIterator(NextGroup()) {} const cChannel* cListGroups::NextChannel(const cChannel *Channel) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + if (Channel) + Channel = Channels->Get(Channels->GetNextGroup(Channel->Index())); +#else if (Channel) Channel = Channels.Get(Channels.GetNextGroup(Channel->Index())); +#endif return Channel; } // @@ -139,8 +231,14 @@ cListGroup::cListGroup(const char *GroupId): cChannelIterator(GetNextChannelInGr const cChannel* cListGroup::GetNextChannelInGroup(const cChannel *Channel) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + if (Channel) + Channel = SkipFakeGroups(Channels->Next(Channel)); +#else if (Channel) Channel = SkipFakeGroups(Channels.Next(Channel)); +#endif return Channel && !Channel->GroupSep() ? Channel : NULL; } @@ -150,25 +248,42 @@ const cChannel* cListGroup::NextChannel(const cChannel *Channel) } // // ********************* cListTree **************** -cListTree::cListTree(const char *SelectedGroupId): cChannelIterator(Channels.Get(Channels.GetNextGroup(-1))) +cListTree::cListTree(const char *SelectedGroupId): cChannelIterator(NextGroup()) { selectedGroup = GetGroup(SelectedGroupId); +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + currentGroup = Channels->Get(Channels->GetNextGroup(-1)); +#else currentGroup = Channels.Get(Channels.GetNextGroup(-1)); +#endif } const cChannel* cListTree::NextChannel(const cChannel *Channel) { if (currentGroup == selectedGroup) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + if (Channel) + Channel = SkipFakeGroups(Channels->Next(Channel)); +#else if (Channel) Channel = SkipFakeGroups(Channels.Next(Channel)); +#endif if (Channel && Channel->GroupSep()) currentGroup = Channel; } else { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; + if (Channel) + Channel = Channels->Get(Channels->GetNextGroup(Channel->Index())); +#else if (Channel) Channel = Channels.Get(Channels.GetNextGroup(Channel->Index())); +#endif currentGroup = Channel; } return Channel; diff --git a/server/menuHTTP.h b/server/menuHTTP.h index 91a00b1..5d4ca44 100644 --- a/server/menuHTTP.h +++ b/server/menuHTTP.h @@ -48,6 +48,9 @@ class cChannelIterator: public cItemIterator const cChannel *first; const cChannel *current; protected: + virtual const cChannel* FirstChannel(); + virtual const cChannel* NextNormal(); + virtual const cChannel* NextGroup(); virtual const cChannel* NextChannel(const cChannel *Channel) = 0; static inline const cChannel* SkipFakeGroups(const cChannel *Channel); // Helper which returns the group by its index @@ -208,8 +211,15 @@ class cRssMenuList: public cMenuList inline const cChannel* cChannelIterator::SkipFakeGroups(const cChannel* Group) { +#if APIVERSNUM >= 20300 + LOCK_CHANNELS_READ; +#endif while (Group && Group->GroupSep() && !*Group->Name()) +#if APIVERSNUM >= 20300 + Group = Channels->Next(Group); +#else Group = Channels.Next(Group); +#endif return Group; } diff --git a/server/server.c b/server/server.c index 8dd122e..328f728 100644 --- a/server/server.c +++ b/server/server.c @@ -177,7 +177,11 @@ void cStreamdevServer::Action(void) } } +#if APIVERSNUM >= 20300 +cList& cStreamdevServer::Clients(cThreadLock& Lock) +#else const cList& cStreamdevServer::Clients(cThreadLock& Lock) +#endif { Lock.Lock(m_Instance); return m_Clients; diff --git a/server/server.h b/server/server.h index 91a9cae..c70e099 100644 --- a/server/server.h +++ b/server/server.h @@ -37,7 +37,11 @@ public: static void Destruct(void); static bool Active(void); +#if APIVERSNUM >= 20300 + static cList& Clients(cThreadLock& Lock); +#else static const cList& Clients(cThreadLock& Lock); +#endif }; inline bool cStreamdevServer::Active(void) diff --git a/server/streamdev-server.c b/server/streamdev-server.c index 33d08a5..04b2380 100644 --- a/server/streamdev-server.c +++ b/server/streamdev-server.c @@ -21,7 +21,11 @@ cList cMainThreadHookSubscriber::m_Subscribers; cMutex cMainThreadHookSubscriber::m_Mutex; +#if APIVERSNUM >= 20300 +cList& cMainThreadHookSubscriber::Subscribers(cMutexLock& Lock) +#else const cList& cMainThreadHookSubscriber::Subscribers(cMutexLock& Lock) +#endif { Lock.Lock(&m_Mutex); return m_Subscribers; @@ -163,7 +167,11 @@ void cPluginStreamdevServer::MainThreadHook(void) } cMutexLock lock; +#if APIVERSNUM >= 20300 + cList& subs = cMainThreadHookSubscriber::Subscribers(lock); +#else const cList& subs = cMainThreadHookSubscriber::Subscribers(lock); +#endif for (cMainThreadHookSubscriber *s = subs.First(); s; s = subs.Next(s)) s->MainThreadHook(); } @@ -199,7 +207,11 @@ cString cPluginStreamdevServer::SVDRPCommand(const char *Command, const char *Op { reply = ""; cThreadLock lock; +#if APIVERSNUM >= 20300 + cList& clients = cStreamdevServer::Clients(lock); +#else const cList& clients = cStreamdevServer::Clients(lock); +#endif cServerConnection *s = clients.First(); if (!s) { @@ -223,7 +235,11 @@ cString cPluginStreamdevServer::SVDRPCommand(const char *Command, const char *Op } else { cThreadLock lock; +#if APIVERSNUM >= 20300 + cList& clients = cStreamdevServer::Clients(lock); +#else const cList& clients = cStreamdevServer::Clients(lock); +#endif cServerConnection *s = clients.First(); for (; s && s != client; s = clients.Next(s)); diff --git a/server/streamdev-server.h b/server/streamdev-server.h index 4654e26..18e61c2 100644 --- a/server/streamdev-server.h +++ b/server/streamdev-server.h @@ -15,7 +15,11 @@ private: static cList m_Subscribers; static cMutex m_Mutex; public: +#if APIVERSNUM >= 20300 + static cList& Subscribers(cMutexLock& Lock); +#else static const cList& Subscribers(cMutexLock& Lock); +#endif virtual void MainThreadHook() = 0;