Add HDHomeRun OTA tuner support
Change-Id: Ief7fdb5a223529596f4981c081d2466ad18c891c
diff --git a/hdhomerun_plugin.c b/hdhomerun_plugin.c
old mode 100755
new mode 100644
index 573edf1..8cca2da
--- a/hdhomerun_plugin.c
+++ b/hdhomerun_plugin.c
@@ -45,9 +45,11 @@
void* dev_init( int *num )
{
int i, index = 0, tuner_num;
- char *type_name[2] ={ "NR", "CC" };
- sage_log(( _LOG_TRACE, 3, "hdhr::hdhomerun device init" ));
- struct device_list *devices = (struct device_list *)malloc( sizeof(struct device_list) );
+ struct device_list *devices;
+
+ sage_log((_LOG_TRACE, 3, "hdhr:hdhomerun device init"));
+
+ devices = (struct device_list *)malloc( sizeof(struct device_list) );
if ( devices != NULL ) {
devices->hdhrs = (struct hdhr_tuner_t *)malloc(sizeof(struct hdhr_tuner_t) * MAX_TUNER_NUM );
memset( devices->hdhrs, 0, sizeof(sizeof(struct hdhr_tuner_t) * MAX_TUNER_NUM) );
@@ -59,15 +61,14 @@
devices->tuner_num = 0;
tuner_num = discover_hdhrs( devices->hdhrs, MAX_TUNER_NUM );
for ( i = 0; i<tuner_num; i++ ) {
- int type = 0;
devices->hdhrs[i].tuner_id = index++;
- if ( devices->hdhrs[i].cc_tuner )
- type = 1;
- else
- type = 0;
- snprintf( devices->hdhrs[i].tuner_name, sizeof(devices->hdhrs[i].tuner_name), "HDHR-%s-%s", type_name[type], devices->hdhrs[i].name );
+ snprintf(devices->hdhrs[i].tuner_name,
+ sizeof(devices->hdhrs[i].tuner_name), "%s-%s",
+ devices->hdhrs[i].model, devices->hdhrs[i].name);
devices->tuner_num++;
- sage_log(( _LOG_TRACE, 3, "hdhr:%d %s %s %s", i, devices->hdhrs[i].tuner_name, devices->hdhrs[i].model, devices->hdhrs[i].cc_tuner?"CableCard":"" ));
+ sage_log((_LOG_TRACE, 3, "hdhr:%d %s %s %s", i,
+ devices->hdhrs[i].tuner_name, devices->hdhrs[i].model,
+ devices->hdhrs[i].cc_tuner ? "CableCard" : ""));
}
devices->tuner_num = tuner_num;
*num = tuner_num;
@@ -105,7 +106,6 @@
if ( index >= devices->tuner_num )
return NULL;
hdhr = &devices->hdhrs[index];
- hdhr->type = attr; //1:atsc 2:qam
hdhr->hd = open_hdhr( hdhr->name );
return hdhr;
}
@@ -134,8 +134,9 @@
sage_log(( _LOG_TRACE, 3, "hdhr:ERROR: stream target \"%s\" is wrong.", stream_tar ));
return 0;
}
- //cablecard tuner:HDHomerun prime unit
+
if ( hdhr->cc_tuner ) {
+ /* HDHomeRun PRIME */
if ( strstr( channel, "vchan:" ) == NULL ) {
char vchan[32];
snprintf( vchan, sizeof(vchan), "vchan:%d", atoi(channel) );
@@ -143,11 +144,31 @@
} else
ret = tune_channel( hdhr->hd, channel, "", stream_tar );
} else {
- //HDHomeRun unit
- char tune_str[32], map_str[8], prog_str[8];
- int ch = -1, prog = -1;
+ /* HDHomeRun US */
+ char tune_str[32], map_str[32], prog_str[8];
+ int ch = -1, prog = -1, vch_major = -1, vch_minor = -1;
char *ps, *pe;
map_str[0] = 0x0;
+
+ /*
+ * channel format: xx-yy-zz
+ * xx=physical channel, yy=virtual major channel, zz=virtual minor channel
+ */
+ if (sscanf(channel, "%d-%d-%d", &ch, &vch_major, &vch_minor) == 3) {
+ ret = tune_vchannel(hdhr->hd, ch, vch_major, vch_minor, stream_tar);
+ goto out;
+ }
+
+ /*
+ * channel format: xx-yy
+ * xx=physical channel, yy=virtual major channel
+ */
+ if (sscanf(channel, "%d-%d", &ch, &vch_major) == 2) {
+ vch_minor = 0;
+ ret = tune_vchannel(hdhr->hd, ch, vch_major, vch_minor, stream_tar);
+ goto out;
+ }
+
//if channel in format "map:xxx-yy|auto:zzz prog:ppp"
if ( ( ps = strstr( channel, "map:" ))!= NULL &&
( pe = strchr( ps+4, '|' )) != NULL ) {
@@ -164,8 +185,7 @@
if ( map_str[0] == 0x0 && prog > 0 && ch == -1 ) {
ch=atoi( channel );
if ( ch > 0 ) {
- int atsc = ( hdhr->type == 1 ); //TODO dvb
- snprintf( map_str, sizeof( map_str), "map:us-%s", atsc? "atsc":"cable" );
+ snprintf( map_str, sizeof(map_str), "map:us-bcast" );
}
}
if ( map_str[0] && ch > 0 && prog > 0 ) {
@@ -177,6 +197,8 @@
return 0;
}
}
+
+out:
sage_log(( _LOG_TRACE, 3, "hdhr:hdhomerun tune %s %s.", (char*)channel, ret>0?"successful":"failed" ));
return ret > 0;
}
@@ -224,7 +246,8 @@
*cl_p = cl;
return ret;
} else {
- //TODO
+ sage_log((_LOG_TRACE, 3, "hdhr:hdhomerun ATSC dev_scan not implemented %s.",
+ (char*)hdhr->name));
}
return 0;
@@ -256,8 +279,9 @@
}
release_vchan_tbl( vt );
return cl;
- } else { //TODO
-
+ } else {
+ sage_log((_LOG_TRACE, 3, "hdhr:hdhomerun ATSC build_hdhr_channel_table not implemented %s.",
+ (char*)hdhr->name));
}
return NULL;
}
diff --git a/hdhomerun_tuner.c b/hdhomerun_tuner.c
index ae837b9..3dd1a0d 100644
--- a/hdhomerun_tuner.c
+++ b/hdhomerun_tuner.c
@@ -50,6 +50,7 @@
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;
@@ -65,7 +66,6 @@
char vchannel_str[16];
char channel_map[32];
struct hdhomerun_device_t *hd =(struct hdhomerun_device_t *)device;
- struct hdhomerun_channel_list_t *channel_list=NULL;
int ret;
if ( hd == NULL ) {
@@ -88,11 +88,6 @@
printf("hdhomerun %p invalid channel program %s\n", device, program );
return -1;
}
- channel_list = hdhomerun_channel_list_create( channel_map );
- if ( channel_list == NULL ) {
- printf( "hdhomerun failed to create channel map\n");
- 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 );
@@ -111,17 +106,128 @@
}
char target[64];
- snprintf( target, sizeof(target), "%s ttl-2",stream_target );
+ 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 );
}
- if ( channel_list )
- hdhomerun_channel_list_destroy( channel_list );
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 )
{
diff --git a/hdhomerun_tuner.h b/hdhomerun_tuner.h
index 2ffe6db..0a3a5ef 100644
--- a/hdhomerun_tuner.h
+++ b/hdhomerun_tuner.h
@@ -36,6 +36,9 @@
int scan_all( void* device, struct channel_entry_t *ce, int ce_num );
int tuner_input_sharing( struct hdhr_tuner_t *ht1, struct hdhr_tuner_t *ht2 );
int tune_channel( void* device, char *channel, char *program, char* stream_target );
+int tune_vchannel(void *device, unsigned int channel,
+ unsigned int vchannel_major, unsigned int vchannel_minor,
+ char *stream_target);
int stop_channel( void* device );
int scan_vchannel( void* device, int vchannel, struct channel_entry_t *ce );
int tuner_input_sharing( struct hdhr_tuner_t *ht1, struct hdhr_tuner_t *ht2 );