static THREAD_FUNC_PREFIX hdhomerun_debug_thread_execute(void *arg) { struct hdhomerun_debug_t *dbg = (struct hdhomerun_debug_t *)arg; while (!dbg->terminate) { pthread_mutex_lock(&dbg->queue_lock); struct hdhomerun_debug_message_t *message = dbg->queue_tail; uint32_t queue_depth = dbg->queue_depth; pthread_mutex_unlock(&dbg->queue_lock); if (!message) { msleep_approx(250); continue; } if (queue_depth > 1024) { hdhomerun_debug_pop_and_free_message(dbg); continue; } if (!hdhomerun_debug_output_message(dbg, message)) { msleep_approx(250); continue; } hdhomerun_debug_pop_and_free_message(dbg); } return 0; }
void msleep_minimum(uint64_t ms) { uint64_t stop_time = getcurrenttime() + ms; while (1) { uint64_t current_time = getcurrenttime(); if (current_time >= stop_time) { return; } msleep_approx(stop_time - current_time); } }
void hdhomerun_debug_flush(struct hdhomerun_debug_t *dbg, uint64_t timeout) { if (!dbg) { return; } timeout = getcurrenttime() + timeout; while (getcurrenttime() < timeout) { pthread_mutex_lock(&dbg->queue_lock); struct hdhomerun_debug_message_t *message = dbg->queue_tail; pthread_mutex_unlock(&dbg->queue_lock); if (!message) { return; } msleep_approx(10); } }
static int channelscan_find_lock(struct hdhomerun_channelscan_t *scan, uint32_t frequency, struct hdhomerun_channelscan_result_t *result) { /* Set channel. */ char channel_str[64]; hdhomerun_sprintf(channel_str, channel_str + sizeof(channel_str), "auto:%u", (unsigned int)frequency); int ret = hdhomerun_device_set_tuner_channel(scan->hd, channel_str); if (ret <= 0) { return ret; } /* Wait for lock. */ ret = hdhomerun_device_wait_for_lock(scan->hd, &result->status); if (ret <= 0) { return ret; } if (!result->status.lock_supported) { return 1; } /* Wait for symbol quality = 100%. */ uint64_t timeout = getcurrenttime() + 5000; while (1) { ret = hdhomerun_device_get_tuner_status(scan->hd, NULL, &result->status); if (ret <= 0) { return ret; } if (result->status.symbol_error_quality == 100) { return 1; } if (getcurrenttime() >= timeout) { return 1; } msleep_approx(250); } }
static bool_t hdhomerun_sock_wait_for_write_event(hdhomerun_sock_t sock, uint64_t stop_time) { uint64_t current_time = getcurrenttime(); if (current_time >= stop_time) { return FALSE; } if (sock < FD_SETSIZE) { uint64_t timeout = stop_time - current_time; struct timeval t; t.tv_sec = timeout / 1000; t.tv_usec = (timeout % 1000) * 1000; fd_set writefds; FD_ZERO(&writefds); FD_SET(sock, &writefds); fd_set errorfds; FD_ZERO(&errorfds); FD_SET(sock, &errorfds); if (select(sock + 1, NULL, &writefds, &errorfds, &t) <= 0) { return FALSE; } if (!FD_ISSET(sock, &writefds)) { return FALSE; } } else { uint64_t delay = stop_time - current_time; if (delay > 5) { delay = 5; } msleep_approx(delay); } return TRUE; }
static int cmd_save(const char *tuner_str, const char *filename) { if (hdhomerun_device_set_tuner_from_str(hd, tuner_str) <= 0) { fprintf(stderr, "invalid tuner number\n"); return -1; } FILE *fp; if (strcmp(filename, "null") == 0) { fp = NULL; } else if (strcmp(filename, "-") == 0) { fp = stdout; } else { fp = fopen(filename, "wb"); if (!fp) { fprintf(stderr, "unable to create file %s\n", filename); return -1; } } int ret = hdhomerun_device_stream_start(hd); if (ret <= 0) { fprintf(stderr, "unable to start stream\n"); if (fp && fp != stdout) { fclose(fp); } return ret; } register_signal_handlers(sigabort_handler, sigabort_handler, siginfo_handler); struct hdhomerun_video_stats_t stats_old, stats_cur; hdhomerun_device_get_video_stats(hd, &stats_old); uint64_t next_progress = getcurrenttime() + 1000; while (!sigabort_flag) { uint64_t loop_start_time = getcurrenttime(); if (siginfo_flag) { fprintf(stderr, "\n"); cmd_save_print_stats(); siginfo_flag = FALSE; } size_t actual_size; uint8_t *ptr = hdhomerun_device_stream_recv(hd, VIDEO_DATA_BUFFER_SIZE_1S, &actual_size); if (!ptr) { msleep_approx(64); continue; } if (fp) { if (fwrite(ptr, 1, actual_size, fp) != actual_size) { fprintf(stderr, "error writing output\n"); return -1; } } if (loop_start_time >= next_progress) { next_progress += 1000; if (loop_start_time >= next_progress) { next_progress = loop_start_time + 1000; } /* Windows - indicate activity to suppress auto sleep mode. */ #if defined(__WINDOWS__) SetThreadExecutionState(ES_SYSTEM_REQUIRED); #endif /* Video stats. */ hdhomerun_device_get_video_stats(hd, &stats_cur); if (stats_cur.overflow_error_count > stats_old.overflow_error_count) { fprintf(stderr, "o"); } else if (stats_cur.network_error_count > stats_old.network_error_count) { fprintf(stderr, "n"); } else if (stats_cur.transport_error_count > stats_old.transport_error_count) { fprintf(stderr, "t"); } else if (stats_cur.sequence_error_count > stats_old.sequence_error_count) { fprintf(stderr, "s"); } else { fprintf(stderr, "."); } stats_old = stats_cur; fflush(stderr); } int32_t delay = 64 - (int32_t)(getcurrenttime() - loop_start_time); if (delay <= 0) { continue; } msleep_approx(delay); } if (fp) { fclose(fp); } hdhomerun_device_stream_stop(hd); fprintf(stderr, "\n"); fprintf(stderr, "-- Video statistics --\n"); cmd_save_print_stats(); return 0; }
int channelscan_detect(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result) { scan->scanned_channels++; /* Find lock. */ int ret = channelscan_find_lock(scan, result->frequency, result); if (ret <= 0) { return ret; } if (!result->status.lock_supported) { return 1; } /* Detect programs. */ result->program_count = 0; uint64_t timeout; if (strstr(hdhomerun_device_get_model_str(scan->hd), "atsc")) { timeout = getcurrenttime() + 4000; } else { timeout = getcurrenttime() + 10000; } uint64_t complete_time = getcurrenttime() + 1000; while (1) { bool_t changed, incomplete; ret = channelscan_detect_programs(scan, result, &changed, &incomplete); if (ret <= 0) { return ret; } if (changed) { complete_time = getcurrenttime() + 1000; } if (!incomplete && (getcurrenttime() >= complete_time)) { break; } if (getcurrenttime() >= timeout) { break; } msleep_approx(250); } /* Lock => skip overlapping channels. */ uint32_t max_next_frequency = result->frequency - 5500000; while (1) { if (!scan->next_channel) { break; } if (hdhomerun_channel_entry_frequency(scan->next_channel) <= max_next_frequency) { break; } scan->next_channel = hdhomerun_channel_list_prev(scan->channel_list, scan->next_channel); } /* Success. */ return 1; }