blob: 573edf160493688eedeb1e6f578e495aae9869ba [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 <assert.h>
#include "utility.h"
#include "hdhomerun_plugin.h"
#include "libhdhomerun/hdhomerun.h"
#include "hdhomerun_tuner.h"
#include "hdhomerun_dev.h"
#include "hdhomerun_tuner.h"
#include "channel_buffer.h"
#include "sagelog.h"
#define MAX_TUNER_NUM 16
struct device_list {
int tuner_num;
int list_num;
struct hdhr_tuner_t *hdhrs;
};
static int discover_hdhrs( struct hdhr_tuner_t *ht, int max_ht_num )
{
int i, ret = 0 ;
ret = discover_device( ht, max_ht_num );
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] );
}
return i;
}
return 0;
}
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) );
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) );
if ( devices->hdhrs == NULL ) {
free( devices);
return 0;
}
devices->list_num = MAX_TUNER_NUM;
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 );
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":"" ));
}
devices->tuner_num = tuner_num;
*num = tuner_num;
return devices;
}
return NULL;
}
void dev_release( void* handle )
{
struct device_list *devices = (struct device_list *)handle;
if ( devices != NULL ) {
if ( devices->hdhrs != NULL )
free( devices->hdhrs );
free( devices );
}
sage_log(( _LOG_TRACE, 3, "hdhr:hdhomerun device release." ));
}
int get_dev_name( void* handle, int index, char* name, int max_name_len )
{
struct device_list *devices = (struct device_list *)handle;
if ( devices != NULL && index < devices->tuner_num ) {
struct hdhr_tuner_t* hdhr = &devices->hdhrs[index];
strncpy( name, hdhr->tuner_name, max_name_len );
return 1;
}
return 0;
}
void* dev_open( void* handle, int index, int attr )
{
struct device_list *devices = (struct device_list *)handle;
struct hdhr_tuner_t* hdhr;
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;
}
void dev_close( void* dev )
{
struct hdhr_tuner_t* hdhr = (struct hdhr_tuner_t*)dev;
if ( hdhr == NULL ) {
sage_log(( _LOG_TRACE, 3, "hdhr:ERROR: invalid device handle." ));
return;
}
stop_channel( hdhr->hd );
close_hdhr( hdhr->hd );
}
int dev_tune( void* dev, char* channel, char* stream_tar )
{
int ret;
struct hdhr_tuner_t* hdhr = (struct hdhr_tuner_t*)dev;
if ( hdhr == NULL ) {
sage_log(( _LOG_TRACE, 3, "hdhr:ERROR: invalid device handle." ));
return 0;
}
sage_log(( _LOG_TRACE, 3, "hdhr:hdhomerun tune %s %s.", hdhr->name, (char*)channel ));
if ( strstr( stream_tar, "udp://" ) == NULL ) {
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 ) {
if ( strstr( channel, "vchan:" ) == NULL ) {
char vchan[32];
snprintf( vchan, sizeof(vchan), "vchan:%d", atoi(channel) );
ret = tune_channel( hdhr->hd, vchan, "", stream_tar );
} 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;
char *ps, *pe;
map_str[0] = 0x0;
//if channel in format "map:xxx-yy|auto:zzz prog:ppp"
if ( ( ps = strstr( channel, "map:" ))!= NULL &&
( pe = strchr( ps+4, '|' )) != NULL ) {
strncpy( map_str, ps+4, pe-(ps+4) );
map_str[pe-(ps+4)] = 0x0;
}
get_int_val_by_name( channel, "auto", &ch, NULL );
get_int_val_by_name( channel, "prog", &prog, NULL );
if ( prog == -1 ) {
sage_log(( _LOG_TRACE, 3, "hdhr:ERROR: invalid channel string %s", channel ));
return 0;
}
//if channel in format "nnn prog:mmm", based on dev to guess map
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" );
}
}
if ( map_str[0] && ch > 0 && prog > 0 ) {
snprintf( tune_str, sizeof(tune_str), "%s|auto:%d", map_str, ch );
snprintf( prog_str, sizeof(prog), "%d", prog );
ret = tune_channel( hdhr->hd, tune_str, prog_str, stream_tar );
} else {
sage_log(( _LOG_ERROR, 3, "hdhr:ERROR: invalid channel string %s", channel ));
return 0;
}
}
sage_log(( _LOG_TRACE, 3, "hdhr:hdhomerun tune %s %s.", (char*)channel, ret>0?"successful":"failed" ));
return ret > 0;
}
int dev_stop( void* dev )
{
struct hdhr_tuner_t* hdhr = (struct hdhr_tuner_t*)dev;
if ( hdhr == NULL ) {
sage_log(( _LOG_TRACE, 3, "hdhr:ERROR: invalid device handle." ));
return 0;
}
sage_log(( _LOG_TRACE, 3, "hdhr:hdhomerun stop %s.", (char*)hdhr->name ));
int ret = stop_channel( hdhr->hd );
return ret > 0;
}
int dev_scan( void* dev, char* tuner_name, char* channel, struct channel_list_t **cl_p )
{
struct hdhr_tuner_t* hdhr = (struct hdhr_tuner_t*)dev;
if ( hdhr == NULL ) {
sage_log(( _LOG_TRACE, 3, "hdhr:ERROR: invalid device handle." ));
return 0;
}
sage_log(( _LOG_TRACE, 3, "hdhr:hdhomerun scan %s.", (char*)hdhr->name ));
if ( hdhr->cc_tuner ) {
int vchannel;
char *p;
if ( ( p = strstr( channel, "vchan:" ) ) == NULL )
vchannel = atoi(channel) ;
else
vchannel = atoi(p+6);
if ( vchannel == 0 )
return 0;
struct channel_list_t *cl = _create_channel_list( 1 );
int ret = scan_vchannel( hdhr->hd, vchannel, cl->ce );
char unit_name[16];
snprintf( cl->ce[0].dev_name, sizeof(cl->ce[0].dev_name)-1, "HDHR.%s", get_unit_name( hdhr, unit_name, sizeof(unit_name) ));
cl->channel_num = ret;
if ( ret == 0 ) {
_release_channel_list( cl );
cl = NULL;
}
if ( cl_p != NULL )
*cl_p = cl;
return ret;
} else {
//TODO
}
return 0;
}
static struct channel_list_t * build_hdhr_channel_table( struct hdhr_tuner_t* hdhr )
{
if ( hdhr->cc_tuner ) {
struct vchan_tbl_t* vt = create_vchan_tbl( hdhr );
struct channel_list_t *cl = NULL;
if ( get_vchannel_list( vt ) > 0 ) {
int num = vt->channel_num;
cl = _create_channel_list( num );
int i;
for ( i = 0; i<num; i++ ) {
char unit_name[16];
cl->ce[i].state = 1;
snprintf( cl->ce[i].dev_tuning, sizeof(cl->ce[i].dev_tuning)-1, "vchan:%d", vt->vchan[i].guide_id );
snprintf( cl->ce[i].ch_name, sizeof(cl->ce[i].ch_name)-1, "%d", vt->vchan[i].guide_id );
strncpy( cl->ce[i].ch_desc, vt->vchan[i].guide_name, sizeof(cl->ce[i].ch_desc)-1 );
cl->ce[i].src_ip[0] = 0x0;
cl->ce[i].src_port = 0; //dynamic assigning
snprintf( cl->ce[i].dev_name, sizeof(cl->ce[i].dev_name)-1, "HDHR.%s", get_unit_name( hdhr, unit_name, sizeof(unit_name) ));
cl->ce[i].ch = vt->vchan[i].guide_id;
cl->ce[i].frq = 0;
cl->ce[i].av_inf[0] = 0;
}
cl->channel_num = i;
}
release_vchan_tbl( vt );
return cl;
} else { //TODO
}
return NULL;
}
int dev_build_channel_table( void* dev, char* option, struct channel_list_t **cl_p )
{
struct hdhr_tuner_t* hdhr = (struct hdhr_tuner_t*)dev;
if ( hdhr == NULL ) {
sage_log(( _LOG_TRACE, 3, "hdhr:ERROR: invalid device handle." ));
return 0;
}
sage_log(( _LOG_TRACE, 3, "hdhr:hdhomerun dev_build_channel_table %s.", (char*)hdhr->name ));
struct channel_list_t *cl= build_hdhr_channel_table( hdhr );
if ( cl_p != NULL ) {
*cl_p = cl;
if ( cl == NULL )
return 0;
return cl->channel_num;
}
return 0;
}
int dev_release_channel_table( void* dev )
{
struct hdhr_tuner_t* hdhr = (struct hdhr_tuner_t*)dev;
if ( hdhr == NULL ) {
sage_log(( _LOG_TRACE, 3, "hdhr:ERROR: invalid device handle." ));
return 0;
}
sage_log(( _LOG_TRACE, 3, "hdhr:hdhomerun dev_release_channel_table %s.", (char*)hdhr->name ));
if ( hdhr->channel_table != NULL ) {
free( hdhr->channel_table );
hdhr->channel_table = NULL;
return 1;
} else { //TODO
}
return 0;
}