mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Implemented recording and replaying with a single DVB card
This commit is contained in:
		
							
								
								
									
										9
									
								
								HISTORY
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								HISTORY
									
									
									
									
									
								
							| @@ -1431,9 +1431,16 @@ Video Disk Recorder Revision History | ||||
|   time changed into the future (thanks to Matthias Schniedermeyer for reporting | ||||
|   this one). | ||||
|  | ||||
| 2002-08-28: Version 1.1.9 | ||||
| 2002-09-04: Version 1.1.9 | ||||
|  | ||||
| - Fixed the 'newplugin' script to make it name the target for creating the | ||||
|   distribution package 'dist', as stated in the PLUGINS.html documentation. | ||||
|   If you have already created a plugin source directory and Makefile you may | ||||
|   want to check it and replace the 'package' target with 'dist' if necessary. | ||||
| - Changed device handling for being able to do simultaneous recording and | ||||
|   replay on the same device (Time Shifting). In order for this to work you need | ||||
|   to use a driver with a firmware version that has this feature implemented. | ||||
| - cDevice::ProvidesCa() is no longer virtual. The new function | ||||
|   cDevice::ProvidesChannel() is now used to determine whether a device can | ||||
|   receive a given channel, and by default this function returns false. So a | ||||
|   device that is a pure replaying device doesn't need to do anything here. | ||||
|   | ||||
							
								
								
									
										46
									
								
								PLUGINS.html
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								PLUGINS.html
									
									
									
									
									
								
							| @@ -21,18 +21,18 @@ VDR program and present itself to the user. | ||||
| The <i>inside</i> interface provides the plugin code access to VDR's internal data | ||||
| structures and allows it to hook itself into specific areas to perform special actions. | ||||
| <p> | ||||
| <!--X1.1.5--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%> | ||||
| Important modifications introduced in version 1.1.5 are marked like this. | ||||
| <!--X1.1.5--></td></tr></table> | ||||
| <!--X1.1.6--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%> | ||||
| <!--X1.1.6--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%> | ||||
| Important modifications introduced in version 1.1.6 are marked like this. | ||||
| <!--X1.1.6--></td></tr></table> | ||||
| <!--X1.1.7--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%> | ||||
| <!--X1.1.7--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%> | ||||
| Important modifications introduced in version 1.1.7 are marked like this. | ||||
| <!--X1.1.7--></td></tr></table> | ||||
| <!--X1.1.8--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%> | ||||
| <!--X1.1.8--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%> | ||||
| Important modifications introduced in version 1.1.8 are marked like this. | ||||
| <!--X1.1.8--></td></tr></table> | ||||
| <!--X1.1.9--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%> | ||||
| Important modifications introduced in version 1.1.9 are marked like this. | ||||
| <!--X1.1.9--></td></tr></table> | ||||
|  | ||||
| <a name="Part I - The Outside Interface"><hr><center><h1>Part I - The Outside Interface</h1></center> | ||||
|  | ||||
| @@ -352,20 +352,20 @@ these values inside the plugin. Here's an example: | ||||
|  | ||||
| <p><table><tr><td bgcolor=#F0F0F0><pre><br> | ||||
| bool cPluginHello::ProcessArgs(int argc, char *argv[]) | ||||
| {  | ||||
| { | ||||
|   // Implement command line argument processing here if applicable. | ||||
|   static struct option long_options[] = { | ||||
|        { "aaa",      required_argument, NULL, 'a' }, | ||||
|        { "bbb",      no_argument,       NULL, 'b' }, | ||||
|        { NULL } | ||||
|      }; | ||||
|    | ||||
|  | ||||
|   int c; | ||||
|   while ((c = getopt_long(argc, argv, "a:b", long_options, NULL)) != -1) { | ||||
|         switch (c) { | ||||
|           case 'a': option_a = optarg; | ||||
|                     break; | ||||
|           case 'b': option_b = true;  | ||||
|           case 'b': option_b = true; | ||||
|                     break; | ||||
|           default:  return false; | ||||
|           } | ||||
| @@ -609,7 +609,7 @@ public: | ||||
|   }; | ||||
|  | ||||
| cMenuSetupHello::cMenuSetupHello(void) | ||||
| {  | ||||
| { | ||||
|   newGreetingTime = GreetingTime; | ||||
|   newUseAlternateGreeting = UseAlternateGreeting; | ||||
|   Add(new cMenuEditIntItem( tr("Greeting time (s)"),      &newGreetingTime)); | ||||
| @@ -617,7 +617,7 @@ cMenuSetupHello::cMenuSetupHello(void) | ||||
| } | ||||
|  | ||||
| void cMenuSetupHello::Store(void) | ||||
| {  | ||||
| { | ||||
|   SetupStore("GreetingTime", GreetingTime = newGreetingTime); | ||||
|   SetupStore("UseAlternateGreeting", UseAlternateGreeting = newUseAlternateGreeting); | ||||
| } | ||||
| @@ -957,7 +957,7 @@ stream. There are no prerequisites regarding the length or alignment of an | ||||
| individual block of data. The sum of all blocks must simply result in the | ||||
| desired video data stream, and it must be delivered fast enough so that the | ||||
| DVB device doesn't run out of data. | ||||
| <!--X1.1.7--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%> | ||||
| <!--X1.1.7--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%> | ||||
| To avoid busy loops the player should call its member function | ||||
|  | ||||
| <p><table><tr><td bgcolor=#F0F0F0><pre><br> | ||||
| @@ -1034,7 +1034,7 @@ void DeviceStillPicture(const uchar *Data, int Length); | ||||
|  | ||||
| which can be called to display a still picture. VDR uses this function when handling | ||||
| its editing marks. A special case of a "player" might use this function to implement | ||||
| a "picture viewer".  | ||||
| a "picture viewer". | ||||
| <p> | ||||
| For detailed information on how to implement your own player, please take a look | ||||
| at VDR's <tt>cDvbPlayer</tt> and <tt>cDvbPlayerControl</tt> classes. | ||||
| @@ -1065,7 +1065,7 @@ enjoy additional players, since they will be able to control them with actions | ||||
| that they already know. If you absolutely want to do things differently, just go | ||||
| ahead - it's your show... | ||||
|  | ||||
| <!--X1.1.6--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%> | ||||
| <!--X1.1.6--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%> | ||||
| <hr><h2>Receivers</h2> | ||||
|  | ||||
| <center><i><b>Tapping into the stream...</b></i></center><p> | ||||
| @@ -1121,7 +1121,6 @@ If the <tt>cReceiver</tt> isn't needed any more, it may simply be <i>deleted</i> | ||||
| and will automatically detach itself from the <tt>cDevice</tt>. | ||||
| <!--X1.1.6--></td></tr></table> | ||||
|  | ||||
| <!--X1.1.5--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%> | ||||
| <hr><h2>The On Screen Display</h2> | ||||
|  | ||||
| <center><i><b>Express yourself</b></i></center><p> | ||||
| @@ -1151,9 +1150,8 @@ MyOsd->Create(...); | ||||
| to define an actual OSD drawing area (see VDR/osdbase.h for the declarations | ||||
| of these functions, and VDR/osd.c to see how VDR opens the OSD and sets up | ||||
| its windows and color depths). | ||||
| <!--X1.1.5--></td></tr></table> | ||||
|  | ||||
| <!--X1.1.6--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%> | ||||
| <!--X1.1.6--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%> | ||||
| <hr><h2>Devices</h2> | ||||
|  | ||||
| <center><i><b>Expanding the possibilities</b></i></center><p> | ||||
| @@ -1189,12 +1187,16 @@ the <tt>cDvbDevice</tt>, which is used to access the DVB PCI cards. | ||||
| If the new device can receive, it most likely needs to provide a way of | ||||
| selecting which channel it shall tune to: | ||||
|  | ||||
| <!--X1.1.9--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%> | ||||
| <p><table><tr><td bgcolor=#F0F0F0><pre><br> | ||||
| virtual bool SetChannelDevice(const cChannel *Channel); | ||||
| virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSwitchChannel = NULL); | ||||
| virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); | ||||
| </pre></td></tr></table><p> | ||||
|  | ||||
| This function will be called with the desired channel and shall return whether | ||||
| tuning to it was successful. | ||||
| These functions will be called with the desired channel and shall return whether | ||||
| this device can provide the requested channel and whether tuning to it was successful, | ||||
| repectively. | ||||
| <!--X1.1.9--></td></tr></table> | ||||
| <p> | ||||
| <b>Recording</b> | ||||
| <p> | ||||
| @@ -1226,7 +1228,7 @@ to indicate this to VDR. | ||||
| <p> | ||||
| The functions to implement replaying capabilites are | ||||
|  | ||||
| <!--X1.1.7--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%> | ||||
| <!--X1.1.7--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%> | ||||
| <p><table><tr><td bgcolor=#F0F0F0><pre><br> | ||||
| virtual bool HasDecoder(void) const; | ||||
| virtual bool SetPlayMode(ePlayMode PlayMode); | ||||
| @@ -1250,7 +1252,7 @@ virtual void SetVideoFormat(bool VideoFormat16_9); | ||||
| virtual void SetVolumeDevice(int Volume); | ||||
| </pre></td></tr></table><p> | ||||
|  | ||||
| <!--X1.1.8--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%> | ||||
| <!--X1.1.8--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%> | ||||
| <p> | ||||
| <b>On Screen Display</b> | ||||
| <p> | ||||
|   | ||||
							
								
								
									
										32
									
								
								config.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								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.104 2002/08/11 11:35:18 kls Exp $ | ||||
|  * $Id: config.c 1.105 2002/09/04 13:45:56 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "config.h" | ||||
| @@ -293,30 +293,6 @@ bool cChannel::Save(FILE *f) | ||||
|   return fprintf(f, ToText()) > 0; | ||||
| } | ||||
|  | ||||
| bool cChannel::Switch(cDevice *Device, bool Log) | ||||
| { | ||||
|   if (!Device) | ||||
|      Device = cDevice::PrimaryDevice(); | ||||
|   if (!(Device->IsPrimaryDevice() && Device->Receiving()) && !groupSep) { | ||||
|      if (Log) | ||||
|         isyslog("switching to channel %d", number); | ||||
|      for (int i = 3; i--;) { | ||||
|          switch (Device->SetChannel(this)) { | ||||
|            case scrOk:         return true; | ||||
|            case scrNoTransfer: if (Interface) | ||||
|                                   Interface->Error(tr("Can't start Transfer Mode!")); | ||||
|                                return false; | ||||
|            case scrFailed:     break; // loop will retry | ||||
|            } | ||||
|          esyslog("retrying"); | ||||
|          } | ||||
|      return false; | ||||
|      } | ||||
|   if (Device->IsPrimaryDevice() && Device->Receiving()) | ||||
|      Interface->Error(tr("Channel locked (recording)!")); | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| // -- cTimer ----------------------------------------------------------------- | ||||
|  | ||||
| char *cTimer::buffer = NULL; | ||||
| @@ -836,10 +812,10 @@ cChannel *cChannels::GetByServiceID(unsigned short ServiceId) | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| bool cChannels::SwitchTo(int Number, cDevice *Device) | ||||
| bool cChannels::SwitchTo(int Number) | ||||
| { | ||||
|   cChannel *channel = GetByNumber(Number); | ||||
|   return channel && channel->Switch(Device); | ||||
|   return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true); | ||||
| } | ||||
|  | ||||
| const char *cChannels::GetChannelNameByNumber(int Number) | ||||
| @@ -944,7 +920,7 @@ bool cSetupLine::operator< (const cListObject &ListObject) | ||||
| { | ||||
|   const cSetupLine *sl = (cSetupLine *)&ListObject; | ||||
|   if (!plugin && !sl->plugin) | ||||
|      return strcasecmp(name, sl->name) < 0;  | ||||
|      return strcasecmp(name, sl->name) < 0; | ||||
|   if (!plugin) | ||||
|      return true; | ||||
|   if (!sl->plugin) | ||||
|   | ||||
							
								
								
									
										7
									
								
								config.h
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								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.125 2002/08/28 19:26:56 kls Exp $ | ||||
|  * $Id: config.h 1.126 2002/09/04 11:04:55 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __CONFIG_H | ||||
| @@ -119,7 +119,6 @@ public: | ||||
|   const char *ToText(void); | ||||
|   bool Parse(const char *s); | ||||
|   bool Save(FILE *f); | ||||
|   bool Switch(cDevice *Device = NULL, bool Log = true); | ||||
|   }; | ||||
|  | ||||
| enum eTimerActive { taInactive = 0, | ||||
| @@ -198,6 +197,8 @@ public: | ||||
|   bool Accepts(in_addr_t Address); | ||||
|   }; | ||||
|  | ||||
| #define CACONFBASE 100 | ||||
|  | ||||
| class cCaDefinition : public cListObject { | ||||
| private: | ||||
|   int number; | ||||
| @@ -296,7 +297,7 @@ public: | ||||
|   cChannel *GetByNumber(int Number); | ||||
|   cChannel *GetByServiceID(unsigned short ServiceId); | ||||
|   const char *GetChannelNameByNumber(int Number); | ||||
|   bool SwitchTo(int Number, cDevice *Device = NULL); | ||||
|   bool SwitchTo(int Number); | ||||
|   int MaxNumber(void) { return maxNumber; } | ||||
|   }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										128
									
								
								device.c
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								device.c
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: device.c 1.13 2002/08/25 09:16:51 kls Exp $ | ||||
|  * $Id: device.c 1.14 2002/09/04 17:26:02 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "device.h" | ||||
| @@ -12,6 +12,7 @@ | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/mman.h> | ||||
| #include "eit.h" | ||||
| #include "i18n.h" | ||||
| #include "player.h" | ||||
| #include "receiver.h" | ||||
| #include "status.h" | ||||
| @@ -101,11 +102,6 @@ bool cDevice::SetPrimaryDevice(int n) | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool cDevice::CanBeReUsed(int Frequency, int Vpid) | ||||
| { | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool cDevice::HasDecoder(void) const | ||||
| { | ||||
|   return false; | ||||
| @@ -116,31 +112,26 @@ cOsdBase *cDevice::NewOsd(int x, int y) | ||||
|   return NULL; | ||||
| } | ||||
|  | ||||
| cDevice *cDevice::GetDevice(int Ca, int Priority, int Frequency, int Vpid, bool *ReUse) | ||||
| cDevice *cDevice::GetDevice(int Index) | ||||
| { | ||||
|   return (0 <= Index && Index < numDevices) ? device[Index] : NULL; | ||||
| } | ||||
|  | ||||
| cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsSwitchChannel) | ||||
| { | ||||
|   if (ReUse) | ||||
|      *ReUse = false; | ||||
|   cDevice *d = NULL; | ||||
|   int Provides[MAXDEVICES]; | ||||
|   // Check which devices provide Ca: | ||||
|   for (int i = 0; i < numDevices; i++) { | ||||
|       if ((Provides[i] = device[i]->ProvidesCa(Ca)) != 0) { // this device is basicly able to do the job | ||||
|          //XXX+ dsyslog("GetDevice: %d %d %d %5d %5d", i, device[i]->HasDecoder(), device[i]->Receiving(), Frequency, device[i]->frequency);//XXX | ||||
|          if (device[i]->CanBeReUsed(Frequency, Vpid)) { | ||||
|             d = device[i]; | ||||
|             if (ReUse) | ||||
|                *ReUse = true; | ||||
|             break; | ||||
|             } | ||||
|          if (Priority > device[i]->Priority() // Priority is high enough to use this device | ||||
|             && (!d // we don't have a device yet, or... | ||||
|                || device[i]->Priority() < d->Priority() // ...this one has an even lower Priority | ||||
|                || (device[i]->Priority() == d->Priority() // ...same Priority... | ||||
|                   && Provides[i] < Provides[d->CardIndex()] // ...but this one provides fewer Ca values | ||||
|                   ) | ||||
|                ) | ||||
|       bool nsc; | ||||
|       if (device[i]->ProvidesChannel(Channel, Priority, &nsc) // this device is basicly able to do the job | ||||
|          && (!d // we don't have a device yet, or... | ||||
|             || device[i]->Priority() < d->Priority() // ...this one has an even lower Priority, or... | ||||
|             || device[i]->Priority() == d->Priority() // ...same Priority... | ||||
|                && device[i]->ProvidesCa(Channel->ca) < d->ProvidesCa(Channel->ca) // ...but this one provides fewer Ca values | ||||
|             ) | ||||
|             d = device[i]; | ||||
|          ) { | ||||
|          d = device[i]; | ||||
|          if (NeedsSwitchChannel) | ||||
|             *NeedsSwitchChannel = nsc; | ||||
|          } | ||||
|       } | ||||
|   /*XXX+ too complex with multiple recordings per device | ||||
| @@ -189,9 +180,18 @@ void cDevice::SetVideoFormat(bool VideoFormat16_9) | ||||
| { | ||||
| } | ||||
|  | ||||
| //#define PRINTPIDS(s) { char b[500]; char *q = b; q += sprintf(q, "%d %s ", CardIndex(), s); for (int i = 0; i < MAXPIDHANDLES; i++) q += sprintf(q, " %s%4d %d", i == ptOther ? "* " : "", pidHandles[i].pid, pidHandles[i].used); dsyslog(b); } //XXX+ | ||||
| //#define PRINTPIDS(s) { char b[500]; char *q = b; q += sprintf(q, "%d %s ", CardIndex(), s); for (int i = 0; i < MAXPIDHANDLES; i++) q += sprintf(q, " %s%4d %d", i == ptOther ? "* " : "", pidHandles[i].pid, pidHandles[i].used); dsyslog(b); } | ||||
| #define PRINTPIDS(s) | ||||
|  | ||||
| bool cDevice::HasPid(int Pid) | ||||
| { | ||||
|   for (int i = 0; i < MAXPIDHANDLES; i++) { | ||||
|       if (pidHandles[i].pid == Pid) | ||||
|          return true; | ||||
|       } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool cDevice::AddPid(int Pid, ePidType PidType) | ||||
| { | ||||
|   if (Pid) { | ||||
| @@ -207,10 +207,10 @@ bool cDevice::AddPid(int Pid, ePidType PidType) | ||||
|         // The Pid is already in use | ||||
|         if (++pidHandles[n].used == 2 && n <= ptTeletext) { | ||||
|            // It's a special PID that may have to be switched into "tap" mode | ||||
|            PRINTPIDS("A");//XXX+ | ||||
|            PRINTPIDS("A"); | ||||
|            return SetPid(&pidHandles[n], n, true); | ||||
|            } | ||||
|         PRINTPIDS("a");//XXX+ | ||||
|         PRINTPIDS("a"); | ||||
|         return true; | ||||
|         } | ||||
|      else if (PidType < ptOther) { | ||||
| @@ -226,7 +226,7 @@ bool cDevice::AddPid(int Pid, ePidType PidType) | ||||
|      if (n >= 0) { | ||||
|         pidHandles[n].pid = Pid; | ||||
|         pidHandles[n].used = 1; | ||||
|         PRINTPIDS("C");//XXX+ | ||||
|         PRINTPIDS("C"); | ||||
|         return SetPid(&pidHandles[n], n, true); | ||||
|         } | ||||
|      } | ||||
| @@ -238,14 +238,15 @@ void cDevice::DelPid(int Pid) | ||||
|   if (Pid) { | ||||
|      for (int i = 0; i < MAXPIDHANDLES; i++) { | ||||
|          if (pidHandles[i].pid == Pid) { | ||||
|             PRINTPIDS("D"); | ||||
|             if (--pidHandles[i].used < 2) { | ||||
|                SetPid(&pidHandles[i], i, false); | ||||
|                if (pidHandles[i].used == 0) { | ||||
|                    pidHandles[i].handle = -1; | ||||
|                    pidHandles[i].pid = 0; | ||||
|                    } | ||||
|                   pidHandles[i].handle = -1; | ||||
|                   pidHandles[i].pid = 0; | ||||
|                   } | ||||
|                } | ||||
|             PRINTPIDS("D");//XXX+ | ||||
|             PRINTPIDS("E"); | ||||
|             } | ||||
|          } | ||||
|      } | ||||
| @@ -256,11 +257,35 @@ bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On) | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| eSetChannelResult cDevice::SetChannel(const cChannel *Channel) | ||||
| bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsSwitchChannel) | ||||
| { | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView) | ||||
| { | ||||
|   if (LiveView) | ||||
|      isyslog("switching to channel %d", Channel->number); | ||||
|   for (int i = 3; i--;) { | ||||
|       switch (SetChannel(Channel, LiveView)) { | ||||
|         case scrOk:           return true; | ||||
|         case scrNotAvailable: return false; | ||||
|         case scrNoTransfer:   if (Interface) | ||||
|                                  Interface->Error(tr("Can't start Transfer Mode!")); | ||||
|                               return false; | ||||
|         case scrFailed:       break; // loop will retry | ||||
|         } | ||||
|       esyslog("retrying"); | ||||
|       } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) | ||||
| { | ||||
|   cStatus::MsgChannelSwitch(this, 0); | ||||
|  | ||||
|   StopReplay(); | ||||
|   if (LiveView) | ||||
|      StopReplay(); | ||||
|  | ||||
|   // Must set this anyway to avoid getting stuck when switching through | ||||
|   // channels with 'Up' and 'Down' keys: | ||||
| @@ -269,7 +294,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel) | ||||
|   // If this card can't receive this channel, we must not actually switch | ||||
|   // the channel here, because that would irritate the driver when we | ||||
|   // start replaying in Transfer Mode immediately after switching the channel: | ||||
|   bool NeedsTransferMode = (IsPrimaryDevice() && !ProvidesCa(Channel->ca)); | ||||
|   bool NeedsTransferMode = (LiveView && IsPrimaryDevice() && !ProvidesChannel(Channel, Setup.PrimaryLimit)); | ||||
|  | ||||
|   eSetChannelResult Result = scrOk; | ||||
|  | ||||
| @@ -277,13 +302,18 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel) | ||||
|   // use the card that actually can receive it and transfer data from there: | ||||
|  | ||||
|   if (NeedsTransferMode) { | ||||
|      cDevice *CaDevice = GetDevice(Channel->ca, 0); | ||||
|      if (CaDevice && !CaDevice->Receiving() && CaDevice->SetChannel(Channel) == scrOk) | ||||
|         cControl::Launch(new cTransferControl(CaDevice, Channel->vpid, Channel->apid1, 0, 0, 0));//XXX+ | ||||
|      bool NeedsSwitchChannel = false; | ||||
|      cDevice *CaDevice = GetDevice(Channel, 0, &NeedsSwitchChannel); | ||||
|      if (CaDevice) { | ||||
|         if (!NeedsSwitchChannel || CaDevice->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()! | ||||
|            cControl::Launch(new cTransferControl(CaDevice, Channel->vpid, Channel->apid1, 0, 0, 0));//XXX+ | ||||
|         else | ||||
|            Result = scrNoTransfer; | ||||
|         } | ||||
|      else | ||||
|         Result = scrNoTransfer; | ||||
|         Result = scrNotAvailable; | ||||
|      } | ||||
|   else if (!SetChannelDevice(Channel)) | ||||
|   else if (!SetChannelDevice(Channel, LiveView)) | ||||
|      Result = scrFailed; | ||||
|  | ||||
|   if (IsPrimaryDevice()) | ||||
| @@ -294,7 +324,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel) | ||||
|   return Result; | ||||
| } | ||||
|  | ||||
| bool cDevice::SetChannelDevice(const cChannel *Channel) | ||||
| bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) | ||||
| { | ||||
|   return false; | ||||
| } | ||||
| @@ -357,10 +387,6 @@ bool cDevice::Replaying(void) | ||||
|  | ||||
| bool cDevice::AttachPlayer(cPlayer *Player) | ||||
| { | ||||
|   if (Receiving()) { | ||||
|      esyslog("ERROR: attempt to attach a cPlayer while receiving on device %d - ignored", CardIndex() + 1); | ||||
|      return false; | ||||
|      } | ||||
|   if (HasDecoder()) { | ||||
|      if (player) | ||||
|         Detach(player); | ||||
| @@ -419,9 +445,7 @@ int cDevice::PlayAudio(const uchar *Data, int Length) | ||||
|  | ||||
| int cDevice::Priority(void) | ||||
| { | ||||
|   if (IsPrimaryDevice() && !Receiving()) | ||||
|      return Setup.PrimaryLimit - 1; | ||||
|   int priority = DEFAULTPRIORITY; | ||||
|   int priority = IsPrimaryDevice() ? Setup.PrimaryLimit - 1 : DEFAULTPRIORITY; | ||||
|   for (int i = 0; i < MAXRECEIVERS; i++) { | ||||
|       if (receiver[i]) | ||||
|          priority = max(receiver[i]->priority, priority); | ||||
| @@ -551,12 +575,10 @@ int cDevice::GetTSPacket(uchar *Data) | ||||
|  | ||||
| bool cDevice::AttachReceiver(cReceiver *Receiver) | ||||
| { | ||||
|   //XXX+ check for same transponder??? | ||||
|   if (!Receiver) | ||||
|      return false; | ||||
|   if (Receiver->device == this) | ||||
|      return true; | ||||
|   StopReplay(); | ||||
|   for (int i = 0; i < MAXRECEIVERS; i++) { | ||||
|       if (!receiver[i]) { | ||||
|          for (int n = 0; n < MAXRECEIVEPIDS; n++) | ||||
|   | ||||
							
								
								
									
										64
									
								
								device.h
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								device.h
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: device.h 1.10 2002/08/25 09:16:34 kls Exp $ | ||||
|  * $Id: device.h 1.11 2002/09/04 11:33:12 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __DEVICE_H | ||||
| @@ -24,7 +24,7 @@ | ||||
| #define TS_SYNC_BYTE     0x47 | ||||
| #define PID_MASK_HI      0x1F | ||||
|  | ||||
| enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed }; | ||||
| enum eSetChannelResult { scrOk, scrNotAvailable, scrNoTransfer, scrFailed }; | ||||
|  | ||||
| enum ePlayMode { pmNone,       // audio/video from decoder | ||||
|                  pmAudioVideo, // audio/video from player | ||||
| @@ -69,19 +69,13 @@ public: | ||||
|          // 1...numDevices) and returns true if this was possible. | ||||
|   static cDevice *PrimaryDevice(void) { return primaryDevice; } | ||||
|          // Returns the primary device. | ||||
|   static cDevice *GetDevice(int Ca, int Priority, int Frequency = 0, int Vpid = 0, bool *ReUse = NULL); | ||||
|          // Selects a free device, avoiding the primaryDevice if possible. | ||||
|          // If Ca is not 0, the device with the given number will be returned | ||||
|          // in case Ca is <= MAXDEVICES, or the device that provides the given | ||||
|          // value in its caCaps. | ||||
|          // If there is a device that is already receiving and can be re-used to | ||||
|          // receive another data stream, that device will be returned. | ||||
|          // If all devices are currently receiving, the one receiving with the | ||||
|          // lowest priority (if any) that is lower than the given Priority | ||||
|          // will be returned. | ||||
|          // If ReUse is given, the caller will be informed whether the device can be re-used | ||||
|          // for a new recording. If ReUse returns 'true', the caller must NOT switch the channel | ||||
|          // (the device is already properly tuned). Otherwise the caller MUST switch the channel. | ||||
|   static cDevice *GetDevice(int Index); | ||||
|          // Returns the device with the Index (if Index is in the range | ||||
|          // 0..numDevices-1, NULL otherwise). | ||||
|   static cDevice *GetDevice(const cChannel *Channel, int Priority = -1, bool *NeedsSwitchChannel = NULL); | ||||
|          // Returns a device that is able to receive the given Channel at the | ||||
|          // given Priority (see ProvidesChannel() for more information on how | ||||
|          // priorities are handled, and the meaning of NeedsSwitchChannel). | ||||
|   static void SetCaCaps(int Index = -1); | ||||
|          // Sets the CaCaps of the given device according to the Setup data. | ||||
|          // By default the CaCaps of all devices are set. | ||||
| @@ -115,18 +109,13 @@ public: | ||||
|   bool IsPrimaryDevice(void) const { return this == primaryDevice; } | ||||
|   int CardIndex(void) const { return cardIndex; } | ||||
|          // Returns the card index of this device (0 ... MAXDEVICES - 1). | ||||
|   virtual int ProvidesCa(int Ca); | ||||
|          //XXX TODO temporarily made this function virtual - until a general | ||||
|          //XXX      mechanism has been implemented | ||||
|   int ProvidesCa(int Ca); | ||||
|          // Checks whether this device provides the given value in its | ||||
|          // caCaps. Returns 0 if the value is not provided, 1 if only this | ||||
|          // value is provided, and > 1 if this and other values are provided. | ||||
|          // If the given value is equal to the number of this device, | ||||
|          // 1 is returned. If it is 0 (FTA), 1 plus the number of other values | ||||
|          // in caCaps is returned. | ||||
|   virtual bool CanBeReUsed(int Frequency, int Vpid);//XXX TODO make it more abstract | ||||
|          // Tells whether this device is already receiving and allows another | ||||
|          // receiver with the given settings to be attached to it. | ||||
|   virtual bool HasDecoder(void) const; | ||||
|          // Tells whether this device has an MPEG decoder. | ||||
|  | ||||
| @@ -145,10 +134,33 @@ public: | ||||
| protected: | ||||
|   int currentChannel; | ||||
| public: | ||||
|   eSetChannelResult SetChannel(const cChannel *Channel); | ||||
|   virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSwitchChannel = NULL); | ||||
|          // Returns true if this device can provide the given channel. | ||||
|          // In case the device has cReceivers attached to it or it is the primary | ||||
|          // device, Priority is used to decide whether the caller's request can | ||||
|          // be honored. | ||||
|          // The special Priority value -1 will tell the caller whether this device | ||||
|          // is principally able to provide the given Channel, regardless of any | ||||
|          // attached cReceivers. | ||||
|          // If NeedsSwitchChannel is given, the resulting value in it will tell the | ||||
|          // caller whether or not it shall call SwitchChannel to actually switch the | ||||
|          // device to the desired channel. If NeedsSwitchChannel returns false, the | ||||
|          // caller must not call SwitchChannel, since there are receivers attached | ||||
|          // to the device and it is already switched to the given channel. Note | ||||
|          // that the return value in NeedsSwitchChannel is only meaningful if the | ||||
|          // function itself actually returns true. | ||||
|          // The default implementation always returns false, so a derived cDevice | ||||
|          // class that can provide channels must implement this function. | ||||
|   bool SwitchChannel(const cChannel *Channel, bool LiveView); | ||||
|          // Switches the device to the given Channel, initiating transfer mode | ||||
|          // if necessary. | ||||
| private: | ||||
|   eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView); | ||||
|          // Sets the device to the given channel (general setup). | ||||
|   virtual bool SetChannelDevice(const cChannel *Channel); | ||||
| protected: | ||||
|   virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); | ||||
|          // Sets the device to the given channel (actual physical setup). | ||||
| public: | ||||
|   static int CurrentChannel(void) { return primaryDevice ? primaryDevice->currentChannel : 0; } | ||||
|          // Returns the number of the current channel on the primary device. | ||||
|   int Channel(void) { return currentChannel; } | ||||
| @@ -169,6 +181,8 @@ protected: | ||||
|     cPidHandle(void) { pid = used = 0; handle = -1; } | ||||
|     }; | ||||
|   cPidHandle pidHandles[MAXPIDHANDLES]; | ||||
|   bool HasPid(int Pid); | ||||
|          // Returns true if this device is currently receiving the given PID. | ||||
|   bool AddPid(int Pid, ePidType PidType = ptOther); | ||||
|          // Adds a PID to the set of PIDs this device shall receive. | ||||
|   void DelPid(int Pid); | ||||
| @@ -263,12 +277,12 @@ public: | ||||
| private: | ||||
|   cReceiver *receiver[MAXRECEIVERS]; | ||||
|   int ca; | ||||
|   int CanShift(int Ca, int Priority, int UsedCards = 0); | ||||
| protected: | ||||
|   int Priority(void); | ||||
|       // Returns the priority of the current receiving session (0..MAXPRIORITY), | ||||
|       // or -1 if no receiver is currently active. The primary device will | ||||
|       // always return at least Setup.PrimaryLimit-1. | ||||
|   int CanShift(int Ca, int Priority, int UsedCards = 0); | ||||
| protected: | ||||
|   virtual bool OpenDvr(void); | ||||
|       // Opens the DVR of this device and prepares it to deliver a Transport | ||||
|       // Stream for use in a cReceiver. | ||||
|   | ||||
							
								
								
									
										412
									
								
								dvbdevice.c
									
									
									
									
									
								
							
							
						
						
									
										412
									
								
								dvbdevice.c
									
									
									
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: dvbdevice.c 1.8 2002/08/25 09:20:53 kls Exp $ | ||||
|  * $Id: dvbdevice.c 1.9 2002/09/04 13:46:03 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "dvbdevice.h" | ||||
| @@ -20,10 +20,12 @@ extern "C" { | ||||
| #include <linux/videodev.h> | ||||
| #ifdef NEWSTRUCT | ||||
| #include <linux/dvb/audio.h> | ||||
| #include <linux/dvb/dmx.h> | ||||
| #include <linux/dvb/frontend.h> | ||||
| #include <linux/dvb/video.h> | ||||
| #else | ||||
| #include <ost/audio.h> | ||||
| #include <ost/dmx.h> | ||||
| #include <ost/sec.h> | ||||
| #include <ost/video.h> | ||||
| #endif | ||||
| @@ -35,8 +37,6 @@ extern "C" { | ||||
| #include "status.h" | ||||
| #include "transfer.h" | ||||
|  | ||||
| #define MAXDVBDEVICES     4 | ||||
|  | ||||
| #define DEV_VIDEO         "/dev/video" | ||||
| #ifdef NEWSTRUCT | ||||
| #define DEV_DVB_ADAPTER   "/dev/dvb/adapter" | ||||
| @@ -91,10 +91,10 @@ cDvbDevice::cDvbDevice(int n) | ||||
|   fd_osd      = DvbOpen(DEV_DVB_OSD,    n, O_RDWR); | ||||
|   fd_video    = DvbOpen(DEV_DVB_VIDEO,  n, O_RDWR | O_NONBLOCK); | ||||
|   fd_audio    = DvbOpen(DEV_DVB_AUDIO,  n, O_RDWR | O_NONBLOCK); | ||||
|    | ||||
|  | ||||
| #ifndef NEWSTRUCT | ||||
|   // Devices that are only present on DVB-S cards: | ||||
|   | ||||
|  | ||||
|   fd_sec      = DvbOpen(DEV_DVB_SEC,      n, O_RDWR); | ||||
| #endif | ||||
|  | ||||
| @@ -179,15 +179,6 @@ void cDvbDevice::MakePrimaryDevice(bool On) | ||||
|   cDvbOsd::SetDvbDevice(On ? this : NULL); | ||||
| } | ||||
|  | ||||
| bool cDvbDevice::CanBeReUsed(int Frequency, int Vpid) | ||||
| { | ||||
|   return Receiving() // to be reused the DVB device must already be receiving... | ||||
|       && frequency == Frequency // ...and tuned to the requested frequency... | ||||
|       && (!HasDecoder() // ...and either be a "budget card" which can receive multiple channels... | ||||
|           || pidHandles[ptVideo].pid == Vpid // ...or be a "full featured card" that's already tuned to the requested video PID | ||||
|          ); | ||||
| } | ||||
|  | ||||
| bool cDvbDevice::HasDecoder(void) const | ||||
| { | ||||
|   return fd_video >= 0 && fd_audio >= 0; | ||||
| @@ -235,10 +226,10 @@ bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int Siz | ||||
|                mem1[0] = tmp; | ||||
|                mem1 += 3; | ||||
|                } | ||||
|           | ||||
|  | ||||
|            if (Quality < 0) | ||||
|               Quality = 255; //XXX is this 'best'??? | ||||
|           | ||||
|  | ||||
|            isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height); | ||||
|            FILE *f = fopen(FileName, "wb"); | ||||
|            if (f) { | ||||
| @@ -253,11 +244,11 @@ bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int Siz | ||||
|                  cinfo.image_height = vm.height; | ||||
|                  cinfo.input_components = 3; | ||||
|                  cinfo.in_color_space = JCS_RGB; | ||||
|           | ||||
|  | ||||
|                  jpeg_set_defaults(&cinfo); | ||||
|                  jpeg_set_quality(&cinfo, Quality, true); | ||||
|                  jpeg_start_compress(&cinfo, true); | ||||
|           | ||||
|  | ||||
|                  int rs = vm.width * 3; | ||||
|                  JSAMPROW rp[vm.height]; | ||||
|                  for (int k = 0; k < vm.height; k++) | ||||
| @@ -313,6 +304,14 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On) | ||||
|      else { | ||||
|         CHECK(ioctl(Handle->handle, DMX_STOP)); | ||||
|         if (Handle->used == 0) { | ||||
|            dmxPesFilterParams pesFilterParams; | ||||
|            memset(&pesFilterParams, 0, sizeof(pesFilterParams)); | ||||
|            pesFilterParams.pid     = 0x1FFF; | ||||
|            pesFilterParams.input   = DMX_IN_FRONTEND; | ||||
|            pesFilterParams.output  = DMX_OUT_DECODER; | ||||
|            pesFilterParams.pesType = PesTypes[Type < ptOther ? Type : ptOther]; | ||||
|            pesFilterParams.flags   = DMX_IMMEDIATE_START; | ||||
|            CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams)); | ||||
|            close(Handle->handle); | ||||
|            Handle->handle = -1; | ||||
|            return true; | ||||
| @@ -339,8 +338,58 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On) | ||||
|   return true; | ||||
| } | ||||
|  | ||||
| bool cDvbDevice::SetChannelDevice(const cChannel *Channel) | ||||
| bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsSwitchChannel) | ||||
| { | ||||
|   bool result = false; | ||||
|   bool hasPriority = Priority < 0 || Priority > this->Priority(); | ||||
|   bool needsSwitchChannel = true; | ||||
|  | ||||
|   if (ProvidesCa(Channel->ca)) { | ||||
|      if (Receiving()) { | ||||
|         if (frequency == Channel->frequency) { | ||||
|            needsSwitchChannel = false; | ||||
|            if (!HasPid(Channel->vpid)) { | ||||
|               if (Channel->ca > CACONFBASE) { | ||||
|                  needsSwitchChannel = true; | ||||
|                  result = hasPriority; | ||||
|                  } | ||||
|               else if (!HasDecoder()) | ||||
|                  result = true; // if it has no decoder it can't be the primary device | ||||
|               else { | ||||
| #define DVB_DRIVER_VERSION 2002090101 //XXX+ | ||||
| #define MIN_DVB_DRIVER_VERSION_FOR_TIMESHIFT 2002090101 | ||||
| #ifdef DVB_DRIVER_VERSION | ||||
| #if (DVB_DRIVER_VERSION >= MIN_DVB_DRIVER_VERSION_FOR_TIMESHIFT) | ||||
|                  if (pidHandles[ptVideo].used) | ||||
|                     needsSwitchChannel = true; // to have it turn off the live PIDs | ||||
|                  result = !IsPrimaryDevice() || Priority >= Setup.PrimaryLimit; | ||||
| #endif | ||||
| #else | ||||
| #warning "DVB_DRIVER_VERSION not defined - time shift with only one DVB device disabled!" | ||||
| #endif | ||||
|                  } | ||||
|               } | ||||
|            else | ||||
|               result = !IsPrimaryDevice() || Priority >= Setup.PrimaryLimit; | ||||
|            } | ||||
|         else | ||||
|            result = hasPriority; | ||||
|         } | ||||
|      else | ||||
|         result = hasPriority; | ||||
|      } | ||||
|   if (NeedsSwitchChannel) | ||||
|      *NeedsSwitchChannel = needsSwitchChannel; | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView) | ||||
| { | ||||
| #if (DVB_DRIVER_VERSION < MIN_DVB_DRIVER_VERSION_FOR_TIMESHIFT) | ||||
|   if (HasDecoder()) | ||||
|      LiveView = true; | ||||
| #endif | ||||
|  | ||||
|   // Avoid noise while switching: | ||||
|  | ||||
|   if (HasDecoder()) { | ||||
| @@ -357,204 +406,209 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel) | ||||
|  | ||||
|   // Turn off current PIDs: | ||||
|  | ||||
|   if (HasDecoder()) { | ||||
|   if (HasDecoder() && (LiveView || pidHandles[ptVideo].pid == Channel->vpid)) { | ||||
|      DelPid(pidHandles[ptVideo].pid); | ||||
|      DelPid(pidHandles[ptAudio].pid); | ||||
|      DelPid(pidHandles[ptTeletext].pid); | ||||
|      DelPid(pidHandles[ptDolby].pid); | ||||
|      } | ||||
|  | ||||
|   if (frequency != Channel->frequency || Channel->ca > CACONFBASE) { // CA channels can only be decrypted in "live" mode | ||||
|  | ||||
| #ifdef NEWSTRUCT | ||||
|   dvb_frontend_parameters Frontend; | ||||
|      dvb_frontend_parameters Frontend; | ||||
| #else | ||||
|   FrontendParameters Frontend; | ||||
|      FrontendParameters Frontend; | ||||
| #endif | ||||
|  | ||||
|   memset(&Frontend, 0, sizeof(Frontend)); | ||||
|      memset(&Frontend, 0, sizeof(Frontend)); | ||||
|  | ||||
|   switch (frontendType) { | ||||
|     case FE_QPSK: { // DVB-S | ||||
|      switch (frontendType) { | ||||
|        case FE_QPSK: { // DVB-S | ||||
|  | ||||
|          // Frequency offsets: | ||||
|             // Frequency offsets: | ||||
|  | ||||
|          unsigned int freq = Channel->frequency; | ||||
|          int tone = SEC_TONE_OFF; | ||||
|             unsigned int freq = Channel->frequency; | ||||
|             int tone = SEC_TONE_OFF; | ||||
|  | ||||
|          if (freq < (unsigned int)Setup.LnbSLOF) { | ||||
|             freq -= Setup.LnbFrequLo; | ||||
|             tone = SEC_TONE_OFF; | ||||
|             if (freq < (unsigned int)Setup.LnbSLOF) { | ||||
|                freq -= Setup.LnbFrequLo; | ||||
|                tone = SEC_TONE_OFF; | ||||
|                } | ||||
|             else { | ||||
|                freq -= Setup.LnbFrequHi; | ||||
|                tone = SEC_TONE_ON; | ||||
|                } | ||||
|  | ||||
| #ifdef NEWSTRUCT | ||||
|             Frontend.frequency = freq * 1000UL; | ||||
|             Frontend.inversion = INVERSION_AUTO; | ||||
|             Frontend.u.qpsk.symbol_rate = Channel->srate * 1000UL; | ||||
|             Frontend.u.qpsk.fec_inner = FEC_AUTO; | ||||
| #else | ||||
|             Frontend.Frequency = freq * 1000UL; | ||||
|             Frontend.Inversion = INVERSION_AUTO; | ||||
|             Frontend.u.qpsk.SymbolRate = Channel->srate * 1000UL; | ||||
|             Frontend.u.qpsk.FEC_inner = FEC_AUTO; | ||||
| #endif | ||||
|  | ||||
|             int volt = (Channel->polarization == 'v' || Channel->polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; | ||||
|  | ||||
|             // DiSEqC: | ||||
|  | ||||
| #ifdef NEWSTRUCT | ||||
|             struct dvb_diseqc_master_cmd cmd = { {0xE0, 0x10, 0x38, 0xF0, 0x00, 0x00}, 4}; | ||||
|             cmd.msg[3] = 0xF0 | (((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0)); | ||||
|  | ||||
|             if (Setup.DiSEqC) | ||||
|                CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); | ||||
|             CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt)); | ||||
|             if (Setup.DiSEqC) { | ||||
|                usleep(15 * 1000); | ||||
|                CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); | ||||
|                usleep(15 * 1000); | ||||
|                CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, (Channel->diseqc / 4) % 2 ? SEC_MINI_B : SEC_MINI_A)); | ||||
|                usleep(15 * 1000); | ||||
|                } | ||||
|             CHECK(ioctl(fd_frontend, FE_SET_TONE, tone)); | ||||
| #else | ||||
|             secCommand scmd; | ||||
|             scmd.type = 0; | ||||
|             scmd.u.diseqc.addr = 0x10; | ||||
|             scmd.u.diseqc.cmd = 0x38; | ||||
|             scmd.u.diseqc.numParams = 1; | ||||
|             scmd.u.diseqc.params[0] = 0xF0 | ((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0); | ||||
|  | ||||
|             secCmdSequence scmds; | ||||
|             scmds.voltage = volt; | ||||
|             scmds.miniCommand = SEC_MINI_NONE; | ||||
|             scmds.continuousTone = tone; | ||||
|             scmds.numCommands = Setup.DiSEqC ? 1 : 0; | ||||
|             scmds.commands = &scmd; | ||||
|  | ||||
|             CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); | ||||
| #endif | ||||
|             } | ||||
|          else { | ||||
|             freq -= Setup.LnbFrequHi; | ||||
|             tone = SEC_TONE_ON; | ||||
|             break; | ||||
|        case FE_QAM: { // DVB-C | ||||
|  | ||||
|             // Frequency and symbol rate: | ||||
|  | ||||
| #ifdef NEWSTRUCT | ||||
|             Frontend.frequency = Channel->frequency * 1000000UL; | ||||
|             Frontend.inversion = INVERSION_AUTO; | ||||
|             Frontend.u.qam.symbol_rate = Channel->srate * 1000UL; | ||||
|             Frontend.u.qam.fec_inner = FEC_AUTO; | ||||
|             Frontend.u.qam.modulation = QAM_64; | ||||
| #else | ||||
|             Frontend.Frequency = Channel->frequency * 1000000UL; | ||||
|             Frontend.Inversion = INVERSION_AUTO; | ||||
|             Frontend.u.qam.SymbolRate = Channel->srate * 1000UL; | ||||
|             Frontend.u.qam.FEC_inner = FEC_AUTO; | ||||
|             Frontend.u.qam.QAM = QAM_64; | ||||
| #endif | ||||
|             } | ||||
|             break; | ||||
|        case FE_OFDM: { // DVB-T | ||||
|  | ||||
|             // Frequency and OFDM paramaters: | ||||
|  | ||||
| #ifdef NEWSTRUCT | ||||
|          Frontend.frequency = freq * 1000UL; | ||||
|          Frontend.inversion = INVERSION_AUTO; | ||||
|          Frontend.u.qpsk.symbol_rate = Channel->srate * 1000UL; | ||||
|          Frontend.u.qpsk.fec_inner = FEC_AUTO; | ||||
|             Frontend.frequency = Channel->frequency * 1000UL; | ||||
|             Frontend.inversion = INVERSION_AUTO; | ||||
|             Frontend.u.ofdm.bandwidth=BANDWIDTH_8_MHZ; | ||||
|             Frontend.u.ofdm.code_rate_HP = FEC_2_3; | ||||
|             Frontend.u.ofdm.code_rate_LP = FEC_1_2; | ||||
|             Frontend.u.ofdm.constellation = QAM_64; | ||||
|             Frontend.u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; | ||||
|             Frontend.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; | ||||
|             Frontend.u.ofdm.hierarchy_information = HIERARCHY_NONE; | ||||
| #else | ||||
|          Frontend.Frequency = freq * 1000UL; | ||||
|          Frontend.Inversion = INVERSION_AUTO; | ||||
|          Frontend.u.qpsk.SymbolRate = Channel->srate * 1000UL; | ||||
|          Frontend.u.qpsk.FEC_inner = FEC_AUTO; | ||||
|             Frontend.Frequency = Channel->frequency * 1000UL; | ||||
|             Frontend.Inversion = INVERSION_AUTO; | ||||
|             Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ; | ||||
|             Frontend.u.ofdm.HP_CodeRate=FEC_2_3; | ||||
|             Frontend.u.ofdm.LP_CodeRate=FEC_1_2; | ||||
|             Frontend.u.ofdm.Constellation=QAM_64; | ||||
|             Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K; | ||||
|             Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32; | ||||
|             Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE; | ||||
| #endif | ||||
|  | ||||
|          int volt = (Channel->polarization == 'v' || Channel->polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18; | ||||
|  | ||||
|          // DiSEqC: | ||||
|  | ||||
| #ifdef NEWSTRUCT | ||||
|          struct dvb_diseqc_master_cmd cmd = { {0xE0, 0x10, 0x38, 0xF0, 0x00, 0x00}, 4}; | ||||
|          cmd.msg[3] = 0xF0 | (((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0)); | ||||
|  | ||||
|          if (Setup.DiSEqC) | ||||
|             CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF)); | ||||
|          CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt)); | ||||
|          if (Setup.DiSEqC) { | ||||
|             usleep(15 * 1000); | ||||
|             CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd)); | ||||
|             usleep(15 * 1000); | ||||
|             CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, (Channel->diseqc / 4) % 2 ? SEC_MINI_B : SEC_MINI_A)); | ||||
|             usleep(15 * 1000); | ||||
|             } | ||||
|          CHECK(ioctl(fd_frontend, FE_SET_TONE, tone)); | ||||
| #else | ||||
|          secCommand scmd; | ||||
|          scmd.type = 0; | ||||
|          scmd.u.diseqc.addr = 0x10; | ||||
|          scmd.u.diseqc.cmd = 0x38; | ||||
|          scmd.u.diseqc.numParams = 1; | ||||
|          scmd.u.diseqc.params[0] = 0xF0 | ((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0); | ||||
|             break; | ||||
|        default: | ||||
|             esyslog("ERROR: attempt to set channel with unknown DVB frontend type"); | ||||
|             return false; | ||||
|        } | ||||
|  | ||||
|          secCmdSequence scmds; | ||||
|          scmds.voltage = volt; | ||||
|          scmds.miniCommand = SEC_MINI_NONE; | ||||
|          scmds.continuousTone = tone; | ||||
|          scmds.numCommands = Setup.DiSEqC ? 1 : 0; | ||||
|          scmds.commands = &scmd; | ||||
| #ifdef NEWSTRUCT | ||||
|      // Discard stale events: | ||||
|  | ||||
|          CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds)); | ||||
| #endif | ||||
|      for (;;) { | ||||
|          dvb_frontend_event event; | ||||
|          if (ioctl(fd_frontend, FE_GET_EVENT, &event) < 0) | ||||
|             break; | ||||
|          } | ||||
|          break; | ||||
|     case FE_QAM: { // DVB-C | ||||
| #endif | ||||
|  | ||||
|          // Frequency and symbol rate: | ||||
|      // Tuning: | ||||
|  | ||||
|      CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); | ||||
|  | ||||
|      // Wait for channel lock: | ||||
|  | ||||
| #ifdef NEWSTRUCT | ||||
|          Frontend.frequency = Channel->frequency * 1000000UL; | ||||
|          Frontend.inversion = INVERSION_AUTO; | ||||
|          Frontend.u.qam.symbol_rate = Channel->srate * 1000UL; | ||||
|          Frontend.u.qam.fec_inner = FEC_AUTO; | ||||
|          Frontend.u.qam.modulation = QAM_64; | ||||
| #else | ||||
|          Frontend.Frequency = Channel->frequency * 1000000UL; | ||||
|          Frontend.Inversion = INVERSION_AUTO; | ||||
|          Frontend.u.qam.SymbolRate = Channel->srate * 1000UL; | ||||
|          Frontend.u.qam.FEC_inner = FEC_AUTO; | ||||
|          Frontend.u.qam.QAM = QAM_64; | ||||
| #endif | ||||
|      FrontendStatus status = FrontendStatus(0); | ||||
|      for (int i = 0; i < 100; i++) { | ||||
|          CHECK(ioctl(fd_frontend, FE_READ_STATUS, &status)); | ||||
|          if (status & FE_HAS_LOCK) | ||||
|             break; | ||||
|          usleep(10 * 1000); | ||||
|          } | ||||
|          break; | ||||
|     case FE_OFDM: { // DVB-T | ||||
|  | ||||
|          // Frequency and OFDM paramaters: | ||||
|  | ||||
| #ifdef NEWSTRUCT | ||||
|          Frontend.frequency = Channel->frequency * 1000UL; | ||||
|          Frontend.inversion = INVERSION_AUTO; | ||||
|          Frontend.u.ofdm.bandwidth=BANDWIDTH_8_MHZ; | ||||
|          Frontend.u.ofdm.code_rate_HP = FEC_2_3; | ||||
|          Frontend.u.ofdm.code_rate_LP = FEC_1_2; | ||||
|          Frontend.u.ofdm.constellation = QAM_64; | ||||
|          Frontend.u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; | ||||
|          Frontend.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; | ||||
|          Frontend.u.ofdm.hierarchy_information = HIERARCHY_NONE; | ||||
|      if (!(status & FE_HAS_LOCK)) { | ||||
|         esyslog("ERROR: channel %d not locked on DVB card %d!", Channel->number, CardIndex() + 1); | ||||
|         if (IsPrimaryDevice()) | ||||
|            cThread::RaisePanic(); | ||||
|         return false; | ||||
|         } | ||||
| #else | ||||
|          Frontend.Frequency = Channel->frequency * 1000UL; | ||||
|          Frontend.Inversion = INVERSION_AUTO; | ||||
|          Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ; | ||||
|          Frontend.u.ofdm.HP_CodeRate=FEC_2_3; | ||||
|          Frontend.u.ofdm.LP_CodeRate=FEC_1_2; | ||||
|          Frontend.u.ofdm.Constellation=QAM_64; | ||||
|          Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K; | ||||
|          Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32; | ||||
|          Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE; | ||||
| #endif | ||||
|          } | ||||
|          break; | ||||
|     default: | ||||
|          esyslog("ERROR: attempt to set channel with unknown DVB frontend type"); | ||||
|          return false; | ||||
|     } | ||||
|  | ||||
| #ifdef NEWSTRUCT | ||||
|   // Discard stale events: | ||||
|  | ||||
|   for (;;) { | ||||
|       dvb_frontend_event event; | ||||
|       if (ioctl(fd_frontend, FE_GET_EVENT, &event) < 0) | ||||
|          break; | ||||
|       } | ||||
| #endif | ||||
|  | ||||
|   // Tuning: | ||||
|  | ||||
|   CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend)); | ||||
|  | ||||
|   // Wait for channel lock: | ||||
|  | ||||
| #ifdef NEWSTRUCT | ||||
|   FrontendStatus status = FrontendStatus(0); | ||||
|   for (int i = 0; i < 100; i++) { | ||||
|       CHECK(ioctl(fd_frontend, FE_READ_STATUS, &status)); | ||||
|       if (status & FE_HAS_LOCK) | ||||
|          break; | ||||
|       usleep(10 * 1000); | ||||
|       } | ||||
|   if (!(status & FE_HAS_LOCK)) { | ||||
|      esyslog("ERROR: channel %d not locked on DVB card %d!", Channel->number, CardIndex() + 1); | ||||
|      if (IsPrimaryDevice()) | ||||
|         cThread::RaisePanic(); | ||||
|      return false; | ||||
|      } | ||||
| #else | ||||
|   if (cFile::FileReady(fd_frontend, 5000)) { | ||||
|      FrontendEvent event; | ||||
|      if (ioctl(fd_frontend, FE_GET_EVENT, &event) >= 0) { | ||||
|         if (event.type != FE_COMPLETION_EV) { | ||||
|            esyslog("ERROR: channel %d not sync'ed on DVB card %d!", Channel->number, CardIndex() + 1); | ||||
|            if (IsPrimaryDevice()) | ||||
|               cThread::RaisePanic(); | ||||
|            return false; | ||||
|      if (cFile::FileReady(fd_frontend, 5000)) { | ||||
|         FrontendEvent event; | ||||
|         if (ioctl(fd_frontend, FE_GET_EVENT, &event) >= 0) { | ||||
|            if (event.type != FE_COMPLETION_EV) { | ||||
|               esyslog("ERROR: channel %d not sync'ed on DVB card %d!", Channel->number, CardIndex() + 1); | ||||
|               if (IsPrimaryDevice()) | ||||
|                  cThread::RaisePanic(); | ||||
|               return false; | ||||
|               } | ||||
|            } | ||||
|         else | ||||
|            esyslog("ERROR in frontend get event (channel %d, card %d): %m", Channel->number, CardIndex() + 1); | ||||
|         } | ||||
|      else | ||||
|         esyslog("ERROR in frontend get event (channel %d, card %d): %m", Channel->number, CardIndex() + 1); | ||||
|      } | ||||
|   else | ||||
|      esyslog("ERROR: timeout while tuning on DVB card %d", CardIndex() + 1); | ||||
|         esyslog("ERROR: timeout while tuning on DVB card %d", CardIndex() + 1); | ||||
| #endif | ||||
|  | ||||
|   frequency = Channel->frequency; | ||||
|      frequency = Channel->frequency; | ||||
|  | ||||
|      } | ||||
|  | ||||
|   // PID settings: | ||||
|  | ||||
|   if (HasDecoder()) { | ||||
|      if (!(AddPid(Channel->vpid, ptVideo) && AddPid(Channel->apid1, ptAudio))) {//XXX+ dolby dpid1!!! (if audio plugins are attached) | ||||
|         esyslog("ERROR: failed to set PIDs for channel %d", Channel->number); | ||||
|         return false; | ||||
|   if (HasDecoder() && (LiveView || Channel->ca > CACONFBASE)) { // CA channels can only be decrypted in "live" mode | ||||
|      if (!HasPid(Channel->vpid)) { | ||||
|         if (!(AddPid(Channel->vpid, ptVideo) && AddPid(Channel->apid1, ptAudio))) {//XXX+ dolby dpid1!!! (if audio plugins are attached) | ||||
|            esyslog("ERROR: failed to set PIDs for channel %d", Channel->number); | ||||
|            return false; | ||||
|            } | ||||
|         if (IsPrimaryDevice()) | ||||
|            AddPid(Channel->tpid, ptTeletext); | ||||
|         CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); | ||||
|         CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); | ||||
|         CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); | ||||
|         } | ||||
|      if (IsPrimaryDevice()) | ||||
|         AddPid(Channel->tpid, ptTeletext); | ||||
|      CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true)); | ||||
|      } | ||||
|  | ||||
|   if (HasDecoder()) { | ||||
|      CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false)); | ||||
|      CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false)); | ||||
|      else | ||||
|         cControl::Launch(new cTransferControl(this, Channel->vpid, Channel->apid1, 0, 0, 0)); | ||||
|      } | ||||
|  | ||||
|   // Start setting system time: | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: dvbdevice.h 1.6 2002/08/25 09:19:34 kls Exp $ | ||||
|  * $Id: dvbdevice.h 1.7 2002/09/04 13:31:42 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #ifndef __DVBDEVICE_H | ||||
| @@ -23,6 +23,8 @@ | ||||
| #include "device.h" | ||||
| #include "eit.h" | ||||
|  | ||||
| #define MAXDVBDEVICES  4 | ||||
|  | ||||
| class cDvbDevice : public cDevice { | ||||
|   friend class cDvbOsd; | ||||
| private: | ||||
| @@ -45,7 +47,6 @@ protected: | ||||
| public: | ||||
|   cDvbDevice(int n); | ||||
|   virtual ~cDvbDevice(); | ||||
|   virtual bool CanBeReUsed(int Frequency, int Vpid); | ||||
|   virtual bool HasDecoder(void) const; | ||||
|  | ||||
| // OSD facilities | ||||
| @@ -58,7 +59,9 @@ public: | ||||
| private: | ||||
|   int frequency; | ||||
| public: | ||||
|   virtual bool SetChannelDevice(const cChannel *Channel); | ||||
|   virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSwitchChannel = NULL); | ||||
| protected: | ||||
|   virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView); | ||||
|  | ||||
| // PID handle facilities | ||||
|  | ||||
|   | ||||
							
								
								
									
										17
									
								
								eitscan.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								eitscan.c
									
									
									
									
									
								
							| @@ -4,11 +4,12 @@ | ||||
|  * See the main source file 'vdr.c' for copyright information and | ||||
|  * how to reach the author. | ||||
|  * | ||||
|  * $Id: eitscan.c 1.5 2002/08/11 11:11:39 kls Exp $ | ||||
|  * $Id: eitscan.c 1.6 2002/09/04 13:32:38 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "eitscan.h" | ||||
| #include <stdlib.h> | ||||
| #include "dvbdevice.h" | ||||
|  | ||||
| cEITScanner::cEITScanner(void) | ||||
| { | ||||
| @@ -49,9 +50,9 @@ void cEITScanner::Process(void) | ||||
|   if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) { | ||||
|      time_t now = time(NULL); | ||||
|      if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) { | ||||
|         for (int i = 0; i < MAXDEVICES; i++) { | ||||
|             cDevice *Device = cDevice::GetDevice(i + 1, MAXPRIORITY + 1); | ||||
|             if (Device) { | ||||
|         for (int i = 0; i < cDevice::NumDevices(); i++) { | ||||
|             cDevice *Device = cDevice::GetDevice(i); | ||||
|             if (Device && Device->CardIndex() < MAXDVBDEVICES) { | ||||
|                if (Device != cDevice::PrimaryDevice() || (cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) { | ||||
|                   if (!(Device->Receiving() || Device->Replaying())) { | ||||
|                      int oldCh = lastChannel; | ||||
| @@ -63,12 +64,12 @@ void cEITScanner::Process(void) | ||||
|                               } | ||||
|                            cChannel *Channel = Channels.GetByNumber(ch); | ||||
|                            if (Channel) { | ||||
|                               if (Channel->ca <= MAXDEVICES && !Device->ProvidesCa(Channel->ca)) | ||||
|                                  break; // the channel says it explicitly needs a different card | ||||
|                               if (!Device->ProvidesChannel(Channel)) | ||||
|                                  break; | ||||
|                               if (Channel->pnr && !TransponderScanned(Channel)) { | ||||
|                                  if (Device == cDevice::PrimaryDevice() && !currentChannel) | ||||
|                                     currentChannel = Device->Channel(); | ||||
|                                  Channel->Switch(Device, false); | ||||
|                                  Device->SwitchChannel(Channel, false); | ||||
|                                  lastChannel = ch; | ||||
|                                  break; | ||||
|                                  } | ||||
| @@ -78,6 +79,8 @@ void cEITScanner::Process(void) | ||||
|                      } | ||||
|                   } | ||||
|                } | ||||
|             else | ||||
|                lastChannel++; // avoid hangup in case the last channel in the list is not provided by a DVB card | ||||
|             } | ||||
|         lastScan = time(NULL); | ||||
|         } | ||||
|   | ||||
							
								
								
									
										17
									
								
								menu.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								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.206 2002/08/25 10:56:09 kls Exp $ | ||||
|  * $Id: menu.c 1.207 2002/09/04 13:27:13 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "menu.h" | ||||
| @@ -508,7 +508,7 @@ eOSState cMenuChannels::Switch(void) | ||||
| { | ||||
|   cChannel *ch = Channels.Get(Current()); | ||||
|   if (ch) | ||||
|      ch->Switch(); | ||||
|      cDevice::PrimaryDevice()->SwitchChannel(ch, true); | ||||
|   return osEnd; | ||||
| } | ||||
|  | ||||
| @@ -1054,7 +1054,7 @@ eOSState cMenuWhatsOn::Switch(void) | ||||
|   cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current()); | ||||
|   if (item) { | ||||
|      cChannel *channel = Channels.GetByServiceID(item->eventInfo->GetServiceID()); | ||||
|      if (channel && channel->Switch()) | ||||
|      if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true)) | ||||
|         return osEnd; | ||||
|      } | ||||
|   Interface->Error(tr("Can't switch channel!")); | ||||
| @@ -2519,12 +2519,12 @@ bool cRecordControls::Start(cTimer *Timer) | ||||
|   cChannel *channel = Channels.GetByNumber(ch); | ||||
|  | ||||
|   if (channel) { | ||||
|      bool ReUse = false; | ||||
|      cDevice *device = cDevice::GetDevice(channel->ca, Timer ? Timer->priority : Setup.DefaultPriority, channel->frequency, channel->vpid, &ReUse); | ||||
|      bool NeedsSwitchChannel = false; | ||||
|      cDevice *device = cDevice::GetDevice(channel, Timer ? Timer->priority : Setup.DefaultPriority, &NeedsSwitchChannel); | ||||
|      if (device) { | ||||
|         if (!ReUse) { | ||||
|         if (NeedsSwitchChannel) { | ||||
|            Stop(device); | ||||
|            if (!channel->Switch(device)) { | ||||
|            if (!device->SwitchChannel(channel, false)) { | ||||
|               cThread::EmergencyExit(true); | ||||
|               return false; | ||||
|               } | ||||
| @@ -2570,7 +2570,8 @@ void cRecordControls::Stop(cDevice *Device) | ||||
| bool cRecordControls::StopPrimary(bool DoIt) | ||||
| { | ||||
|   if (cDevice::PrimaryDevice()->Receiving()) { | ||||
|      cDevice *device = cDevice::GetDevice(cDevice::PrimaryDevice()->Ca(), 0); | ||||
|      //XXX+ disabled for the moment - might become obsolete with DVB_DRIVER_VERSION >= 2002090101 | ||||
|      cDevice *device = NULL;//XXX cDevice::GetDevice(cDevice::PrimaryDevice()->Ca(), 0); | ||||
|      if (device) { | ||||
|         if (DoIt) | ||||
|            Stop(cDevice::PrimaryDevice()); | ||||
|   | ||||
							
								
								
									
										8
									
								
								svdrp.c
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								svdrp.c
									
									
									
									
									
								
							| @@ -10,7 +10,7 @@ | ||||
|  * and interact with the Video Disk Recorder - or write a full featured | ||||
|  * graphical interface that sits on top of an SVDRP connection. | ||||
|  * | ||||
|  * $Id: svdrp.c 1.40 2002/08/25 10:40:46 kls Exp $ | ||||
|  * $Id: svdrp.c 1.41 2002/09/04 10:49:42 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include "svdrp.h" | ||||
| @@ -417,13 +417,9 @@ void cSVDRP::CmdCHAN(const char *Option) | ||||
|         Reply(501, "Undefined channel \"%s\"", Option); | ||||
|         return; | ||||
|         } | ||||
|      if (Interface->Recording()) { | ||||
|         Reply(550, "Can't switch channel, interface is recording"); | ||||
|         return; | ||||
|         } | ||||
|      cChannel *channel = Channels.GetByNumber(n); | ||||
|      if (channel) { | ||||
|         if (!channel->Switch()) { | ||||
|         if (!cDevice::PrimaryDevice()->SwitchChannel(channel, true)) { | ||||
|            Reply(554, "Error switching to channel \"%d\"", channel->number); | ||||
|            return; | ||||
|            } | ||||
|   | ||||
							
								
								
									
										4
									
								
								vdr.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								vdr.c
									
									
									
									
									
								
							| @@ -22,7 +22,7 @@ | ||||
|  * | ||||
|  * The project's page is at http://www.cadsoft.de/people/kls/vdr | ||||
|  * | ||||
|  * $Id: vdr.c 1.120 2002/08/16 09:54:03 kls Exp $ | ||||
|  * $Id: vdr.c 1.121 2002/09/04 13:29:19 kls Exp $ | ||||
|  */ | ||||
|  | ||||
| #include <getopt.h> | ||||
| @@ -548,7 +548,7 @@ int main(int argc, char *argv[]) | ||||
|                       int n = cDevice::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1); | ||||
|                       cChannel *channel = Channels.GetByNumber(n); | ||||
|                       if (channel) | ||||
|                          channel->Switch(); | ||||
|                          cDevice::PrimaryDevice()->SwitchChannel(channel, true); | ||||
|                       break; | ||||
|                       } | ||||
|                  // Viewing Control: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user