| // Copyright 2011 Google Inc. All Rights Reserved. |
| // Author: qianzhang@google.com (Qian Zhang) |
| |
| #include <stdio.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <inttypes.h> |
| #include "utility.h" |
| #include "channel_buffer.h" |
| #include "libhdhomerun/hdhomerun.h" |
| #include "hdhomerun_tuner.h" |
| #include "hdhomerun_dev.h" |
| #include "sagelog.h" |
| |
| #define PARSE_TIMEOUT 2 |
| #define CHANNE_SCAN_SRC "227.0.0.1" |
| #define CHANNEL_SCAN_PORT 6069 |
| |
| static volatile sig_atomic_t sigabort_flag = FALSE; |
| static volatile sig_atomic_t siginfo_flag = FALSE; |
| |
| static const char *map_tbl[] = {"us-bcast", "us-cable", "us-hrc", "us-irc", |
| "au-bcast", "tw-bcast", "eu-bcast", 0x0}; |
| |
| static void sigabort_handler(int arg) |
| { |
| sigabort_flag = TRUE; |
| } |
| |
| static void siginfo_handler(int arg) |
| { |
| siginfo_flag = TRUE; |
| } |
| |
| static void register_signal_handlers(sig_t sigpipe_handler, |
| sig_t sigint_handler, |
| sig_t siginfo_handler) |
| { |
| #if defined(SIGPIPE) |
| signal(SIGPIPE, sigpipe_handler); |
| #endif |
| #if defined(SIGINT) |
| signal(SIGINT, sigint_handler); |
| #endif |
| #if defined(SIGINFO) |
| signal(SIGINFO, siginfo_handler); |
| #endif |
| } |
| |
| // channel format: map:us-cable,auto:68 |
| void *open_hdhr(char *name) |
| { |
| struct hdhomerun_device_t *hd; |
| hd = hdhomerun_device_create_from_str(name, NULL); |
| return hd; |
| } |
| |
| void close_hdhr(void *device) |
| { |
| struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)device; |
| if (hd) { |
| hdhomerun_device_stream_stop(hd); |
| hdhomerun_device_destroy(hd); |
| } |
| } |
| |
| int tune_channel(void *device, char *channel, char *program, |
| char *stream_target) |
| { |
| char channel_str[32] = "auto:"; |
| char vchannel_str[16]; |
| char channel_map[32]; |
| struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)device; |
| int ret; |
| |
| if (hd == NULL) { |
| printf("hdhomerun invalid handle\n"); |
| return -1; |
| } |
| |
| if (!get_string_by_name(channel, "vchan", vchannel_str, sizeof(vchannel_str), |
| NULL)) { |
| vchannel_str[0] = 0x0; |
| |
| if (!get_string_by_name(channel, "auto", channel_str + 5, |
| sizeof(channel_str) - 5, NULL)) { |
| printf("hdhomerun %p invalid channel %s\n", device, channel); |
| return -1; |
| } |
| if (!get_string_by_name(channel, "map", channel_map, sizeof(channel_map), |
| NULL)) { |
| printf("hdhomerun %p invalid channel map %s\n", device, channel); |
| strncpy(channel_map, "us-cable", sizeof(channel_map)); |
| } |
| if (program[0] == 0x0) { |
| printf("hdhomerun %p invalid channel program %s\n", device, program); |
| return -1; |
| } |
| ret = hdhomerun_device_set_tuner_channelmap(hd, channel_map); |
| if (ret < 0) |
| printf("hdhomerun failed to set tuner channel map %s\n", channel_map); |
| |
| ret = hdhomerun_device_set_tuner_channel(hd, channel_str); |
| if (ret < 0) |
| printf("hdhomerun tuning failed:%s ret:%d\n", channel_str, ret); |
| |
| ret = hdhomerun_device_set_tuner_program(hd, program); |
| if (ret <= 0) |
| printf("hdhomerun failed set program:%s ret:%d\n", program, ret); |
| } else { |
| ret = hdhomerun_device_set_tuner_vchannel(hd, vchannel_str); |
| if (ret < 0) |
| printf("hdhomerun tuning failed: vchannel:%s ret:%d\n", vchannel_str, |
| ret); |
| } |
| |
| char target[64]; |
| snprintf(target, sizeof(target), "%s ttl=2", stream_target); |
| ret = hdhomerun_device_set_tuner_target(hd, target); |
| if (ret < 0) { |
| printf("hdhomerun failed set target %s ret:%d\n", target, ret); |
| } |
| |
| return ret; |
| } |
| |
| int vchan_to_prog_num(char *streaminfo, unsigned int vchan_major, |
| unsigned int vchan_minor, unsigned int *prog_num) |
| { |
| char *line; |
| char *next_line; |
| unsigned int program_number; |
| unsigned int virtual_major, virtual_minor; |
| |
| next_line = streaminfo; |
| |
| while (1) { |
| line = next_line; |
| next_line = strchr(line, '\n'); |
| if (!next_line) { |
| break; |
| } |
| *next_line++ = 0; |
| |
| if (sscanf(line, "%u: %u.%u", &program_number, &virtual_major, |
| &virtual_minor) != 3) { |
| if (sscanf(line, "%u: %u", &program_number, &virtual_major) != 2) { |
| continue; |
| } |
| virtual_minor = 0; |
| } |
| |
| if (vchan_major == virtual_major && vchan_minor == virtual_minor) { |
| *prog_num = program_number; |
| return 1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| int tune_vchannel(void *device, unsigned int channel, |
| unsigned int vchannel_major, unsigned int vchannel_minor, |
| char *stream_target) |
| { |
| char channel_map[16]; |
| char channel_str[16]; |
| char program_str[16]; |
| char target_str[64]; |
| struct hdhomerun_device_t *hd; |
| struct hdhomerun_tuner_status_t ts; |
| char *streaminfo; |
| unsigned int program; |
| int i, ret; |
| |
| hd = (struct hdhomerun_device_t *)device; |
| |
| // Set tuner channel map to US broadcast |
| snprintf(channel_map, sizeof(channel_map), "us-bcast"); |
| ret = hdhomerun_device_set_tuner_channelmap(hd, channel_map); |
| if (ret < 0) { |
| printf("hdhr:ERROR: set tuner channel map %s\n", channel_map); |
| goto out; |
| } |
| |
| // Tune to physical channel |
| snprintf(channel_str, sizeof(channel_str), "auto:%u", channel); |
| ret = hdhomerun_device_set_tuner_channel(hd, channel_str); |
| if (ret <= 0) { |
| printf("hdhr:ERROR: set tuner channel %s\n", channel_str); |
| goto out; |
| } |
| |
| // Wait for SER to hit 100% (max 3 secs) |
| usleep(500000); |
| for (i = 0; i < 10; i++) { |
| ret = hdhomerun_device_get_tuner_status(hd, NULL, &ts); |
| if (ret > 0 && ts.symbol_error_quality >= 100) { |
| break; |
| } |
| usleep(250000); |
| } |
| |
| // Get MPEG2-TS stream info |
| ret = hdhomerun_device_get_tuner_streaminfo(hd, &streaminfo); |
| if (ret <= 0) { |
| printf("hdhr:ERROR: get tuner streaminfo\n"); |
| goto out; |
| } |
| printf("hdhr:hdhomerun streaminfo:\n%s", streaminfo); |
| |
| // Translate virtual channel (major.minor) to program number |
| ret = vchan_to_prog_num(streaminfo, vchannel_major, vchannel_minor, &program); |
| if (ret <= 0) { |
| printf("hdhr:ERROR: vchannel %d.%d not found in streaminfo\n", |
| vchannel_major, vchannel_minor); |
| goto out; |
| } |
| printf("hdhr:hdhomerun vchannel %u.%u -> program %u\n", vchannel_major, |
| vchannel_minor, program); |
| |
| // Set tuner program |
| snprintf(program_str, sizeof(program_str), "%u", program); |
| ret = hdhomerun_device_set_tuner_program(hd, program_str); |
| if (ret <= 0) { |
| printf("hdhr:ERROR: set tuner program %s\n", program_str); |
| goto out; |
| } |
| |
| // Set tuner stream target |
| snprintf(target_str, sizeof(target_str), "%s ttl=2", stream_target); |
| ret = hdhomerun_device_set_tuner_target(hd, target_str); |
| if (ret <= 0) { |
| printf("hdhr:ERROR: set tuner target %s\n", target_str); |
| } |
| |
| out: |
| return ret; |
| } |
| |
| // channel format: map:us-cable,auto:68 |
| int stop_channel(void *device) |
| { |
| int ret; |
| struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)device; |
| if (hd == NULL) { |
| printf("hdhomerun invalid handle\n"); |
| return -1; |
| } |
| |
| ret = hdhomerun_device_set_tuner_channel(hd, "none"); |
| if (ret < 0) { |
| printf("hdhomerun failed set channel none to stop streaming ret:%d\n", |
| ret); |
| } |
| |
| ret = hdhomerun_device_set_tuner_vchannel(hd, "none"); |
| if (ret < 0) { |
| printf("hdhomerun failed set vchannel none to stop streaming ret:%d\n", |
| ret); |
| } |
| |
| ret = hdhomerun_device_set_tuner_target(hd, "none"); |
| if (ret < 0) { |
| printf("hdhomerun failed set target none to stop streaming ret:%d\n", ret); |
| } |
| |
| return ret; |
| } |
| |
| char *get_unit_name(struct hdhr_tuner_t *ht, char *name, int size) |
| { |
| char *p = strchr(ht->name, '-'); |
| if (p != NULL) { |
| int len = p - ht->name; |
| strncpy(name, ht->name, len); |
| name[len] = 0x0; |
| return name; |
| } |
| name[0] = 0x0; |
| return name; |
| } |
| |
| static char *ip4_address(int ip4, char *buf, int size) |
| { |
| snprintf(buf, size, "%u.%u.%u.%u", (unsigned int)(ip4 >> 24) & 0xFF, |
| (unsigned int)(ip4 >> 16) & 0xFF, (unsigned int)(ip4 >> 8) & 0xFF, |
| (unsigned int)(ip4 >> 0) & 0xFF); |
| return buf; |
| } |
| |
| int discover_device(struct hdhr_tuner_t *ht, int max_ht_num) |
| { |
| int i, k, num = 0; |
| struct hdhomerun_discover_device_t *device_info = |
| malloc(max_ht_num * sizeof(struct hdhomerun_discover_device_t)); |
| int ret = hdhomerun_discover_find_devices_custom( |
| 0, HDHOMERUN_DEVICE_TYPE_TUNER, -1, device_info, 16); |
| if (ret <= 0) { |
| free(device_info); |
| return 0; |
| } |
| // printf( "found %d hdhomerun device\n", ret ); |
| for (i = 0; i < ret; i++) { |
| // printf( "ip:%x type:%x id:%x num:%d\n", device_info[i].ip_addr, |
| // device_info[i].device_type, device_info[i].device_id, |
| // device_info[i].tuner_count ); |
| for (k = 0; k < device_info[i].tuner_count && num < max_ht_num; k++) { |
| snprintf(ht[num].name, sizeof(ht[num].name), "%X-%d", |
| device_info[i].device_id, k); |
| ip4_address(device_info[i].ip_addr, ht[num].ip, sizeof(ht[num].ip)); |
| ht[num].type = device_info[i].device_type; |
| ht[num].cc_tuner = 0; |
| ht[num].model[0] = 0; |
| num++; |
| } |
| } |
| free(device_info); |
| return num; |
| } |
| |
| static char *get_tune_string(char *result, char *tune_str, int tune_str_len) |
| { |
| int i = 0; |
| int ch; |
| while (map_tbl[i][0]) { |
| if (get_int_val_by_name(result, map_tbl[i], &ch, NULL) > 0) { |
| snprintf(tune_str, tune_str_len, "map:%s|auto:%d", map_tbl[i], ch); |
| return tune_str; |
| } |
| i++; |
| } |
| return ""; |
| } |
| |
| static int get_tune_channel(char *result) |
| { |
| int i = 0; |
| int ch; |
| while (map_tbl[i][0]) { |
| if (get_int_val_by_name(result, map_tbl[i], &ch, NULL) > 0) { |
| return ch; |
| } |
| i++; |
| } |
| return 0; |
| } |
| |
| int scan_all(void *device, struct channel_entry_t *ce, int ce_num) |
| { |
| int found_channel = 0; |
| struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)device; |
| if (hd == NULL) { |
| printf("hdhomerun invalid handle\n"); |
| return -1; |
| } |
| |
| char *ret_error; |
| if (hdhomerun_device_tuner_lockkey_request(hd, &ret_error) <= 0) { |
| fprintf(stderr, "failed to lock tuner\n"); |
| if (ret_error) { |
| fprintf(stderr, "%s\n", ret_error); |
| } |
| return -1; |
| } |
| |
| hdhomerun_device_set_tuner_target(hd, "none"); |
| |
| char *channelmap; |
| if (hdhomerun_device_get_tuner_channelmap(hd, &channelmap) <= 0) { |
| fprintf(stderr, "failed to query channelmap from device\n"); |
| return -1; |
| } |
| |
| const char *channelmap_scan_group = |
| hdhomerun_channelmap_get_channelmap_scan_group(channelmap); |
| if (!channelmap_scan_group) { |
| fprintf(stderr, "unknown channelmap '%s'\n", channelmap); |
| return -1; |
| } |
| |
| if (hdhomerun_device_channelscan_init(hd, channelmap_scan_group) <= 0) { |
| fprintf(stderr, "failed to initialize channel scan\n"); |
| return -1; |
| } |
| |
| register_signal_handlers(sigabort_handler, sigabort_handler, siginfo_handler); |
| |
| int ret = 0; |
| while (!sigabort_flag && found_channel < ce_num) { |
| struct hdhomerun_channelscan_result_t result; |
| char tune_str[32]; |
| char channel_name[32]; |
| int channel_num; |
| ret = hdhomerun_device_channelscan_advance(hd, &result); |
| if (ret <= 0) { |
| break; |
| } |
| |
| ret = hdhomerun_device_channelscan_detect(hd, &result); |
| if (ret < 0) { |
| break; |
| } |
| if (ret == 0) { |
| continue; |
| } |
| if (0) |
| printf("LOCK: %s %s (ss=%u snq=%u seq=%u)\n", |
| get_tune_string(result.channel_str, tune_str, sizeof(tune_str)), |
| result.status.lock_str, result.status.signal_strength, |
| result.status.signal_to_noise_quality, |
| result.status.symbol_error_quality); |
| |
| channel_num = get_tune_channel(result.channel_str); |
| int i; |
| for (i = 0; i < result.program_count; i++) { |
| struct hdhomerun_channelscan_program_t *program = &result.programs[i]; |
| if (strstr(program->program_str, "encrypted") == NULL) { |
| int program_id = atoi(program->program_str); |
| |
| if (!get_string_by_token(program->program_str, 2, channel_name, |
| sizeof(channel_name), NULL)) { |
| if (!get_string_by_token(program->program_str, 1, channel_name, |
| sizeof(channel_name), NULL)) |
| snprintf(channel_name, sizeof(channel_name), "%d.%d", channel_num, |
| i); |
| else { |
| if (!strcmp(channel_name, "0")) |
| snprintf(channel_name, sizeof(channel_name), "%d.%d", channel_num, |
| i); |
| } |
| } |
| snprintf( |
| ce->dev_tuning, sizeof(ce->dev_tuning), "%s prog:%d", |
| get_tune_string(result.channel_str, tune_str, sizeof(tune_str)), |
| program_id); |
| strncpy(ce->ch_name, channel_name, sizeof(ce->ch_name)); |
| strncpy(ce->dev_name, device, sizeof(ce->dev_name)); |
| ce->ch = found_channel; |
| ce->frq = result.frequency; |
| ce->av_inf[0] = 0x0; |
| ce++; |
| if (++found_channel >= ce_num) |
| break; |
| |
| printf("o"); |
| } |
| } |
| |
| printf("."); |
| fflush(stdout); |
| } |
| |
| hdhomerun_device_tuner_lockkey_release(hd); |
| |
| if (ret < 0) { |
| fprintf(stderr, |
| "communication error sending request to hdhomerun device\n"); |
| } |
| return found_channel; |
| } |
| |
| struct vchan_tbl_t *create_vchan_tbl(struct hdhr_tuner_t *ht) |
| { |
| struct vchan_tbl_t *vt = malloc(sizeof(struct vchan_tbl_t)); |
| vt->ht = *ht; |
| vt->channel_size = 500; |
| vt->channel_num = 0; |
| vt->vchan = malloc(sizeof(struct vchan_t) * vt->channel_size); |
| memset(vt->vchan, 0x0, sizeof(struct vchan_t) * vt->channel_size); |
| return vt; |
| } |
| |
| void release_vchan_tbl(struct vchan_tbl_t *vt) |
| { |
| if (vt->vchan) |
| free(vt->vchan); |
| free(vt); |
| } |
| |
| int grow_vhcan_tbl(struct vchan_tbl_t *vt) |
| { |
| int new_channel_size = vt->channel_size + 100; |
| struct vchan_t *new_vchan_list = |
| malloc(sizeof(struct vchan_t) * new_channel_size); |
| if (new_vchan_list == NULL) |
| return 0; |
| memcpy(new_vchan_list, vt->vchan, vt->channel_size * sizeof(struct vchan_t)); |
| free(vt->vchan); |
| vt->vchan = new_vchan_list; |
| vt->channel_size = new_channel_size; |
| return 1; |
| } |
| |
| int tuner_input_sharing(struct hdhr_tuner_t *ht1, struct hdhr_tuner_t *ht2) |
| { |
| if (ht1->cc_tuner == 1 && !strcmp(ht1->ip, ht2->ip)) |
| return 1; |
| return 0; |
| } |
| |
| #ifdef TEST_APP |
| static int scan_channel(void *device, int index, struct channel_entry_t *ce, |
| int ce_channel_num, int ce_num) |
| { |
| int found_channel = 0; |
| struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)device; |
| if (hd == NULL) { |
| printf("hdhomerun invalid handle\n"); |
| return -1; |
| } |
| |
| char *ret_error; |
| if (hdhomerun_device_tuner_lockkey_request(hd, &ret_error) <= 0) { |
| fprintf(stderr, "failed to lock tuner\n"); |
| if (ret_error) { |
| fprintf(stderr, "%s\n", ret_error); |
| } |
| return -1; |
| } |
| |
| hdhomerun_device_set_tuner_target(hd, "none"); |
| |
| char *channelmap; |
| if (hdhomerun_device_get_tuner_channelmap(hd, &channelmap) <= 0) { |
| fprintf(stderr, "failed to query channelmap from device\n"); |
| return -1; |
| } |
| |
| const char *channelmap_scan_group = |
| hdhomerun_channelmap_get_channelmap_scan_group(channelmap); |
| if (!channelmap_scan_group) { |
| fprintf(stderr, "unknown channelmap '%s'\n", channelmap); |
| return -1; |
| } |
| |
| if (hdhomerun_device_channelscan_init(hd, channelmap_scan_group) <= 0) { |
| fprintf(stderr, "failed to initialize channel scan\n"); |
| return -1; |
| } |
| |
| register_signal_handlers(sigabort_handler, sigabort_handler, siginfo_handler); |
| |
| int ret = 0, i; |
| do { |
| struct hdhomerun_channelscan_result_t result; |
| char tune_str[32]; |
| char channel_name[32]; |
| int channel_num; |
| ret = hdhomerun_device_channelscan_at(hd, index, &result); |
| // ret = hdhomerun_device_channelscan_advance( hd, &result ); |
| if (ret <= 0) { |
| break; |
| } |
| // skip duplicated channel |
| for (i = 0; i < ce_channel_num; i++) { |
| if (ce->frq == result.frequency) |
| break; |
| } |
| if (ce->frq == result.frequency) |
| break; |
| ret = hdhomerun_device_channelscan_detect(hd, &result); |
| if (ret < 0) { |
| break; |
| } |
| if (ret == 0) { |
| continue; |
| } |
| |
| if (0) |
| printf("LOCK: %s %s (ss=%u snq=%u seq=%u)\n", |
| get_tune_string(result.channel_str, tune_str, sizeof(tune_str)), |
| result.status.lock_str, result.status.signal_strength, |
| result.status.signal_to_noise_quality, |
| result.status.symbol_error_quality); |
| |
| channel_num = get_tune_channel(result.channel_str); |
| for (i = 0; i < result.program_count; i++) { |
| struct hdhomerun_channelscan_program_t *program = &result.programs[i]; |
| if (strstr(program->program_str, "encrypted") == NULL) { |
| int program_id = atoi(program->program_str); |
| |
| if (!get_string_by_token(program->program_str, 2, channel_name, |
| sizeof(channel_name), NULL)) { |
| if (!get_string_by_token(program->program_str, 1, channel_name, |
| sizeof(channel_name), NULL)) |
| snprintf(channel_name, sizeof(channel_name), "%d.%d", channel_num, |
| i); |
| else { |
| if (!strcmp(channel_name, "0")) |
| snprintf(channel_name, sizeof(channel_name), "%d.%d", channel_num, |
| i); |
| } |
| } |
| struct channel_entry_t *ce_p = &ce[ce_channel_num]; |
| snprintf( |
| ce->dev_tuning, sizeof(ce->dev_tuning), "%s prog:%d", |
| get_tune_string(result.channel_str, tune_str, sizeof(tune_str)), |
| program_id); |
| strncpy(ce_p->ch_name, channel_name, sizeof(ce_p->ch_name)); |
| strncpy(ce_p->dev_name, device, sizeof(ce_p->dev_name)); |
| ce_p->ch = found_channel + ce_channel_num; |
| ce_p->frq = result.frequency; |
| ce_p->av_inf[0] = 0x0; |
| char stream_tar[32]; |
| snprintf(stream_tar, sizeof(stream_tar), "udp://%s:%u", CHANNE_SCAN_SRC, |
| CHANNEL_SCAN_PORT); |
| ret = tune_channel(hd, ce_p->dev_tuning, "", stream_tar); |
| if (ret > 0) |
| ret = parse_avinf(CHANNE_SCAN_SRC, CHANNEL_SCAN_PORT, ce_p->av_inf, |
| sizeof(ce_p->av_inf), PARSE_TIMEOUT); |
| if (ret > 0) |
| ret = strstr(ce_p->av_inf, "ENCRYPTED") == NULL && |
| strstr(ce_p->av_inf, "NO-DATA") == NULL; |
| if (ret) |
| if (++ce_channel_num > ce_num) |
| break; |
| } |
| } |
| } while (0); |
| |
| hdhomerun_device_tuner_lockkey_release(hd); |
| |
| if (ret < 0) { |
| fprintf(stderr, |
| "communication error sending request to hdhomerun device\n"); |
| } |
| return found_channel; |
| } |
| |
| int scan_vchannel(void *device, int vchannel, struct channel_entry_t *ce) |
| { |
| int ret; |
| struct hdhomerun_device_t *hd = (struct hdhomerun_device_t *)device; |
| if (hd == NULL) { |
| sage_log((_LOG_ERROR, 3, "hdhomerun invalid handle.")); |
| return -1; |
| } |
| |
| ce->state = 1; |
| ce->ch = vchannel; |
| ce->frq = 0; |
| ce->av_inf[0] = 0x0; |
| char stream_tar[32]; |
| snprintf(ce->ch_name, sizeof(ce->ch_name), "%d", vchannel); |
| snprintf(ce->dev_tuning, sizeof(ce->dev_tuning), "vchan:%d", vchannel); |
| snprintf(stream_tar, sizeof(stream_tar), "udp://%s:%u", CHANNE_SCAN_SRC, |
| CHANNEL_SCAN_PORT); |
| ret = tune_channel(device, ce->dev_tuning, "", stream_tar); |
| if (ret > 0) |
| ret = parse_avinf(CHANNE_SCAN_SRC, CHANNEL_SCAN_PORT, ce->av_inf, |
| sizeof(ce->av_inf), PARSE_TIMEOUT); |
| if (ret > 0) |
| ret = strstr(ce->av_inf, "ENCRYPTED") == NULL && |
| strstr(ce->av_inf, "NO-DATA") == NULL; |
| if (ret <= 0) { |
| ce->state = 0; |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| static int _make_channel_entry_buffer(struct channel_entry_t *ce, char *buf, |
| int size) |
| { |
| int pos = 0; |
| pos += snprintf(buf + pos, size - pos, "ch:%03d ", ce->ch); |
| if (ce->ch_name[0]) |
| pos += snprintf(buf + pos, size - pos, "name:%s ", ce->ch_name); |
| if (ce->src_ip[0] && ce->src_port) |
| pos += snprintf(buf + pos, size - pos, "ip:%s port:%d ", ce->src_ip, |
| ce->src_port); |
| if (ce->epg_id[0]) |
| pos += snprintf(buf + pos, size - pos, "epg:%s ", ce->epg_id); |
| if (ce->dev_name[0]) |
| pos += snprintf(buf + pos, size - pos, "dev:%s ", ce->dev_name); |
| if (ce->dev_tuning[0]) |
| pos += snprintf(buf + pos, size - pos, "tune:%s ", ce->dev_tuning); |
| if (ce->av_inf[0]) |
| pos += snprintf(buf + pos, size - pos, "av:\"%s\" ", ce->av_inf); |
| pos += snprintf(buf + pos, size - pos, "\n"); |
| return pos; |
| } |
| |
| static int _save_channel_entry(char *file_name, struct channel_entry_t *ce, |
| int num) |
| { |
| int i; |
| char buf[2048]; |
| FILE *fp; |
| fp = fopen(file_name, "w"); |
| if (fp == NULL) { |
| // printf( "Can't open file %s to save channel table, errno:%d\n", |
| // file_name, errno ); |
| return -1; |
| } |
| fputs("#Google sagetv channel table ver 1.0., maximum 2048 bytes per line\n", |
| fp); |
| fprintf(fp, "total_channel:%d\n", num); |
| for (i = 0; i < num; i++) { |
| _make_channel_entry_buffer(ce, buf, sizeof(buf)); |
| fputs(buf, fp); |
| ce++; |
| } |
| fclose(fp); |
| return 1; |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| int i, ret = 0; |
| int tuner_count = 0; |
| struct hdhr_tuner_t ht[16]; |
| |
| ret = discover_device(ht, 16); |
| printf("found tuners:%d\n", ret); |
| if (ret > 0) { |
| for (i = 0; i < ret; i++) { |
| // if a unit shares a source input in a device, copy data. |
| if (i > 0 && tuner_input_sharing(&ht[i - 1], &ht[i])) { |
| ht[i].cc_tuner = ht[i - 1].cc_tuner; |
| strncpy(ht[i].model, ht[i - 1].model, sizeof(ht[i].model)); |
| } else |
| get_dev_model(&ht[i]); |
| |
| printf("%d tuner:%s ip:%s type:%d cc:%d model:%s\n", i, ht[i].name, |
| ht[i].ip, ht[i].type, ht[i].cc_tuner, ht[i].model); |
| } |
| tuner_count = ret; |
| } |
| |
| // test channel scan |
| if (0) { |
| time_t t0 = time(NULL); |
| struct channel_entry_t ce[400]; |
| int channel_num = 0; |
| // channel_num = scan_all( "101007FD-0", ce, 400 ); |
| for (i = 60; i <= 70; i++) { |
| ret = scan_channel("101007FD-1", i, ce, channel_num, 400); |
| if (ret < 0 || sigabort_flag) |
| break; |
| printf("find channe:%d\n", ret); |
| channel_num += ret; |
| } |
| printf("time:%ld\n", time(NULL) - t0); |
| _save_channel_entry("channel-scan.txt", ce, channel_num); |
| } |
| |
| // test vchannel scan |
| if (0) { |
| struct hdhr_tuner_t *cc_ht = NULL; |
| for (i = 0; i < tuner_count; i++) { |
| if (ht[i].cc_tuner) { |
| cc_ht = &ht[i]; |
| break; |
| } |
| } |
| |
| if (cc_ht != NULL) { |
| time_t t0 = time(NULL); |
| struct vchan_tbl_t *vt = create_vchan_tbl(cc_ht); |
| ret = get_vchannel_list(vt); |
| if (ret > 0) { |
| int n; |
| int channel_num = 0; |
| struct channel_list_t *cl = create_channel_list(ret); |
| for (n = 1; n < vt->channel_num && channel_num < 500; n++) { |
| printf("TRACE %d %s\n", n, vt->vchan[n].guide_name); |
| ret = scan_vchannel(vt, n, cl); |
| if (ret > 0) { |
| struct channel_entry_t *ce_p = &cl->ce[channel_num]; |
| snprintf(ce_p->dev_name, sizeof(ce_p->dev_name), "HDHR.%s", device, |
| sizeof(ce_p->dev_name)); |
| channel_num++; |
| } |
| printf("TRACE channel %d, %d\n", channel_num, n); |
| } |
| _save_channel_entry("channel-scan.txt", cl); |
| } |
| release_vchan_tbl(vt); |
| printf("time:%ld\n", time(NULL) - t0); |
| } |
| } |
| |
| // test tune |
| if (1) { |
| // printf( "tuning %s \n", device[i] ); |
| char *dev_name = "1311A273-0"; //"101007FD-1"; |
| // ret = tune_channel( dev_name, "map:us-cable|auto:68", "343", |
| // "udp://226.0.0.1:4096" ); |
| ret = tune_channel(dev_name, "vchan:600", "", "udp://226.0.0.1:4096"); |
| printf("hit enter to stop\n"); |
| getchar(); |
| ret = stop_channel(dev_name); |
| } |
| |
| return ret; |
| } |
| |
| #endif |