Exemple #1
0
/*
 * Connected
 */
static int
iptv_rtsp_header ( http_client_t *hc )
{
  iptv_mux_t *im = hc->hc_aux;
  rtsp_priv_t *rp;
  int r;

  if (im == NULL) {
    /* teardown (or teardown timeout) */
    if (hc->hc_cmd == RTSP_CMD_TEARDOWN) {
      pthread_mutex_lock(&global_lock);
      mtimer_arm_rel(&hc->hc_close_timer, iptv_rtsp_close_cb, hc, 0);
      pthread_mutex_unlock(&global_lock);
    }
    return 0;
  }

  if (hc->hc_cmd == RTSP_CMD_GET_PARAMETER && hc->hc_code != HTTP_STATUS_OK) {
    tvhtrace("iptv", "GET_PARAMETER command returned invalid error code %d for '%s', "
        "fall back to OPTIONS in keep alive loop.", hc->hc_code, im->mm_iptv_url_raw);
    hc->hc_rtsp_keep_alive_cmd = RTSP_CMD_OPTIONS;
    return 0;
  }

  if (hc->hc_code != HTTP_STATUS_OK) {
    tvherror("iptv", "invalid error code %d for '%s'", hc->hc_code, im->mm_iptv_url_raw);
    return 0;
  }

  rp = im->im_data;

  switch (hc->hc_cmd) {
  case RTSP_CMD_SETUP:
    r = rtsp_setup_decode(hc, 0);
    if (r >= 0) {
      rtsp_play(hc, rp->path, rp->query);
      rp->play = 1;
    }
    break;
  case RTSP_CMD_PLAY:
    // Now let's set peer port for RTCP
    // Use the HTTP host for sending RTCP reports, NOT the hc_rtp_dest (which is where the stream is sent)
    if (udp_connect(rp->rtcp_info->connection, "rtcp", hc->hc_host, hc->hc_rtcp_server_port)) {
        tvhlog(LOG_WARNING, "rtsp", "Can't connect to remote, RTCP receiver reports won't be sent");
    }
    hc->hc_cmd = HTTP_CMD_NONE;
    pthread_mutex_lock(&global_lock);
    iptv_input_mux_started(hc->hc_aux);
    mtimer_arm_rel(&rp->alive_timer, iptv_rtsp_alive_cb, im,
                   sec2mono(MAX(1, (hc->hc_rtp_timeout / 2) - 1)));
    pthread_mutex_unlock(&global_lock);
    break;
  default:
    break;
  }

  return 0;
}
void
linuxdvb_ca_enqueue_capmt(linuxdvb_ca_t *lca, uint8_t slot, const uint8_t *ptr,
                          int len, uint8_t list_mgmt, uint8_t cmd_id)
{
  linuxdvb_ca_capmt_t *lcc;
  int c = 1;

  if (!lca)
    return;

  if (lca->lca_capmt_query && cmd_id == CA_PMT_CMD_ID_OK_DESCRAMBLING)
    c = 2;

  while (c--) {
    lcc = calloc(1, sizeof(*lcc));

    if (!lcc)
      return;

    lcc->data = malloc(len);
    lcc->len = len;
    lcc->slot = slot;
    lcc->list_mgmt = list_mgmt;
    lcc->cmd_id = (c ? CA_PMT_CMD_ID_QUERY : cmd_id);
    memcpy(lcc->data, ptr, len);

    TAILQ_INSERT_TAIL(&lca->lca_capmt_queue, lcc, lcc_link);

    tvhtrace(LS_EN50221, "%s CAPMT enqueued (%s)", ca_pmt_cmd_id2str(lcc->cmd_id),
             ca_pmt_list_mgmt2str(lcc->list_mgmt));
  }

  mtimer_arm_rel(&lca->lca_capmt_queue_timer,
                 linuxdvb_ca_process_capmt_queue, lca, ms2mono(50));
}
void
mpegts_network_scan_timer_cb ( void *p )
{
  mpegts_network_t *mn = p;
  mpegts_mux_t *mm, *nxt = NULL;
  int r;

  /* Process Q */
  for (mm = TAILQ_FIRST(&mn->mn_scan_pend); mm != NULL; mm = nxt) {
    nxt = TAILQ_NEXT(mm, mm_scan_link);
    assert(mm->mm_scan_state == MM_SCAN_STATE_PEND || mm->mm_scan_state == MM_SCAN_STATE_ACTIVE);

    /* Don't try to subscribe already tuned muxes */
    if (mm->mm_active) continue;

    /* Attempt to tune */
    r = mpegts_mux_subscribe(mm, NULL, "scan", mm->mm_scan_weight,
                             mm->mm_scan_flags |
                             SUBSCRIPTION_ONESHOT |
                             SUBSCRIPTION_TABLES);

    /* Started */
    if (!r) {
      assert(mm->mm_scan_state == MM_SCAN_STATE_ACTIVE);
      continue;
    }
    assert(mm->mm_scan_state == MM_SCAN_STATE_PEND);

    /* No free tuners - stop */
    if (r == SM_CODE_NO_FREE_ADAPTER || r == SM_CODE_NO_ADAPTERS)
      break;

    /* No valid tuners (subtly different, might be able to tuner a later
     * mux)
     */
    if (r == SM_CODE_NO_VALID_ADAPTER && mm->mm_is_enabled(mm))
      continue;

    /* Failed */
    TAILQ_REMOVE(&mn->mn_scan_pend, mm, mm_scan_link);
    if (mm->mm_scan_result != MM_SCAN_FAIL) {
      mm->mm_scan_result = MM_SCAN_FAIL;
      idnode_changed(&mm->mm_id);
    }
    mm->mm_scan_state  = MM_SCAN_STATE_IDLE;
    mm->mm_scan_weight = 0;
    mpegts_network_scan_notify(mm);
  }

  /* Re-arm timer. Really this is just a safety measure as we'd normally
   * expect the timer to be forcefully triggered on finish of a mux scan
   */
  mtimer_arm_rel(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, sec2mono(120));
}
Exemple #4
0
static void
epggrab_ota_kick ( int delay )
{
  /* next round is pending? queue rest of ota muxes */
  if (epggrab_ota_pending_flag) {
    epggrab_ota_pending_flag = 0;
    epggrab_ota_requeue();
  }

  if (TAILQ_EMPTY(&epggrab_ota_pending))
    return;

  mtimer_arm_rel(&epggrab_ota_kick_timer, epggrab_ota_kick_cb, NULL, sec2mono(delay));
}
Exemple #5
0
/*
 * Alive timeout
 */
static void
iptv_rtsp_alive_cb ( void *aux )
{
  iptv_mux_t *im = aux;
  rtsp_priv_t *rp = im->im_data;
  if(rp->hc->hc_rtsp_keep_alive_cmd == RTSP_CMD_GET_PARAMETER)
    rtsp_get_parameter(rp->hc, "position");
  else if(rp->hc->hc_rtsp_keep_alive_cmd == RTSP_CMD_OPTIONS)
    rtsp_send(rp->hc, RTSP_CMD_OPTIONS, rp->path, rp->query, NULL);
  else
    return;
  mtimer_arm_rel(&rp->alive_timer, iptv_rtsp_alive_cb, im,
                 sec2mono(MAX(1, (rp->hc->hc_rtp_timeout / 2) - 1)));
}
static void
linuxdvb_ca_monitor ( void *aux )
{
  linuxdvb_ca_t *lca = aux;
  ca_slot_info_t csi;
  int state;

  csi.num = 0;

  if (lca->lca_ca_fd >= 0) {
    if ((ioctl(lca->lca_ca_fd, CA_GET_SLOT_INFO, &csi)) != 0) {
      tvherror(LS_LINUXDVB, "failed to get CAM slot %u info [e=%s]",
               csi.num, strerror(errno));
    }
    if (csi.flags & CA_CI_MODULE_READY)
      state = CA_SLOT_STATE_MODULE_READY;
    else if (csi.flags & CA_CI_MODULE_PRESENT)
      state = CA_SLOT_STATE_MODULE_PRESENT;
    else
      state = CA_SLOT_STATE_EMPTY;

    lca->lca_state_str = ca_slot_state2str(state);

    if (lca->lca_state != state) {
      tvhnotice(LS_LINUXDVB, "CAM slot %u status changed to %s",
                csi.num, lca->lca_state_str);
      idnode_notify_title_changed(&lca->lca_id, NULL);
      lca->lca_state = state;
    }

    if ((!lca->lca_en50221_thread_running) &&
        (state == CA_SLOT_STATE_MODULE_READY)) 
    {
      lca->lca_en50221_thread_running = 1;
      tvhthread_create(&lca->lca_en50221_thread, NULL,
                       linuxdvb_ca_en50221_thread, lca, "lnxdvb-ca");
    } else if (lca->lca_en50221_thread_running &&
               (state != CA_SLOT_STATE_MODULE_READY))
    {
      lca->lca_en50221_thread_running = 0;
      pthread_join(lca->lca_en50221_thread, NULL);
    }

  }

  mtimer_arm_rel(&lca->lca_monitor_timer, linuxdvb_ca_monitor, lca, ms2mono(250));
}
void
mpegts_network_scan_queue_add
  ( mpegts_mux_t *mm, int weight, int flags, int delay )
{
  int reload = 0;
  char buf[256], buf2[256];;
  mpegts_network_t *mn = mm->mm_network;

  if (!mm->mm_is_enabled(mm)) return;

  if (weight <= 0) return;

  if (weight > mm->mm_scan_weight) {
    mm->mm_scan_weight = weight;
    reload             = 1;
  }

  /* Already active */
  if (mm->mm_scan_state == MM_SCAN_STATE_ACTIVE)
    return;

  /* Remove entry (or ignore) */
  if (mm->mm_scan_state == MM_SCAN_STATE_PEND) {
    if (!reload)
      return;
    TAILQ_REMOVE(&mn->mn_scan_pend, mm, mm_scan_link);
  }

  mpegts_mux_nice_name(mm, buf, sizeof(buf));
  mn->mn_display_name(mn, buf2, sizeof(buf2));
  tvhdebug(LS_MPEGTS, "%s - adding mux %s to scan queue weight %d flags %04X",
           buf2, buf, weight, flags);

  /* Add new entry */
  mm->mm_scan_state  = MM_SCAN_STATE_PEND;
  mm->mm_scan_flags |= flags;
  if (mm->mm_scan_flags == 0)
    mm->mm_scan_flags = SUBSCRIPTION_IDLESCAN;
  TAILQ_INSERT_SORTED_R(&mn->mn_scan_pend, mpegts_mux_queue,
                        mm, mm_scan_link, mm_cmp);
  mtimer_arm_rel(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, sec2mono(delay));
  mpegts_network_scan_notify(mm);
}
void
mpegts_network_scan_queue_del ( mpegts_mux_t *mm )
{
  mpegts_network_t *mn = mm->mm_network;
  char buf[256], buf2[256];
  if (mm->mm_scan_state == MM_SCAN_STATE_ACTIVE) {
    TAILQ_REMOVE(&mn->mn_scan_active, mm, mm_scan_link);
  } else if (mm->mm_scan_state == MM_SCAN_STATE_PEND) {
    TAILQ_REMOVE(&mn->mn_scan_pend, mm, mm_scan_link);
  }
  mpegts_mux_nice_name(mm, buf, sizeof(buf));
  mn->mn_display_name(mn, buf2, sizeof(buf2));
  tvhdebug(LS_MPEGTS, "%s - removing mux %s from scan queue", buf2, buf);
  mm->mm_scan_state  = MM_SCAN_STATE_IDLE;
  mm->mm_scan_weight = 0;
  mtimer_disarm(&mm->mm_scan_timeout);
  mtimer_arm_rel(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, 0);
  mpegts_network_scan_notify(mm);
}
linuxdvb_ca_t *
linuxdvb_ca_create
  ( htsmsg_t *conf, linuxdvb_adapter_t *la, int number, const char *ca_path)
{
  linuxdvb_ca_t *lca;
  char id[6];
  const char *uuid = NULL;

  lca = calloc(1, sizeof(linuxdvb_ca_t));
  memset(lca, 0, sizeof(linuxdvb_ca_t));
  lca->lca_number = number;
  lca->lca_ca_path  = strdup(ca_path);
  lca->lca_ca_fd = -1;
  lca->lca_capmt_interval = 100;
  lca->lca_capmt_query_interval = 1200;

  /* Internal config ID */
  snprintf(id, sizeof(id), "ca%u", number);

  if (conf)
    conf = htsmsg_get_map(conf, id);
  if (conf)
    uuid = htsmsg_get_str(conf, "uuid");

  if (idnode_insert(&lca->lca_id, uuid, &linuxdvb_ca_class, 0)) {
    free(lca);
    return NULL;
  }

  if (conf)
    idnode_load(&lca->lca_id, conf);

  /* Adapter link */
  lca->lca_adapter = la;
  LIST_INSERT_HEAD(&la->la_ca_devices, lca, lca_link);

  TAILQ_INIT(&lca->lca_capmt_queue);

  mtimer_arm_rel(&lca->lca_monitor_timer, linuxdvb_ca_monitor, lca, ms2mono(250));

  return lca;
}
/* Finished */
static inline void
mpegts_network_scan_mux_done0
  ( mpegts_mux_t *mm, mpegts_mux_scan_result_t result, int weight )
{
  mpegts_network_t *mn = mm->mm_network;
  mpegts_mux_scan_state_t state = mm->mm_scan_state;

  /* prevent double del: */
  /*   mpegts_mux_stop -> mpegts_network_scan_mux_cancel */
  mm->mm_scan_state = MM_SCAN_STATE_IDLE;
  mpegts_mux_unsubscribe_by_name(mm, "scan");
  mm->mm_scan_state = state;

  if (state == MM_SCAN_STATE_PEND) {
    if (weight || mn->mn_idlescan) {
      if (!weight)
        mm->mm_scan_weight = SUBSCRIPTION_PRIO_SCAN_IDLE;
      TAILQ_REMOVE(&mn->mn_scan_pend, mm, mm_scan_link);
      TAILQ_INSERT_SORTED_R(&mn->mn_scan_pend, mpegts_mux_queue,
                            mm, mm_scan_link, mm_cmp);
      mtimer_arm_rel(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, sec2mono(10));
      weight = 0;
    } else {
      mpegts_network_scan_queue_del(mm);
    }
  } else {
    if (!weight && mn->mn_idlescan)
      weight = SUBSCRIPTION_PRIO_SCAN_IDLE;
    mpegts_network_scan_queue_del(mm);
  }

  if (result != MM_SCAN_NONE && mm->mm_scan_result != result) {
    mm->mm_scan_result = result;
    idnode_changed(&mm->mm_id);
  }

  /* Re-enable? */
  if (weight > 0)
    mpegts_network_scan_queue_add(mm, weight, mm->mm_scan_flags, 10);
}
Exemple #11
0
static void
linuxdvb_ca_process_capmt_queue ( void *aux )
{
  linuxdvb_ca_t *lca = aux;
  linuxdvb_ca_capmt_t *lcc;
  struct section *section;
  struct section_ext *result;
  struct mpeg_pmt_section *pmt;
  uint8_t capmt[4096];
  int size, i;

  lcc = TAILQ_FIRST(&lca->lca_capmt_queue);

  if (!lcc)
    return;

  if (!(section = section_codec(lcc->data, lcc->len))){
    tvherror(LS_EN50221, "failed to decode PMT section");
    goto done;
  }

  if (!(result = section_ext_decode(section, 0))){
    tvherror(LS_EN50221, "failed to decode PMT ext_section");
    goto done;
  }

  if (!(pmt = mpeg_pmt_section_codec(result))){
    tvherror(LS_EN50221, "failed to decode PMT");
    goto done;
  }

  size = en50221_ca_format_pmt(pmt, capmt, sizeof(capmt), 0,
                               lcc->list_mgmt, lcc->cmd_id);

  if (size < 0) {
    tvherror(LS_EN50221, "Failed to format CAPMT");
  }

  if (en50221_app_ca_pmt(lca->lca_ca_resource, lca->lca_ca_session_number,
                         capmt, size)) {
        tvherror(LS_EN50221, "Failed to send CAPMT");
  }

  tvhtrace(LS_EN50221, "%s CAPMT sent (%s)", ca_pmt_cmd_id2str(lcc->cmd_id),
           ca_pmt_list_mgmt2str(lcc->list_mgmt));
  tvhlog_hexdump(LS_EN50221, capmt, size);

done:
  i = (lcc->cmd_id == CA_PMT_CMD_ID_QUERY) ?
    lca->lca_capmt_query_interval : lca->lca_capmt_interval;

  TAILQ_REMOVE(&lca->lca_capmt_queue, lcc, lcc_link);

  free(lcc->data);
  free(lcc);

  if (!TAILQ_EMPTY(&lca->lca_capmt_queue)) {
    mtimer_arm_rel(&lca->lca_capmt_queue_timer,
                   linuxdvb_ca_process_capmt_queue, lca, ms2mono(i));
  }
}