static void satip_discovery_timer_cb(void *aux) { int i; if (!tvheadend_running) return; if (!upnp_running) { gtimer_arm(&satip_discovery_timer, satip_discovery_timer_cb, NULL, 1); return; } if (satip_discovery_service == NULL) { satip_discovery_service = upnp_service_create(upnp_service); if (satip_discovery_service) { satip_discovery_service->us_received = satip_discovery_service_received; satip_discovery_service->us_destroy = satip_discovery_service_destroy; } } if (satip_discovery_service) satip_discovery_send_msearch((void *)1); for (i = 0; i < satip_static_clients->num; i++) satip_discovery_static(satip_static_clients->str[i]); gtimer_arm(&satip_discovery_timer, satip_discovery_timer_cb, NULL, 3600); #undef MSG }
void satip_device_discovery_start( void ) { if (!satip_enabled) return; gtimer_arm(&satip_discovery_timer, satip_discovery_timer_cb, NULL, 1); gtimer_arm(&satip_discovery_static_timer, satip_discovery_static_timer_cb, NULL, 1); }
/* * 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); gtimer_arm(&hc->hc_close_timer, iptv_rtsp_close_cb, hc, 0); pthread_mutex_unlock(&global_lock); } return 0; } if (hc->hc_code != HTTP_STATUS_OK) { tvherror("iptv", "invalid error code %d for '%s'", hc->hc_code, im->mm_iptv_url); 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); gtimer_arm(&rp->alive_timer, iptv_rtsp_alive_cb, im, MAX(1, (hc->hc_rtp_timeout / 2) - 1)); pthread_mutex_unlock(&global_lock); break; default: break; } return 0; }
static void satip_discovery_timerq_cb(void *aux) { satip_discovery_t *d, *next; int r; lock_assert(&global_lock); next = TAILQ_FIRST(&satip_discoveries); while (next) { d = next; next = TAILQ_NEXT(d, disc_link); if (d->http_client) { if (dispatch_clock - d->http_start > 4) satip_discovery_destroy(d, 1); continue; } d->http_client = http_client_connect(d, HTTP_VERSION_1_1, d->url.scheme, d->url.host, d->url.port, NULL); if (d->http_client == NULL) satip_discovery_destroy(d, 1); else { d->http_start = dispatch_clock; d->http_client->hc_conn_closed = satip_discovery_http_closed; http_client_register(d->http_client); r = http_client_simple(d->http_client, &d->url); if (r < 0) satip_discovery_destroy(d, 1); } } if (TAILQ_FIRST(&satip_discoveries)) gtimer_arm(&satip_discovery_timerq, satip_discovery_timerq_cb, NULL, 5); }
/* 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_unsubscribe_by_name(mm, "scan"); if (mm->mm_scan_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); gtimer_arm(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, 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; mm->mm_config_save(mm); } /* Re-enable? */ if (weight > 0) mpegts_network_scan_queue_add(mm, weight, mm->mm_scan_flags, 10); }
/* * 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); gtimer_arm(&hc->hc_close_timer, iptv_rtsp_close_cb, hc, 0); pthread_mutex_unlock(&global_lock); } return 0; } if (hc->hc_code != HTTP_STATUS_OK) { tvherror("iptv", "invalid error code %d for '%s'", hc->hc_code, im->mm_iptv_url); 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: hc->hc_cmd = HTTP_CMD_NONE; pthread_mutex_lock(&global_lock); iptv_input_mux_started(hc->hc_aux); gtimer_arm(&rp->alive_timer, iptv_rtsp_alive_cb, im, MAX(1, (hc->hc_rtp_timeout / 2) - 1)); pthread_mutex_unlock(&global_lock); break; default: break; } return 0; }
/* * Alive timeout */ static void iptv_rtsp_alive_cb ( void *aux ) { iptv_mux_t *im = aux; rtsp_priv_t *rp = im->im_data; rtsp_options(rp->hc); gtimer_arm(&rp->alive_timer, iptv_rtsp_alive_cb, im, rp->hc->hc_rtp_timeout / 2); }
/* * Alive timeout */ static void iptv_rtsp_alive_cb ( void *aux ) { iptv_mux_t *im = aux; rtsp_priv_t *rp = im->im_data; rtsp_send(rp->hc, RTSP_CMD_OPTIONS, rp->path, rp->query, NULL); gtimer_arm(&rp->alive_timer, iptv_rtsp_alive_cb, im, MAX(1, (rp->hc->hc_rtp_timeout / 2) - 1)); }
static void satip_discovery_static_timer_cb(void *aux) { int i; if (!tvheadend_running) return; for (i = 0; i < satip_static_clients->num; i++) satip_discovery_static(satip_static_clients->str[i]); gtimer_arm(&satip_discovery_static_timer, satip_discovery_static_timer_cb, NULL, 3600); }
static void satip_discovery_timer_cb(void *aux) { if (!tvheadend_running) return; if (!upnp_running) { gtimer_arm(&satip_discovery_timer, satip_discovery_timer_cb, NULL, 1); return; } if (satip_discovery_service == NULL) { satip_discovery_service = upnp_service_create(upnp_service); if (satip_discovery_service) { satip_discovery_service->us_received = satip_discovery_service_received; satip_discovery_service->us_destroy = satip_discovery_service_destroy; } } if (satip_discovery_service) satip_discovery_send_msearch((void *)1); gtimer_arm(&satip_discovery_timer, satip_discovery_timer_cb, NULL, 3600); }
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); /* 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) 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; mm->mm_config_save(mm); } 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 */ gtimer_arm(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, 120); }
void download_start( download_t *dn, const char *url, void *aux ) { if (dn->http_client) { http_client_close(dn->http_client); dn->http_client = NULL; } if (url) dn->url = strdup(url); dn->aux = aux; gtimer_arm(&dn->fetch_timer, download_fetch, dn, 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; gtimer_arm(&epggrab_ota_kick_timer, epggrab_ota_kick_cb, NULL, delay); }
void mpegts_network_scan_queue_del ( mpegts_mux_t *mm ) { mpegts_network_t *mn = mm->mm_network; 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); } mm->mm_scan_state = MM_SCAN_STATE_IDLE; mm->mm_scan_weight = 0; gtimer_disarm(&mm->mm_scan_timeout); gtimer_arm(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, 0); mpegts_network_scan_notify(mm); }
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("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); gtimer_arm(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, 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("mpegts", "%s - removing mux %s from scan queue", buf2, buf); mm->mm_scan_state = MM_SCAN_STATE_IDLE; mm->mm_scan_weight = 0; gtimer_disarm(&mm->mm_scan_timeout); gtimer_arm(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, 0); mpegts_network_scan_notify(mm); }
static int download_fetch_complete(http_client_t *hc) { download_t *dn = hc->hc_aux; const char *last_url = NULL; url_t u; switch (hc->hc_code) { case HTTP_STATUS_MOVED: case HTTP_STATUS_FOUND: case HTTP_STATUS_SEE_OTHER: case HTTP_STATUS_NOT_MODIFIED: return 0; } urlinit(&u); if (!urlparse(dn->url, &u)) { last_url = strrchr(u.path, '/'); if (last_url) last_url++; } pthread_mutex_lock(&global_lock); if (dn->http_client == NULL) goto out; if (hc->hc_code == HTTP_STATUS_OK && hc->hc_result == 0 && hc->hc_data_size > 0) dn->process(dn->aux, last_url, hc->hc_url, hc->hc_data, hc->hc_data_size); else tvherror(dn->log, "unable to fetch data from url [%d-%d/%zd]", hc->hc_code, hc->hc_result, hc->hc_data_size); /* note: http_client_close must be called outside http_client callbacks */ gtimer_arm(&dn->fetch_timer, download_fetch_done, hc, 0); out: pthread_mutex_unlock(&global_lock); urlreset(&u); return 0; }
/** * Front end monitor * * Monitor status every second */ static void dvb_fe_monitor(void *aux) { th_dvb_adapter_t *tda = aux; fe_status_t fe_status; int status, v, update = 0, vv, i, fec, q; th_dvb_mux_instance_t *tdmi = tda->tda_mux_current; char buf[50]; gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1); if(tdmi == NULL) return; /** * Read out front end status */ if(ioctl(tda->tda_fe_fd, FE_READ_STATUS, &fe_status)) fe_status = 0; if(fe_status & FE_HAS_LOCK) status = -1; else if(fe_status & (FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_CARRIER)) status = TDMI_FE_BAD_SIGNAL; else if(fe_status & FE_HAS_SIGNAL) status = TDMI_FE_FAINT_SIGNAL; else status = TDMI_FE_NO_SIGNAL; if(tda->tda_fe_monitor_hold > 0) { /* Post tuning threshold */ if(status == -1) { /* We have a lock, don't hold off */ tda->tda_fe_monitor_hold = 0; /* Reset FEC counter */ dvb_fe_get_unc(tda); } else { tda->tda_fe_monitor_hold--; return; } } if(status == -1) { /* Read FEC counter (delta) */ fec = dvb_fe_get_unc(tda); tdmi->tdmi_fec_err_histogram[tdmi->tdmi_fec_err_ptr++] = fec; if(tdmi->tdmi_fec_err_ptr == TDMI_FEC_ERR_HISTOGRAM_SIZE) tdmi->tdmi_fec_err_ptr = 0; v = vv = 0; for(i = 0; i < TDMI_FEC_ERR_HISTOGRAM_SIZE; i++) { if(tdmi->tdmi_fec_err_histogram[i] > DVB_FEC_ERROR_LIMIT) v++; vv += tdmi->tdmi_fec_err_histogram[i]; } vv = vv / TDMI_FEC_ERR_HISTOGRAM_SIZE; if(v == 0) { status = TDMI_FE_OK; } else if(v == 1) { status = TDMI_FE_BURSTY_FEC; } else { status = TDMI_FE_CONSTANT_FEC; } /* bit error rate */ if(ioctl(tda->tda_fe_fd, FE_READ_BER, &tdmi->tdmi_ber) == -1) tdmi->tdmi_ber = -2; /* signal strength */ if(ioctl(tda->tda_fe_fd, FE_READ_SIGNAL_STRENGTH, &tdmi->tdmi_signal) == -1) tdmi->tdmi_signal = -2; /* signal/noise ratio */ if(ioctl(tda->tda_fe_fd, FE_READ_SNR, &tdmi->tdmi_snr) == -1) tdmi->tdmi_snr = -2; } if(status != tdmi->tdmi_fe_status) { tdmi->tdmi_fe_status = status; dvb_mux_nicename(buf, sizeof(buf), tdmi); tvhlog(LOG_DEBUG, "dvb", "\"%s\" on adapter \"%s\", status changed to %s", buf, tda->tda_displayname, dvb_mux_status(tdmi)); update = 1; } if(status != TDMI_FE_UNKNOWN) { if(tda->tda_qmon) { q = tdmi->tdmi_quality + (status - TDMI_FE_OK + 1); q = MAX(MIN(q, 100), 0); } else { q = 100; } if(q != tdmi->tdmi_quality) { tdmi->tdmi_quality = q; update = 1; } } if(update) { htsmsg_t *m = htsmsg_create_map(); htsmsg_add_str(m, "id", tdmi->tdmi_identifier); htsmsg_add_u32(m, "quality", tdmi->tdmi_quality); notify_by_msg("dvbMux", m); dvb_mux_save(tdmi); } }
static void satip_discovery_service_received (uint8_t *data, size_t len, udp_connection_t *conn, struct sockaddr_storage *storage) { char *buf, *ptr, *saveptr; char *argv[10]; char *st = NULL; char *location = NULL; char *server = NULL; char *uuid = NULL; char *bootid = NULL; char *configid = NULL; char *deviceid = NULL; char sockbuf[128]; satip_discovery_t *d; int n, i; if (len > 8191 || satip_discoveries_count > 100) return; buf = alloca(len+1); memcpy(buf, data, len); buf[len] = '\0'; ptr = strtok_r(buf, "\r\n", &saveptr); /* Request decoder */ if (ptr) { if (http_tokenize(ptr, argv, 3, -1) != 3) return; if (conn->multicast) { if (strcmp(argv[0], "NOTIFY")) return; if (strcmp(argv[1], "*")) return; if (strcmp(argv[2], "HTTP/1.1")) return; } else { if (strcmp(argv[0], "HTTP/1.1")) return; if (strcmp(argv[1], "200")) return; } ptr = strtok_r(NULL, "\r\n", &saveptr); } /* Header decoder */ while (1) { if (ptr == NULL) break; if (http_tokenize(ptr, argv, 2, ':') == 2) { if (strcmp(argv[0], "ST") == 0) st = argv[1]; else if (strcmp(argv[0], "LOCATION") == 0) location = argv[1]; else if (strcmp(argv[0], "SERVER") == 0) server = argv[1]; else if (strcmp(argv[0], "BOOTID.UPNP.ORG") == 0) bootid = argv[1]; else if (strcmp(argv[0], "CONFIGID.UPNP.ORG") == 0) configid = argv[1]; else if (strcmp(argv[0], "DEVICEID.SES.COM") == 0) deviceid = argv[1]; else if (strcmp(argv[0], "USN") == 0) { n = http_tokenize(argv[1], argv, ARRAY_SIZE(argv), ':'); for (i = 0; i < n-1; i++) if (argv[i] && strcmp(argv[i], "uuid") == 0) { uuid = argv[++i]; break; } } } ptr = strtok_r(NULL, "\r\n", &saveptr); } /* Sanity checks */ if (st == NULL || strcmp(st, "urn:ses-com:device:SatIPServer:1")) goto add_uuid; if (uuid == NULL || strlen(uuid) < 16 || satip_server_match_uuid(uuid)) goto add_uuid; if (location == NULL || strncmp(location, "http://", 7)) goto add_uuid; if (bootid == NULL || configid == NULL || server == NULL) goto add_uuid; /* Forward information to next layer */ d = calloc(1, sizeof(satip_discovery_t)); if (inet_ntop(conn->ip.ss_family, IP_IN_ADDR(conn->ip), sockbuf, sizeof(sockbuf)) == NULL) { satip_discovery_destroy(d, 0); return; } d->myaddr = strdup(sockbuf); d->location = strdup(location); d->server = strdup(server); d->uuid = strdup(uuid); d->bootid = strdup(bootid); d->configid = strdup(configid); d->deviceid = strdup(deviceid ? deviceid : ""); if (urlparse(d->location, &d->url)) { satip_discovery_destroy(d, 0); return; } pthread_mutex_lock(&global_lock); i = 1; if (!satip_discovery_find(d) && !satip_device_find(d->uuid)) { TAILQ_INSERT_TAIL(&satip_discoveries, d, disc_link); satip_discoveries_count++; gtimer_arm_ms(&satip_discovery_timerq, satip_discovery_timerq_cb, NULL, 250); i = 0; } pthread_mutex_unlock(&global_lock); if (i) /* duplicate */ satip_discovery_destroy(d, 0); return; add_uuid: if (deviceid == NULL || uuid == NULL) return; /* if new uuid was discovered, retrigger MSEARCH */ pthread_mutex_lock(&global_lock); if (!satip_device_find(uuid)) gtimer_arm(&satip_discovery_timer, satip_discovery_timer_cb, NULL, 5); pthread_mutex_unlock(&global_lock); }
void satip_device_discovery_start( void ) { gtimer_arm(&satip_discovery_timer, satip_discovery_timer_cb, NULL, 1); gtimer_arm(&satip_discovery_static_timer, satip_discovery_static_timer_cb, NULL, 1); }
static void tvhdhomerun_device_discovery_start( void ) { gtimer_arm(&tvhdhomerun_discovery_timer, tvhdhomerun_discovery_timer_cb, NULL, 1); }