blob: d9ad83065d731679803063a62fcf7dcba7108946 [file] [log] [blame]
// 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;
}
static 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_atsc_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_channelmap %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 symbol error quality to hit 100% (max 3 secs)
for (i = 0; i < 5; i++) {
usleep(i == 0 ? 1000000 : 500000);
ret = hdhomerun_device_get_tuner_status(hd, NULL, &ts);
if (ret > 0 && ts.symbol_error_quality >= 100) {
break;
}
}
printf("hdhr:hdhomerun tuner status: ch=%s lock=%s ss=%u snq=%u seq=%u\n",
ts.channel, ts.lock_str, ts.signal_strength,
ts.signal_to_noise_quality, ts.symbol_error_quality);
// Translate virtual channel to program number (max 2 secs)
for (i = 0; i < 5; i++) {
usleep(i == 0 ? 0 : 500000);
ret = hdhomerun_device_get_tuner_streaminfo(hd, &streaminfo);
if (ret > 0) {
printf("hdhr:hdhomerun tuner streaminfo:\n%s", streaminfo);
ret = vchan_to_prog_num(streaminfo, vchannel_major, vchannel_minor,
&program);
if (ret > 0) {
break;
}
}
}
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;
}
int tune_cable_vchannel(void *device, unsigned int channel, char *stream_target)
{
char channel_str[8];
char target_str[64];
struct hdhomerun_device_t *hd;
struct hdhomerun_tuner_status_t ts;
struct hdhomerun_tuner_vstatus_t tvs;
int ret;
hd = (struct hdhomerun_device_t *)device;
// Set tuner vchannel
snprintf(channel_str, sizeof(channel_str), "%u", channel);
ret = hdhomerun_device_set_tuner_vchannel(hd, channel_str);
if (ret <= 0) {
printf("hdhr:ERROR: set_tuner_vchannel %s\n", channel_str);
goto out;
}
sleep(1);
// Get tuner status
ret = hdhomerun_device_get_tuner_status(hd, NULL, &ts);
if (ret > 0) {
printf("hdhr:hdhomerun tuner status: ch=%s lock=%s ss=%u snq=%u seq=%u\n",
ts.channel, ts.lock_str, ts.signal_strength,
ts.signal_to_noise_quality, ts.symbol_error_quality);
} else {
printf("hdhr:ERROR: get_tuner_status\n");
}
// Get tuner vstatus
ret = hdhomerun_device_get_tuner_vstatus(hd, NULL, &tvs);
if (ret > 0) {
printf("hdhr:hdhomerun tuner vstatus: vch=%s name=%s auth=%s cci=%s "
"cgms=%s\n", tvs.vchannel, tvs.name, tvs.auth, tvs.cci, tvs.cgms);
} else {
printf("hdhr:ERROR: get_tuner_vstatus\n");
}
// 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_devices(struct hdhr_tuner_t *ht, int max_ht_num)
{
int i, k, count, num = 0;
struct hdhomerun_discover_device_t device_info[max_ht_num];
struct hdhr_tuner_t hdhr;
printf("hdhr:discovering devices...\n");
while (1) {
count = hdhomerun_discover_find_devices_custom(0,
HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD,
device_info, max_ht_num);
if (count > 0) {
break;
}
sleep(3);
}
for (i = 0; i < count; i++) {
printf("hdhr:get device %d model and fw\n", i);
while (1) {
memset(&hdhr, 0, sizeof(hdhr));
ip4_address(device_info[i].ip_addr, hdhr.ip, sizeof(hdhr.ip));
if (get_dev_model_and_fw(&hdhr) > 0) {
break;
}
sleep(3);
}
for (k = 0; k < device_info[i].tuner_count && num < max_ht_num; k++) {
ht[num].tuner_id = num;
ht[num].type = device_info[i].device_type;
snprintf(ht[num].name, sizeof(ht[num].name), "%X-%d",
device_info[i].device_id, k);
snprintf(ht[num].ip, sizeof(ht[num].ip), "%s", hdhr.ip);
snprintf(ht[num].model, sizeof(ht[num].model), "%s", hdhr.model);
snprintf(ht[num].firmware, sizeof(ht[num].firmware), "%s", hdhr.firmware);
snprintf(ht[num].tuner_name, sizeof(ht[num].tuner_name), "%s-%s",
ht[num].model, ht[num].name);
ht[num].cc_tuner = hdhr.cc_tuner;
ht[num].transcode_tuner = hdhr.transcode_tuner;
num++;
}
}
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;
}
#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_devices(ht, 16);
printf("found tuners:%d\n", ret);
if (ret > 0) {
for (i = 0; i < ret; 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