Example #1
0
static void _process_msg
  ( timeshift_t *ts, streaming_message_t *sm, int *run )
{
  int err;
  timeshift_file_t *tsf;

  /* Process */
  switch (sm->sm_type) {

    /* Terminate */
    case SMT_EXIT:
      if (run) *run = 0;
      break;
    case SMT_STOP:
      if (sm->sm_code == 0 && run)
        *run = 0;
      break;

    /* Timeshifting */
    case SMT_SKIP:
    case SMT_SPEED:
      break;

    /* Status */
    case SMT_GRACE:
    case SMT_NOSTART:
    case SMT_NOSTART_WARN:
    case SMT_SERVICE_STATUS:
    case SMT_TIMESHIFT_STATUS:
      break;

    /* Store */
    case SMT_SIGNAL_STATUS:
    case SMT_START:
    case SMT_MPEGTS:
    case SMT_PACKET:
      pthread_mutex_lock(&ts->rdwr_mutex);
      if ((tsf = timeshift_filemgr_get(ts, 1)) && (tsf->wfd >= 0 || tsf->ram)) {
        if ((err = _process_msg0(ts, tsf, &sm)) < 0) {
          timeshift_filemgr_close(tsf);
          tsf->bad = 1;
          ts->full = 1; ///< Stop any more writing
        }
        tsf->refcount--;
      }
      pthread_mutex_unlock(&ts->rdwr_mutex);
      break;
  }

  /* Next */
  if (sm)
    streaming_msg_free(sm);
}
Example #2
0
/*
 * Get current / new file
 */
timeshift_file_t *timeshift_filemgr_get ( timeshift_t *ts, int create )
{
  int fd;
  struct timespec tp;
  timeshift_file_t *tsf_tl, *tsf_hd, *tsf_tmp;
  timeshift_index_data_t *ti;
  char path[512];
  time_t time;

  /* Return last file */
  if (!create)
    return timeshift_filemgr_newest(ts);

  /* No space */
  if (ts->full)
    return NULL;

  /* Store to file */
  clock_gettime(CLOCK_MONOTONIC_COARSE, &tp);
  time   = tp.tv_sec / TIMESHIFT_FILE_PERIOD;
  tsf_tl = TAILQ_LAST(&ts->files, timeshift_file_list);
  if (!tsf_tl || tsf_tl->time != time) {
    tsf_hd = TAILQ_FIRST(&ts->files);

    /* Close existing */
    if (tsf_tl && tsf_tl->fd != -1)
      timeshift_filemgr_close(tsf_tl);

    /* Check period */
    if (ts->max_time && tsf_hd && tsf_tl) {
      time_t d = (tsf_tl->time - tsf_hd->time) * TIMESHIFT_FILE_PERIOD;
      if (d > (ts->max_time+5)) {
        if (!tsf_hd->refcount) {
          timeshift_filemgr_remove(ts, tsf_hd, 0);
          tsf_hd = NULL;
        } else {
          tvhlog(LOG_DEBUG, "timeshift", "ts %d buffer full", ts->id);
          ts->full = 1;
        }
      }
    }

    /* Check size */
    if (!timeshift_unlimited_size &&
        atomic_pre_add_u64(&timeshift_total_size, 0) >= timeshift_max_size) {

      /* Remove the last file (if we can) */
      if (tsf_hd && !tsf_hd->refcount) {
        timeshift_filemgr_remove(ts, tsf_hd, 0);

      /* Full */
      } else {
        tvhlog(LOG_DEBUG, "timeshift", "ts %d buffer full", ts->id);
        ts->full = 1;
      }
    }
      
    /* Create new file */
    tsf_tmp = NULL;
    if (!ts->full) {

      /* Create directories */
      if (!ts->path) {
        if (timeshift_filemgr_makedirs(ts->id, path, sizeof(path)))
          return NULL;
        ts->path = strdup(path);
      }

      /* Create File */
      snprintf(path, sizeof(path), "%s/tvh-%"PRItime_t, ts->path, time);
      tvhtrace("timeshift", "ts %d create file %s", ts->id, path);
      if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) > 0) {
        tsf_tmp = calloc(1, sizeof(timeshift_file_t));
        tsf_tmp->time     = time;
        tsf_tmp->fd       = fd;
        tsf_tmp->path     = strdup(path);
        tsf_tmp->refcount = 0;
        tsf_tmp->last     = getmonoclock();
        TAILQ_INIT(&tsf_tmp->iframes);
        TAILQ_INIT(&tsf_tmp->sstart);
        TAILQ_INSERT_TAIL(&ts->files, tsf_tmp, link);

        /* Copy across last start message */
        if (tsf_tl && (ti = TAILQ_LAST(&tsf_tl->sstart, timeshift_index_data_list))) {
          tvhtrace("timeshift", "ts %d copy smt_start to new file",
                   ts->id);
          timeshift_index_data_t *ti2 = calloc(1, sizeof(timeshift_index_data_t));
          ti2->data = streaming_msg_clone(ti->data);
          TAILQ_INSERT_TAIL(&tsf_tmp->sstart, ti2, link);
        }
      }
    }
    tsf_tl = tsf_tmp;
  }

  if (tsf_tl)
    tsf_tl->refcount++;
  return tsf_tl;
}
Example #3
0
/*
 * Get current / new file
 */
timeshift_file_t *timeshift_filemgr_get ( timeshift_t *ts, int create )
{
  int fd;
  struct timespec tp;
  timeshift_file_t *tsf_tl, *tsf_hd, *tsf_tmp;
  timeshift_index_data_t *ti;
  char path[512];

  /* Return last file */
  if (!create)
    return TAILQ_LAST(&ts->files, timeshift_file_list);

  /* No space */
  if (ts->full)
    return NULL;

  /* Store to file */
  clock_gettime(CLOCK_MONOTONIC_COARSE, &tp);
  tsf_tl = TAILQ_LAST(&ts->files, timeshift_file_list);
  if (!tsf_tl || tsf_tl->time != tp.tv_sec) {
    tsf_hd = TAILQ_FIRST(&ts->files);

    /* Close existing */
    if (tsf_tl && tsf_tl->fd != -1)
      timeshift_filemgr_close(tsf_tl);

    /* Check period */
    if (ts->max_time && tsf_hd && tsf_tl) {
      time_t d = tsf_tl->time - tsf_hd->time;
      if (d > (ts->max_time+5)) {
        if (!tsf_hd->refcount) {
          timeshift_filemgr_remove(ts, tsf_hd, 0);
        } else {
#ifdef TSHFT_TRACE
          tvhlog(LOG_DEBUG, "timeshift", "ts %d buffer full", ts->id);
#endif
          ts->full = 1;
        }
      }
    }

    /* Check size */
    // TODO: need to implement this

    /* Create new file */
    tsf_tmp = NULL;
    if (!ts->full) {
      snprintf(path, sizeof(path), "%s/tvh-%"PRItime_t, ts->path, tp.tv_sec);
#ifdef TSHFT_TRACE
      tvhlog(LOG_DEBUG, "timeshift", "ts %d create file %s", ts->id, path);
#endif
      if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) > 0) {
        tsf_tmp = calloc(1, sizeof(timeshift_file_t));
        tsf_tmp->time     = tp.tv_sec;
        tsf_tmp->fd       = fd;
        tsf_tmp->path     = strdup(path);
        tsf_tmp->refcount = 0;
        tsf_tmp->last     = getmonoclock();
        TAILQ_INIT(&tsf_tmp->iframes);
        TAILQ_INIT(&tsf_tmp->sstart);
        TAILQ_INSERT_TAIL(&ts->files, tsf_tmp, link);

        /* Copy across last start message */
        if (tsf_tl && (ti = TAILQ_LAST(&tsf_tl->sstart, timeshift_index_data_list))) {
#ifdef TSHFT_TRACE
          tvhlog(LOG_DEBUG, "timeshift", "ts %d copy smt_start to new file",
                 ts->id);
#endif
          timeshift_index_data_t *ti2 = calloc(1, sizeof(timeshift_index_data_t));
          ti2->data = streaming_msg_clone(ti->data);
          TAILQ_INSERT_TAIL(&tsf_tmp->sstart, ti2, link);
        }
      }
    }
    tsf_tl = tsf_tmp;
  }

  return tsf_tl;
}
Example #4
0
/*
 * Get current / new file
 */
timeshift_file_t *timeshift_filemgr_get ( timeshift_t *ts, int create )
{
  int fd;
  struct timespec tp;
  timeshift_file_t *tsf_tl, *tsf_hd, *tsf_tmp;
  timeshift_index_data_t *ti;
  char path[PATH_MAX];
  time_t time;

  /* Return last file */
  if (!create)
    return timeshift_filemgr_newest(ts);

  /* No space */
  if (ts->full)
    return NULL;

  /* Store to file */
  clock_gettime(CLOCK_MONOTONIC_COARSE, &tp);
  time   = tp.tv_sec / TIMESHIFT_FILE_PERIOD;
  tsf_tl = TAILQ_LAST(&ts->files, timeshift_file_list);
  if (!tsf_tl || tsf_tl->time != time ||
      (tsf_tl->ram && tsf_tl->woff >= timeshift_conf.ram_segment_size)) {
    tsf_hd = TAILQ_FIRST(&ts->files);

    /* Close existing */
    if (tsf_tl)
      timeshift_filemgr_close(tsf_tl);

    /* Check period */
    if (!timeshift_conf.unlimited_period &&
        ts->max_time && tsf_hd && tsf_tl) {
      time_t d = (tsf_tl->time - tsf_hd->time) * TIMESHIFT_FILE_PERIOD;
      if (d > (ts->max_time+5)) {
        if (!tsf_hd->refcount) {
          timeshift_filemgr_remove(ts, tsf_hd, 0);
          tsf_hd = NULL;
        } else {
          tvhlog(LOG_DEBUG, "timeshift", "ts %d buffer full", ts->id);
          ts->full = 1;
        }
      }
    }

    /* Check size */
    if (!timeshift_conf.unlimited_size &&
        atomic_pre_add_u64(&timeshift_conf.total_size, 0) >= timeshift_conf.max_size) {

      /* Remove the last file (if we can) */
      if (tsf_hd && !tsf_hd->refcount) {
        timeshift_filemgr_remove(ts, tsf_hd, 0);

      /* Full */
      } else {
        tvhlog(LOG_DEBUG, "timeshift", "ts %d buffer full", ts->id);
        ts->full = 1;
      }
    }

    /* Create new file */
    tsf_tmp = NULL;
    if (!ts->full) {

      tvhtrace("timeshift", "ts %d RAM total %"PRId64" requested %"PRId64" segment %"PRId64,
                   ts->id, atomic_pre_add_u64(&timeshift_total_ram_size, 0),
                   timeshift_conf.ram_size, timeshift_conf.ram_segment_size);
      if (timeshift_conf.ram_size >= 8*1024*1024 &&
          atomic_pre_add_u64(&timeshift_total_ram_size, 0) <
            timeshift_conf.ram_size + (timeshift_conf.ram_segment_size / 2)) {
        tsf_tmp = timeshift_filemgr_file_init(ts, time);
        tsf_tmp->ram_size = MIN(16*1024*1024, timeshift_conf.ram_segment_size);
        tsf_tmp->ram = malloc(tsf_tmp->ram_size);
        if (!tsf_tmp->ram) {
          free(tsf_tmp);
          tsf_tmp = NULL;
        } else {
          tvhtrace("timeshift", "ts %d create RAM segment with %"PRId64" bytes (time %li)",
                   ts->id, tsf_tmp->ram_size, (long)time);
        }
      }
      
      if (!tsf_tmp && !timeshift_conf.ram_only) {
        /* Create directories */
        if (!ts->path) {
          if (timeshift_filemgr_makedirs(ts->id, path, sizeof(path)))
            return NULL;
          ts->path = strdup(path);
        }

        /* Create File */
        snprintf(path, sizeof(path), "%s/tvh-%"PRItime_t, ts->path, time);
        tvhtrace("timeshift", "ts %d create file %s", ts->id, path);
        if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) > 0) {
          tsf_tmp = timeshift_filemgr_file_init(ts, time);
          tsf_tmp->wfd = fd;
          tsf_tmp->path = strdup(path);
        }
      }

      if (tsf_tmp) {
        /* Copy across last start message */
        if (tsf_tl && (ti = TAILQ_LAST(&tsf_tl->sstart, timeshift_index_data_list))) {
          tvhtrace("timeshift", "ts %d copy smt_start to new file",
                   ts->id);
          timeshift_index_data_t *ti2 = calloc(1, sizeof(timeshift_index_data_t));
          ti2->data = streaming_msg_clone(ti->data);
          TAILQ_INSERT_TAIL(&tsf_tmp->sstart, ti2, link);
        }
      }
    }
    tsf_tl = tsf_tmp;
  }

  if (tsf_tl)
    tsf_tl->refcount++;
  return tsf_tl;
}
Example #5
0
static void _process_msg
  ( timeshift_t *ts, streaming_message_t *sm, int *run )
{
  int err;
  timeshift_file_t *tsf;

  /* Process */
  switch (sm->sm_type) {

    /* Terminate */
    case SMT_EXIT:
      if (run) *run = 0;
      break;
    case SMT_STOP:
      if (sm->sm_code != SM_CODE_SOURCE_RECONFIGURED && run)
        *run = 0;
      goto live;

    /* Timeshifting */
    case SMT_SKIP:
    case SMT_SPEED:
      break;

    /* Status */
    case SMT_GRACE:
    case SMT_NOSTART:
    case SMT_NOSTART_WARN:
    case SMT_SERVICE_STATUS:
    case SMT_TIMESHIFT_STATUS:
    case SMT_DESCRAMBLE_INFO:
      goto live;

    /* Store */
    case SMT_SIGNAL_STATUS:
    case SMT_START:
    case SMT_MPEGTS:
    case SMT_PACKET:
      pthread_mutex_lock(&ts->state_mutex);
      ts->buf_time = sm->sm_time;
      if (ts->state == TS_LIVE) {
        streaming_target_deliver2(ts->output, streaming_msg_clone(sm));
        if (sm->sm_type == SMT_PACKET)
          timeshift_packet_log("liv", ts, sm);
      }
      if (sm->sm_type == SMT_START)
        _update_smt_start(ts, (streaming_start_t *)sm->sm_data);
      if (ts->dobuf) {
        if ((tsf = timeshift_filemgr_get(ts, sm->sm_time)) != NULL) {
          if (tsf->wfd >= 0 || tsf->ram) {
            if ((err = _process_msg0(ts, tsf, sm)) < 0) {
              timeshift_filemgr_close(tsf);
              tsf->bad = 1;
              ts->full = 1; ///< Stop any more writing
            } else {
              timeshift_packet_log("sav", ts, sm);
            }
          }
          timeshift_file_put(tsf);
        }
      }
      pthread_mutex_unlock(&ts->state_mutex);
      break;
  }

  /* Next */
  streaming_msg_free(sm);
  return;

live:
  pthread_mutex_lock(&ts->state_mutex);
  if (ts->state == TS_LIVE)
    streaming_target_deliver2(ts->output, sm);
  else
    streaming_msg_free(sm);
  pthread_mutex_unlock(&ts->state_mutex);
}