00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "hdhomerun.h"
00034
00035 struct hdhomerun_channelscan_t {
00036 struct hdhomerun_device_t *hd;
00037 uint32_t scanned_channels;
00038 struct hdhomerun_channel_list_t *channel_list;
00039 struct hdhomerun_channel_entry_t *next_channel;
00040 };
00041
00042 struct hdhomerun_channelscan_t *channelscan_create(struct hdhomerun_device_t *hd, const char *channelmap)
00043 {
00044 struct hdhomerun_channelscan_t *scan = (struct hdhomerun_channelscan_t *)calloc(1, sizeof(struct hdhomerun_channelscan_t));
00045 if (!scan) {
00046 return NULL;
00047 }
00048
00049 scan->hd = hd;
00050
00051 scan->channel_list = hdhomerun_channel_list_create(channelmap);
00052 if (!scan->channel_list) {
00053 free(scan);
00054 return NULL;
00055 }
00056
00057 scan->next_channel = hdhomerun_channel_list_last(scan->channel_list);
00058 return scan;
00059 }
00060
00061 void channelscan_destroy(struct hdhomerun_channelscan_t *scan)
00062 {
00063 free(scan);
00064 }
00065
00066 static int channelscan_find_lock(struct hdhomerun_channelscan_t *scan, uint32_t frequency, struct hdhomerun_channelscan_result_t *result)
00067 {
00068
00069 char channel_str[64];
00070 sprintf(channel_str, "auto:%ld", (unsigned long)frequency);
00071
00072 int ret = hdhomerun_device_set_tuner_channel(scan->hd, channel_str);
00073 if (ret <= 0) {
00074 return ret;
00075 }
00076
00077
00078 ret = hdhomerun_device_wait_for_lock(scan->hd, &result->status);
00079 if (ret <= 0) {
00080 return ret;
00081 }
00082 if (!result->status.lock_supported) {
00083 return 1;
00084 }
00085
00086
00087 uint64_t timeout = getcurrenttime() + 5000;
00088 while (1) {
00089 ret = hdhomerun_device_get_tuner_status(scan->hd, NULL, &result->status);
00090 if (ret <= 0) {
00091 return ret;
00092 }
00093
00094 if (result->status.symbol_error_quality == 100) {
00095 return 1;
00096 }
00097
00098 if (getcurrenttime() >= timeout) {
00099 return 1;
00100 }
00101
00102 msleep(250);
00103 }
00104 }
00105
00106 static void channelscan_extract_name(struct hdhomerun_channelscan_program_t *program, const char *line)
00107 {
00108
00109 const char *start = strchr(line, ' ');
00110 if (!start) {
00111 return;
00112 }
00113 start++;
00114
00115 start = strchr(start, ' ');
00116 if (!start) {
00117 return;
00118 }
00119 start++;
00120
00121
00122 const char *end = strstr(start, " (");
00123 if (!end) {
00124 end = strchr(line, 0);
00125 }
00126
00127 if (end <= start) {
00128 return;
00129 }
00130
00131
00132 size_t length = (size_t)(end - start);
00133 if (length > sizeof(program->name) - 1) {
00134 length = sizeof(program->name) - 1;
00135 }
00136
00137 strncpy(program->name, start, length);
00138 program->name[length] = 0;
00139 }
00140
00141 static int channelscan_detect_programs(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result, bool_t *pchanged, bool_t *pincomplete)
00142 {
00143 *pchanged = FALSE;
00144 *pincomplete = FALSE;
00145
00146 char *streaminfo;
00147 int ret = hdhomerun_device_get_tuner_streaminfo(scan->hd, &streaminfo);
00148 if (ret <= 0) {
00149 return ret;
00150 }
00151
00152 char *next_line = streaminfo;
00153 int program_count = 0;
00154
00155 while (1) {
00156 char *line = next_line;
00157
00158 next_line = strchr(line, '\n');
00159 if (!next_line) {
00160 break;
00161 }
00162 *next_line++ = 0;
00163
00164 unsigned int transport_stream_id;
00165 if (sscanf(line, "tsid=0x%x", &transport_stream_id) == 1) {
00166 result->transport_stream_id = transport_stream_id;
00167 result->transport_stream_id_detected = TRUE;
00168 continue;
00169 }
00170
00171 if (program_count >= HDHOMERUN_CHANNELSCAN_MAX_PROGRAM_COUNT) {
00172 continue;
00173 }
00174
00175 struct hdhomerun_channelscan_program_t program;
00176 memset(&program, 0, sizeof(program));
00177
00178 strncpy(program.program_str, line, sizeof(program.program_str));
00179 program.program_str[sizeof(program.program_str) - 1] = 0;
00180
00181 unsigned int program_number;
00182 unsigned int virtual_major, virtual_minor;
00183 if (sscanf(line, "%u: %u.%u", &program_number, &virtual_major, &virtual_minor) != 3) {
00184 if (sscanf(line, "%u: %u", &program_number, &virtual_major) != 2) {
00185 continue;
00186 }
00187 virtual_minor = 0;
00188 }
00189
00190 program.program_number = program_number;
00191 program.virtual_major = virtual_major;
00192 program.virtual_minor = virtual_minor;
00193
00194 channelscan_extract_name(&program, line);
00195
00196 if (strstr(line, "(control)")) {
00197 program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_CONTROL;
00198 } else if (strstr(line, "(encrypted)")) {
00199 program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_ENCRYPTED;
00200 } else if (strstr(line, "(no data)")) {
00201 program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_NODATA;
00202 *pincomplete = TRUE;
00203 } else {
00204 program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_NORMAL;
00205 if ((program.virtual_major == 0) || (program.name[0] == 0)) {
00206 *pincomplete = TRUE;
00207 }
00208 }
00209
00210 if (memcmp(&result->programs[program_count], &program, sizeof(program)) != 0) {
00211 memcpy(&result->programs[program_count], &program, sizeof(program));
00212 *pchanged = TRUE;
00213 }
00214
00215 program_count++;
00216 }
00217
00218 if (program_count == 0) {
00219 *pincomplete = TRUE;
00220 }
00221 if (result->program_count != program_count) {
00222 result->program_count = program_count;
00223 *pchanged = TRUE;
00224 }
00225
00226 return 1;
00227 }
00228
00229 int channelscan_advance(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result)
00230 {
00231 memset(result, 0, sizeof(struct hdhomerun_channelscan_result_t));
00232
00233 struct hdhomerun_channel_entry_t *entry = scan->next_channel;
00234 if (!entry) {
00235 return 0;
00236 }
00237
00238
00239 result->frequency = hdhomerun_channel_entry_frequency(entry);
00240 strncpy(result->channel_str, hdhomerun_channel_entry_name(entry), sizeof(result->channel_str) - 1);
00241 result->channel_str[sizeof(result->channel_str) - 1] = 0;
00242
00243 while (1) {
00244 entry = hdhomerun_channel_list_prev(scan->channel_list, entry);
00245 if (!entry) {
00246 scan->next_channel = NULL;
00247 break;
00248 }
00249
00250 if (hdhomerun_channel_entry_frequency(entry) != result->frequency) {
00251 scan->next_channel = entry;
00252 break;
00253 }
00254
00255 char *ptr = strchr(result->channel_str, 0);
00256 sprintf(ptr, ", %s", hdhomerun_channel_entry_name(entry));
00257 }
00258
00259 return 1;
00260 }
00261
00262 int channelscan_detect(struct hdhomerun_channelscan_t *scan, struct hdhomerun_channelscan_result_t *result)
00263 {
00264 scan->scanned_channels++;
00265
00266
00267 int ret = channelscan_find_lock(scan, result->frequency, result);
00268 if (ret <= 0) {
00269 return ret;
00270 }
00271 if (!result->status.lock_supported) {
00272 return 1;
00273 }
00274
00275
00276 result->program_count = 0;
00277
00278 uint64_t timeout;
00279 if (strstr(hdhomerun_device_get_model_str(scan->hd), "atsc")) {
00280 timeout = getcurrenttime() + 4000;
00281 } else {
00282 timeout = getcurrenttime() + 10000;
00283 }
00284
00285 uint64_t complete_time = getcurrenttime() + 1000;
00286
00287 while (1) {
00288 bool_t changed, incomplete;
00289 ret = channelscan_detect_programs(scan, result, &changed, &incomplete);
00290 if (ret <= 0) {
00291 return ret;
00292 }
00293
00294 if (changed) {
00295 complete_time = getcurrenttime() + 1000;
00296 }
00297
00298 if (!incomplete && (getcurrenttime() >= complete_time)) {
00299 break;
00300 }
00301
00302 if (getcurrenttime() >= timeout) {
00303 break;
00304 }
00305
00306 msleep(250);
00307 }
00308
00309
00310 uint32_t max_next_frequency = result->frequency - 5500000;
00311 while (1) {
00312 if (!scan->next_channel) {
00313 break;
00314 }
00315
00316 if (hdhomerun_channel_entry_frequency(scan->next_channel) <= max_next_frequency) {
00317 break;
00318 }
00319
00320 scan->next_channel = hdhomerun_channel_list_prev(scan->channel_list, scan->next_channel);
00321 }
00322
00323
00324 return 1;
00325 }
00326
00327 uint8_t channelscan_get_progress(struct hdhomerun_channelscan_t *scan)
00328 {
00329 struct hdhomerun_channel_entry_t *entry = scan->next_channel;
00330 if (!entry) {
00331 return 100;
00332 }
00333
00334 uint32_t channels_remaining = 1;
00335 uint32_t frequency = hdhomerun_channel_entry_frequency(entry);
00336
00337 while (1) {
00338 entry = hdhomerun_channel_list_prev(scan->channel_list, entry);
00339 if (!entry) {
00340 break;
00341 }
00342
00343 if (hdhomerun_channel_entry_frequency(entry) != frequency) {
00344 channels_remaining++;
00345 frequency = hdhomerun_channel_entry_frequency(entry);
00346 }
00347 }
00348
00349 return scan->scanned_channels * 100 / (scan->scanned_channels + channels_remaining);
00350 }