int cLiveStreamer::SwitchChannel(const cChannel *channel)
{
  if (channel == NULL) {
    return XVDR_RET_ERROR;
  }

  if(m_PatFilter != NULL && m_Device != NULL) {
    m_Device->Detach(m_PatFilter);
    delete m_PatFilter;
    m_PatFilter = NULL;
  }

  if(IsAttached()) {
    Detach();
  }

  // check if any device is able to decrypt the channel - code taken from VDR
  int NumUsableSlots = 0;

  if (channel->Ca() >= CA_ENCRYPTED_MIN) {
    for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
      if (CamSlot->ModuleStatus() == msReady) {
        if (CamSlot->ProvidesCa(channel->Caids())) {
          if (!ChannelCamRelations.CamChecked(channel->GetChannelID(), CamSlot->SlotNumber())) {
            NumUsableSlots++;
          }
       }
      }
    }
    if (!NumUsableSlots) {
      return XVDR_RET_ENCRYPTED;
    }
  }

  // get device for this channel
  {
    cMutexLock lock(&m_DeviceMutex);
    m_Device = cDevice::GetDevice(channel, LIVEPRIORITY, false);
  }

  if (m_Device == NULL)
  {
    // return status "recording running" if there is an active timer
    time_t now = time(NULL);

    for (cTimer *ti = Timers.First(); ti; ti = Timers.Next(ti)) {
      if (ti->Recording() && ti->Matches(now)) {
        return XVDR_RET_RECRUNNING;
      }
    }

    return XVDR_RET_DATALOCKED;
  }

  INFOLOG("Found available device %d", m_Device->DeviceNumber() + 1);

  if (!m_Device->SwitchChannel(channel, false))
  {
    ERRORLOG("Can't switch to channel %i - %s", channel->Number(), channel->Name());
    return XVDR_RET_ERROR;
  }

  // get cached demuxer data
  cChannelCache cache = cChannelCache::GetFromCache(m_uid);

  // channel not found in cache -> add it from vdr
  if(cache.size() == 0) {
    INFOLOG("adding channel to cache");
    cChannelCache::AddToCache(channel);
    cache = cChannelCache::GetFromCache(m_uid);
  }

  // channel already in cache
  else {
    INFOLOG("Channel information found in cache");
  }

  // recheck cache item
  if(cache.size() != 0) {
    INFOLOG("Creating demuxers");
    cache.CreateDemuxers(this);
  }

  RequestStreamChange();

  INFOLOG("Successfully switched to channel %i - %s", channel->Number(), channel->Name());

  if(m_waitforiframe) {
    INFOLOG("Will wait for first I-Frame ...");
  }

  // clear cached data
  Clear();
  m_Queue->Cleanup();

  m_uid = CreateChannelUID(channel);

  if(!Attach()) {
    INFOLOG("Unable to attach receiver !");
    return XVDR_RET_DATALOCKED;
  }

  INFOLOG("Starting PAT scanner");
  m_PatFilter = new cLivePatFilter(this);
  m_PatFilter->SetChannel(channel);
  m_Device->AttachFilter(m_PatFilter);

  INFOLOG("done switching.");
  return XVDR_RET_OK;
}
int cLiveStreamer::StreamChannel(const cChannel *channel, int sock, bool waitforiframe)
{
  if (channel == NULL)
  {
    ERRORLOG("Starting streaming of channel without valid channel");
    return XVDR_RET_ERROR;
  }

  m_uid = CreateChannelUID(channel);
  m_waitforiframe = waitforiframe;

  if(m_waitforiframe) {
    INFOLOG("Will wait for first I-Frame ...");
  }

  // check if any device is able to decrypt the channel - code taken from VDR
  int NumUsableSlots = 0;

  if (channel->Ca() >= CA_ENCRYPTED_MIN) {
    for (cCamSlot *CamSlot = CamSlots.First(); CamSlot; CamSlot = CamSlots.Next(CamSlot)) {
      if (CamSlot->ModuleStatus() == msReady) {
        if (CamSlot->ProvidesCa(channel->Caids())) {
          if (!ChannelCamRelations.CamChecked(channel->GetChannelID(), CamSlot->SlotNumber())) {
            NumUsableSlots++;
          }
       }
      }
    }
    if (!NumUsableSlots) {
      ERRORLOG("Unable to decrypt channel %i - %s", channel->Number(), channel->Name());
      return XVDR_RET_ENCRYPTED;
    }
  }

  // get device for this channel
  m_Device = cDevice::GetDevice(channel, LIVEPRIORITY, true);

  // try a bit harder if we can't find a device
  if(m_Device == NULL)
    m_Device = cDevice::GetDevice(channel, LIVEPRIORITY, false);

  INFOLOG("--------------------------------------");
  INFOLOG("Channel streaming request: %i - %s", channel->Number(), channel->Name());

  if (m_Device == NULL)
  {
    ERRORLOG("Can't get device for channel %i - %s", channel->Number(), channel->Name());

    // return status "recording running" if there is an active timer
    time_t now = time(NULL);
    if(Timers.GetMatch(now) != NULL)
      return XVDR_RET_RECRUNNING;

    return XVDR_RET_DATALOCKED;
  }

  INFOLOG("Found available device %d", m_Device->DeviceNumber() + 1);

  if (!m_Device->SwitchChannel(channel, false))
  {
    ERRORLOG("Can't switch to channel %i - %s", channel->Number(), channel->Name());
    return XVDR_RET_ERROR;
  }

  // create send queue
  if (m_Queue == NULL)
  {
    m_Queue = new cLiveQueue(sock);
    m_Queue->Start();
  }

  m_PatFilter = new cLivePatFilter(this, channel);

  // get cached demuxer data
  cChannelCache cache = cChannelCache::GetFromCache(m_uid);

  // channel not found in cache -> add it from vdr
  if(cache.size() == 0) {
    INFOLOG("adding channel to cache");
    cChannelCache::AddToCache(channel);
    cache = cChannelCache::GetFromCache(m_uid);
  }

  // channel already in cache
  else {
    INFOLOG("Channel information found in cache");
  }

  // recheck cache item
  if(cache.size() != 0) {
    INFOLOG("Creating demuxers");
    cache.CreateDemuxers(this);
  }

  if(!Attach()) {
    INFOLOG("Unable to attach receiver !");
    return XVDR_RET_DATALOCKED;
  }

  RequestStreamChange();

  DEBUGLOG("Starting PAT scanner");
  m_Device->AttachFilter(m_PatFilter);

  INFOLOG("Successfully switched to channel %i - %s", channel->Number(), channel->Name());

  Start();

  return XVDR_RET_OK;
}