From eff7aa4a3d2247ee3c44031e6bf5d745723cc5ce Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Mon, 1 May 2000 16:29:46 +0200 Subject: [PATCH] Prepared for more than one DVB card --- HISTORY | 17 ++++++ MANUAL | 6 ++- config.c | 26 ++++++--- config.h | 8 +-- dvbapi.c | 103 +++++++++++++++++++++++++++++------ dvbapi.h | 26 +++++++-- interface.c | 24 +++++---- interface.h | 4 +- menu.c | 151 ++++++++++++++++++++++++++++++++++++++++------------ menu.h | 32 ++++++++--- osd.h | 3 +- vdr.c | 61 ++++++++++----------- 12 files changed, 338 insertions(+), 123 deletions(-) diff --git a/HISTORY b/HISTORY index 95cd350b..dbe65c05 100644 --- a/HISTORY +++ b/HISTORY @@ -32,3 +32,20 @@ Video Disk Recorder Revision History kick in too early). - Channel selection is now blocked when recording or replaying. - Improved process handling. + +2000-05-01: Version 0.05 + +- Prepared for support of more than one DVB card. +- Instant recordings no longer get the name "instant". They now get the name + of the channel, with a prepended '@' character. +- Timers that are not given an explicit Name now use the channel name with + a prepended '@' character. +- If an instant recording is currently active, the Main menu now contains + an option to stop that recording. +- Timers are now only processed when the Menu is not active. So after editing + a timer the effect will take place only after the menu has been closed. + In order to avoid missing a timer event by inadvertently leaving the menu + open, the menu will be closed automatically after about two minutes of + inactivity. +- If a recording is currently being replayed, the Main menu now contains an + option to stop replaying. diff --git a/MANUAL b/MANUAL index 27759dbd..40ec5f94 100644 --- a/MANUAL +++ b/MANUAL @@ -49,7 +49,7 @@ Video Disk Recorder User's Manual * Instant Recording You can start recording the current channel by pressing the "Record" - button. This will create a timer event named "instant" that starts + button. This will create a timer event named "@channelname" that starts at the current time and records for two hours. If you want to modify the recording time you need to edit the timer. Stop instant recording by pressing the "Menu" button and selecting @@ -60,6 +60,8 @@ Video Disk Recorder User's Manual All recordings are listed in the "Recordings" menu. Browse through the list with the "Up" and "Down" button and press "Ok" (or the "Red" button) to start playback. + Playback can be stopped via the Main menu by selecting "Stop replaying", + or by pressing the "Stop" button outside the menu. * Replay Control @@ -67,7 +69,7 @@ Video Disk Recorder User's Manual - "Begin" Positions to beginning of the recording and starts playback from there. - - "Pause" Halts playback at the current frame. Press again to continue + - "Pause" Halts playback at the current position. Press again to continue playback. - "Stop" Stops playback and stores the current position, so that playback can be resumed later at that point. diff --git a/config.c b/config.c index 0a39cc50..16e34ccb 100644 --- a/config.c +++ b/config.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.c 1.5 2000/04/24 09:44:15 kls Exp $ + * $Id: config.c 1.6 2000/05/01 16:29:31 kls Exp $ */ #include "config.h" @@ -201,13 +201,15 @@ bool cChannel::Save(FILE *f) return fprintf(f, "%s:%d:%c:%d:%d:%d:%d:%d:%d\n", name, frequency, polarization, diseqc, srate, vpid, apid, ca, pnr) > 0; } -bool cChannel::Switch(void) +bool cChannel::Switch(cDvbApi *DvbApi) { - if (!DvbApi.Recording()) { + if (!DvbApi) + DvbApi = cDvbApi::PrimaryDvbApi; + if (!DvbApi->Recording()) { isyslog(LOG_INFO, "switching to channel %d", Index() + 1); CurrentChannel = Index(); for (int i = 3; --i;) { - if (DvbApi.SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) + if (DvbApi->SetChannel(frequency, polarization, diseqc, srate, vpid, apid, ca, pnr)) return true; esyslog(LOG_ERR, "retrying"); } @@ -217,10 +219,16 @@ bool cChannel::Switch(void) return false; } -bool cChannel::SwitchTo(int i) +bool cChannel::SwitchTo(int i, cDvbApi *DvbApi) { cChannel *channel = Channels.Get(i); - return channel && channel->Switch(); + return channel && channel->Switch(DvbApi); +} + +const char *cChannel::GetChannelName(int i) +{ + cChannel *channel = Channels.Get(i); + return channel ? channel->name : NULL; } // -- cTimer ----------------------------------------------------------------- @@ -241,7 +249,9 @@ cTimer::cTimer(bool Instant) //TODO VPS??? priority = 99; lifetime = 99; - strcpy(file, Instant ? "instant" : ""); + *file = 0; + if (Instant) + snprintf(file, sizeof(file), "@%s", cChannel::GetChannelName(CurrentChannel)); } int cTimer::TimeToInt(int t) @@ -382,7 +392,7 @@ cTimer *cTimer::GetMatch(void) { cTimer *t = (cTimer *)Timers.First(); while (t) { - if (t->Matches()) + if (!t->recording && t->Matches()) return t; t = (cTimer *)t->Next(); } diff --git a/config.h b/config.h index 42af0f85..a66a2579 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.4 2000/04/24 09:44:17 kls Exp $ + * $Id: config.h 1.5 2000/05/01 10:45:17 kls Exp $ */ #ifndef __CONFIG_H @@ -14,6 +14,7 @@ #include #include #include +#include "dvbapi.h" #include "tools.h" #define MaxBuffer 1000 @@ -79,8 +80,9 @@ public: cChannel(const cChannel *Channel); bool Parse(char *s); bool Save(FILE *f); - bool Switch(void); - static bool SwitchTo(int i); + bool Switch(cDvbApi *DvbApi = NULL); + static bool SwitchTo(int i, cDvbApi *DvbApi = NULL); + static const char *GetChannelName(int i); }; class cTimer : public cListObject { diff --git a/dvbapi.c b/dvbapi.c index 719437d4..f855cadc 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.8 2000/04/24 15:30:35 kls Exp $ + * $Id: dvbapi.c 1.9 2000/05/01 13:18:29 kls Exp $ */ #include "dvbapi.h" @@ -987,13 +987,16 @@ int cReplayBuffer::Write(int Max) // --- cDvbApi --------------------------------------------------------------- -cDvbApi::cDvbApi(void) +int cDvbApi::NumDvbApis = 0; +cDvbApi *cDvbApi::dvbApi[MAXDVBAPI] = { NULL }; +cDvbApi *cDvbApi::PrimaryDvbApi = NULL; + +cDvbApi::cDvbApi(const char *FileName) { - isMainProcess = true; pidRecord = pidReplay = 0; fromRecord = toRecord = -1; fromReplay = toReplay = -1; - videoDev = open(VIDEODEVICE, O_RDWR | O_NONBLOCK); + videoDev = open(FileName, O_RDWR | O_NONBLOCK); if (videoDev < 0) LOG_ERROR; cols = rows = 0; @@ -1017,20 +1020,84 @@ cDvbApi::cDvbApi(void) cDvbApi::~cDvbApi() { - if (isMainProcess) { - if (videoDev >= 0) { - Close(); - StopReplay(); - StopRecord(); - close(videoDev); - } -#if defined(DEBUG_REMOTE) || defined(DEBUG_OSD) - endwin(); -#endif + if (videoDev >= 0) { + Close(); + StopReplay(); + StopRecord(); + close(videoDev); } +#if defined(DEBUG_REMOTE) || defined(DEBUG_OSD) + endwin(); +#endif delete replayTitle; } +cDvbApi *cDvbApi::GetDvbApi(int Ca) +{ + Ca--; + for (int i = MAXDVBAPI; --i >= 0; ) { + if (dvbApi[i]) { + if ((i == Ca || Ca < 0) && !dvbApi[i]->Recording()) + return dvbApi[i]; + } + } + return NULL; +} + +int cDvbApi::Index(void) +{ + for (int i = 0; i < MAXDVBAPI; i++) { + if (dvbApi[i] == this) + return i; + } + return -1; +} + +bool cDvbApi::Init(void) +{ + char fileName[strlen(VIDEODEVICE) + 10]; + int i; + + NumDvbApis = 0; + for (i = 0; i < MAXDVBAPI; i++) { + sprintf(fileName, "%s%d", VIDEODEVICE, i); + if (access(fileName, F_OK | R_OK | W_OK) == 0) { + dsyslog(LOG_INFO, "probing %s", fileName); + int f = open(fileName, O_RDWR); + if (f >= 0) { + close(f); + dvbApi[i] = new cDvbApi(fileName); + NumDvbApis++; + } + else { + if (errno != ENODEV) + LOG_ERROR_STR(fileName); + break; + } + } + else { + if (errno != ENOENT) + LOG_ERROR_STR(fileName); + break; + } + } + PrimaryDvbApi = dvbApi[0]; + if (NumDvbApis > 0) + isyslog(LOG_INFO, "found %d video device%s", NumDvbApis, NumDvbApis > 1 ? "s" : ""); + else + esyslog(LOG_ERR, "ERROR: no video device found, giving up!"); + return NumDvbApis > 0; +} + +void cDvbApi::Cleanup(void) +{ + for (int i = 0; i < MAXDVBAPI; i++) { + delete dvbApi[i]; + dvbApi[i] = NULL; + } + PrimaryDvbApi = NULL; +} + #ifdef DEBUG_OSD void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg) { @@ -1100,7 +1167,9 @@ void cDvbApi::Open(int w, int h) void cDvbApi::Close(void) { -#ifndef DEBUG_OSD +#ifdef DEBUG_OSD + delwin(window); +#else Cmd(OSD_Close); #endif lastProgress = -1; @@ -1247,6 +1316,8 @@ bool cDvbApi::StartRecord(const char *FileName) } if (videoDev >= 0) { + StopReplay(); // TODO: remove this if the driver is able to do record and replay at the same time + // Check FileName: if (!FileName) { @@ -1285,7 +1356,6 @@ bool cDvbApi::StartRecord(const char *FileName) // This is the actual recording process dsyslog(LOG_INFO, "start recording process (pid=%d)", getpid()); - isMainProcess = false; bool DataStreamBroken = false; int fromMain = toRecordPipe[0]; int toMain = fromRecordPipe[1]; @@ -1411,7 +1481,6 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title) // This is the actual replaying process dsyslog(LOG_INFO, "start replaying process (pid=%d)", getpid()); - isMainProcess = false; int fromMain = toReplayPipe[0]; int toMain = fromReplayPipe[1]; cReplayBuffer *Buffer = new cReplayBuffer(&videoDev, FileName); diff --git a/dvbapi.h b/dvbapi.h index 91e554e9..6a9e3aa6 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.8 2000/04/24 15:31:07 kls Exp $ + * $Id: dvbapi.h 1.9 2000/05/01 12:46:25 kls Exp $ */ #ifndef __DVBAPI_H @@ -43,10 +43,29 @@ enum eDvbColor { clrBackground, class cDvbApi { private: int videoDev; + cDvbApi(const char *FileName); public: - cDvbApi(void); ~cDvbApi(); +#define MAXDVBAPI 2 + static int NumDvbApis; +private: + static cDvbApi *dvbApi[MAXDVBAPI]; +public: + static cDvbApi *PrimaryDvbApi; + static cDvbApi *GetDvbApi(int Ca = 0); + // Selects a free DVB device, starting with the highest device number. + // If Ca is nor 0, the device with the given number will be returned + // if it is not currently recording. + int Index(void); + // Returns the index of this DvbApi. + static bool Init(void); + // Initializes the DVB API and probes for existing DVB devices. + // Must be called before accessing any DVB functions. + static void Cleanup(void); + // Closes down all DVB devices. + // Must be called at the end of the program. + // On Screen Display facilities private: @@ -91,7 +110,6 @@ private: dvbSkip, dvbGetIndex, }; - bool isMainProcess; pid_t pidRecord, pidReplay; int fromRecord, toRecord; int fromReplay, toReplay; @@ -133,5 +151,5 @@ public: // beginning of the recording. bool GetIndex(int *Current, int *Total = NULL); }; - + #endif //__DVBAPI_H diff --git a/interface.c b/interface.c index 446f9c43..add13bec 100644 --- a/interface.c +++ b/interface.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.6 2000/04/24 09:44:23 kls Exp $ + * $Id: interface.c 1.7 2000/05/01 10:11:26 kls Exp $ */ #include "interface.h" @@ -15,8 +15,6 @@ cRcIo RcIo("/dev/ttyS1"); #endif -cDvbApi DvbApi; //XXX member of cInterface??? - cInterface Interface; cInterface::cInterface(void) @@ -36,7 +34,7 @@ void cInterface::Init(void) void cInterface::Open(int NumCols, int NumLines) { if (!open++) - DvbApi.Open(NumCols, NumLines); + cDvbApi::PrimaryDvbApi->Open(NumCols, NumLines); } void cInterface::Close(void) @@ -44,7 +42,7 @@ void cInterface::Close(void) if (open == 1) Clear(); if (!--open) - DvbApi.Close(); + cDvbApi::PrimaryDvbApi->Close(); } unsigned int cInterface::GetCh(bool Wait) @@ -91,13 +89,13 @@ eKeys cInterface::Wait(int Seconds, bool KeepChar) void cInterface::Clear(void) { if (open) - DvbApi.Clear(); + cDvbApi::PrimaryDvbApi->Clear(); } void cInterface::ClearEol(int x, int y, eDvbColor Color) { if (open) - DvbApi.ClrEol(x, y, Color); + cDvbApi::PrimaryDvbApi->ClrEol(x, y, Color); } void cInterface::SetCols(int *c) @@ -112,7 +110,7 @@ void cInterface::SetCols(int *c) void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor) { if (open) - DvbApi.Text(x, y, s, FgColor, BgColor); + cDvbApi::PrimaryDvbApi->Text(x, y, s, FgColor, BgColor); } void cInterface::WriteText(int x, int y, const char *s, bool Current) @@ -198,8 +196,8 @@ void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvb int l = (w - strlen(Text)) / 2; if (l < 0) l = 0; - DvbApi.Fill(Index * w, -1, w, 1, BgColor); - DvbApi.Text(Index * w + l, -1, Text, FgColor, BgColor); + cDvbApi::PrimaryDvbApi->Fill(Index * w, -1, w, 1, BgColor); + cDvbApi::PrimaryDvbApi->Text(Index * w + l, -1, Text, FgColor, BgColor); } } @@ -337,3 +335,9 @@ void cInterface::DisplayChannel(int Number, const char *Name) Close(); } } + +bool cInterface::Recording(void) +{ + // This is located here because the Interface has to do with the "PrimaryDvbApi" anyway + return cDvbApi::PrimaryDvbApi->Recording(); +} diff --git a/interface.h b/interface.h index eb4e76bc..9c47a44b 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.7 2000/04/24 09:44:25 kls Exp $ + * $Id: interface.h 1.8 2000/05/01 10:10:08 kls Exp $ */ #ifndef __INTERFACE_H @@ -43,9 +43,9 @@ public: void Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL); void LearnKeys(void); void DisplayChannel(int Number, const char *Name = NULL); + bool Recording(void); }; extern cInterface Interface; -extern cDvbApi DvbApi; //XXX member of cInterface??? #endif //__INTERFACE_H diff --git a/menu.c b/menu.c index f6bd4a40..2d738445 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.12 2000/04/30 11:10:49 kls Exp $ + * $Id: menu.c 1.13 2000/05/01 16:29:46 kls Exp $ */ #include "menu.h" @@ -12,9 +12,10 @@ #include #include #include "config.h" -#include "dvbapi.h" #include "recording.h" +#define MENUTIMEOUT 120 // seconds + const char *FileNameChars = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.# "; // --- cMenuEditItem --------------------------------------------------------- @@ -744,7 +745,7 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key) if (state == osUnknown) { if (Key == kOk) { if (!*data.file) - strcpy(data.file, "unnamed"); + strcpy(data.file, cChannel::GetChannelName(data.channel - 1)); if (timer && memcmp(timer, &data, sizeof(data)) != 0) { *timer = data; Timers.Save(); @@ -991,15 +992,25 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key) // --- cMenuMain ------------------------------------------------------------- -cMenuMain::cMenuMain(bool Recording) +#define STOP_RECORDING "Stop recording " + +cMenuMain::cMenuMain(bool Replaying) :cOsdMenu("Main") { Add(new cOsdItem("Channels", osChannels)); Add(new cOsdItem("Timer", osTimer)); Add(new cOsdItem("Recordings", osRecordings)); - if (Recording) - Add(new cOsdItem("Stop Recording", osStopRecord)); + if (Replaying) + Add(new cOsdItem("Stop replaying", osStopReplay)); + const char *s = NULL; + while ((s = cRecordControls::GetInstantId(s)) != NULL) { + char *buffer = NULL; + asprintf(&buffer, "%s%s", STOP_RECORDING, s); + Add(new cOsdItem(buffer, osStopRecord)); + delete buffer; + } Display(); + lastActivity = time(NULL); } eOSState cMenuMain::ProcessKey(eKeys Key) @@ -1010,42 +1021,55 @@ eOSState cMenuMain::ProcessKey(eKeys Key) case osChannels: return AddSubMenu(new cMenuChannels); case osTimer: return AddSubMenu(new cMenuTimers); case osRecordings: return AddSubMenu(new cMenuRecordings); - case osStopRecord: if (!Interface.Confirm("Stop Recording?")) - return osContinue; + case osStopRecord: if (Interface.Confirm("Stop Recording?")) { + cOsdItem *item = Get(Current()); + if (item) { + cRecordControls::Stop(item->Text() + strlen(STOP_RECORDING)); + return osEnd; + } + } default: if (Key == kMenu) state = osEnd; } + if (Key != kNone) + lastActivity = time(NULL); + else if (time(NULL) - lastActivity > MENUTIMEOUT) + state = osEnd; return state; } // --- cRecordControl -------------------------------------------------------- -cRecordControl::cRecordControl(cTimer *Timer) +cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer) { + instantId = NULL; + dvbApi = DvbApi; + if (!dvbApi) dvbApi = cDvbApi::PrimaryDvbApi;//XXX timer = Timer; - isInstant = !timer; if (!timer) { timer = new cTimer(true); Timers.Add(timer); Timers.Save(); + asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s on %d" : "%s", cChannel::GetChannelName(timer->channel - 1), dvbApi->Index() + 1); } timer->SetRecording(true); - cChannel::SwitchTo(timer->channel - 1); + cChannel::SwitchTo(timer->channel - 1, dvbApi); cRecording Recording(timer); - DvbApi.StartRecord(Recording.FileName()); + dvbApi->StartRecord(Recording.FileName()); } cRecordControl::~cRecordControl() { Stop(true); + delete instantId; } void cRecordControl::Stop(bool KeepInstant) { if (timer) { - DvbApi.StopRecord(); + dvbApi->StopRecord(); timer->SetRecording(false); - if ((isInstant && !KeepInstant) || (timer->IsSingleEvent() && !timer->Matches())) { + if ((IsInstant() && !KeepInstant) || (timer->IsSingleEvent() && !timer->Matches())) { // checking timer->Matches() to make sure we don't delete the timer // if the program was cancelled before the timer's stop time! isyslog(LOG_INFO, "deleting timer %d", timer->Index() + 1); @@ -1056,17 +1080,73 @@ void cRecordControl::Stop(bool KeepInstant) } } -eOSState cRecordControl::ProcessKey(eKeys Key) +bool cRecordControl::Process(void) { - if (!timer->Matches()) - return osEnd; - switch (Key) { - case kNone: break; - case kMenu: return osMenu; // allow switching to menu - default: return osUnknown; // anything else is blocked while recording - } + if (!timer || !timer->Matches()) + return false; AssertFreeDiskSpace(); - return osContinue; + return true; +} + +// --- cRecordControls ------------------------------------------------------- + +cRecordControl *cRecordControls::RecordControls[MAXDVBAPI] = { NULL }; + +bool cRecordControls::Start(cTimer *Timer) +{ + int ch = Timer ? Timer->channel - 1 : CurrentChannel; + cChannel *channel = Channels.Get(ch); + + if (channel) { + cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca); + if (dvbApi) { + for (int i = 0; i < MAXDVBAPI; i++) { + if (!RecordControls[i]) { + RecordControls[i] = new cRecordControl(dvbApi, Timer); + return true; + } + } + } + else + esyslog(LOG_ERR, "ERROR: no free DVB device to record channel %d!", ch); + } + else + esyslog(LOG_ERR, "ERROR: channel %d not defined!", ch + 1); + return false; +} + +void cRecordControls::Stop(const char *InstantId) +{ + for (int i = 0; i < MAXDVBAPI; i++) { + if (RecordControls[i]) { + const char *id = RecordControls[i]->InstantId(); + if (id && strcmp(id, InstantId) == 0) + RecordControls[i]->Stop(); + } + } +} + +const char *cRecordControls::GetInstantId(const char *LastInstantId) +{ + for (int i = 0; i < MAXDVBAPI; i++) { + if (RecordControls[i]) { + if (!LastInstantId && RecordControls[i]->InstantId()) + return RecordControls[i]->InstantId(); + if (LastInstantId && LastInstantId == RecordControls[i]->InstantId()) + LastInstantId = NULL; + } + } + return NULL; +} + +void cRecordControls::Process(void) +{ + for (int i = 0; i < MAXDVBAPI; i++) { + if (RecordControls[i]) { + if (!RecordControls[i]->Process()) + DELETENULL(RecordControls[i]); + } + } } // --- cReplayControl -------------------------------------------------------- @@ -1076,15 +1156,16 @@ char *cReplayControl::title = NULL; cReplayControl::cReplayControl(void) { + dvbApi = cDvbApi::PrimaryDvbApi;//XXX visible = shown = false; if (fileName) - DvbApi.StartReplay(fileName, title); + dvbApi->StartReplay(fileName, title); } cReplayControl::~cReplayControl() { Hide(); - DvbApi.StopReplay(); + dvbApi->StopReplay(); } void cReplayControl::SetRecording(const char *FileName, const char *Title) @@ -1100,7 +1181,7 @@ void cReplayControl::Show(void) if (!visible) { Interface.Open(MenuColumns, -3); needsFastResponse = visible = true; - shown = DvbApi.ShowProgress(true); + shown = dvbApi->ShowProgress(true); } } @@ -1114,20 +1195,20 @@ void cReplayControl::Hide(void) eOSState cReplayControl::ProcessKey(eKeys Key) { - if (!DvbApi.Replaying()) + if (!dvbApi->Replaying()) return osEnd; if (visible) - shown = DvbApi.ShowProgress(!shown) || shown; + shown = dvbApi->ShowProgress(!shown) || shown; switch (Key) { - case kBegin: DvbApi.Skip(-INT_MAX); break; - case kPause: DvbApi.PauseReplay(); break; + case kBegin: dvbApi->Skip(-INT_MAX); break; + case kPause: dvbApi->PauseReplay(); break; case kStop: Hide(); - DvbApi.StopReplay(); + dvbApi->StopReplay(); return osEnd; - case kSearchBack: DvbApi.FastRewind(); break; - case kSearchForward: DvbApi.FastForward(); break; - case kSkipBack: DvbApi.Skip(-60); break; - case kSkipForward: DvbApi.Skip(60); break; + case kSearchBack: dvbApi->FastRewind(); break; + case kSearchForward: dvbApi->FastForward(); break; + case kSkipBack: dvbApi->Skip(-60); break; + case kSkipForward: dvbApi->Skip(60); break; case kMenu: Hide(); return osMenu; // allow direct switching to menu case kOk: visible ? Hide() : Show(); break; default: return osUnknown; diff --git a/menu.h b/menu.h index 47bc993b..6ba080cb 100644 --- a/menu.h +++ b/menu.h @@ -4,34 +4,52 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.h 1.8 2000/04/30 10:58:49 kls Exp $ + * $Id: menu.h 1.9 2000/05/01 15:16:23 kls Exp $ */ #ifndef _MENU_H #define _MENU_H +#define _GNU_SOURCE + +#include "dvbapi.h" #include "osd.h" class cMenuMain : public cOsdMenu { +private: + time_t lastActivity; public: - cMenuMain(bool Recording); + cMenuMain(bool Replaying); virtual eOSState ProcessKey(eKeys Key); }; -class cRecordControl : public cOsdBase { +class cRecordControl { private: + cDvbApi *dvbApi; cTimer *timer; - bool isInstant; + char *instantId; public: - cRecordControl(cTimer *Timer = NULL); + cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL); virtual ~cRecordControl(); - virtual eOSState ProcessKey(eKeys Key); + bool Process(void); void Stop(bool KeepInstant = false); - bool IsInstant(void) { return isInstant; } + bool IsInstant(void) { return instantId; } + const char *InstantId(void) { return instantId; } + }; + +class cRecordControls { +private: + static cRecordControl *RecordControls[MAXDVBAPI]; +public: + static bool Start(cTimer *Timer = NULL); + static void Stop(const char *InstantId); + static const char *GetInstantId(const char *LastInstantId); + static void Process(void); }; class cReplayControl : public cOsdBase { private: + cDvbApi *dvbApi; bool visible, shown; void Show(void); void Hide(void); diff --git a/osd.h b/osd.h index 6c7aa4a5..6362b0a7 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.7 2000/04/30 10:37:15 kls Exp $ + * $Id: osd.h 1.8 2000/05/01 15:16:00 kls Exp $ */ #ifndef __OSD_H @@ -24,6 +24,7 @@ enum eOSState { osUnknown, osRecordings, osReplay, osStopRecord, + osStopReplay, osBack, osEnd, }; diff --git a/vdr.c b/vdr.c index 32ae9eba..bc931bc9 100644 --- a/vdr.c +++ b/vdr.c @@ -22,11 +22,12 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.16 2000/04/30 11:06:41 kls Exp $ + * $Id: vdr.c 1.17 2000/05/01 15:24:56 kls Exp $ */ #include #include "config.h" +#include "dvbapi.h" #include "interface.h" #include "menu.h" #include "recording.h" @@ -52,6 +53,9 @@ int main(int argc, char *argv[]) openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); isyslog(LOG_INFO, "started"); + if (!cDvbApi::Init()) + return 1; + Channels.Load("channels.conf"); Timers.Load("timers.conf"); if (!Keys.Load(KEYS_CONF)) @@ -65,7 +69,6 @@ int main(int argc, char *argv[]) if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN); cMenuMain *Menu = NULL; - cRecordControl *RecordControl = NULL; cReplayControl *ReplayControl = NULL; int dcTime = 0, dcNumber = 0; int LastChannel = -1; @@ -73,7 +76,7 @@ int main(int argc, char *argv[]) while (!Interrupted) { // Channel display: if (CurrentChannel != LastChannel) { - if (!RecordControl) { + if (!Menu && !Interface.Recording()) { cChannel *channel = Channels.Get(CurrentChannel); if (channel) Interface.DisplayChannel(CurrentChannel + 1, channel->name); @@ -86,43 +89,32 @@ int main(int argc, char *argv[]) dcNumber = 0; LastChannel = -1; // in case an invalid channel number was entered! } - // Timer Processing: - else if (!RecordControl) { + // Timers and Recordings: + if (!Menu) { cTimer *Timer = cTimer::GetMatch(); if (Timer) { - DELETENULL(Menu); - DELETENULL(ReplayControl); - RecordControl = new cRecordControl(Timer); + if (!cRecordControls::Start(Timer)) { + //TODO need to do something to prevent the timer from hitting over and over again... + } } + cRecordControls::Process(); } // User Input: cOsdBase **Interact = Menu ? (cOsdBase **)&Menu : (cOsdBase **)&ReplayControl; eKeys key = Interface.GetKey(!*Interact || !(*Interact)->NeedsFastResponse()); - if (RecordControl) { - switch (RecordControl->ProcessKey(key)) { - case osMenu: break; - case osEnd: DELETENULL(Menu); // must make sure no menu uses the timer - DELETENULL(RecordControl); - break; - default: if (!*Interact) - continue; - } - } if (*Interact) { switch ((*Interact)->ProcessKey(key)) { case osMenu: DELETENULL(Menu); - Menu = new cMenuMain(RecordControl && RecordControl->IsInstant()); + Menu = new cMenuMain(ReplayControl); break; case osReplay: DELETENULL(Menu); DELETENULL(ReplayControl); ReplayControl = new cReplayControl; break; - case osStopRecord: if (RecordControl) { - RecordControl->Stop(); - DELETENULL(Menu); // must make sure no menu uses the timer - DELETENULL(RecordControl); - } - break; + case osStopReplay: + DELETENULL(*Interact); + DELETENULL(ReplayControl); + break; case osBack: case osEnd: DELETENULL(*Interact); break; @@ -134,28 +126,29 @@ int main(int argc, char *argv[]) // Direct Channel Select (input): case k0: case k1: case k2: case k3: case k4: case k5: case k6: case k7: case k8: case k9: { - if (!RecordControl) { + if (!Interface.Recording()) { dcNumber = dcNumber * 10 + key - k0; dcTime = time_ms(); Interface.DisplayChannel(dcNumber); } } break; - // Instant Recording: - case kRecord: if (!RecordControl) - RecordControl = new cRecordControl; - break; - // Menu Control: - case kMenu: Menu = new cMenuMain(RecordControl && RecordControl->IsInstant()); break; // Up/Down Channel Select: case kUp: - case kDown: if (!RecordControl) { + case kDown: if (!Interface.Recording()) { int n = CurrentChannel + (key == kUp ? 1 : -1); cChannel *channel = Channels.Get(n); if (channel) channel->Switch(); } break; + // Instant Recording: + case kRecord: DELETENULL(Menu); + if (!cRecordControls::Start()) + Interface.Error("No free DVB device to record!"); + break; + // Menu Control: + case kMenu: Menu = new cMenuMain(ReplayControl); break; // Viewing Control: case kOk: LastChannel = -1; break; // forces channel display default: break; @@ -164,8 +157,8 @@ int main(int argc, char *argv[]) } isyslog(LOG_INFO, "caught signal %d", Interrupted); delete Menu; - delete RecordControl; delete ReplayControl; + cDvbApi::Cleanup(); isyslog(LOG_INFO, "exiting"); closelog(); return 0;