Home

Dokumentation

Impressum

Dokumentation VDR
 

Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

device.c

Go to the documentation of this file.
00001 /*
00002  * device.c: The basic device interface
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: device.c 1.35 2002/11/10 10:17:57 kls Exp $
00008  */
00009 
00010 #include "device.h"
00011 #include <errno.h>
00012 #include <sys/ioctl.h>
00013 #include <sys/mman.h>
00014 #include "audio.h"
00015 #include "channels.h"
00016 #include "eit.h"
00017 #include "i18n.h"
00018 #include "player.h"
00019 #include "receiver.h"
00020 #include "status.h"
00021 #include "transfer.h"
00022 
00023 // --- cDevice ---------------------------------------------------------------
00024 
00025 // The default priority for non-primary devices:
00026 #define DEFAULTPRIORITY  -2
00027 
00028 // The maximum time we wait before assuming that a recorded video data stream
00029 // is broken:
00030 #define MAXBROKENTIMEOUT 30 // seconds
00031 
00032 int cDevice::numDevices = 0;
00033 int cDevice::useDevice = 0;
00034 int cDevice::nextCardIndex = 0;
00035 int cDevice::currentChannel = 0;
00036 cDevice *cDevice::device[MAXDEVICES] = { NULL };
00037 cDevice *cDevice::primaryDevice = NULL;
00038 
00039 cDevice::cDevice(void)
00040 {
00041   cardIndex = nextCardIndex++;
00042 
00043   SetVideoFormat(Setup.VideoFormat);
00044 
00045   active = false;
00046 
00047   mute = false;
00048   volume = Setup.CurrentVolume;
00049 
00050   player = NULL;
00051 
00052   playerDetached = false;
00053 
00054   for (int i = 0; i < MAXRECEIVERS; i++)
00055       receiver[i] = NULL;
00056 
00057   if (numDevices < MAXDEVICES) {
00058      device[numDevices++] = this;
00059      SetCaCaps(cardIndex);
00060      }
00061   else
00062      esyslog("ERROR: too many devices!");
00063 }
00064 
00065 cDevice::~cDevice()
00066 {
00067   Detach(player);
00068   for (int i = 0; i < MAXRECEIVERS; i++)
00069       Detach(receiver[i]);
00070 }
00071 
00072 void cDevice::SetUseDevice(int n)
00073 {
00074   if (n < MAXDEVICES)
00075      useDevice |= (1 << n);
00076 }
00077 
00078 int cDevice::NextCardIndex(int n)
00079 {
00080   if (n > 0) {
00081      nextCardIndex += n;
00082      if (nextCardIndex >= MAXDEVICES)
00083         esyslog("ERROR: nextCardIndex too big (%d)", nextCardIndex);
00084      }
00085   else if (n < 0)
00086      esyslog("ERROR: illegal value in IncCardIndex(%d)", n);
00087   return nextCardIndex;
00088 }
00089 
00090 int cDevice::DeviceNumber(void) const
00091 {
00092   for (int i = 0; i < numDevices; i++) {
00093       if (device[i] == this)
00094          return i;
00095       }
00096   return -1;
00097 }
00098 
00099 void cDevice::MakePrimaryDevice(bool On)
00100 {
00101 }
00102 
00103 bool cDevice::SetPrimaryDevice(int n)
00104 {
00105   n--;
00106   if (0 <= n && n < numDevices && device[n]) {
00107      isyslog("setting primary device to %d", n + 1);
00108      if (primaryDevice)
00109         primaryDevice->MakePrimaryDevice(false);
00110      primaryDevice = device[n];
00111      primaryDevice->MakePrimaryDevice(true);
00112      return true;
00113      }
00114   esyslog("invalid primary device number: %d", n + 1);
00115   return false;
00116 }
00117 
00118 bool cDevice::HasDecoder(void) const
00119 {
00120   return false;
00121 }
00122 
00123 bool cDevice::PlayerDetached(void)
00124 {
00125   bool result = playerDetached;
00126   playerDetached = false;
00127   return result;
00128 }
00129 
00130 cOsdBase *cDevice::NewOsd(int x, int y)
00131 {
00132   return NULL;
00133 }
00134 
00135 cSpuDecoder *cDevice::GetSpuDecoder(void)
00136 {
00137   return NULL;
00138 }
00139 
00140 cDevice *cDevice::GetDevice(int Index)
00141 {
00142   return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
00143 }
00144 
00145 cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers)
00146 {
00147   cDevice *d = NULL;
00148   for (int i = 0; i < numDevices; i++) {
00149       bool ndr;
00150       if (device[i]->ProvidesChannel(Channel, Priority, &ndr) // this device is basicly able to do the job
00151          && (!d // we don't have a device yet, or...
00152             || (device[i]->Receiving() && !ndr) // ...this one is already receiving and allows additional receivers, or...
00153             || !d->Receiving() // ...the one we have is not receiving...
00154                && (device[i]->Priority() < d->Priority() // ...this one has an even lower Priority, or...
00155                   || device[i]->Priority() == d->Priority() // ...same Priority...
00156                      && device[i]->ProvidesCa(Channel->Ca()) < d->ProvidesCa(Channel->Ca()) // ...but this one provides fewer Ca values
00157                   )
00158             )
00159          ) {
00160          d = device[i];
00161          if (NeedsDetachReceivers)
00162             *NeedsDetachReceivers = ndr;
00163          }
00164       }
00165   /*XXX+ too complex with multiple recordings per device
00166   if (!d && Ca > MAXDEVICES) {
00167      // We didn't find one the easy way, so now we have to try harder:
00168      int ShiftLevel = -1;
00169      for (int i = 0; i < numDevices; i++) {
00170          if (Provides[i]) { // this device is basicly able to do the job, but for some reason we didn't get it above
00171             int sl = device[i]->CanShift(Ca, Priority); // asks this device to shift its job to another device
00172             if (sl >= 0 && (ShiftLevel < 0 || sl < ShiftLevel)) {
00173                d = device[i]; // found one that can be shifted with the fewest number of subsequent shifts
00174                ShiftLevel = sl;
00175                }
00176             }
00177          }
00178      }
00179   XXX*/
00180   return d;
00181 }
00182 
00183 void cDevice::SetCaCaps(int Index)
00184 {
00185   for (int d = 0; d < numDevices; d++) {
00186       if (Index < 0 || Index == device[d]->CardIndex()) {
00187          for (int i = 0; i < MAXCACAPS; i++)
00188              device[d]->caCaps[i] = Setup.CaCaps[device[d]->CardIndex()][i];
00189          }
00190       }
00191 }
00192 
00193 void cDevice::Shutdown(void)
00194 {
00195   for (int i = 0; i < numDevices; i++) {
00196       delete device[i];
00197       device[i] = NULL;
00198       }
00199   primaryDevice = NULL;
00200 }
00201 
00202 bool cDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
00203 {
00204   return false;
00205 }
00206 
00207 void cDevice::SetVideoFormat(bool VideoFormat16_9)
00208 {
00209 }
00210 
00211 //#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); }
00212 #define PRINTPIDS(s)
00213 
00214 bool cDevice::HasPid(int Pid) const
00215 {
00216   for (int i = 0; i < MAXPIDHANDLES; i++) {
00217       if (pidHandles[i].pid == Pid)
00218          return true;
00219       }
00220   return false;
00221 }
00222 
00223 bool cDevice::AddPid(int Pid, ePidType PidType)
00224 {
00225   if (Pid) {
00226      int n = -1;
00227      int a = -1;
00228      for (int i = 0; i < MAXPIDHANDLES; i++) {
00229          if (pidHandles[i].pid == Pid)
00230             n = i;
00231          else if (a < 0 && i >= ptOther && !pidHandles[i].used)
00232             a = i;
00233          }
00234      if (n >= 0) {
00235         // The Pid is already in use
00236         if (++pidHandles[n].used == 2 && n <= ptTeletext) {
00237            // It's a special PID that may have to be switched into "tap" mode
00238            PRINTPIDS("A");
00239            return SetPid(&pidHandles[n], n, true);
00240            }
00241         PRINTPIDS("a");
00242         return true;
00243         }
00244      else if (PidType < ptOther) {
00245         // The Pid is not yet in use and it is a special one
00246         n = PidType;
00247         }
00248      else if (a >= 0) {
00249         // The Pid is not yet in use and we have a free slot
00250         n = a;
00251         }
00252      else
00253         esyslog("ERROR: no free slot for PID %d", Pid);
00254      if (n >= 0) {
00255         pidHandles[n].pid = Pid;
00256         pidHandles[n].used = 1;
00257         PRINTPIDS("C");
00258         return SetPid(&pidHandles[n], n, true);
00259         }
00260      }
00261   return true;
00262 }
00263 
00264 void cDevice::DelPid(int Pid)
00265 {
00266   if (Pid) {
00267      for (int i = 0; i < MAXPIDHANDLES; i++) {
00268          if (pidHandles[i].pid == Pid) {
00269             PRINTPIDS("D");
00270             if (--pidHandles[i].used < 2) {
00271                SetPid(&pidHandles[i], i, false);
00272                if (pidHandles[i].used == 0) {
00273                   pidHandles[i].handle = -1;
00274                   pidHandles[i].pid = 0;
00275                   }
00276                }
00277             PRINTPIDS("E");
00278             }
00279          }
00280      }
00281 }
00282 
00283 bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
00284 {
00285   return false;
00286 }
00287 
00288 bool cDevice::ProvidesSource(int Source) const
00289 {
00290   return false;
00291 }
00292 
00293 bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
00294 {
00295   return false;
00296 }
00297 
00298 bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView)
00299 {
00300   if (LiveView)
00301      isyslog("switching to channel %d", Channel->Number());
00302   for (int i = 3; i--;) {
00303       switch (SetChannel(Channel, LiveView)) {
00304         case scrOk:           return true;
00305         case scrNotAvailable: if (Interface)
00306                                  Interface->Error(tr("Channel not available!"));
00307                               return false;
00308         case scrNoTransfer:   if (Interface)
00309                                  Interface->Error(tr("Can't start Transfer Mode!"));
00310                               return false;
00311         case scrFailed:       break; // loop will retry
00312         }
00313       esyslog("retrying");
00314       }
00315   return false;
00316 }
00317 
00318 bool cDevice::SwitchChannel(int Direction)
00319 {
00320   bool result = false;
00321   Direction = sgn(Direction);
00322   if (Direction) {
00323      int n = CurrentChannel() + Direction;
00324      int first = n;
00325      cChannel *channel;
00326      while ((channel = Channels.GetByNumber(n, Direction)) != NULL) {
00327            // try only channels which are currently available
00328            if (PrimaryDevice()->ProvidesChannel(channel, Setup.PrimaryLimit) || PrimaryDevice()->CanReplay() && GetDevice(channel, 0))
00329               break;
00330            n = channel->Number() + Direction;
00331            }
00332      if (channel) {
00333         int d = n - first;
00334         if (abs(d) == 1)
00335            dsyslog("skipped channel %d", first);
00336         else if (d)
00337            dsyslog("skipped channels %d..%d", first, n - sgn(d));
00338         if (PrimaryDevice()->SwitchChannel(channel, true))
00339            result = true;
00340         }
00341      else if (n != first && Interface)
00342         Interface->Error(tr("Channel not available!"));
00343      }
00344   return result;
00345 }
00346 
00347 eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
00348 {
00349   if (LiveView)
00350      StopReplay();
00351 
00352   // If this card can't receive this channel, we must not actually switch
00353   // the channel here, because that would irritate the driver when we
00354   // start replaying in Transfer Mode immediately after switching the channel:
00355   bool NeedsTransferMode = (LiveView && IsPrimaryDevice() && !ProvidesChannel(Channel, Setup.PrimaryLimit));
00356 
00357   eSetChannelResult Result = scrOk;
00358 
00359   // If this DVB card can't receive this channel, let's see if we can
00360   // use the card that actually can receive it and transfer data from there:
00361 
00362   if (NeedsTransferMode) {
00363      cDevice *CaDevice = GetDevice(Channel, 0);
00364      if (CaDevice && CanReplay()) {
00365         cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel
00366         if (CaDevice->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()!
00367            cControl::Launch(new cTransferControl(CaDevice, Channel->Vpid(), Channel->Apid1(), Channel->Apid2(), Channel->Dpid1(), Channel->Dpid2()));//XXX+
00368         else
00369            Result = scrNoTransfer;
00370         }
00371      else
00372         Result = scrNotAvailable;
00373      }
00374   else {
00375      cStatus::MsgChannelSwitch(this, 0); // only report status if we are actually going to switch the channel
00376      if (!SetChannelDevice(Channel, LiveView))
00377         Result = scrFailed;
00378      }
00379 
00380   if (Result == scrOk) {
00381      if (LiveView && IsPrimaryDevice()) {
00382         cSIProcessor::SetCurrentChannelID(Channel->GetChannelID());
00383         currentChannel = Channel->Number();
00384         }
00385      cStatus::MsgChannelSwitch(this, Channel->Number()); // only report status if channel switch successfull
00386      }
00387 
00388   return Result;
00389 }
00390 
00391 bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
00392 {
00393   return false;
00394 }
00395 
00396 void cDevice::SetVolumeDevice(int Volume)
00397 {
00398 }
00399 
00400 int cDevice::NumAudioTracksDevice(void) const
00401 {
00402   return 0;
00403 }
00404 
00405 const char **cDevice::GetAudioTracksDevice(int *CurrentTrack) const
00406 {
00407   return NULL;
00408 }
00409 
00410 void cDevice::SetAudioTrackDevice(int Index)
00411 {
00412 }
00413 
00414 bool cDevice::ToggleMute(void)
00415 {
00416   int OldVolume = volume;
00417   mute = !mute;
00418   SetVolume(0, mute);
00419   volume = OldVolume;
00420   Audios.MuteAudio(mute);
00421   return mute;
00422 }
00423 
00424 void cDevice::SetVolume(int Volume, bool Absolute)
00425 {
00426   volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME);
00427   SetVolumeDevice(volume);
00428   cStatus::MsgSetVolume(volume, Absolute);
00429   if (volume > 0) {
00430      mute = false;
00431      Audios.MuteAudio(mute);
00432      }
00433 }
00434 
00435 int cDevice::NumAudioTracks(void) const
00436 {
00437   return player ? player->NumAudioTracks() : NumAudioTracksDevice();
00438 }
00439 
00440 const char **cDevice::GetAudioTracks(int *CurrentTrack) const
00441 {
00442   return player ? player->GetAudioTracks(CurrentTrack) : GetAudioTracksDevice(CurrentTrack);
00443 }
00444 
00445 void cDevice::SetAudioTrack(int Index)
00446 {
00447   if (player)
00448      player->SetAudioTrack(Index);
00449   else
00450      SetAudioTrackDevice(Index);
00451 }
00452 
00453 bool cDevice::CanReplay(void) const
00454 {
00455   return HasDecoder();
00456 }
00457 
00458 bool cDevice::SetPlayMode(ePlayMode PlayMode)
00459 {
00460   return false;
00461 }
00462 
00463 void cDevice::TrickSpeed(int Speed)
00464 {
00465 }
00466 
00467 void cDevice::Clear(void)
00468 {
00469   Audios.ClearAudio();
00470 }
00471 
00472 void cDevice::Play(void)
00473 {
00474 }
00475 
00476 void cDevice::Freeze(void)
00477 {
00478 }
00479 
00480 void cDevice::Mute(void)
00481 {
00482   Audios.MuteAudio(true);
00483 }
00484 
00485 void cDevice::StillPicture(const uchar *Data, int Length)
00486 {
00487 }
00488 
00489 bool cDevice::Replaying(void) const
00490 {
00491   return player != NULL;
00492 }
00493 
00494 bool cDevice::AttachPlayer(cPlayer *Player)
00495 {
00496   if (CanReplay()) {
00497      if (player)
00498         Detach(player);
00499      player = Player;
00500      player->device = this;
00501      SetPlayMode(player->playMode);
00502      player->Activate(true);
00503      return true;
00504      }
00505   return false;
00506 }
00507 
00508 void cDevice::Detach(cPlayer *Player)
00509 {
00510   if (Player && player == Player) {
00511      player->Activate(false);
00512      player->device = NULL;
00513      player = NULL;
00514      SetPlayMode(pmNone);
00515      playerDetached = true;
00516      }
00517 }
00518 
00519 void cDevice::StopReplay(void)
00520 {
00521   if (player) {
00522      Detach(player);
00523      if (IsPrimaryDevice())
00524         cControl::Shutdown();
00525      }
00526 }
00527 
00528 bool cDevice::Poll(cPoller &Poller, int TimeoutMs)
00529 {
00530   return false;
00531 }
00532 
00533 int cDevice::PlayVideo(const uchar *Data, int Length)
00534 {
00535   return -1;
00536 }
00537 
00538 void cDevice::PlayAudio(const uchar *Data, int Length)
00539 {
00540   Audios.PlayAudio(Data, Length);
00541 }
00542 
00543 int cDevice::Ca(void) const
00544 {
00545   int ca = 0;
00546   for (int i = 0; i < MAXRECEIVERS; i++) {
00547       if (receiver[i] && (ca = receiver[i]->ca) != 0)
00548          break; // all receivers have the same ca
00549       }
00550   return ca;
00551 }
00552 
00553 int cDevice::Priority(void) const
00554 {
00555   int priority = IsPrimaryDevice() ? Setup.PrimaryLimit - 1 : DEFAULTPRIORITY;
00556   for (int i = 0; i < MAXRECEIVERS; i++) {
00557       if (receiver[i])
00558          priority = max(receiver[i]->priority, priority);
00559       }
00560   return priority;
00561 }
00562 
00563 int cDevice::CanShift(int Ca, int Priority, int UsedCards) const
00564 {
00565   return -1;//XXX+ too complex with multiple recordings per device
00566   // Test whether a receiver on this device can be shifted to another one
00567   // in order to perform a new receiving with the given Ca and Priority on this device:
00568   int ShiftLevel = -1; // default means this device can't be shifted
00569   if (UsedCards & (1 << CardIndex()) != 0)
00570      return ShiftLevel; // otherwise we would get into a loop
00571   if (Receiving()) {
00572      if (ProvidesCa(Ca) // this device provides the requested Ca
00573         && (Ca != this->Ca() // the requested Ca is different from the one currently used...
00574            || Priority > this->Priority())) { // ...or the request comes from a higher priority
00575         cDevice *d = NULL;
00576         int Provides[MAXDEVICES];
00577         UsedCards |= (1 << CardIndex());
00578         for (int i = 0; i < numDevices; i++) {
00579             if ((Provides[i] = device[i]->ProvidesCa(this->Ca())) != 0) { // this device is basicly able to do the job
00580                if (device[i] != this) { // it is not _this_ device
00581                   int sl = device[i]->CanShift(this->Ca(), Priority, UsedCards); // this is the original Priority!
00582                   if (sl >= 0 && (ShiftLevel < 0 || sl < ShiftLevel)) {
00583                      d = device[i];
00584                      ShiftLevel = sl;
00585                      }
00586                   }
00587                }
00588             }
00589         if (ShiftLevel >= 0)
00590            ShiftLevel++; // adds the device's own shift
00591         }
00592      }
00593   else if (Priority > this->Priority())
00594      ShiftLevel = 0; // no shifting necessary, this device can do the job
00595   return ShiftLevel;
00596 }
00597 
00598 int cDevice::ProvidesCa(int Ca) const
00599 {
00600   if (Ca == CardIndex() + 1)
00601      return 1; // exactly _this_ card was requested
00602   if (Ca && Ca <= MAXDEVICES)
00603      return 0; // a specific card was requested, but not _this_ one
00604   int result = Ca ? 0 : 1; // by default every card can provide FTA
00605   int others = Ca ? 1 : 0;
00606   for (int i = 0; i < MAXCACAPS; i++) {
00607       if (caCaps[i]) {
00608          if (caCaps[i] == Ca)
00609             result = 1;
00610          else
00611             others++;
00612          }
00613       }
00614   return result ? result + others : 0;
00615 }
00616 
00617 bool cDevice::Receiving(bool CheckAny) const
00618 {
00619   for (int i = 0; i < MAXRECEIVERS; i++) {
00620       if (receiver[i] && (CheckAny || receiver[i]->priority >= 0)) // cReceiver with priority < 0 doesn't count
00621          return true;
00622       }
00623   return false;
00624 }
00625 
00626 void cDevice::Action(void)
00627 {
00628   dsyslog("receiver thread started on device %d (pid=%d)", CardIndex() + 1, getpid());
00629 
00630   if (OpenDvr()) {
00631      time_t t = time(NULL);
00632      active = true;
00633      for (; active;) {
00634          // Read data from the DVR device:
00635          uchar *b = NULL;
00636          if (GetTSPacket(b)) {
00637             if (b) {
00638                int Pid = (((uint16_t)b[1] & PID_MASK_HI) << 8) | b[2];
00639                // Distribute the packet to all attached receivers:
00640                Lock();
00641                for (int i = 0; i < MAXRECEIVERS; i++) {
00642                    if (receiver[i] && receiver[i]->WantsPid(Pid))
00643                       receiver[i]->Receive(b, TS_SIZE);
00644                    }
00645                Unlock();
00646                t = time(NULL);
00647                }
00648             }
00649          else
00650             break;
00651 
00652          //XXX+ put this into the recorder??? or give the receiver a flag whether it wants this?
00653          if (time(NULL) - t > MAXBROKENTIMEOUT) {
00654             esyslog("ERROR: video data stream broken on device %d", CardIndex() + 1);
00655             cThread::EmergencyExit(true);
00656             t = time(NULL);
00657             }
00658          }
00659      CloseDvr();
00660      }
00661 
00662   dsyslog("receiver thread ended on device %d (pid=%d)", CardIndex() + 1, getpid());
00663 }
00664 
00665 bool cDevice::OpenDvr(void)
00666 {
00667   return false;
00668 }
00669 
00670 void cDevice::CloseDvr(void)
00671 {
00672 }
00673 
00674 bool cDevice::GetTSPacket(uchar *&Data)
00675 {
00676   return false;
00677 }
00678 
00679 bool cDevice::AttachReceiver(cReceiver *Receiver)
00680 {
00681   if (!Receiver)
00682      return false;
00683   if (Receiver->device == this)
00684      return true;
00685   for (int i = 0; i < MAXRECEIVERS; i++) {
00686       if (!receiver[i]) {
00687          for (int n = 0; n < MAXRECEIVEPIDS; n++)
00688              AddPid(Receiver->pids[n]);//XXX+ retval!
00689          Receiver->Activate(true);
00690          Lock();
00691          Receiver->device = this;
00692          receiver[i] = Receiver;
00693          Unlock();
00694          Start();
00695          return true;
00696          }
00697       }
00698   esyslog("ERROR: no free receiver slot!");
00699   return false;
00700 }
00701 
00702 void cDevice::Detach(cReceiver *Receiver)
00703 {
00704   if (!Receiver || Receiver->device != this)
00705      return;
00706   bool receiversLeft = false;
00707   for (int i = 0; i < MAXRECEIVERS; i++) {
00708       if (receiver[i] == Receiver) {
00709          Receiver->Activate(false);
00710          Lock();
00711          receiver[i] = NULL;
00712          Receiver->device = NULL;
00713          Unlock();
00714          for (int n = 0; n < MAXRECEIVEPIDS; n++)
00715              DelPid(Receiver->pids[n]);
00716          }
00717       else if (receiver[i])
00718          receiversLeft = true;
00719       }
00720   if (!receiversLeft) {
00721      active = false;
00722      Cancel(3);
00723      }
00724 }
00725 
00726 // --- cTSBuffer -------------------------------------------------------------
00727 
00728 cTSBuffer::cTSBuffer(int File, int Size, int CardIndex)
00729 {
00730   f = File;
00731   size = Size / TS_SIZE * TS_SIZE;
00732   cardIndex = CardIndex;
00733   tsRead = tsWrite = 0;
00734   buf = (f >= 0 && size >= TS_SIZE) ? MALLOC(uchar, size + TS_SIZE) : NULL;
00735   // the '+ TS_SIZE' allocates some extra space for handling packets that got split by a buffer roll-over
00736   firstRead = true;
00737 }
00738 
00739 cTSBuffer::~cTSBuffer()
00740 {
00741   free(buf);
00742 }
00743 
00744 int cTSBuffer::Read(void)
00745 {
00746   if (buf) {
00747      cPoller Poller(f, false);
00748      bool repeat;
00749      int total = 0;
00750      do {
00751         repeat = false;
00752         if (firstRead || Used() > TS_SIZE || Poller.Poll(100)) { // only wait if there's not enough data in the buffer
00753            firstRead = false;
00754            if (tsRead == tsWrite)
00755               tsRead = tsWrite = 0; // keep the maximum buffer space available
00756            if (tsWrite >= size && tsRead > 0)
00757               tsWrite = 0;
00758            int free = tsRead <= tsWrite ? size - tsWrite : tsRead - tsWrite - 1;
00759            if (free > 0) {
00760               int r = read(f, buf + tsWrite, free);
00761               if (r > 0) {
00762                  total += r;
00763                  tsWrite += r;
00764                  if (tsWrite >= size && tsRead > 0) {
00765                     tsWrite = 0;
00766                     repeat = true; // read again after a boundary roll-over
00767                     }
00768                  }
00769               }
00770            }
00771         } while (repeat);
00772      return total;
00773      }
00774   return -1;
00775 }
00776 
00777 uchar *cTSBuffer::Get(void)
00778 {
00779   if (Used() >= TS_SIZE) {
00780      uchar *p = buf + tsRead;
00781      if (*p != TS_SYNC_BYTE) {
00782         esyslog("ERROR: not sync'ed to TS packet on device %d", cardIndex);
00783         int tsMax = tsRead < tsWrite ? tsWrite : size;
00784         for (int i = tsRead; i < tsMax; i++) {
00785             if (buf[i] == TS_SYNC_BYTE) {
00786                esyslog("ERROR: skipped %d bytes to sync on TS packet on device %d", i - tsRead, cardIndex);
00787                tsRead = i;
00788                return NULL;
00789                }
00790             }
00791         if ((tsRead = tsMax) >= size)
00792            tsRead = 0;
00793         return NULL;
00794         }
00795      if (tsRead + TS_SIZE > size) {
00796         // the packet rolled over the buffer boundary, so let's fetch the rest from the beginning (which MUST be there, since Used() >= TS_SIZE)
00797         int rest = TS_SIZE - (size - tsRead);
00798         memcpy(buf + size, buf, rest);
00799         tsRead = rest;
00800         }
00801      else if ((tsRead += TS_SIZE) >= size)
00802         tsRead = 0;
00803      return p;
00804      }
00805   return NULL;
00806 }

Generated on Wed Feb 5 23:30:08 2003 for VDR by doxygen1.3-rc2