static htsmsg_t * make_usage_report(void) { extern const char *htsversion_full; htsmsg_t *out = htsmsg_create_map(); htsmsg_add_str(out, "deviceid", gconf.device_id); htsmsg_add_str(out, "version", htsversion_full); htsmsg_add_str(out, "arch", arch_get_system_type()); htsmsg_add_u32(out, "verint", app_get_version_int()); htsmsg_add_u32(out, "generated", time(NULL)); if(gconf.os_info[0]) htsmsg_add_str(out, "os" , gconf.os_info); time_t now = arch_get_ts() / 1000000LL; int runtime = now - usage_time_base; htsmsg_s32_inc(usage_counters, "runtime", runtime); usage_time_base = now; htsmsg_add_msg(out, "counters", usage_counters); usage_counters = htsmsg_create_map(); htsmsg_add_msg(out, "plugincounters", plugin_counters); plugin_counters = htsmsg_create_map(); return out; }
event_t * mp_dequeue_event_deadline(media_pipe_t *mp, int timeout) { event_t *e; hts_mutex_lock(&mp->mp_mutex); if(timeout == 0) { e = TAILQ_FIRST(&mp->mp_eq); } else { int64_t ts = arch_get_ts() + timeout * 1000LL; while((e = TAILQ_FIRST(&mp->mp_eq)) == NULL) { if(hts_cond_wait_timeout_abs(&mp->mp_backpressure, &mp->mp_mutex, ts)) break; } } if(e != NULL) TAILQ_REMOVE(&mp->mp_eq, e, e_link); hts_mutex_unlock(&mp->mp_mutex); return e; }
int longpress_up(lphelper_t *lph) { int r = lph->expire > arch_get_ts() && lph->down != 2; lph->down = 0; return r; }
static int set_timer(duk_context *duk, int repeat) { es_context_t *ec = es_get(duk); es_timer_t *et = es_resource_create(ec, &es_resource_timer, 1); int val = duk_require_int(duk, 1); es_root_register(duk, 0, et); et->et_interval = val * repeat; int64_t now = arch_get_ts(); et->et_expire = now + val * 1000LL; hts_mutex_lock(&timer_mutex); if(thread_running == 0) { thread_running = 1; hts_thread_create_detached("estimer", timer_thread, NULL, THREAD_PRIO_MODEL); } else { hts_cond_signal(&timer_cond); } LIST_INSERT_SORTED(&timers, et, et_link, estimercmp, es_timer_t); hts_mutex_unlock(&timer_mutex); es_resource_push(duk, &et->super); return 1; }
static void es_timer_info(es_resource_t *eres, char *dst, size_t dstsize) { es_timer_t *et = (es_timer_t *)eres; int64_t delta = et->et_expire - arch_get_ts(); snprintf(dst, dstsize, "in %d ms repeat %d ms", (int)(delta / 1000), et->et_interval); }
void longpress_down(lphelper_t *lph) { if(lph->down) return; lph->expire = arch_get_ts() + LP_TIMEOUT; lph->down = 1; }
static void * timer_thread(void *aux) { int destroy = 0; es_timer_t *et; hts_mutex_lock(&timer_mutex); while(1) { et = LIST_FIRST(&timers); if(et == NULL) break; int64_t now = arch_get_ts(); int64_t delta = et->et_expire - now; if(delta > 0) { int ms = (delta + 999) / 1000; hts_cond_wait_timeout(&timer_cond, &timer_mutex, ms); continue; } LIST_REMOVE(et, et_link); if(et->et_interval) { et->et_expire = now + et->et_interval * 1000LL; LIST_INSERT_SORTED(&timers, et, et_link, estimercmp, es_timer_t); } else { et->et_expire = 0; destroy = 1; } es_resource_retain(&et->super); hts_mutex_unlock(&timer_mutex); es_context_t *ec = et->super.er_ctx; es_context_begin(ec); duk_context *ctx = ec->ec_duk; es_push_root(ctx, et); int rc = duk_pcall(ctx, 0); if(rc) es_dump_err(ctx); duk_pop(ctx); es_resource_release(&et->super); if(destroy) es_resource_destroy(&et->super); es_context_end(ec, 0); hts_mutex_lock(&timer_mutex); } thread_running = 0; hts_mutex_unlock(&timer_mutex); return NULL; }
static int check_vsync(glw_x11_t *gx11) { int i; int64_t c; glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glXSwapBuffers(gx11->display, gx11->win); c = arch_get_ts(); for(i = 0; i < 5; i++) { glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glXSwapBuffers(gx11->display, gx11->win); } c = arch_get_ts() - c; return c > 25000; // Probably working }
static void current_media_playstatus(void *opaque, const char *str) { // Reset time to avoid risk of turning off as soon as track playback // has ended if UI has been idle last_activity = arch_get_ts(); active_media = !!str; // If str is something then we're playing, paused, etc }
void usage_init(void) { hts_mutex_init(&usage_mutex); usage_time_base = arch_get_ts() / 1000000LL; usage_counters = htsmsg_create_map(); plugin_counters = htsmsg_create_map(); }
static void tmdb_check_rate_limit(void) { while(1) { hts_mutex_lock(&tmdb_mutex); int64_t sleeptime = tmdb_no_request_before - arch_get_ts(); hts_mutex_unlock(&tmdb_mutex); if(sleeptime < 0) return; usleep(MIN(sleeptime, 10000000)); } }
void * event_create(event_type_t type, size_t size) { event_t *e = malloc(size); e->e_timestamp = arch_get_ts(); e->e_nav = NULL; e->e_dtor = NULL; atomic_set(&e->e_refcount, 1); e->e_flags = 0; e->e_type = type; return e; }
/** * Periodically check if we should auto standby */ static void check_autostandby(callout_t *c, void *aux) { int64_t idle = arch_get_ts() - last_activity; idle /= (1000000 * 60); // Convert to minutes if(standby_delay && idle >= standby_delay && !active_media) { TRACE(TRACE_INFO, "runcontrol", "Automatic standby after %d minutes idle", standby_delay); app_shutdown(APP_EXIT_STANDBY); return; } callout_arm(&autostandby_timer, check_autostandby, NULL, 1); }
static void tmdb_handle_rate_limit(struct http_header_list *response_headers) { const char *retry = http_header_get(response_headers, "retry-after"); int waittime = 5; if(retry != NULL) waittime = atoi(retry) + 1; http_headers_free(response_headers); TMDB_TRACE("Rate limited - Throttling requests for %d seconds", waittime); hts_mutex_lock(&tmdb_mutex); tmdb_no_request_before = arch_get_ts() + waittime * 1000000; hts_mutex_unlock(&tmdb_mutex); }
int hts_cond_wait_timeout_abs(hts_cond_t *c, hts_mutex_t *m, int64_t deadline) { #if defined(__APPLE__) int64_t ts = deadline - arch_get_ts(); if(ts <= 0) return 1; return hts_cond_wait_timeout(c, m, ts / 1000); #else struct timespec ts; ts.tv_sec = deadline / 1000000LL; ts.tv_nsec = (deadline % 1000000LL) * 1000; return pthread_cond_timedwait(c, m, &ts) == ETIMEDOUT; #endif }
void usage_fini(void) { if(gconf.device_id[0] == 0) return; hts_mutex_lock(&usage_mutex); int runtime = arch_get_ts() / 1000000LL - usage_time_base; htsmsg_s32_inc(usage_counters, "runtime", runtime); htsmsg_t *r = make_usage_report(); hts_mutex_unlock(&usage_mutex); htsmsg_store_save(r, "usage"); htsmsg_release(r); }
static void init_autostandby(void) { setting_create(SETTING_INT, gconf.settings_general, SETTINGS_INITIAL_UPDATE, SETTING_TITLE(_p("Automatic standby")), SETTING_STORE("runcontrol", "autostandby"), SETTING_WRITE_INT(&standby_delay), SETTING_RANGE(0, 60), SETTING_STEP(5), SETTING_UNIT_CSTR("min"), SETTING_ZERO_TEXT(_p("Off")), NULL); last_activity = arch_get_ts(); prop_subscribe(0, PROP_TAG_NAME("global", "media", "current", "playstatus"), PROP_TAG_CALLBACK_STRING, current_media_playstatus, NULL, NULL); callout_arm(&autostandby_timer, check_autostandby, NULL, 1); }
static void render_unlocked(glw_root_t *gr) { glw_backend_root_t *gbr = &gr->gr_be; render_state_t rs = {0}; int64_t ts = arch_get_ts(); int current_blendmode = GLW_BLEND_NORMAL; glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE); const float *vertices = gr->gr_vertex_buffer; glBindBuffer(GL_ARRAY_BUFFER, gbr->gbr_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * VERTEX_SIZE * gr->gr_vertex_offset, vertices, GL_STATIC_DRAW); int current_frontface = GLW_CCW; glFrontFace(GL_CCW); vertices = NULL; glVertexAttribPointer(0, 4, GL_FLOAT, 0, sizeof(float) * VERTEX_SIZE, vertices); glVertexAttribPointer(1, 4, GL_FLOAT, 0, sizeof(float) * VERTEX_SIZE, vertices + 4); glVertexAttribPointer(2, 4, GL_FLOAT, 0, sizeof(float) * VERTEX_SIZE, vertices + 8); for(int j = 0; j < gr->gr_num_render_jobs; j++) { const glw_render_order_t *ro = gr->gr_render_order + j; const glw_render_job_t *rj = ro->job; if(unlikely(rj->num_vertices == 0)) continue; const struct glw_backend_texture *t0 = rj->t0; glw_program_t *gp = load_program(gr, t0, rj->t1, rj->blur, rj->flags, rj->gpa, &rs, rj); if(gbr->gbr_use_stencil_buffer) glStencilFunc(GL_GEQUAL, ro->zindex, 0xFF); if(unlikely(gp == NULL)) { #if ENABLE_GLW_BACKEND_OPENGL if(rj->eyespace) { glLoadMatrixf(glw_identitymtx); } else { glLoadMatrixf(glw_mtx_get(rj->m)); } glBegin(GL_QUADS); if(t0 != NULL) glTexCoord2i(0, t0->height); glVertex3i(-1, -1, 0); if(t0 != NULL) glTexCoord2i(t0->width, t0->height); glVertex3i(1, -1, 0); if(t0 != NULL) glTexCoord2i(t0->width, 0); glVertex3i(1, 1, 0); if(t0 != NULL) glTexCoord2i(0, 0); glVertex3i(-1, 1, 0); glEnd(); glDisable(t0->gltype); #endif continue; } else { glUniform4f(gp->gp_uniform_color_offset, rj->rgb_off.r, rj->rgb_off.g, rj->rgb_off.b, 0); glUniform4f(gbr->gbr_current->gp_uniform_color, rj->rgb_mul.r, rj->rgb_mul.g, rj->rgb_mul.b, rj->alpha); if(gp->gp_uniform_time != -1) glUniform1f(gp->gp_uniform_time, gr->gr_time_sec); if(gp->gp_uniform_resolution != -1) glUniform2f(gp->gp_uniform_resolution, rj->width, rj->height); if(gp->gp_uniform_blur != -1 && t0 != NULL) glUniform3f(gp->gp_uniform_blur, rj->blur, 1.5 / t0->width, 1.5 / t0->height); if(rj->eyespace) { glUniformMatrix4fv(gp->gp_uniform_modelview, 1, 0, glw_identitymtx); } else { glUniformMatrix4fv(gp->gp_uniform_modelview, 1, 0, glw_mtx_get(rj->m)); } } if(unlikely(current_blendmode != rj->blendmode)) { current_blendmode = rj->blendmode; switch(current_blendmode) { case GLW_BLEND_NORMAL: glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE); break; case GLW_BLEND_ADDITIVE: glBlendFuncSeparate(GL_SRC_COLOR, GL_ONE, GL_ONE_MINUS_DST_ALPHA, GL_ONE); break; } } if(unlikely(current_frontface != rj->frontface)) { current_frontface = rj->frontface; glFrontFace(current_frontface == GLW_CW ? GL_CW : GL_CCW); } glDrawArrays(rj->primitive_type, rj->vertex_offset, rj->num_vertices); } if(current_blendmode != GLW_BLEND_NORMAL) { glBlendFuncSeparate(GL_SRC_COLOR, GL_ONE, GL_ONE_MINUS_DST_ALPHA, GL_ONE); } ts = arch_get_ts() - ts; static int hold; hold++; if(hold < 20) return; #if 0 static int cnt; static int64_t tssum; tssum += ts; cnt++; printf("%16d (%d) %d saved texloads\n", (int)ts, (int)(tssum/cnt), rs.texload_skips); #endif }
static int ssdp_loop(int log_fail) { struct sockaddr_in si = {0}; int fdm, fdu; int one = 1, r; int64_t next_send = 0; struct pollfd fds[2]; struct ip_mreq imr; fdm = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); setsockopt(fdm, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)); #if defined(SO_REUSEPORT) setsockopt(fdm, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(int)); #endif #if defined(IP_RECVDSTADDR) setsockopt(fdm, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(int)); #endif si.sin_family = AF_INET; si.sin_port = htons(1900); if(bind(fdm, (struct sockaddr *)&si, sizeof(struct sockaddr_in)) == -1) { if(log_fail) TRACE(TRACE_ERROR, "SSDP", "Unable to bind -- %s", strerror(errno)); close(fdm); return 1; } memset(&imr, 0, sizeof(imr)); imr.imr_multiaddr.s_addr = htonl(0xeffffffa); // 239.255.255.250 if(setsockopt(fdm, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) == -1) { if(log_fail) TRACE(TRACE_ERROR, "SSDP", "Unable to join 239.255.255.250: %s", strerror(errno)); close(fdm); return 1; } fdu = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); #if defined(IP_RECVDSTADDR) setsockopt(fdu, IPPROTO_IP, IP_RECVDSTADDR, &one, sizeof(int)); #endif si.sin_family = AF_INET; si.sin_port = 0; if(bind(fdu, (struct sockaddr *)&si, sizeof(struct sockaddr_in)) == -1) { if(log_fail) TRACE(TRACE_ERROR, "SSDP", "Unable to bind -- %s", strerror(errno)); close(fdu); close(fdm); return 1; } ssdp_fdm = fdm; ssdp_fdu = fdu; ssdp_send_static(fdu, SEARCHREQ); fds[0].fd = fdm; fds[0].events = POLLIN; fds[1].fd = fdu; fds[1].events = POLLIN; TRACE(TRACE_DEBUG, "SSDP", "Running"); while(ssdp_run) { int64_t delta = next_send - arch_get_ts(); if(delta <= 0) { delta = 15000000LL; next_send = arch_get_ts() + delta; ssdp_send_notify("ssdp:alive"); } r = poll(fds, 2, (delta / 1000) + 1); if(r > 0 && fds[0].revents & POLLIN) ssdp_input(fdm, 1); if(r > 0 && fds[1].revents & POLLIN) ssdp_input(fdu, 0); } return 0; }
/** * Called from various places to indicate that user is active * * Defined in main.h */ void runcontrol_activity(void) { if(standby_delay) last_activity = arch_get_ts(); }
static void render_unlocked(glw_root_t *gr) { glw_backend_root_t *gbr = &gr->gr_be; render_state_t rs = {0}; int64_t ts = arch_get_ts(); int uni_calls = 0; int saved_calls = 0; int current_blendmode = GLW_BLEND_NORMAL; glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE); const float *vertices = gr->gr_vertex_buffer; glBindBuffer(GL_ARRAY_BUFFER, gbr->gbr_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * VERTEX_SIZE * gr->gr_vertex_offset, vertices, GL_STATIC_DRAW); int current_frontface = GLW_CCW; glFrontFace(GL_CCW); vertices = NULL; glVertexAttribPointer(0, 4, GL_FLOAT, 0, sizeof(float) * VERTEX_SIZE, vertices); glVertexAttribPointer(1, 4, GL_FLOAT, 0, sizeof(float) * VERTEX_SIZE, vertices + 4); glVertexAttribPointer(2, 4, GL_FLOAT, 0, sizeof(float) * VERTEX_SIZE, vertices + 8); for(int j = 0; j < gr->gr_num_render_jobs; j++) { const glw_render_order_t *ro = gr->gr_render_order + j; const glw_render_job_t *rj = ro->job; if(unlikely(rj->num_vertices == 0)) continue; const struct glw_backend_texture *t0 = rj->t0; glw_program_t *gp = load_program(gr, t0, rj->t1, rj->blur, rj->flags, rj->gpa, &rs, rj); if(gbr->gbr_use_stencil_buffer) glStencilFunc(GL_GEQUAL, ro->zindex, 0xFF); if(unlikely(gp == NULL)) { #if ENABLE_GLW_BACKEND_OPENGL if(rj->eyespace) { glLoadMatrixf(glw_identitymtx); } else { glLoadMatrixf(glw_mtx_get(rj->m)); } glBegin(GL_QUADS); if(t0 != NULL) glTexCoord2i(0, t0->height); glVertex3i(-1, -1, 0); if(t0 != NULL) glTexCoord2i(t0->width, t0->height); glVertex3i(1, -1, 0); if(t0 != NULL) glTexCoord2i(t0->width, 0); glVertex3i(1, 1, 0); if(t0 != NULL) glTexCoord2i(0, 0); glVertex3i(-1, 1, 0); glEnd(); glDisable(t0->gltype); #endif continue; } else { if(!glw_rgb_cmp(&gp->gp_current_color_offset, &rj->rgb_off)) { glw_rgb_cpy(&gp->gp_current_color_offset, &rj->rgb_off); glUniform4f(gp->gp_uniform_color_offset, rj->rgb_off.r, rj->rgb_off.g, rj->rgb_off.b, 0); uni_calls++; } else { saved_calls++; } if(!glw_rgb_cmp(&gp->gp_current_color_mul, &rj->rgb_mul) || gp->gp_current_alpha != rj->alpha) { glw_rgb_cpy(&gp->gp_current_color_mul, &rj->rgb_mul); gp->gp_current_alpha = rj->alpha; glUniform4f(gbr->gbr_current->gp_uniform_color, rj->rgb_mul.r, rj->rgb_mul.g, rj->rgb_mul.b, rj->alpha); uni_calls++; } else { saved_calls++; } if(gp->gp_uniform_time != -1) { glUniform1f(gp->gp_uniform_time, gr->gr_time_sec); uni_calls++; } if(gp->gp_uniform_resolution != -1) { glUniform3f(gp->gp_uniform_resolution, rj->width, rj->height, 1); uni_calls++; } if(gp->gp_uniform_blur != -1 && t0 != NULL) { glUniform3f(gp->gp_uniform_blur, rj->blur, 1.5 / t0->width, 1.5 / t0->height); uni_calls++; } if(rj->eyespace) { if(!gp->gp_identity_mvm) { glUniformMatrix4fv(gp->gp_uniform_modelview, 1, 0, glw_identitymtx); gp->gp_identity_mvm = 1; uni_calls++; } else { saved_calls++; } } else { gp->gp_identity_mvm = 0; glUniformMatrix4fv(gp->gp_uniform_modelview, 1, 0, glw_mtx_get(rj->m)); uni_calls++; } } if(unlikely(current_blendmode != rj->blendmode)) { current_blendmode = rj->blendmode; switch(current_blendmode) { case GLW_BLEND_NORMAL: glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE); break; case GLW_BLEND_ADDITIVE: glBlendFuncSeparate(GL_SRC_COLOR, GL_ONE, GL_ONE_MINUS_DST_ALPHA, GL_ONE); break; } } if(unlikely(current_frontface != rj->frontface)) { current_frontface = rj->frontface; glFrontFace(current_frontface == GLW_CW ? GL_CW : GL_CCW); } glDrawElements(rj->primitive_type, rj->num_indices, GL_UNSIGNED_SHORT, gr->gr_index_buffer + rj->index_offset); } if(current_blendmode != GLW_BLEND_NORMAL) { glBlendFuncSeparate(GL_SRC_COLOR, GL_ONE, GL_ONE_MINUS_DST_ALPHA, GL_ONE); } int64_t tse = arch_get_ts(); ts = tse - ts; static int hold; hold++; if(hold < 20) return; #if 0 static int cnt; static int avg; static int acc[16]; avg -= acc[cnt & 0xf]; acc[cnt & 0xf] = ts; avg += acc[cnt & 0xf]; cnt++; int t = avg/16; printf("tt:%-5d jobs:%-4d vertices:%-4d ps:%-3d uniforms:%-4d (%-4d) tpv:%2.2f\n", t, gr->gr_num_render_jobs, gr->gr_vertex_offset, rs.program_switches, uni_calls, saved_calls, (float)t / gr->gr_vertex_offset); #endif }
int64_t arch_get_avtime(void) { return arch_get_ts(); }