Prepared for more than one DVB card

This commit is contained in:
Klaus Schmidinger 2000-05-01 16:29:46 +02:00
parent f7ac74ede4
commit eff7aa4a3d
12 changed files with 338 additions and 123 deletions

17
HISTORY
View File

@ -32,3 +32,20 @@ Video Disk Recorder Revision History
kick in too early). kick in too early).
- Channel selection is now blocked when recording or replaying. - Channel selection is now blocked when recording or replaying.
- Improved process handling. - 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.

6
MANUAL
View File

@ -49,7 +49,7 @@ Video Disk Recorder User's Manual
* Instant Recording * Instant Recording
You can start recording the current channel by pressing the "Record" 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. at the current time and records for two hours.
If you want to modify the recording time you need to edit the timer. If you want to modify the recording time you need to edit the timer.
Stop instant recording by pressing the "Menu" button and selecting 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 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) list with the "Up" and "Down" button and press "Ok" (or the "Red" button)
to start playback. 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 * Replay Control
@ -67,7 +69,7 @@ Video Disk Recorder User's Manual
- "Begin" Positions to beginning of the recording and starts playback - "Begin" Positions to beginning of the recording and starts playback
from there. 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. playback.
- "Stop" Stops playback and stores the current position, so that - "Stop" Stops playback and stores the current position, so that
playback can be resumed later at that point. playback can be resumed later at that point.

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #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; 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); isyslog(LOG_INFO, "switching to channel %d", Index() + 1);
CurrentChannel = Index(); CurrentChannel = Index();
for (int i = 3; --i;) { 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; return true;
esyslog(LOG_ERR, "retrying"); esyslog(LOG_ERR, "retrying");
} }
@ -217,10 +219,16 @@ bool cChannel::Switch(void)
return false; return false;
} }
bool cChannel::SwitchTo(int i) bool cChannel::SwitchTo(int i, cDvbApi *DvbApi)
{ {
cChannel *channel = Channels.Get(i); 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 ----------------------------------------------------------------- // -- cTimer -----------------------------------------------------------------
@ -241,7 +249,9 @@ cTimer::cTimer(bool Instant)
//TODO VPS??? //TODO VPS???
priority = 99; priority = 99;
lifetime = 99; lifetime = 99;
strcpy(file, Instant ? "instant" : ""); *file = 0;
if (Instant)
snprintf(file, sizeof(file), "@%s", cChannel::GetChannelName(CurrentChannel));
} }
int cTimer::TimeToInt(int t) int cTimer::TimeToInt(int t)
@ -382,7 +392,7 @@ cTimer *cTimer::GetMatch(void)
{ {
cTimer *t = (cTimer *)Timers.First(); cTimer *t = (cTimer *)Timers.First();
while (t) { while (t) {
if (t->Matches()) if (!t->recording && t->Matches())
return t; return t;
t = (cTimer *)t->Next(); t = (cTimer *)t->Next();
} }

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __CONFIG_H
@ -14,6 +14,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include "dvbapi.h"
#include "tools.h" #include "tools.h"
#define MaxBuffer 1000 #define MaxBuffer 1000
@ -79,8 +80,9 @@ public:
cChannel(const cChannel *Channel); cChannel(const cChannel *Channel);
bool Parse(char *s); bool Parse(char *s);
bool Save(FILE *f); bool Save(FILE *f);
bool Switch(void); bool Switch(cDvbApi *DvbApi = NULL);
static bool SwitchTo(int i); static bool SwitchTo(int i, cDvbApi *DvbApi = NULL);
static const char *GetChannelName(int i);
}; };
class cTimer : public cListObject { class cTimer : public cListObject {

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "dvbapi.h"
@ -987,13 +987,16 @@ int cReplayBuffer::Write(int Max)
// --- cDvbApi --------------------------------------------------------------- // --- 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; pidRecord = pidReplay = 0;
fromRecord = toRecord = -1; fromRecord = toRecord = -1;
fromReplay = toReplay = -1; fromReplay = toReplay = -1;
videoDev = open(VIDEODEVICE, O_RDWR | O_NONBLOCK); videoDev = open(FileName, O_RDWR | O_NONBLOCK);
if (videoDev < 0) if (videoDev < 0)
LOG_ERROR; LOG_ERROR;
cols = rows = 0; cols = rows = 0;
@ -1017,7 +1020,6 @@ cDvbApi::cDvbApi(void)
cDvbApi::~cDvbApi() cDvbApi::~cDvbApi()
{ {
if (isMainProcess) {
if (videoDev >= 0) { if (videoDev >= 0) {
Close(); Close();
StopReplay(); StopReplay();
@ -1027,10 +1029,75 @@ cDvbApi::~cDvbApi()
#if defined(DEBUG_REMOTE) || defined(DEBUG_OSD) #if defined(DEBUG_REMOTE) || defined(DEBUG_OSD)
endwin(); endwin();
#endif #endif
}
delete replayTitle; 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 #ifdef DEBUG_OSD
void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg) void cDvbApi::SetColor(eDvbColor colorFg, eDvbColor colorBg)
{ {
@ -1100,7 +1167,9 @@ void cDvbApi::Open(int w, int h)
void cDvbApi::Close(void) void cDvbApi::Close(void)
{ {
#ifndef DEBUG_OSD #ifdef DEBUG_OSD
delwin(window);
#else
Cmd(OSD_Close); Cmd(OSD_Close);
#endif #endif
lastProgress = -1; lastProgress = -1;
@ -1247,6 +1316,8 @@ bool cDvbApi::StartRecord(const char *FileName)
} }
if (videoDev >= 0) { if (videoDev >= 0) {
StopReplay(); // TODO: remove this if the driver is able to do record and replay at the same time
// Check FileName: // Check FileName:
if (!FileName) { if (!FileName) {
@ -1285,7 +1356,6 @@ bool cDvbApi::StartRecord(const char *FileName)
// This is the actual recording process // This is the actual recording process
dsyslog(LOG_INFO, "start recording process (pid=%d)", getpid()); dsyslog(LOG_INFO, "start recording process (pid=%d)", getpid());
isMainProcess = false;
bool DataStreamBroken = false; bool DataStreamBroken = false;
int fromMain = toRecordPipe[0]; int fromMain = toRecordPipe[0];
int toMain = fromRecordPipe[1]; int toMain = fromRecordPipe[1];
@ -1411,7 +1481,6 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title)
// This is the actual replaying process // This is the actual replaying process
dsyslog(LOG_INFO, "start replaying process (pid=%d)", getpid()); dsyslog(LOG_INFO, "start replaying process (pid=%d)", getpid());
isMainProcess = false;
int fromMain = toReplayPipe[0]; int fromMain = toReplayPipe[0];
int toMain = fromReplayPipe[1]; int toMain = fromReplayPipe[1];
cReplayBuffer *Buffer = new cReplayBuffer(&videoDev, FileName); cReplayBuffer *Buffer = new cReplayBuffer(&videoDev, FileName);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __DVBAPI_H
@ -43,10 +43,29 @@ enum eDvbColor { clrBackground,
class cDvbApi { class cDvbApi {
private: private:
int videoDev; int videoDev;
cDvbApi(const char *FileName);
public: public:
cDvbApi(void);
~cDvbApi(); ~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 // On Screen Display facilities
private: private:
@ -91,7 +110,6 @@ private:
dvbSkip, dvbSkip,
dvbGetIndex, dvbGetIndex,
}; };
bool isMainProcess;
pid_t pidRecord, pidReplay; pid_t pidRecord, pidReplay;
int fromRecord, toRecord; int fromRecord, toRecord;
int fromReplay, toReplay; int fromReplay, toReplay;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "interface.h"
@ -15,8 +15,6 @@
cRcIo RcIo("/dev/ttyS1"); cRcIo RcIo("/dev/ttyS1");
#endif #endif
cDvbApi DvbApi; //XXX member of cInterface???
cInterface Interface; cInterface Interface;
cInterface::cInterface(void) cInterface::cInterface(void)
@ -36,7 +34,7 @@ void cInterface::Init(void)
void cInterface::Open(int NumCols, int NumLines) void cInterface::Open(int NumCols, int NumLines)
{ {
if (!open++) if (!open++)
DvbApi.Open(NumCols, NumLines); cDvbApi::PrimaryDvbApi->Open(NumCols, NumLines);
} }
void cInterface::Close(void) void cInterface::Close(void)
@ -44,7 +42,7 @@ void cInterface::Close(void)
if (open == 1) if (open == 1)
Clear(); Clear();
if (!--open) if (!--open)
DvbApi.Close(); cDvbApi::PrimaryDvbApi->Close();
} }
unsigned int cInterface::GetCh(bool Wait) unsigned int cInterface::GetCh(bool Wait)
@ -91,13 +89,13 @@ eKeys cInterface::Wait(int Seconds, bool KeepChar)
void cInterface::Clear(void) void cInterface::Clear(void)
{ {
if (open) if (open)
DvbApi.Clear(); cDvbApi::PrimaryDvbApi->Clear();
} }
void cInterface::ClearEol(int x, int y, eDvbColor Color) void cInterface::ClearEol(int x, int y, eDvbColor Color)
{ {
if (open) if (open)
DvbApi.ClrEol(x, y, Color); cDvbApi::PrimaryDvbApi->ClrEol(x, y, Color);
} }
void cInterface::SetCols(int *c) 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) void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor)
{ {
if (open) 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) 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; int l = (w - strlen(Text)) / 2;
if (l < 0) if (l < 0)
l = 0; l = 0;
DvbApi.Fill(Index * w, -1, w, 1, BgColor); cDvbApi::PrimaryDvbApi->Fill(Index * w, -1, w, 1, BgColor);
DvbApi.Text(Index * w + l, -1, Text, FgColor, BgColor); cDvbApi::PrimaryDvbApi->Text(Index * w + l, -1, Text, FgColor, BgColor);
} }
} }
@ -337,3 +335,9 @@ void cInterface::DisplayChannel(int Number, const char *Name)
Close(); Close();
} }
} }
bool cInterface::Recording(void)
{
// This is located here because the Interface has to do with the "PrimaryDvbApi" anyway
return cDvbApi::PrimaryDvbApi->Recording();
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #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 Help(const char *Red, const char *Green = NULL, const char *Yellow = NULL, const char *Blue = NULL);
void LearnKeys(void); void LearnKeys(void);
void DisplayChannel(int Number, const char *Name = NULL); void DisplayChannel(int Number, const char *Name = NULL);
bool Recording(void);
}; };
extern cInterface Interface; extern cInterface Interface;
extern cDvbApi DvbApi; //XXX member of cInterface???
#endif //__INTERFACE_H #endif //__INTERFACE_H

151
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "menu.h"
@ -12,9 +12,10 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "config.h" #include "config.h"
#include "dvbapi.h"
#include "recording.h" #include "recording.h"
#define MENUTIMEOUT 120 // seconds
const char *FileNameChars = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.# "; const char *FileNameChars = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.# ";
// --- cMenuEditItem --------------------------------------------------------- // --- cMenuEditItem ---------------------------------------------------------
@ -744,7 +745,7 @@ eOSState cMenuEditTimer::ProcessKey(eKeys Key)
if (state == osUnknown) { if (state == osUnknown) {
if (Key == kOk) { if (Key == kOk) {
if (!*data.file) if (!*data.file)
strcpy(data.file, "unnamed"); strcpy(data.file, cChannel::GetChannelName(data.channel - 1));
if (timer && memcmp(timer, &data, sizeof(data)) != 0) { if (timer && memcmp(timer, &data, sizeof(data)) != 0) {
*timer = data; *timer = data;
Timers.Save(); Timers.Save();
@ -991,15 +992,25 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key)
// --- cMenuMain ------------------------------------------------------------- // --- cMenuMain -------------------------------------------------------------
cMenuMain::cMenuMain(bool Recording) #define STOP_RECORDING "Stop recording "
cMenuMain::cMenuMain(bool Replaying)
:cOsdMenu("Main") :cOsdMenu("Main")
{ {
Add(new cOsdItem("Channels", osChannels)); Add(new cOsdItem("Channels", osChannels));
Add(new cOsdItem("Timer", osTimer)); Add(new cOsdItem("Timer", osTimer));
Add(new cOsdItem("Recordings", osRecordings)); Add(new cOsdItem("Recordings", osRecordings));
if (Recording) if (Replaying)
Add(new cOsdItem("Stop Recording", osStopRecord)); 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(); Display();
lastActivity = time(NULL);
} }
eOSState cMenuMain::ProcessKey(eKeys Key) eOSState cMenuMain::ProcessKey(eKeys Key)
@ -1010,42 +1021,55 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
case osChannels: return AddSubMenu(new cMenuChannels); case osChannels: return AddSubMenu(new cMenuChannels);
case osTimer: return AddSubMenu(new cMenuTimers); case osTimer: return AddSubMenu(new cMenuTimers);
case osRecordings: return AddSubMenu(new cMenuRecordings); case osRecordings: return AddSubMenu(new cMenuRecordings);
case osStopRecord: if (!Interface.Confirm("Stop Recording?")) case osStopRecord: if (Interface.Confirm("Stop Recording?")) {
return osContinue; cOsdItem *item = Get(Current());
if (item) {
cRecordControls::Stop(item->Text() + strlen(STOP_RECORDING));
return osEnd;
}
}
default: if (Key == kMenu) default: if (Key == kMenu)
state = osEnd; state = osEnd;
} }
if (Key != kNone)
lastActivity = time(NULL);
else if (time(NULL) - lastActivity > MENUTIMEOUT)
state = osEnd;
return state; return state;
} }
// --- cRecordControl -------------------------------------------------------- // --- cRecordControl --------------------------------------------------------
cRecordControl::cRecordControl(cTimer *Timer) cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer)
{ {
instantId = NULL;
dvbApi = DvbApi;
if (!dvbApi) dvbApi = cDvbApi::PrimaryDvbApi;//XXX
timer = Timer; timer = Timer;
isInstant = !timer;
if (!timer) { if (!timer) {
timer = new cTimer(true); timer = new cTimer(true);
Timers.Add(timer); Timers.Add(timer);
Timers.Save(); Timers.Save();
asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s on %d" : "%s", cChannel::GetChannelName(timer->channel - 1), dvbApi->Index() + 1);
} }
timer->SetRecording(true); timer->SetRecording(true);
cChannel::SwitchTo(timer->channel - 1); cChannel::SwitchTo(timer->channel - 1, dvbApi);
cRecording Recording(timer); cRecording Recording(timer);
DvbApi.StartRecord(Recording.FileName()); dvbApi->StartRecord(Recording.FileName());
} }
cRecordControl::~cRecordControl() cRecordControl::~cRecordControl()
{ {
Stop(true); Stop(true);
delete instantId;
} }
void cRecordControl::Stop(bool KeepInstant) void cRecordControl::Stop(bool KeepInstant)
{ {
if (timer) { if (timer) {
DvbApi.StopRecord(); dvbApi->StopRecord();
timer->SetRecording(false); 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 // checking timer->Matches() to make sure we don't delete the timer
// if the program was cancelled before the timer's stop time! // if the program was cancelled before the timer's stop time!
isyslog(LOG_INFO, "deleting timer %d", timer->Index() + 1); 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()) if (!timer || !timer->Matches())
return osEnd; return false;
switch (Key) {
case kNone: break;
case kMenu: return osMenu; // allow switching to menu
default: return osUnknown; // anything else is blocked while recording
}
AssertFreeDiskSpace(); 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 -------------------------------------------------------- // --- cReplayControl --------------------------------------------------------
@ -1076,15 +1156,16 @@ char *cReplayControl::title = NULL;
cReplayControl::cReplayControl(void) cReplayControl::cReplayControl(void)
{ {
dvbApi = cDvbApi::PrimaryDvbApi;//XXX
visible = shown = false; visible = shown = false;
if (fileName) if (fileName)
DvbApi.StartReplay(fileName, title); dvbApi->StartReplay(fileName, title);
} }
cReplayControl::~cReplayControl() cReplayControl::~cReplayControl()
{ {
Hide(); Hide();
DvbApi.StopReplay(); dvbApi->StopReplay();
} }
void cReplayControl::SetRecording(const char *FileName, const char *Title) void cReplayControl::SetRecording(const char *FileName, const char *Title)
@ -1100,7 +1181,7 @@ void cReplayControl::Show(void)
if (!visible) { if (!visible) {
Interface.Open(MenuColumns, -3); Interface.Open(MenuColumns, -3);
needsFastResponse = visible = true; needsFastResponse = visible = true;
shown = DvbApi.ShowProgress(true); shown = dvbApi->ShowProgress(true);
} }
} }
@ -1114,20 +1195,20 @@ void cReplayControl::Hide(void)
eOSState cReplayControl::ProcessKey(eKeys Key) eOSState cReplayControl::ProcessKey(eKeys Key)
{ {
if (!DvbApi.Replaying()) if (!dvbApi->Replaying())
return osEnd; return osEnd;
if (visible) if (visible)
shown = DvbApi.ShowProgress(!shown) || shown; shown = dvbApi->ShowProgress(!shown) || shown;
switch (Key) { switch (Key) {
case kBegin: DvbApi.Skip(-INT_MAX); break; case kBegin: dvbApi->Skip(-INT_MAX); break;
case kPause: DvbApi.PauseReplay(); break; case kPause: dvbApi->PauseReplay(); break;
case kStop: Hide(); case kStop: Hide();
DvbApi.StopReplay(); dvbApi->StopReplay();
return osEnd; return osEnd;
case kSearchBack: DvbApi.FastRewind(); break; case kSearchBack: dvbApi->FastRewind(); break;
case kSearchForward: DvbApi.FastForward(); break; case kSearchForward: dvbApi->FastForward(); break;
case kSkipBack: DvbApi.Skip(-60); break; case kSkipBack: dvbApi->Skip(-60); break;
case kSkipForward: DvbApi.Skip(60); break; case kSkipForward: dvbApi->Skip(60); break;
case kMenu: Hide(); return osMenu; // allow direct switching to menu case kMenu: Hide(); return osMenu; // allow direct switching to menu
case kOk: visible ? Hide() : Show(); break; case kOk: visible ? Hide() : Show(); break;
default: return osUnknown; default: return osUnknown;

32
menu.h
View File

@ -4,34 +4,52 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef _MENU_H
#define _MENU_H #define _MENU_H
#define _GNU_SOURCE
#include "dvbapi.h"
#include "osd.h" #include "osd.h"
class cMenuMain : public cOsdMenu { class cMenuMain : public cOsdMenu {
private:
time_t lastActivity;
public: public:
cMenuMain(bool Recording); cMenuMain(bool Replaying);
virtual eOSState ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
class cRecordControl : public cOsdBase { class cRecordControl {
private: private:
cDvbApi *dvbApi;
cTimer *timer; cTimer *timer;
bool isInstant; char *instantId;
public: public:
cRecordControl(cTimer *Timer = NULL); cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL);
virtual ~cRecordControl(); virtual ~cRecordControl();
virtual eOSState ProcessKey(eKeys Key); bool Process(void);
void Stop(bool KeepInstant = false); 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 { class cReplayControl : public cOsdBase {
private: private:
cDvbApi *dvbApi;
bool visible, shown; bool visible, shown;
void Show(void); void Show(void);
void Hide(void); void Hide(void);

3
osd.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __OSD_H
@ -24,6 +24,7 @@ enum eOSState { osUnknown,
osRecordings, osRecordings,
osReplay, osReplay,
osStopRecord, osStopRecord,
osStopReplay,
osBack, osBack,
osEnd, osEnd,
}; };

59
vdr.c
View File

@ -22,11 +22,12 @@
* *
* The project's page is at http://www.cadsoft.de/people/kls/vdr * 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 <signal.h> #include <signal.h>
#include "config.h" #include "config.h"
#include "dvbapi.h"
#include "interface.h" #include "interface.h"
#include "menu.h" #include "menu.h"
#include "recording.h" #include "recording.h"
@ -52,6 +53,9 @@ int main(int argc, char *argv[])
openlog("vdr", LOG_PID | LOG_CONS, LOG_USER); openlog("vdr", LOG_PID | LOG_CONS, LOG_USER);
isyslog(LOG_INFO, "started"); isyslog(LOG_INFO, "started");
if (!cDvbApi::Init())
return 1;
Channels.Load("channels.conf"); Channels.Load("channels.conf");
Timers.Load("timers.conf"); Timers.Load("timers.conf");
if (!Keys.Load(KEYS_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); if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN);
cMenuMain *Menu = NULL; cMenuMain *Menu = NULL;
cRecordControl *RecordControl = NULL;
cReplayControl *ReplayControl = NULL; cReplayControl *ReplayControl = NULL;
int dcTime = 0, dcNumber = 0; int dcTime = 0, dcNumber = 0;
int LastChannel = -1; int LastChannel = -1;
@ -73,7 +76,7 @@ int main(int argc, char *argv[])
while (!Interrupted) { while (!Interrupted) {
// Channel display: // Channel display:
if (CurrentChannel != LastChannel) { if (CurrentChannel != LastChannel) {
if (!RecordControl) { if (!Menu && !Interface.Recording()) {
cChannel *channel = Channels.Get(CurrentChannel); cChannel *channel = Channels.Get(CurrentChannel);
if (channel) if (channel)
Interface.DisplayChannel(CurrentChannel + 1, channel->name); Interface.DisplayChannel(CurrentChannel + 1, channel->name);
@ -86,42 +89,31 @@ int main(int argc, char *argv[])
dcNumber = 0; dcNumber = 0;
LastChannel = -1; // in case an invalid channel number was entered! LastChannel = -1; // in case an invalid channel number was entered!
} }
// Timer Processing: // Timers and Recordings:
else if (!RecordControl) { if (!Menu) {
cTimer *Timer = cTimer::GetMatch(); cTimer *Timer = cTimer::GetMatch();
if (Timer) { if (Timer) {
DELETENULL(Menu); if (!cRecordControls::Start(Timer)) {
DELETENULL(ReplayControl); //TODO need to do something to prevent the timer from hitting over and over again...
RecordControl = new cRecordControl(Timer);
} }
} }
cRecordControls::Process();
}
// User Input: // User Input:
cOsdBase **Interact = Menu ? (cOsdBase **)&Menu : (cOsdBase **)&ReplayControl; cOsdBase **Interact = Menu ? (cOsdBase **)&Menu : (cOsdBase **)&ReplayControl;
eKeys key = Interface.GetKey(!*Interact || !(*Interact)->NeedsFastResponse()); 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) { if (*Interact) {
switch ((*Interact)->ProcessKey(key)) { switch ((*Interact)->ProcessKey(key)) {
case osMenu: DELETENULL(Menu); case osMenu: DELETENULL(Menu);
Menu = new cMenuMain(RecordControl && RecordControl->IsInstant()); Menu = new cMenuMain(ReplayControl);
break; break;
case osReplay: DELETENULL(Menu); case osReplay: DELETENULL(Menu);
DELETENULL(ReplayControl); DELETENULL(ReplayControl);
ReplayControl = new cReplayControl; ReplayControl = new cReplayControl;
break; break;
case osStopRecord: if (RecordControl) { case osStopReplay:
RecordControl->Stop(); DELETENULL(*Interact);
DELETENULL(Menu); // must make sure no menu uses the timer DELETENULL(ReplayControl);
DELETENULL(RecordControl);
}
break; break;
case osBack: case osBack:
case osEnd: DELETENULL(*Interact); case osEnd: DELETENULL(*Interact);
@ -134,28 +126,29 @@ int main(int argc, char *argv[])
// Direct Channel Select (input): // Direct Channel Select (input):
case k0: case k1: case k2: case k3: case k4: case k5: case k6: case k7: case k8: case k9: 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; dcNumber = dcNumber * 10 + key - k0;
dcTime = time_ms(); dcTime = time_ms();
Interface.DisplayChannel(dcNumber); Interface.DisplayChannel(dcNumber);
} }
} }
break; 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: // Up/Down Channel Select:
case kUp: case kUp:
case kDown: if (!RecordControl) { case kDown: if (!Interface.Recording()) {
int n = CurrentChannel + (key == kUp ? 1 : -1); int n = CurrentChannel + (key == kUp ? 1 : -1);
cChannel *channel = Channels.Get(n); cChannel *channel = Channels.Get(n);
if (channel) if (channel)
channel->Switch(); channel->Switch();
} }
break; 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: // Viewing Control:
case kOk: LastChannel = -1; break; // forces channel display case kOk: LastChannel = -1; break; // forces channel display
default: break; default: break;
@ -164,8 +157,8 @@ int main(int argc, char *argv[])
} }
isyslog(LOG_INFO, "caught signal %d", Interrupted); isyslog(LOG_INFO, "caught signal %d", Interrupted);
delete Menu; delete Menu;
delete RecordControl;
delete ReplayControl; delete ReplayControl;
cDvbApi::Cleanup();
isyslog(LOG_INFO, "exiting"); isyslog(LOG_INFO, "exiting");
closelog(); closelog();
return 0; return 0;