summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUGS6
-rw-r--r--HISTORY23
-rw-r--r--INSTALL26
-rw-r--r--MANUAL65
-rw-r--r--TODO7
-rw-r--r--channels.conf14
-rw-r--r--config.c42
-rw-r--r--config.h18
-rw-r--r--dvbapi.c193
-rw-r--r--dvbapi.h28
-rw-r--r--interface.c33
-rw-r--r--interface.h5
-rw-r--r--keys-pc.confbin425 -> 283 bytes
-rw-r--r--menu.c238
-rw-r--r--menu.h50
-rw-r--r--osd.h20
-rw-r--r--recording.c6
-rw-r--r--remote.c13
-rw-r--r--remote.h7
-rw-r--r--timers.conf11
-rw-r--r--vdr.c135
21 files changed, 678 insertions, 262 deletions
diff --git a/BUGS b/BUGS
index 66755f9..d9e2687 100644
--- a/BUGS
+++ b/BUGS
@@ -1,7 +1,7 @@
Video Disk Recorder - Known Bugs
--------------------------------
-* Sometimes picture and sound drift apart.
+* Sometimes the picture "jumps" as if a frame is skipped.
Presumably this is a problem in the card driver or firmware?
* When the on-screen display is activated during recording,
@@ -10,7 +10,3 @@ Video Disk Recorder - Known Bugs
I assume this is a problem in the driver of firmware.
There is no such problem in replay mode.
-* After a replay session the screen may go blank.
- Haven't figured out yet how to ensure that it switches back to
- the current channel.
-
diff --git a/HISTORY b/HISTORY
index 95cd350..9767c3f 100644
--- a/HISTORY
+++ b/HISTORY
@@ -32,3 +32,26 @@ Video Disk Recorder Revision History
kick in too early).
- Channel selection is now blocked when recording or replaying.
- Improved process handling.
+
+2000-05-27: Version 0.05
+
+- Support for more than one DVB card.
+- Simultaneous record and replay (with two DVB cards).
+- 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.
+- Displaying the recording DVB interface status in the decimal points of the
+ RCU display.
+- Reduced the number of remote control keys. Modified the key assignments for
+ the PC keyboard to better resemble the "up-down-left-right-ok" layout on
+ menu controlling remote control units.
diff --git a/INSTALL b/INSTALL
index d7acfb6..bc619d7 100644
--- a/INSTALL
+++ b/INSTALL
@@ -12,7 +12,7 @@ about that driver). For example, if the DVB driver was
extracted into the directory /home/kls/vdr/DVB, then this
package should be extracted into /home/kls/vdr/VDR.
-This program requires the card driver version 0.04 or higher
+This program requires the card driver version 0.05 or higher
to work properly.
After extracting the package, change into the VDR directory
@@ -30,6 +30,10 @@ interface. These modes are useful when testing new menus if you
only have a remote connection to the VDR (which, in my case, is
located in the living room and has neither a monitor nor a keyboard).
+When running, the 'vdr' program writes status information into the
+system log file (/var/log/messages). You may want to watch these
+messages (tail -f /var/log/mesages) to see if there are any problems.
+
The video data directory:
-------------------------
@@ -69,7 +73,9 @@ key after the other so that it can learn the various key codes. You will
at least need to provide an "Up" and a "Down" key, so that you can switch
channels. The rest of the key definitions is optional, but the more keys
you define, the more you will be able to navigate through the menus and
-control recording/replaying.
+control recording/replaying. The program uses only a very small number
+of keys which have multiple meanings in the various modes (see MANUAL
+for a detailed description).
If the program has been built with "DEBUG_REMOTE=1", it will use the
key configuration file 'keys-pc.conf', so that you won't loose data
when switching between normal and debug mode.
@@ -77,19 +83,11 @@ when switching between normal and debug mode.
The default PC key assignments are:
Up, Down, Left, Right Crsr keys in numeric block
- Menu '5' in numeric block
- Ok Enter
- Back Backspace
- 0..9 '0'..'9' in top row
+ Menu 'Home' in numeric block
+ Ok '5' in numeric block
+ Back 'End' in numeric block
Red, Green, Yellow, Blue 'F1'..'F4'
- Record 'r'
- Pause 'p'
- Stop 's'
- Begin 'B'
- SearchForward 'f'
- SearchBack 'b'
- SkipForward 'PgDn' in numeric block
- SkipBack 'PgUp' in numeric block
+ 0..9 '0'..'9' in top row
If you prefer different key assignments, simply delete the file
'keys-pc.conf' and restart 'vdr' to get into learning mode.
diff --git a/MANUAL b/MANUAL
index 36a6298..cea3946 100644
--- a/MANUAL
+++ b/MANUAL
@@ -1,6 +1,28 @@
Video Disk Recorder User's Manual
---------------------------------
+* Remote Control Keys
+
+ The following remote control keys are used to control the VDR
+ operation. To keep the number of different keys as small as
+ possible, several keys have different meanings in the various
+ modes:
+
+ Key Normal Main Channels Timer Edit/New Recordings Replay
+
+ Up Ch up Crsr up Crsr up Crsr up Crsr up Crsr up Begin
+ Down Ch down Crsr down Crsr down Crsr down Crsr down Crsr down Pause
+ Left - - - Disable Decrement - Search back
+ Right - - - Enable Increment - Search forward
+ Ok Ch display Select Switch Edit Accept Play Progress disp.
+ Menu Menu on Menu off Menu off Menu off Menu off Menu off Menu on
+ Back - Menu off Main menu Main menu Discard Main menu -
+ Red - Record Edit Edit - Play -
+ Green - - New New - - Skip -60s
+ Yellow - - Delete Delete - Delete Skip +60s
+ Blue - - Mark Mark - - Stop
+ 0..9 Ch select - - - Numeric inp. - -
+
* Navigating through the On Screen Menus
The "Main" menu can be called up with the "Menu" key of your remote
@@ -22,10 +44,10 @@ Video Disk Recorder User's Manual
keys. "Ok" then confirms the changes.
The "Red", "Green", "Yellow" and "Blue" buttons have special meanings
- in the various menus and are listed at the bottom of the on-screen-display.
+ in various menus and are listed at the bottom of the on-screen-display.
At any point in the menu system, pressing the "Menu" key again will
- immediately leave the menu system.
+ immediately leave the menu system (discarding any pending changes).
* Selecting a Channel
@@ -48,35 +70,40 @@ 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
- at the current time and records for two hours.
+ You can start recording the current channel by pressing the "Red" button
+ in the Main menu. 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 disabling or deleting the timer.
+ Stop instant recording by pressing the "Menu" button and selecting
+ "Stop Recording", or by disabling the timer.
* Replaying a Recording
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 "Blue" button outside the menu.
* Replay Control
The following keys have the listed meaning in Replay mode:
- - "Begin" Positions to beginning of the recording and starts playback
- from there.
- - "Pause" Halts playback at the current frame. Press again to continue
- playback.
- - "Stop" Stops playback and stores the current position, so that
- playback can be resumed later at that point.
- - "Search" Runs playback forward or backward at a higher speed. Press
- again to resume normal speed.
- - "Skip" Skips about 60 seconds forward or backward.
- - "Ok" Brings up the replay progress display, which shows the date,
- time and title of the recording, a progress bar and the
- current and total time of the recording.
- Press "Ok" again to turn off the progress display.
+ - Up Positions to beginning of the recording and starts playback
+ from there.
+ - Down Halts playback at the current position. Press again to continue
+ playback.
+ - Blue Stops playback and stores the current position, so that
+ playback can be resumed later at that point.
+ - Left
+ Right Runs playback forward or backward at a higher speed. Press
+ again to resume normal speed.
+ - Green
+ Yellow Skips about 60 seconds back or forward.
+ - Ok Brings up the replay progress display, which shows the date,
+ time and title of the recording, a progress bar and the
+ current and total time of the recording.
+ Press "Ok" again to turn off the progress display.
* Programming the Timer
diff --git a/TODO b/TODO
index 8f5d2f3..64b31b2 100644
--- a/TODO
+++ b/TODO
@@ -1,11 +1,8 @@
TODO list for the Video Disk Recorder project
---------------------------------------------
-* Make it work with two DVB-S PCI cards to allow simultaneous
- recording of one programme, while replaying another programme
- (or maybe the same one, but time delayed).
- Maybe we can do this with only a single card, if the card
- driver/firmware allows simultaneuos record/playback?
+* Implement simultaneous record/replay with a single DVB card once
+ the card driver/firmware allows this.
* Implement "on-disk editing" to allow "cutting out" of certain
scenes in order to archive them (or, reversely, cut out
commercial breaks).
diff --git a/channels.conf b/channels.conf
index c0e191a..5edd778 100644
--- a/channels.conf
+++ b/channels.conf
@@ -1,14 +1,14 @@
RTL:12188:h:1:27500:163:104:0:0
Sat.1:12552:v:1:22000:163:104:0:0
-Pro 7:12480:v:1:27500:255:256:0:0
+Pro-7:12480:v:1:27500:255:256:0:0
RTL2:12188:h:1:27500:166:128:0:0
ARD:11837:h:1:27500:101:102:0:0
BR3:11837:h:1:27500:201:202:0:0
-Hessen 3:11837:h:1:27500:301:302:0:0
+Hessen-3:11837:h:1:27500:301:302:0:0
N3:11837:h:1:27500:401:402:0:0
SR3:11837:h:1:27500:501:502:0:0
WDR:11837:h:1:27500:601:602:0:0
-BR alpha:11837:h:1:27500:701:702:0:0
+BR-alpha:11837:h:1:27500:701:702:0:0
SWR BW:11837:h:1:27500:801:802:0:0
Phoenix:11837:h:1:27500:901:902:0:0
ZDF:11954:h:1:27500:110:120:0:0
@@ -41,8 +41,14 @@ ORB:12722:h:1:22000:501:502:0:0
B1:12722:h:1:22000:601:602:0:0
ARD Online-Kanal:12722:h:1:22000:8191:701:0:0
Premiere World Promo:11798:h:1:27500:255:256:0:0
+Premiere:11798:h:1:27500:511:512:1:10
+Star Kino:11798:h:1:27500:767:768:1:9
+Cine Action:11798:h:1:27500:1023:1024:1:20
+Cine Comedy:11798:h:1:27500:1279:1280:1:29
+Sci Fantasy:11798:h:1:27500:1535:1536:1:41
+Romantic Movies:11798:h:1:27500:1791:1792:1:11
+Studio Universal:11798:h:1:27500:2047:2048:1:21
TV Niepokalanow:11876:h:1:27500:305:321:0:0
-Premiere:11798:h:1:27500:1023:1024:1:10
Mosaico:11934:v:1:27500:165:100:0:0
Andalucia TV:11934:v:1:27500:166:104:0:0
TVC Internacional:11934:v:1:27500:167:108:0:0
diff --git a/config.c b/config.c
index 0a39cc5..7e02c91 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.7 2000/05/27 14:44:15 kls Exp $
*/
#include "config.h"
@@ -23,6 +23,10 @@ tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
{ kBack, "Back", 0 },
{ kLeft, "Left", 0 },
{ kRight, "Right", 0 },
+ { kRed, "Red", 0 },
+ { kGreen, "Green", 0 },
+ { kYellow, "Yellow", 0 },
+ { kBlue, "Blue", 0 },
{ k0, "0", 0 },
{ k1, "1", 0 },
{ k2, "2", 0 },
@@ -33,18 +37,6 @@ tKey keyTable[] = { // "Up" and "Down" must be the first two keys!
{ k7, "7", 0 },
{ k8, "8", 0 },
{ k9, "9", 0 },
- { kRed, "Red", 0 },
- { kGreen, "Green", 0 },
- { kYellow, "Yellow", 0 },
- { kBlue, "Blue", 0 },
- { kRecord, "Record", 0 },
- { kPause, "Pause", 0 },
- { kStop, "Stop", 0 },
- { kBegin, "Begin", 0 },
- { kSearchForward, "SearchForward", 0 },
- { kSearchBack, "SearchBack", 0 },
- { kSkipForward, "SkipForward", 0 },
- { kSkipBack, "SkipBack", 0 },
{ kNone, "", 0 },
};
@@ -201,13 +193,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 +211,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(DvbApi);
+}
+
+const char *cChannel::GetChannelName(int i)
{
cChannel *channel = Channels.Get(i);
- return channel && channel->Switch();
+ return channel ? channel->name : NULL;
}
// -- cTimer -----------------------------------------------------------------
@@ -241,7 +241,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 +384,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 42af0f8..1e22b88 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.6 2000/05/27 14:43:46 kls Exp $
*/
#ifndef __CONFIG_H
@@ -14,6 +14,7 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
+#include "dvbapi.h"
#include "tools.h"
#define MaxBuffer 1000
@@ -26,19 +27,11 @@ enum eKeys { // "Up" and "Down" must be the first two keys!
kBack,
kLeft,
kRight,
- k0, k1, k2, k3, k4, k5, k6, k7, k8, k9,
kRed,
kGreen,
kYellow,
kBlue,
- kRecord,
- kPause,
- kStop,
- kBegin,
- kSearchForward,
- kSearchBack,
- kSkipForward,
- kSkipBack,
+ k0, k1, k2, k3, k4, k5, k6, k7, k8, k9,
kNone
};
@@ -79,8 +72,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 719437d..e652d99 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.10 2000/05/27 14:07:17 kls Exp $
*/
#include "dvbapi.h"
@@ -70,8 +70,9 @@ private:
struct tIndex { int offset; uchar type; uchar number; short reserved; };
int f;
char *fileName, *pFileExt;
- int last, resume;
+ int size, last, resume;
tIndex *index;
+ bool CatchUp(void);
public:
cIndexFile(const char *FileName, bool Record = false);
~cIndexFile();
@@ -89,6 +90,7 @@ cIndexFile::cIndexFile(const char *FileName, bool Record)
{
f = -1;
fileName = pFileExt = NULL;
+ size = 0;
last = resume = -1;
index = NULL;
if (FileName) {
@@ -108,18 +110,25 @@ cIndexFile::cIndexFile(const char *FileName, bool Record)
}
last = (buf.st_size + delta) / sizeof(tIndex) - 1;
if (!Record && last >= 0) {
- index = new tIndex[last + 1];
- int fi = open(fileName, O_RDONLY);
- if (fi >= 0) {
- if ((int)read(fi, index, buf.st_size) != buf.st_size) {
- esyslog(LOG_ERR, "ERROR: can't read from file '%s'", fileName);
- delete index;
- index = NULL;
+ size = last + 1;
+ index = new tIndex[size];
+ if (index) {
+ f = open(fileName, O_RDONLY);
+ if (f >= 0) {
+ if ((int)read(f, index, buf.st_size) != buf.st_size) {
+ esyslog(LOG_ERR, "ERROR: can't read from file '%s'", fileName);
+ delete index;
+ index = NULL;
+ close(f);
+ f = -1;
+ }
+ // we don't close f here, see CatchUp()!
}
- close(fi);
+ else
+ LOG_ERROR_STR(fileName);
}
else
- LOG_ERROR_STR(fileName);
+ esyslog(LOG_ERR, "ERROR: can't allocate %d bytes for index '%s'", size * sizeof(tIndex), fileName);
}
}
else
@@ -164,6 +173,46 @@ cIndexFile::~cIndexFile()
delete fileName;
}
+bool cIndexFile::CatchUp(void)
+{
+ if (index && f >= 0) {
+ struct stat buf;
+ if (fstat(f, &buf) == 0) {
+ int newLast = buf.st_size / sizeof(tIndex) - 1;
+ if (newLast > last) {
+ if (size <= newLast) {
+ size *= 2;
+ if (size <= newLast)
+ size = newLast + 1;
+ }
+ index = (tIndex *)realloc(index, size * sizeof(tIndex));
+ if (index) {
+ int offset = (last + 1) * sizeof(tIndex);
+ int delta = (newLast - last) * sizeof(tIndex);
+ if (lseek(f, offset, SEEK_SET) == offset) {
+ if (read(f, &index[last + 1], delta) != delta) {
+ esyslog(LOG_ERR, "ERROR: can't read from index");
+ delete index;
+ index = NULL;
+ close(f);
+ f = -1;
+ }
+ last = newLast;
+ return true;
+ }
+ else
+ LOG_ERROR;
+ }
+ else
+ esyslog(LOG_ERR, "ERROR: can't realloc() index");
+ }
+ }
+ else
+ LOG_ERROR;
+ }
+ return false;
+}
+
void cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset)
{
if (f >= 0) {
@@ -181,6 +230,7 @@ void cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset)
bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType)
{
if (index) {
+ CatchUp();
if (Index >= 0 && Index <= last) {
*FileNumber = index[Index].number;
*FileOffset = index[Index].offset;
@@ -195,10 +245,12 @@ bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *Pictu
int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length)
{
if (index) {
+ if (Forward)
+ CatchUp();
int d = Forward ? 1 : -1;
for (;;) {
Index += d;
- if (Index >= 0 && Index <= last) {
+ if (Index >= 0 && Index <= last - 100) { // '- 100': need to stay off the end!
if (index[Index].type == I_FRAME) {
*FileNumber = index[Index].number;
*FileOffset = index[Index].offset;
@@ -226,6 +278,7 @@ int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *F
int cIndexFile::Get(uchar FileNumber, int FileOffset)
{
if (index) {
+ CatchUp();
//TODO implement binary search!
int i;
for (i = 0; i < last; i++) {
@@ -842,6 +895,7 @@ void cReplayBuffer::SkipSeconds(int Seconds)
uchar FileNumber;
int FileOffset;
if (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0)
+ if ((Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset)) >= 0)
NextFile(FileNumber, FileOffset);
}
}
@@ -987,13 +1041,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;
@@ -1011,26 +1068,90 @@ cDvbApi::cDvbApi(void)
leaveok(stdscr, TRUE);
window = NULL;
#endif
- lastProgress = -1;
+ lastProgress = lastTotal = -1;
replayTitle = NULL;
}
cDvbApi::~cDvbApi()
{
- if (isMainProcess) {
- if (videoDev >= 0) {
- Close();
- StopReplay();
- StopRecord();
- close(videoDev);
- }
+ if (videoDev >= 0) {
+ Close();
+ StopReplay();
+ StopRecord();
+ close(videoDev);
+ }
#if defined(DEBUG_REMOTE) || defined(DEBUG_OSD)
- endwin();
+ 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)
{
@@ -1095,15 +1216,17 @@ void cDvbApi::Open(int w, int h)
SETCOLOR(clrMagenta, 0xB0, 0x00, 0xFC, 255);
SETCOLOR(clrWhite, 0xFC, 0xFC, 0xFC, 255);
- lastProgress = -1;
+ lastProgress = lastTotal = -1;
}
void cDvbApi::Close(void)
{
-#ifndef DEBUG_OSD
+#ifdef DEBUG_OSD
+ delwin(window);
+#else
Cmd(OSD_Close);
#endif
- lastProgress = -1;
+ lastProgress = lastTotal = -1;
}
void cDvbApi::Clear(void)
@@ -1158,8 +1281,9 @@ bool cDvbApi::ShowProgress(bool Initial)
if (Initial) {
if (replayTitle)
Text(0, 0, replayTitle);
- Text(-7, 2, cIndexFile::Str(Total));
}
+ if (Total != lastTotal)
+ Text(-7, 2, cIndexFile::Str(Total));
#ifdef DEBUG_OSD
int p = cols * Current / Total;
Fill(0, 1, p, 1, clrGreen);
@@ -1191,6 +1315,7 @@ bool cDvbApi::ShowProgress(bool Initial)
}
#endif
Text(0, 2, cIndexFile::Str(Current));
+ lastTotal = Total;
return true;
}
return false;
@@ -1247,6 +1372,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 +1412,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];
@@ -1371,7 +1497,7 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title)
StopReplay();
if (videoDev >= 0) {
- lastProgress = -1;
+ lastProgress = lastTotal = -1;
delete replayTitle;
if (Title) {
if ((replayTitle = strdup(Title)) == NULL)
@@ -1411,7 +1537,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);
@@ -1440,7 +1565,8 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title)
}
if (FD_ISSET(fromMain, &setIn)) {
switch (readchar(fromMain)) {
- case dvbStop: Buffer->Stop(); break;
+ case dvbStop: SetReplayMode(VID_PLAY_CLEAR_BUFFER);
+ Buffer->Stop(); break;
case dvbPauseReplay: SetReplayMode(Paused ? VID_PLAY_NORMAL : VID_PLAY_PAUSE);
Paused = !Paused;
FastForward = FastRewind = false;
@@ -1459,6 +1585,7 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title)
case dvbSkip: {
int Seconds;
if (readint(fromMain, Seconds)) {
+ SetReplayMode(VID_PLAY_CLEAR_BUFFER);
SetReplayMode(VID_PLAY_NORMAL);
FastForward = FastRewind = Paused = false;
Buffer->SetMode(rmPlay);
diff --git a/dvbapi.h b/dvbapi.h
index 91e554e..e0c74b0 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.10 2000/05/20 14:50:43 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:
@@ -72,7 +91,7 @@ public:
// Progress Display facilities
private:
- int lastProgress;
+ int lastProgress, lastTotal;
char *replayTitle;
public:
bool ShowProgress(bool Initial = false);
@@ -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 446f9c4..82f955d 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.9 2000/05/07 09:28:39 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);
}
}
@@ -323,7 +321,7 @@ void cInterface::DisplayChannel(int Number, const char *Name)
#ifndef DEBUG_REMOTE
RcIo.Number(Number);
#endif
- if (Name) {
+ if (Name && !Recording()) {
Open(MenuColumns, 1);
char buffer[MenuColumns + 1];
snprintf(buffer, sizeof(buffer), "%d %s", Number, Name ? Name : "");
@@ -337,3 +335,16 @@ void cInterface::DisplayChannel(int Number, const char *Name)
Close();
}
}
+
+void cInterface::DisplayRecording(int Index, bool On)
+{
+#ifndef DEBUG_REMOTE
+ RcIo.SetPoints(1 << Index, On);
+#endif
+}
+
+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 eb4e76b..2a1c156 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.9 2000/05/06 15:39:23 kls Exp $
*/
#ifndef __INTERFACE_H
@@ -43,9 +43,10 @@ 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);
+ void DisplayRecording(int Index, bool On);
+ bool Recording(void);
};
extern cInterface Interface;
-extern cDvbApi DvbApi; //XXX member of cInterface???
#endif //__INTERFACE_H
diff --git a/keys-pc.conf b/keys-pc.conf
index 744609d..cb0192b 100644
--- a/keys-pc.conf
+++ b/keys-pc.conf
Binary files differ
diff --git a/menu.c b/menu.c
index 2a4cfa9..aab5fd1 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.8 2000/04/24 15:32:11 kls Exp $
+ * $Id: menu.c 1.16 2000/05/27 16:13:39 kls Exp $
*/
#include "menu.h"
@@ -12,9 +12,10 @@
#include <stdio.h>
#include <string.h>
#include "config.h"
-#include "dvbapi.h"
#include "recording.h"
+#define MENUTIMEOUT 120 // seconds
+
const char *FileNameChars = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789-.# ";
// --- cMenuEditItem ---------------------------------------------------------
@@ -509,7 +510,7 @@ cMenuEditChannel::cMenuEditChannel(int Index)
Add(new cMenuEditIntItem( "Srate", &data.srate, 22000, 27500)); //TODO exact limits - toggle???
Add(new cMenuEditIntItem( "Vpid", &data.vpid, 0, 10000)); //TODO exact limits???
Add(new cMenuEditIntItem( "Apid", &data.apid, 0, 10000)); //TODO exact limits???
- Add(new cMenuEditBoolItem("CA", &data.ca));
+ Add(new cMenuEditIntItem( "CA", &data.ca, 0, cDvbApi::NumDvbApis));
Add(new cMenuEditIntItem( "Pnr", &data.pnr, 0, 10000)); //TODO exact limits???
}
}
@@ -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();
@@ -947,9 +948,8 @@ eOSState cMenuRecordings::Play(void)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri) {
-//XXX what if this recording's file is currently in use???
- if (DvbApi.StartReplay(ri->recording->FileName(), ri->recording->Title()))
- return osEnd;
+ cReplayControl::SetRecording(ri->recording->FileName(), ri->recording->Title());
+ return osReplay;
}
return osContinue;
}
@@ -992,12 +992,26 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key)
// --- cMenuMain -------------------------------------------------------------
-cMenuMain::cMenuMain(void)
+#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 (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;
+ }
+ SetHelp("Record");
+ Display();
+ lastActivity = time(NULL);
}
eOSState cMenuMain::ProcessKey(eKeys Key)
@@ -1008,41 +1022,205 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
case osChannels: return AddSubMenu(new cMenuChannels);
case osTimer: return AddSubMenu(new cMenuTimers);
case osRecordings: return AddSubMenu(new cMenuRecordings);
- default: break;
+ case osStopRecord: if (Interface.Confirm("Stop Recording?")) {
+ cOsdItem *item = Get(Current());
+ if (item) {
+ cRecordControls::Stop(item->Text() + strlen(STOP_RECORDING));
+ return osEnd;
+ }
+ }
+ default: switch (Key) {
+ case kMenu: state = osEnd; break;
+ case kRed: if (!HasSubMenu())
+ state = osRecord;
+ break;
+ default: break;
+ }
}
+ if (Key != kNone)
+ lastActivity = time(NULL);
+ else if (time(NULL) - lastActivity > MENUTIMEOUT)
+ state = osEnd;
return state;
}
-// --- cReplayDisplay --------------------------------------------------------
+// --- cRecordControl --------------------------------------------------------
+
+cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer)
+{
+ instantId = NULL;
+ dvbApi = DvbApi;
+ if (!dvbApi) dvbApi = cDvbApi::PrimaryDvbApi;//XXX
+ timer = 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, dvbApi);
+ cRecording Recording(timer);
+ dvbApi->StartRecord(Recording.FileName());
+ Interface.DisplayRecording(dvbApi->Index(), true);
+}
+
+cRecordControl::~cRecordControl()
+{
+ Stop(true);
+ delete instantId;
+ Interface.DisplayRecording(dvbApi->Index(), false);
+}
+
+void cRecordControl::Stop(bool KeepInstant)
+{
+ if (timer) {
+ dvbApi->StopRecord();
+ timer->SetRecording(false);
+ 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);
+ Timers.Del(timer);
+ Timers.Save();
+ }
+ timer = NULL;
+ }
+}
+
+bool cRecordControl::Process(void)
+{
+ if (!timer || !timer->Matches())
+ return false;
+ AssertFreeDiskSpace();
+ 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();
+ }
+ }
+}
-cReplayDisplay::cReplayDisplay(void)
+const char *cRecordControls::GetInstantId(const char *LastInstantId)
{
- Interface.Open(MenuColumns, -3);
- shown = DvbApi.ShowProgress(true);
+ 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;
}
-cReplayDisplay::~cReplayDisplay()
+void cRecordControls::Process(void)
{
- Interface.Close();
+ for (int i = 0; i < MAXDVBAPI; i++) {
+ if (RecordControls[i]) {
+ if (!RecordControls[i]->Process())
+ DELETENULL(RecordControls[i]);
+ }
+ }
}
-eKeys cReplayDisplay::ProcessKey(eKeys Key)
+// --- cReplayControl --------------------------------------------------------
+
+char *cReplayControl::fileName = NULL;
+char *cReplayControl::title = NULL;
+
+cReplayControl::cReplayControl(void)
{
- if (!DvbApi.Replaying())
- return kOk; // will turn off replay display
- shown = DvbApi.ShowProgress(!shown);
+ dvbApi = cDvbApi::PrimaryDvbApi;//XXX
+ visible = shown = false;
+ if (fileName)
+ dvbApi->StartReplay(fileName, title);
+}
+
+cReplayControl::~cReplayControl()
+{
+ Hide();
+ dvbApi->StopReplay();
+}
+
+void cReplayControl::SetRecording(const char *FileName, const char *Title)
+{
+ delete fileName;
+ delete title;
+ fileName = FileName ? strdup(FileName) : NULL;
+ title = Title ? strdup(Title) : NULL;
+}
+
+void cReplayControl::Show(void)
+{
+ if (!visible) {
+ Interface.Open(MenuColumns, -3);
+ needsFastResponse = visible = true;
+ shown = dvbApi->ShowProgress(true);
+ }
+}
+
+void cReplayControl::Hide(void)
+{
+ if (visible) {
+ Interface.Close();
+ needsFastResponse = visible = false;
+ }
+}
+
+eOSState cReplayControl::ProcessKey(eKeys Key)
+{
+ if (!dvbApi->Replaying())
+ return osEnd;
+ if (visible)
+ shown = dvbApi->ShowProgress(!shown) || shown;
switch (Key) {
- case kBegin:
- case kPause:
- case kStop:
- case kSearchBack:
- case kSearchForward:
- case kSkipBack:
- case kSkipForward: break; // will be done in main loop
- case kMenu: break; // allow direct switching to menu
- case kOk: break; // switches off replay display
- default: Key = kNone; // ignore anything not explicitly known here
+ case kUp: dvbApi->Skip(-INT_MAX); break;
+ case kDown: dvbApi->PauseReplay(); break;
+ case kBlue: Hide();
+ dvbApi->StopReplay();
+ return osEnd;
+ case kLeft: dvbApi->FastRewind(); break;
+ case kRight: dvbApi->FastForward(); break;
+ case kGreen: dvbApi->Skip(-60); break;
+ case kYellow: dvbApi->Skip(60); break;
+ case kMenu: Hide(); return osMenu; // allow direct switching to menu
+ case kOk: visible ? Hide() : Show(); break;
+ default: return osUnknown;
}
- return Key;
+ return osContinue;
}
diff --git a/menu.h b/menu.h
index f665799..6ba080c 100644
--- a/menu.h
+++ b/menu.h
@@ -4,27 +4,63 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.h 1.5 2000/04/24 15:31:53 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(void);
+ cMenuMain(bool Replaying);
virtual eOSState ProcessKey(eKeys Key);
};
-class cReplayDisplay {
+class cRecordControl {
+private:
+ cDvbApi *dvbApi;
+ cTimer *timer;
+ char *instantId;
+public:
+ cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL);
+ virtual ~cRecordControl();
+ bool Process(void);
+ void Stop(bool KeepInstant = false);
+ bool IsInstant(void) { return instantId; }
+ const char *InstantId(void) { return instantId; }
+ };
+
+class cRecordControls {
private:
- bool shown;
+ static cRecordControl *RecordControls[MAXDVBAPI];
public:
- cReplayDisplay(void);
- ~cReplayDisplay();
- eKeys ProcessKey(eKeys Key);
+ 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);
+ static char *fileName;
+ static char *title;
+public:
+ cReplayControl(void);
+ virtual ~cReplayControl();
+ virtual eOSState ProcessKey(eKeys Key);
+ bool Visible(void) { return visible; }
+ static void SetRecording(const char *FileName, const char *Title);
};
#endif //_MENU_H
diff --git a/osd.h b/osd.h
index 99821b8..1d4f4cf 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.4 2000/04/24 09:44:32 kls Exp $
+ * $Id: osd.h 1.9 2000/05/27 15:35:41 kls Exp $
*/
#ifndef __OSD_H
@@ -17,11 +17,15 @@
#define MAXOSDITEMS 9
enum eOSState { osUnknown,
+ osMenu,
osContinue,
- osProcessed,
osChannels,
osTimer,
osRecordings,
+ osRecord,
+ osReplay,
+ osStopRecord,
+ osStopReplay,
osBack,
osEnd,
};
@@ -44,7 +48,17 @@ public:
virtual eOSState ProcessKey(eKeys Key);
};
-class cOsdMenu : public cList<cOsdItem> {
+class cOsdBase {
+protected:
+ bool needsFastResponse;
+public:
+ cOsdBase(bool FastResponse = false) { needsFastResponse = FastResponse; }
+ virtual ~cOsdBase() {}
+ virtual eOSState ProcessKey(eKeys Key) = 0;
+ bool NeedsFastResponse(void) { return needsFastResponse; }
+ };
+
+class cOsdMenu : public cOsdBase, public cList<cOsdItem> {
private:
char *title;
int cols[cInterface::MaxCols];
diff --git a/recording.c b/recording.c
index 46fe53f..2eba90b 100644
--- a/recording.c
+++ b/recording.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recording.c 1.6 2000/04/24 09:45:13 kls Exp $
+ * $Id: recording.c 1.8 2000/05/13 16:16:56 kls Exp $
*/
#define _GNU_SOURCE
@@ -61,8 +61,7 @@ void AssertFreeDiskSpace(void)
// it will get removed during the next call.
static time_t LastFreeDiskCheck = 0;
if (time(NULL) - LastFreeDiskCheck > DISKCHECKDELTA) {
- LastFreeDiskCheck = time(NULL);
- if (DvbApi.Recording() && LowDiskSpace()) {
+ if (LowDiskSpace()) {
// Remove the oldest file that has been "deleted":
cRecordings Recordings;
if (Recordings.Load(true)) {
@@ -97,6 +96,7 @@ void AssertFreeDiskSpace(void)
// Unable to free disk space, but there's nothing we can do about that...
esyslog(LOG_ERR, "low disk space, but no recordings to delete");
}
+ LastFreeDiskCheck = time(NULL);
}
}
diff --git a/remote.c b/remote.c
index 2ba5b22..eb495e1 100644
--- a/remote.c
+++ b/remote.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remote.c 1.6 2000/04/24 09:45:56 kls Exp $
+ * $Id: remote.c 1.7 2000/05/07 09:28:18 kls Exp $
*/
#include "remote.h"
@@ -29,6 +29,7 @@ cRcIo::cRcIo(char *DeviceName)
t = 0;
firstTime = lastTime = 0;
lastCommand = 0;
+ lastNumber = 0;
if ((f = open(DeviceName, O_RDWR | O_NONBLOCK)) >= 0) {
struct termios t;
if (tcgetattr(f, &t) == 0) {
@@ -206,6 +207,7 @@ bool cRcIo::Number(int n, bool Hex)
n = (n << 4) | ((*d - '0') & 0x0F);
}
}
+ lastNumber = n;
for (int i = 0; i < 4; i++) {
if (!Digit(i, n))
return false;
@@ -231,6 +233,15 @@ bool cRcIo::String(char *s)
return Number(n, true);
}
+void cRcIo::SetPoints(unsigned char Dp, bool On)
+{
+ if (On)
+ dp |= Dp;
+ else
+ dp &= ~Dp;
+ Number(lastNumber, true);
+}
+
bool cRcIo::DetectCode(unsigned char *Code, unsigned short *Address)
{
// Caller should initialize 'Code' to 0 and call DetectCode()
diff --git a/remote.h b/remote.h
index 73e50eb..1d0a1cc 100644
--- a/remote.h
+++ b/remote.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remote.h 1.4 2000/04/24 09:46:00 kls Exp $
+ * $Id: remote.h 1.5 2000/05/07 09:27:54 kls Exp $
*/
#ifndef __REMOTE_H
@@ -21,10 +21,12 @@ private:
time_t t;
int firstTime, lastTime;
unsigned int lastCommand;
+ int lastNumber;
bool SendCommand(unsigned char Cmd);
int ReceiveByte(bool Wait = true);
bool SendByteHandshake(unsigned char c);
bool SendByte(unsigned char c);
+ bool Digit(int n, int v);
public:
enum { modeH = 'h', modeB = 'b', modeS = 's' };
cRcIo(char *DeviceName);
@@ -34,9 +36,8 @@ public:
bool SetCode(unsigned char Code, unsigned short Address);
bool SetMode(unsigned char Mode);
bool GetCommand(unsigned int *Command, unsigned short *Address = NULL);
- bool Digit(int n, int v);
bool Number(int n, bool Hex = false);
- void Points(unsigned char Dp) { dp = Dp; }
+ void SetPoints(unsigned char Dp, bool On);
bool String(char *s);
bool DetectCode(unsigned char *Code, unsigned short *Address);
};
diff --git a/timers.conf b/timers.conf
index 6fff8d8..1f9fae0 100644
--- a/timers.conf
+++ b/timers.conf
@@ -1,9 +1,10 @@
-0:15:MTWTF--:1828:1901:10:5:nano
-0:3:M------:2110:2230:99:10:SevenDays
-1:10:-T-----:2058:2150:99:10:Quarks
+1:15:MTWTF--:1828:1901:10:5:nano
+1:3:M------:2110:2230:99:10:SevenDays
+1:10:-T-----:2058:2202:99:10:Quarks
1:3:---T---:2158:2300:99:10:Switch
-1:2:----F--:2110:2155:99:10:Anke
1:1:----F--:2210:2325:99:10:7Tage7Koepfe
1:15:-----S-:1358:1435:99:7:Neues
1:1:-----S-:1445:1600:99:10:Hammerman
-1:2:-----S-:2205:2320:99:10:Wochenshow
+1:2:-----S-:2150:2320:99:10:Wochenshow
+1:14:------S:2155:2245:99:10:AprilHailer
+1:2:--W----:2110:2325:99:99:BulleVonToelz
diff --git a/vdr.c b/vdr.c
index cbc0950..bcda471 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.12 2000/04/24 13:36:39 kls Exp $
+ * $Id: vdr.c 1.19 2000/05/27 15:38:35 kls Exp $
*/
#include <signal.h>
#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,15 +69,14 @@ int main(int argc, char *argv[])
if (signal(SIGTERM, SignalHandler) == SIG_IGN) signal(SIGTERM, SIG_IGN);
cMenuMain *Menu = NULL;
- cReplayDisplay *ReplayDisplay = NULL;
- cTimer *Timer = NULL;
+ cReplayControl *ReplayControl = NULL;
int dcTime = 0, dcNumber = 0;
int LastChannel = -1;
while (!Interrupted) {
// Channel display:
if (CurrentChannel != LastChannel) {
- if (!Menu && !ReplayDisplay) {
+ if (!Menu) {
cChannel *channel = Channels.Get(CurrentChannel);
if (channel)
Interface.DisplayChannel(CurrentChannel + 1, channel->name);
@@ -81,108 +84,80 @@ int main(int argc, char *argv[])
LastChannel = CurrentChannel;
}
// Direct Channel Select (action):
- if (dcNumber) {
- Interface.DisplayChannel(dcNumber);
- if (time_ms() - dcTime > DIRECTCHANNELTIMEOUT) {
- cChannel::SwitchTo(dcNumber - 1);
- dcNumber = 0;
- LastChannel = -1; // in case an invalid channel number was entered!
- }
+ if (dcNumber && time_ms() - dcTime > DIRECTCHANNELTIMEOUT) {
+ cChannel::SwitchTo(dcNumber - 1);
+ dcNumber = 0;
+ LastChannel = -1; // in case an invalid channel number was entered!
}
- // Timer Processing:
- else {
- AssertFreeDiskSpace();
- if (!Timer && (Timer = cTimer::GetMatch()) != NULL) {
- DELETENULL(Menu);
- DELETENULL(ReplayDisplay);
- // make sure the timer won't be deleted:
- Timer->SetRecording(true);
- // switch to channel:
- cChannel::SwitchTo(Timer->channel - 1);
- // start recording:
- cRecording Recording(Timer);
- DvbApi.StartRecord(Recording.FileName());
- }
- if (Timer && !Timer->Matches()) {
- // stop recording:
- DvbApi.StopRecord();
- // release timer:
- Timer->SetRecording(false);
- // clear single event timer:
- if (Timer->IsSingleEvent()) {
- DELETENULL(Menu); // must make sure no menu uses it
- isyslog(LOG_INFO, "deleting timer %d", Timer->Index() + 1);
- Timers.Del(Timer);
- Timers.Save();
+ // Timers and Recordings:
+ if (!Menu) {
+ cTimer *Timer = cTimer::GetMatch();
+ if (Timer) {
+ if (!cRecordControls::Start(Timer)) {
+ //TODO need to do something to prevent the timer from hitting over and over again...
}
- Timer = NULL;
}
+ cRecordControls::Process();
}
// User Input:
- eKeys key = Interface.GetKey(!ReplayDisplay);
- if (Menu) {
- switch (Menu->ProcessKey(key)) {
- default: if (key != kMenu)
- break;
+ cOsdBase **Interact = Menu ? (cOsdBase **)&Menu : (cOsdBase **)&ReplayControl;
+ eKeys key = Interface.GetKey(!*Interact || !(*Interact)->NeedsFastResponse());
+ if (*Interact) {
+ switch ((*Interact)->ProcessKey(key)) {
+ case osMenu: DELETENULL(Menu);
+ Menu = new cMenuMain(ReplayControl);
+ break;
+ case osRecord: DELETENULL(Menu);
+ if (!cRecordControls::Start())
+ Interface.Error("No free DVB device to record!");
+ break;
+ case osReplay: DELETENULL(Menu);
+ DELETENULL(ReplayControl);
+ ReplayControl = new cReplayControl;
+ break;
+ case osStopReplay:
+ DELETENULL(*Interact);
+ DELETENULL(ReplayControl);
+ break;
case osBack:
- case osEnd: DELETENULL(Menu);
- break;
+ case osEnd: DELETENULL(*Interact);
+ break;
+ default: ;
}
}
- else if (!ReplayDisplay || (key = ReplayDisplay->ProcessKey(key)) != kNone) {
+ else {
switch (key) {
// 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 (!(DvbApi.Recording() || DvbApi.Replaying())) {
- dcNumber = dcNumber * 10 + key - k0;
- dcTime = time_ms();
+ {
+ if (!Interface.Recording()) {
+ dcNumber = dcNumber * 10 + key - k0;
+ dcTime = time_ms();
+ Interface.DisplayChannel(dcNumber);
+ }
}
- }
- // Record/Replay Control:
- case kBegin: DvbApi.Skip(-INT_MAX); break;
- case kRecord: if (!(DvbApi.Recording() || DvbApi.Replaying())) {
- cTimer *timer = new cTimer(true);
- Timers.Add(timer);
- Timers.Save();
- }
- break;
- case kPause: DvbApi.PauseReplay(); break;
- case kStop: DELETENULL(ReplayDisplay);
- DvbApi.StopReplay();
- break;
- case kSearchBack: DvbApi.FastRewind(); break;
- case kSearchForward: DvbApi.FastForward(); break;
- case kSkipBack: DvbApi.Skip(-60); break;
- case kSkipForward: DvbApi.Skip(60); break;
- // Menu Control:
- case kMenu: DELETENULL(ReplayDisplay);
- Menu = new cMenuMain;
- Menu->Display();
- break;
+ break;
// Up/Down Channel Select:
case kUp:
- case kDown: if (!(DvbApi.Recording() || DvbApi.Replaying())) {
+ case kDown: if (!Interface.Recording()) {
int n = CurrentChannel + (key == kUp ? 1 : -1);
cChannel *channel = Channels.Get(n);
if (channel)
channel->Switch();
}
break;
+ // Menu Control:
+ case kMenu: Menu = new cMenuMain(ReplayControl); break;
// Viewing Control:
- case kOk: if (ReplayDisplay)
- DELETENULL(ReplayDisplay);
- else if (DvbApi.Replaying())
- ReplayDisplay = new cReplayDisplay;
- else
- LastChannel = -1; break; // forces channel display
+ case kOk: LastChannel = -1; break; // forces channel display
default: break;
}
}
}
isyslog(LOG_INFO, "caught signal %d", Interrupted);
- DvbApi.StopRecord();
- DvbApi.StopReplay();
+ delete Menu;
+ delete ReplayControl;
+ cDvbApi::Cleanup();
isyslog(LOG_INFO, "exiting");
closelog();
return 0;