Exemplo n.º 1
0
int PVRClientMythTV::GetCurrentClientChannel()
{
  if (g_bExtraDebug)
    XBMC->Log(LOG_DEBUG, "%s", __FUNCTION__);

  CLockObject lock(m_lock);

  if (m_rec.IsNull())
    return -1;

  MythProgramInfo currentProgram = m_rec.GetCurrentProgram();
  return currentProgram.ChannelID();
}
Exemplo n.º 2
0
bool PVRClientMythTV::IsRecordingVisible(MythProgramInfo &recording)
{
  // Filter out recordings of special storage groups (like LiveTV or Deleted)

  // When  deleting a recording, it might not be deleted immediately but marked as 'pending delete'.
  // Depending on the protocol version the recording is moved to the group Deleted or
  // the 'delete pending' flag is set
  if (recording.RecordingGroup() == "LiveTV" || recording.RecordingGroup() == "Deleted" || recording.IsDeletePending())
  {
    XBMC->Log(LOG_DEBUG, "%s: Ignoring recording %s", __FUNCTION__, recording.Path().c_str());
    return false;
  }

  return true;
}
Exemplo n.º 3
0
bool MythProgramInfo::operator ==(const MythProgramInfo &other)
{
    if (!this->IsNull() && !other.IsNull())
    {
        if (this->m_proginfo->channel.chanId == other.m_proginfo->channel.chanId &&
                this->m_proginfo->recording.startTs == other.m_proginfo->recording.startTs)
            return true;
    }
    return false;
}
Exemplo n.º 4
0
ProgramInfoMap MythConnection::GetScheduledPrograms()
{
  Lock();

  ProgramInfoMap retval;
  cmyth_proglist_t proglist = NULL;
  CMYTH_CONN_CALL_REF(proglist, proglist == NULL, cmyth_proglist_get_all_scheduled(*m_conn_t));
  int len = cmyth_proglist_get_count(proglist);
  for (int i = 0; i < len; i++)
  {
    MythProgramInfo prog = cmyth_proglist_get_item(proglist, i);
    if (!prog.IsNull()) {
      retval.insert(std::pair<CStdString, MythProgramInfo>(prog.UID().c_str(), prog));
    }
  }
  ref_release(proglist);

  Unlock();

  return retval;
}
Exemplo n.º 5
0
void MythEventHandler::MythEventHandlerPrivate::HandleAskRecording(const CStdString &databuf, MythProgramInfo &programInfo)
{
  // ASK_RECORDING <card id> <time until> <has rec> <has later>[]:[]<program info>
  // Example: ASK_RECORDING 9 29 0 1[]:[]<program>

  // The scheduled recording will hang in MythTV if ASK_RECORDING is just ignored.
  // - Stop recorder (and blocked for time until seconds)
  // - Skip the recording by sending CANCEL_NEXT_RECORDING(true)

  unsigned int cardid;
  int timeuntil, hasrec, haslater;
  if (sscanf(databuf.c_str(), "%d %d %d %d", &cardid, &timeuntil, &hasrec, &haslater) == 4)
    XBMC->Log(LOG_NOTICE, "%s: Event ASK_RECORDING: rec=%d timeuntil=%d hasrec=%d haslater=%d", __FUNCTION__, cardid, timeuntil, hasrec, haslater);
  else
    XBMC->Log(LOG_ERROR, "%s: Incorrect ASK_RECORDING event: rec=%d timeuntil=%d hasrec=%d haslater=%d", __FUNCTION__, cardid, timeuntil, hasrec, haslater);

  CStdString title;
  if (!programInfo.IsNull())
    title = programInfo.Title();
  XBMC->Log(LOG_NOTICE, "%s: Event ASK_RECORDING: title=%s", __FUNCTION__, title.c_str());

  if (timeuntil >= 0 && !m_recorder.IsNull() && m_recorder.ID() == cardid)
  {
    if (g_iLiveTVConflictStrategy == LIVETV_CONFLICT_STRATEGY_CANCELREC ||
      (g_iLiveTVConflictStrategy == LIVETV_CONFLICT_STRATEGY_HASLATER && haslater))
    {
      XBMC->QueueNotification(QUEUE_WARNING, XBMC->GetLocalizedString(30307), title.c_str()); // Canceling conflicting recording: %s
      m_recorder.CancelNextRecording(true);
    }
    else // LIVETV_CONFLICT_STRATEGY_STOPTV
    {
      XBMC->QueueNotification(QUEUE_WARNING, XBMC->GetLocalizedString(30308), title.c_str()); // Stopping Live TV due to conflicting recording: %s
      if (m_observer)
        m_observer->CloseLiveStream();
    }
  }
}
Exemplo n.º 6
0
float PVRClientMythTV::GetRecordingFrameRate(MythProgramInfo &recording)
{
  // MythTV uses frame offsets whereas XBMC expects a time offset.
  // This function can be used to convert the frame offsets to time offsets and back.
  // The average frameRate is calculated by: frameRate = frameCount / duration.
  float frameRate = 0.0f;

  if (g_bExtraDebug)
  {
    XBMC->Log(LOG_DEBUG, "%s - Getting Framerate for: %s)", __FUNCTION__, recording.Title(false).c_str());
  }

  // cmyth_get_bookmark_mark returns the appropriate frame offset for the given byte offset (recordedseek table)
  // This can be used to determine the frame count (by querying the max byte offset)
  long long frameCount = m_db.GetBookmarkMark(recording, LLONG_MAX, 0);
  if (frameCount > 0)
  {
    if (g_bExtraDebug)
    {
      XBMC->Log(LOG_DEBUG, "%s - FrameCount: %lld)", __FUNCTION__, frameCount);
      XBMC->Log(LOG_DEBUG, "%s - Duration: %d)", __FUNCTION__, recording.Duration());
    }

    if (recording.Duration() > 0)
    {
      // Calculate frameRate
      frameRate = (float)frameCount / (float)recording.Duration();

      if (g_bExtraDebug)
      {
        XBMC->Log(LOG_DEBUG, "%s - FrameRate: %f)", __FUNCTION__, frameRate);
      }
    }
  }
  return frameRate;
}
Exemplo n.º 7
0
void *MythEventHandler::MythEventHandlerPrivate::Process()
{
  const char *events[] = {
    "CMYTH_EVENT_UNKNOWN",
    "CMYTH_EVENT_CLOSE",
    "CMYTH_EVENT_RECORDING_LIST_CHANGE",
    "CMYTH_EVENT_RECORDING_LIST_CHANGE_ADD",
    "CMYTH_EVENT_RECORDING_LIST_CHANGE_UPDATE",
    "CMYTH_EVENT_RECORDING_LIST_CHANGE_DELETE",
    "CMYTH_EVENT_SCHEDULE_CHANGE",
    "CMYTH_EVENT_DONE_RECORDING",
    "CMYTH_EVENT_QUIT_LIVETV",
    "CMYTH_EVENT_LIVETV_WATCH",
    "CMYTH_EVENT_LIVETV_CHAIN_UPDATE",
    "CMYTH_EVENT_SIGNAL",
    "CMYTH_EVENT_ASK_RECORDING",
    "CMYTH_EVENT_SYSTEM_EVENT",
    "CMYTH_EVENT_UPDATE_FILE_SIZE",
    "CMYTH_EVENT_GENERATED_PIXMAP",
    "CMYTH_EVENT_CLEAR_SETTINGS_CACHE"
  };
  cmyth_event_t myth_event;
  char databuf[2049];
  databuf[0] = 0;
  bool triggerRecordingUpdate = false;
  unsigned int recordingChangeCount = 0;
  timeval timeout;
  timeout.tv_sec = 0;
  timeout.tv_usec = 100000;

  while (!IsStopped())
  {
    bool recordingChange = false;
    int select = 0;
    m_conn_t->Lock();
    select = cmyth_event_select(*m_conn_t, &timeout);
    m_conn_t->Unlock();

    if (select > 0)
    {
      cmyth_proginfo_t proginfo = NULL;
      m_conn_t->Lock();
      myth_event = cmyth_event_get_message(*m_conn_t, databuf, 2048, &proginfo);
      m_conn_t->Unlock();

      if (g_bExtraDebug)
        XBMC->Log(LOG_DEBUG, "%s - EVENT ID: %s, EVENT databuf: %s", __FUNCTION__, events[myth_event], databuf);

      if (myth_event == CMYTH_EVENT_UPDATE_FILE_SIZE)
      {
        if (g_bExtraDebug)
          XBMC->Log(LOG_NOTICE,"%s - Event file size update: %s", __FUNCTION__, databuf);
        HandleUpdateFileSize(databuf);
      }

      else if (myth_event == CMYTH_EVENT_LIVETV_CHAIN_UPDATE)
      {
        Lock();
        if (!m_recorder.IsNull())
        {
          bool retval = m_recorder.LiveTVChainUpdate(databuf);
          if (g_bExtraDebug)
            XBMC->Log(LOG_NOTICE, "%s - Event chain update: %s", __FUNCTION__, (retval ? "true" : "false"));
        }
        else
          if (g_bExtraDebug)
            XBMC->Log(LOG_NOTICE, "%s - Event chain update: No recorder", __FUNCTION__);
        Unlock();
      }

      else if (myth_event == CMYTH_EVENT_LIVETV_WATCH)
      {
        if (g_bExtraDebug)
          XBMC->Log(LOG_NOTICE,"%s: Event LIVETV_WATCH: recoder %s", __FUNCTION__, databuf);

        Lock();
        if (!m_recorder.IsNull())
        {
          bool retval = m_recorder.LiveTVWatch(databuf);
          if (g_bExtraDebug)
            XBMC->Log(LOG_NOTICE, "%s: Event LIVETV_WATCH: %s", __FUNCTION__, (retval) ? "true " : "false");
        }
        else
          if (g_bExtraDebug)
            XBMC->Log(LOG_NOTICE, "%s: Event LIVETV_WATCH: No recorder", __FUNCTION__);
        Unlock();
      }

      else if(myth_event == CMYTH_EVENT_DONE_RECORDING)
      {
        if (g_bExtraDebug)
          XBMC->Log(LOG_NOTICE, "%s: Event DONE_RECORDING: recorder %s", __FUNCTION__, databuf);

        Lock();
        if (!m_recorder.IsNull())
        {
          bool retval = m_recorder.LiveTVDoneRecording(databuf);
          if (g_bExtraDebug)
            XBMC->Log(LOG_NOTICE, "%s: Event DONE_RECORDING: %s", __FUNCTION__, (retval) ? "true" : "false");
        }
        else
          if (g_bExtraDebug)
            XBMC->Log(LOG_NOTICE, "%s: Event DONE_RECORDING: No recorder", __FUNCTION__);
        Unlock();
      }

      else if (myth_event == CMYTH_EVENT_ASK_RECORDING)
      {
        MythProgramInfo prog(proginfo);
        HandleAskRecording(databuf, prog);
      }

      else if (myth_event == CMYTH_EVENT_SIGNAL)
      {
        HandleUpdateSignal(databuf);
      }

      if (myth_event == CMYTH_EVENT_SCHEDULE_CHANGE)
      {
        if (g_bExtraDebug)
          XBMC->Log(LOG_NOTICE, "%s - Event schedule change", __FUNCTION__);
        PVR->TriggerTimerUpdate();
      }

      else if (myth_event == CMYTH_EVENT_RECORDING_LIST_CHANGE_ADD)
      {
        //Event data: "4121 2010-03-06T01:06:43[]:[]empty"
        unsigned int chanid;
        char recstartts[20];
        if (strlen(databuf)>=24 && sscanf(databuf, "%u %19s", &chanid, recstartts) == 2) {
          Lock();
          m_recordingChangeEventList.push_back(RecordingChangeEvent(CHANGE_ADD, chanid, recstartts));
          Unlock();
          if (g_bExtraDebug)
            XBMC->Log(LOG_DEBUG,"%s - Event recording list add: CHANID=%u TS=%s", __FUNCTION__, chanid, recstartts);
          recordingChange = true;
        }
      }

      else if (myth_event == CMYTH_EVENT_RECORDING_LIST_CHANGE_UPDATE)
      {
        //Event data: Updated 'proginfo' is returned
        MythProgramInfo prog = MythProgramInfo(proginfo);
        if (!prog.IsNull())
        {
          Lock();
          m_recordingChangeEventList.push_back(RecordingChangeEvent(CHANGE_UPDATE, prog));
          Unlock();
          if (g_bExtraDebug)
            XBMC->Log(LOG_DEBUG,"%s - Event recording list update: UID=%s", __FUNCTION__, prog.UID().c_str());
          recordingChange = true;
        }
      }

      else if (myth_event == CMYTH_EVENT_RECORDING_LIST_CHANGE_DELETE)
      {
        //Event data: "4121 2010-03-06T01:06:43[]:[]empty"
        unsigned int chanid;
        char recstartts[20];
        if (strlen(databuf)>=24 && sscanf(databuf, "%u %19s", &chanid, recstartts) == 2) {
          Lock();
          m_recordingChangeEventList.push_back(RecordingChangeEvent(CHANGE_DELETE, chanid, recstartts));
          Unlock();
          if (g_bExtraDebug)
            XBMC->Log(LOG_DEBUG,"%s - Event recording list delete: CHANID=%u TS=%s", __FUNCTION__, chanid, recstartts);
          recordingChange = true;
        }
      }

      else if (myth_event == CMYTH_EVENT_RECORDING_LIST_CHANGE)
      {
        if (g_bExtraDebug)
          XBMC->Log(LOG_NOTICE, "%s - Event recording list change", __FUNCTION__);
        RecordingListChange();
      }

      else if (myth_event == CMYTH_EVENT_UNKNOWN)
      {
        XBMC->Log(LOG_NOTICE, "%s - Event unknown, databuf: %s", __FUNCTION__, databuf);
      }

      else if (myth_event == CMYTH_EVENT_CLOSE)
      {
        XBMC->Log(LOG_NOTICE, "%s - Event client connection closed", __FUNCTION__);
        RetryConnect();
      }

      databuf[0] = 0;
    }
    else if (select < 0)
    {
      XBMC->Log(LOG_ERROR, "%s Event client connection error", __FUNCTION__);
      RetryConnect();
    }
    else if (cmyth_conn_hung(*m_conn_t))
    {
      XBMC->Log(LOG_NOTICE, "%s - Connection hung - reconnect event client connection", __FUNCTION__);
      if (!m_conn_t || !TryReconnect())
        RetryConnect();
    }

    //Accumulate recording change events before triggering PVR event
    //First timeout is 0.5 sec and next 2 secs
    if (recordingChange)
    {
      if (recordingChangeCount == 0)
      {
        timeout.tv_sec = 0;
        timeout.tv_usec = 500000;
      }
      else
      {
        timeout.tv_sec = 2;
        timeout.tv_usec = 0;
      }
      recordingChangeCount++;
      triggerRecordingUpdate = true;
    }
    else
    {
      //Restore timeout
      timeout.tv_sec = 0;
      timeout.tv_usec = 100000;
      //Need PVR update ?
      if (triggerRecordingUpdate)
      {
        XBMC->Log(LOG_DEBUG, "%s - Trigger PVR recording update: %lu recording(s)", __FUNCTION__, recordingChangeCount);
        PVR->TriggerRecordingUpdate();
        triggerRecordingUpdate = false;
      }
      //Reset counter
      recordingChangeCount = 0;
    }
  }
  // Free recording change event
  m_recordingChangeEventList.clear();
  return NULL;
}
bool MythScheduleHelper85::FillTimerEntryWithUpcoming(MythTimerEntry& entry, const MythProgramInfo& recording) const
{
  //Only include timers which have an inactive status if the user has requested it (flag m_showNotRecording)
  switch (recording.Status())
  {
    //Upcoming recordings which are disabled due to being lower priority duplicates or already recorded
    case Myth::RS_EARLIER_RECORDING:  //will record earlier
    case Myth::RS_LATER_SHOWING:      //will record later
    case Myth::RS_CURRENT_RECORDING:  //Already in the current library
    case Myth::RS_PREVIOUS_RECORDING: //Previoulsy recorded but no longer in the library
      if (!m_manager->ShowNotRecording())
      {
        XBMC->Log(LOG_DEBUG, "85::%s: Skipping %s:%s on %s because status %d", __FUNCTION__,
                  recording.Title().c_str(), recording.Subtitle().c_str(), recording.ChannelName().c_str(),
                  recording.Status());
        return false;
      }
    default:
      break;
  }

  MythRecordingRuleNodePtr node = m_manager->FindRuleById(recording.RecordID());
  if (node)
  {
    MythRecordingRule rule = node->GetRule();
    // Relate the main rule as parent
    entry.parentIndex = MythScheduleManager::MakeIndex(node->GetMainRule());
    switch (rule.Type())
    {
      case Myth::RT_SingleRecord:
        return false; // Discard upcoming. We show only main rule.
      case Myth::RT_DontRecord:
        entry.recordingStatus = recording.Status();
        entry.timerType = TIMER_TYPE_DONT_RECORD;
        entry.isInactive = rule.Inactive();
        break;
      case Myth::RT_OverrideRecord:
        entry.recordingStatus = recording.Status();
        entry.timerType = TIMER_TYPE_OVERRIDE;
        entry.isInactive = rule.Inactive();
        break;
      default:
        entry.recordingStatus = recording.Status();
        if (node->GetMainRule().SearchType() == Myth::ST_ManualSearch)
          entry.timerType = TIMER_TYPE_UPCOMING_MANUAL;
        else
          entry.timerType = TIMER_TYPE_UPCOMING;
    }
    entry.startOffset = rule.StartOffset();
    entry.endOffset = rule.EndOffset();
    entry.priority = rule.Priority();
    entry.expiration = GetRuleExpirationId(RuleExpiration(rule.AutoExpire(), 0, false));
  }
  else
    entry.timerType = TIMER_TYPE_ZOMBIE;

  switch (entry.timerType)
  {
    case TIMER_TYPE_UPCOMING:
    case TIMER_TYPE_OVERRIDE:
    case TIMER_TYPE_UPCOMING_MANUAL:
      entry.epgCheck = true;
      break;
    default:
      entry.epgCheck = false;
  }

  entry.description = "";
  entry.chanid = recording.ChannelID();
  entry.callsign = recording.Callsign();
  entry.startTime = recording.StartTime();
  entry.endTime = recording.EndTime();
  entry.title.assign(recording.Title());
  if (!recording.Subtitle().empty())
    entry.title.append(" (").append(recording.Subtitle()).append(")");
  if (recording.Season() || recording.Episode())
    entry.title.append(" - ").append(Myth::IntToString(recording.Season())).append(".").append(Myth::IntToString(recording.Episode()));
  entry.recordingGroup = GetRuleRecordingGroupId(recording.RecordingGroup());
  entry.entryIndex = MythScheduleManager::MakeIndex(recording); // upcoming index
  return true;
}
Exemplo n.º 9
0
MythRecordingRule MythScheduleHelper75::MakeOverride(const MythRecordingRule& rule, const MythProgramInfo& recording)
{
  MythRecordingRule modifier = rule.DuplicateRecordingRule();
  // Do the same as backend even we know the modifier will be rejected for manual rule:
  // Don't know if this behavior is a bug issue or desired: cf libmythtv/recordingrule.cpp
  if (modifier.SearchType() != Myth::ST_ManualSearch)
    modifier.SetSearchType(Myth::ST_NoSearch);

  modifier.SetType(Myth::RT_OverrideRecord);
  modifier.SetParentID(modifier.RecordID());
  modifier.SetRecordID(0);
  modifier.SetInactive(false);
  // Assign recording info
  modifier.SetTitle(recording.Title());
  modifier.SetSubtitle(recording.Subtitle());
  modifier.SetDescription(recording.Description());
  modifier.SetChannelID(recording.ChannelID());
  modifier.SetCallsign(recording.Callsign());
  modifier.SetStartTime(recording.StartTime());
  modifier.SetEndTime(recording.EndTime());
  modifier.SetSeriesID(recording.SerieID());
  modifier.SetProgramID(recording.ProgramID());
  modifier.SetCategory(recording.Category());
  if (rule.InetRef().empty())
  {
    modifier.SetInerRef(recording.Inetref());
    modifier.SetSeason(recording.Season());
    modifier.SetEpisode(recording.Episode());
  }
  return modifier;
}