/* * 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)); }
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)); }
/* * 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); }
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)); } }