diff --git a/src/input/mpegts/dvb.h b/src/input/mpegts/dvb.h index 3dae001bd..fd230fe9c 100644 --- a/src/input/mpegts/dvb.h +++ b/src/input/mpegts/dvb.h @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -/* +/* * Based on: * * ITU-T Recommendation H.222.0 / ISO standard 13818-1 @@ -406,6 +406,7 @@ typedef enum dvb_fe_type { DVB_TYPE_S, /* satellite */ DVB_TYPE_ATSC_T, /* terrestrial - north america */ DVB_TYPE_ATSC_C, /* cable - north america */ + DVB_TYPE_CABLECARD, /* CableCARD - North America */ DVB_TYPE_ISDB_T, /* terrestrial - japan, brazil */ DVB_TYPE_ISDB_C, /* cable - japan, brazil */ DVB_TYPE_ISDB_S, /* satellite - japan, brazil */ @@ -599,6 +600,12 @@ typedef struct dvb_isdbt_config { } layers[3]; } dvb_isdbt_config_t; +typedef struct dvb_fe_vchan { + uint32_t num; + uint16_t minor; + char *name; +} dvb_fe_vchan_t; + typedef struct dvb_mux_conf { dvb_fe_type_t dmc_fe_type; @@ -617,10 +624,11 @@ typedef struct dvb_mux_conf dvb_ofdm_config_t dmc_fe_ofdm; dvb_isdbt_config_t dmc_fe_isdbt; } u; + dvb_fe_vchan_t dmc_fe_vchan; // For scan file configurations LIST_ENTRY(dvb_mux_conf) dmc_link; - + } dvb_mux_conf_t; /* conversion routines */ diff --git a/src/input/mpegts/dvb_support.c b/src/input/mpegts/dvb_support.c index 569d209e4..92680e3d8 100644 --- a/src/input/mpegts/dvb_support.c +++ b/src/input/mpegts/dvb_support.c @@ -252,7 +252,7 @@ static inline size_t dvb_convert(int conv, int dvb_get_string - (char *dst, size_t dstlen, const uint8_t *src, size_t srclen, + (char *dst, size_t dstlen, const uint8_t *src, size_t srclen, const char *dvb_charset, dvb_string_conv_t *conv) { int ic = -1; @@ -302,7 +302,7 @@ dvb_get_string ic = convert_iso_8859[src[2]]; src+=3; srclen-=3; break; - + case 0x11: ic = convert_ucs2; src++; srclen--; @@ -376,7 +376,7 @@ dvb_get_string int -dvb_get_string_with_len(char *dst, size_t dstlen, +dvb_get_string_with_len(char *dst, size_t dstlen, const uint8_t *buf, size_t buflen, const char *dvb_charset, dvb_string_conv_t *conv) { @@ -683,6 +683,7 @@ const static struct strtab delsystab[] = { { "DVBC/ANNEX_A", DVB_SYS_DVBC_ANNEX_A }, { "DVBC_ANNEX_A", DVB_SYS_DVBC_ANNEX_A }, { "ATSC-C", DVB_SYS_DVBC_ANNEX_B }, + { "CableCARD", DVB_SYS_DVBC_ANNEX_B }, { "DVBC/ANNEX_B", DVB_SYS_DVBC_ANNEX_B }, { "DVBC_ANNEX_B", DVB_SYS_DVBC_ANNEX_B }, { "DVB-C/ANNEX-C",DVB_SYS_DVBC_ANNEX_C }, @@ -738,6 +739,8 @@ dvb_delsys2type ( mpegts_network_t *ln, dvb_fe_delivery_system_t delsys ) case DVB_SYS_DVBC_ANNEX_B: if (ln && idnode_is_instance(&ln->mn_id, &dvb_network_dvbc_class)) return DVB_TYPE_C; + if (ln && idnode_is_instance(&ln->mn_id, &dvb_network_cablecard_class)) + return DVB_TYPE_CABLECARD; else return DVB_TYPE_ATSC_C; case DVB_SYS_ISDBT: @@ -944,24 +947,25 @@ const static struct strtab poltab[] = { dvb_str2val(pol); const static struct strtab typetab[] = { - {"DVB-T", DVB_TYPE_T}, - {"DVB-C", DVB_TYPE_C}, - {"DVB-S", DVB_TYPE_S}, - {"ATSC-T", DVB_TYPE_ATSC_T}, - {"ATSC-C", DVB_TYPE_ATSC_C}, - {"ISDB-T", DVB_TYPE_ISDB_T}, - {"ISDB-C", DVB_TYPE_ISDB_C}, - {"ISDB-S", DVB_TYPE_ISDB_S}, - {"DAB", DVB_TYPE_DAB}, - {"DVBT", DVB_TYPE_T}, - {"DVBC", DVB_TYPE_C}, - {"DVBS", DVB_TYPE_S}, - {"ATSC", DVB_TYPE_ATSC_T}, - {"ATSCT", DVB_TYPE_ATSC_T}, - {"ATSCC", DVB_TYPE_ATSC_C}, - {"ISDBT", DVB_TYPE_ISDB_T}, - {"ISDBC", DVB_TYPE_ISDB_C}, - {"ISDBS", DVB_TYPE_ISDB_S} + {"DVB-T", DVB_TYPE_T}, + {"DVB-C", DVB_TYPE_C}, + {"DVB-S", DVB_TYPE_S}, + {"ATSC-T", DVB_TYPE_ATSC_T}, + {"ATSC-C", DVB_TYPE_ATSC_C}, + {"CableCARD", DVB_TYPE_CABLECARD}, + {"ISDB-T", DVB_TYPE_ISDB_T}, + {"ISDB-C", DVB_TYPE_ISDB_C}, + {"ISDB-S", DVB_TYPE_ISDB_S}, + {"DAB", DVB_TYPE_DAB}, + {"DVBT", DVB_TYPE_T}, + {"DVBC", DVB_TYPE_C}, + {"DVBS", DVB_TYPE_S}, + {"ATSC", DVB_TYPE_ATSC_T}, + {"ATSCT", DVB_TYPE_ATSC_T}, + {"ATSCC", DVB_TYPE_ATSC_C}, + {"ISDBT", DVB_TYPE_ISDB_T}, + {"ISDBC", DVB_TYPE_ISDB_C}, + {"ISDBS", DVB_TYPE_ISDB_S} }; dvb_str2val(type); @@ -1079,6 +1083,20 @@ dvb_mux_conf_str_atsc_t ( dvb_mux_conf_t *dmc, char *buf, size_t bufsize ) dvb_qam2str(dmc->dmc_fe_modulation)); } +static int +dvb_mux_conf_str_cablecard(dvb_mux_conf_t *dmc, char *buf, size_t bufsize) +{ + if (!dmc->dmc_fe_vchan.minor) + return snprintf(buf, bufsize, "%s channel %u", + dvb_type2str(dmc->dmc_fe_type), + dmc->dmc_fe_vchan.num); + else + return snprintf(buf, bufsize, "%s channel %u.%u", + dvb_type2str(dmc->dmc_fe_type), + dmc->dmc_fe_vchan.num, + dmc->dmc_fe_vchan.minor); +} + static int dvb_mux_conf_str_isdb_t ( dvb_mux_conf_t *dmc, char *buf, size_t bufsize ) { @@ -1122,6 +1140,8 @@ dvb_mux_conf_str ( dvb_mux_conf_t *dmc, char *buf, size_t bufsize ) return dvb_mux_conf_str_dvbs(dmc, buf, bufsize); case DVB_TYPE_ATSC_T: return dvb_mux_conf_str_atsc_t(dmc, buf, bufsize); + case DVB_TYPE_CABLECARD: + return dvb_mux_conf_str_cablecard(dmc, buf, bufsize); case DVB_TYPE_ISDB_T: return dvb_mux_conf_str_isdb_t(dmc, buf, bufsize); default: diff --git a/src/input/mpegts/mpegts_dvb.h b/src/input/mpegts/mpegts_dvb.h index f22e8b0b9..e67ad9493 100644 --- a/src/input/mpegts/mpegts_dvb.h +++ b/src/input/mpegts/mpegts_dvb.h @@ -50,6 +50,7 @@ extern const idclass_t dvb_network_dvbc_class; extern const idclass_t dvb_network_dvbs_class; extern const idclass_t dvb_network_atsc_t_class; extern const idclass_t dvb_network_atsc_c_class; +extern const idclass_t dvb_network_cablecard_class; extern const idclass_t dvb_network_isdb_t_class; extern const idclass_t dvb_network_isdb_c_class; extern const idclass_t dvb_network_isdb_s_class; @@ -87,6 +88,7 @@ extern const idclass_t dvb_mux_dvbc_class; extern const idclass_t dvb_mux_dvbs_class; extern const idclass_t dvb_mux_atsc_t_class; extern const idclass_t dvb_mux_atsc_c_class; +extern const idclass_t dvb_mux_cablecard_class; extern const idclass_t dvb_mux_isdb_t_class; extern const idclass_t dvb_mux_isdb_c_class; extern const idclass_t dvb_mux_isdb_s_class; diff --git a/src/input/mpegts/mpegts_mux_dvb.c b/src/input/mpegts/mpegts_mux_dvb.c index 134098fc8..2abd1c736 100644 --- a/src/input/mpegts/mpegts_mux_dvb.c +++ b/src/input/mpegts/mpegts_mux_dvb.c @@ -129,6 +129,39 @@ dvb_mux_class_delsys_set (void *o, const void *v) return 0; } +static const void * +dvb_mux_class_vchan_get(void *o) +{ + dvb_mux_t *lm = (dvb_mux_t *)o; + + if (!lm->lm_tuning.dmc_fe_vchan.minor) + snprintf(prop_sbuf, PROP_SBUF_LEN, "%u", + lm->lm_tuning.dmc_fe_vchan.num); + else + snprintf(prop_sbuf, PROP_SBUF_LEN, "%u.%u", + lm->lm_tuning.dmc_fe_vchan.num, + lm->lm_tuning.dmc_fe_vchan.minor); + return &prop_sbuf_ptr; +} + +static int +dvb_mux_class_vchan_set(void *o, const void *v) +{ + dvb_mux_t *lm = (dvb_mux_t *)o; + int r; + + r = sscanf(v, "%u%*[.-]%hu", + &lm->lm_tuning.dmc_fe_vchan.num, + &lm->lm_tuning.dmc_fe_vchan.minor); + switch (r) { + case 0: + return 1; + case 1: + lm->lm_tuning.dmc_fe_vchan.minor = 0; + } + return 0; +} + const idclass_t dvb_mux_class = { .ic_super = &mpegts_mux_class, @@ -614,6 +647,43 @@ const idclass_t dvb_mux_atsc_c_class = } }; +/* + * CableCARD + */ +const idclass_t dvb_mux_cablecard_class = +{ + .ic_super = &dvb_mux_class, + .ic_class = "dvb_mux_cablecard", + .ic_caption = N_("CableCARD multiplex"), + .ic_properties = (const property_t[]){ + { + .type = PT_STR, + .id = "vchan", + .name = N_("Channel"), + .desc = N_("The channel on the cable provider's network."), + .get = dvb_mux_class_vchan_get, + .set = dvb_mux_class_vchan_set, + }, + { + .type = PT_U32, + .id = "frequency", + .name = N_("Frequency (Hz)"), + .desc = N_("The frequency of the mux (in Hertz)."), + .off = offsetof(dvb_mux_t, lm_tuning.dmc_fe_freq), + .opts = PO_RDONLY, + }, + { + .type = PT_STR, + .id = "vchan_name", + .name = N_("Callsign"), + .desc = N_("The channel's name or callsign as set by the cable provider."), + .off = offsetof(dvb_mux_t, lm_tuning.dmc_fe_vchan.name), + .opts = PO_RDONLY, + }, + {} + } +}; + /* * ISDB-T */ @@ -913,26 +983,36 @@ dvb_mux_display_name ( mpegts_mux_t *mm, char *buf, size_t len ) dvb_network_t *ln = (dvb_network_t*)mm->mm_network; uint32_t freq = lm->lm_tuning.dmc_fe_freq, freq2; char extra[8], buf2[5], *p; - if (ln->ln_type == DVB_TYPE_S) { - const char *s = dvb_pol2str(lm->lm_tuning.u.dmc_fe_qpsk.polarisation); - if (s) extra[0] = *s; - extra[1] = '\0'; + + if (lm->lm_tuning.dmc_fe_type == DVB_TYPE_CABLECARD) { + if (!lm->lm_tuning.dmc_fe_vchan.minor) + snprintf(buf, len, "%u", lm->lm_tuning.dmc_fe_vchan.num); + else + snprintf(buf, len, "%u.%u", + lm->lm_tuning.dmc_fe_vchan.num, + lm->lm_tuning.dmc_fe_vchan.minor); } else { + if (ln->ln_type == DVB_TYPE_S) { + const char *s = dvb_pol2str(lm->lm_tuning.u.dmc_fe_qpsk.polarisation); + if (s) extra[0] = *s; + extra[1] = '\0'; + } else { + freq /= 1000; + strcpy(extra, "MHz"); + } + freq2 = freq % 1000; freq /= 1000; - strcpy(extra, "MHz"); - } - freq2 = freq % 1000; - freq /= 1000; - snprintf(buf2, sizeof(buf2), "%03d", freq2); - p = buf2 + 2; - while (freq2 && (freq2 % 10) == 0) { - freq2 /= 10; - *(p--) = '\0'; + snprintf(buf2, sizeof(buf2), "%03d", freq2); + p = buf2 + 2; + while (freq2 && (freq2 % 10) == 0) { + freq2 /= 10; + *(p--) = '\0'; + } + if (freq2) + snprintf(buf, len, "%d.%s%s", freq, buf2, extra); + else + snprintf(buf, len, "%d%s", freq, extra); } - if (freq2) - snprintf(buf, len, "%d.%s%s", freq, buf2, extra); - else - snprintf(buf, len, "%d%s", freq, extra); } static void @@ -997,6 +1077,9 @@ dvb_mux_create0 } else if (ln->ln_type == DVB_TYPE_ATSC_C) { idc = &dvb_mux_atsc_c_class; delsys = DVB_SYS_DVBC_ANNEX_B; + } else if (ln->ln_type == DVB_TYPE_CABLECARD) { + idc = &dvb_mux_cablecard_class; + delsys = DVB_SYS_DVBC_ANNEX_B; } else if (ln->ln_type == DVB_TYPE_ISDB_T) { idc = &dvb_mux_isdb_t_class; delsys = DVB_SYS_ISDBT; diff --git a/src/input/mpegts/mpegts_network_dvb.c b/src/input/mpegts/mpegts_network_dvb.c index 0efe6ffe5..e820023bf 100644 --- a/src/input/mpegts/mpegts_network_dvb.c +++ b/src/input/mpegts/mpegts_network_dvb.c @@ -47,7 +47,7 @@ dvb_network_class_delete ( idnode_t *in ) char ubuf[UUID_HEX_SIZE]; /* remove config */ - hts_settings_remove("input/dvb/networks/%s", + hts_settings_remove("input/dvb/networks/%s", idnode_uuid_as_str(in, ubuf)); /* Parent delete */ @@ -355,6 +355,16 @@ const idclass_t dvb_network_atsc_c_class = } }; +const idclass_t dvb_network_cablecard_class = +{ + .ic_super = &dvb_network_class, + .ic_class = "dvb_network_cablecard", + .ic_caption = N_("CableCARD Network"), + .ic_properties = (const property_t[]){ + {} + } +}; + const idclass_t dvb_network_isdb_t_class = { .ic_super = &dvb_network_class, @@ -600,6 +610,8 @@ dvb_network_mux_class return &dvb_mux_atsc_t_class; if (idnode_is_instance(&mn->mn_id, &dvb_network_atsc_c_class)) return &dvb_mux_atsc_c_class; + if (idnode_is_instance(&mn->mn_id, &dvb_network_cablecard_class)) + return &dvb_mux_cablecard_class; if (idnode_is_instance(&mn->mn_id, &dvb_network_isdb_t_class)) return &dvb_mux_isdb_t_class; if (idnode_is_instance(&mn->mn_id, &dvb_network_isdb_c_class)) @@ -795,7 +807,27 @@ static mpegts_service_t * dvb_network_create_service ( mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid ) { - return mpegts_service_create1(NULL, mm, sid, pmt_pid, NULL); + dvb_mux_t *lm = (dvb_mux_t *)mm; + mpegts_service_t *s; + + s = mpegts_service_create1(NULL, mm, sid, pmt_pid, NULL); + + /* Set service values from mux if CableCARD */ + if (lm->lm_tuning.dmc_fe_type == DVB_TYPE_CABLECARD) { + mpegts_network_t *ln = mm->mm_network; + if (!s->s_dvb_provider && lm->mm_provider_network_name) + s->s_dvb_provider = strdup(lm->mm_provider_network_name); + if (!s->s_dvb_provider && ln->mn_provider_network_name) + s->s_dvb_provider = strdup(ln->mn_provider_network_name); + if (!s->s_dvb_channel_num) + s->s_dvb_channel_num = lm->lm_tuning.dmc_fe_vchan.num; + if (!s->s_dvb_channel_minor && lm->lm_tuning.dmc_fe_vchan.minor) + s->s_dvb_channel_minor = lm->lm_tuning.dmc_fe_vchan.minor; + if (!s->s_dvb_svcname && lm->lm_tuning.dmc_fe_vchan.name) + s->s_dvb_svcname = strdup(lm->lm_tuning.dmc_fe_vchan.name); + } + + return s; } static mpegts_mux_t * @@ -829,7 +861,7 @@ dvb_network_create0 if (!(ln = (dvb_network_t*)mpegts_network_create0((void*)ln, idc, uuid, NULL, conf))) return NULL; - + /* Callbacks */ ln->mn_create_mux = dvb_network_create_mux; ln->mn_create_service = dvb_network_create_service; @@ -872,6 +904,7 @@ static const idclass_t * dvb_network_classes[] = { &dvb_network_dvbs_class, &dvb_network_atsc_t_class, &dvb_network_atsc_c_class, + &dvb_network_cablecard_class, &dvb_network_isdb_t_class, &dvb_network_isdb_c_class, &dvb_network_isdb_s_class, @@ -886,6 +919,7 @@ static const idclass_t * dvb_mux_classes[] = { &dvb_mux_dvbs_class, &dvb_mux_atsc_t_class, &dvb_mux_atsc_c_class, + &dvb_mux_cablecard_class, &dvb_mux_isdb_t_class, &dvb_mux_isdb_c_class, &dvb_mux_isdb_s_class, @@ -912,7 +946,7 @@ void dvb_network_init ( void ) for (i = 0; i < ARRAY_SIZE(dvb_network_classes); i++) mpegts_network_register_builder(dvb_network_classes[i], dvb_network_builder); - + /* Load settings */ if (!(c = hts_settings_load_r(1, "input/dvb/networks"))) return; @@ -965,6 +999,8 @@ const idclass_t *dvb_network_class_by_fe_type(dvb_fe_type_t type) return &dvb_network_atsc_t_class; else if (type == DVB_TYPE_ATSC_C) return &dvb_network_atsc_c_class; + else if (type == DVB_TYPE_CABLECARD) + return &dvb_network_cablecard_class; else if (type == DVB_TYPE_ISDB_T) return &dvb_network_isdb_t_class; else if (type == DVB_TYPE_ISDB_C) @@ -989,6 +1025,8 @@ dvb_fe_type_t dvb_fe_type_by_network_class(const idclass_t *idc) return DVB_TYPE_ATSC_T; else if (idc == &dvb_network_atsc_c_class) return DVB_TYPE_ATSC_C; + else if (idc == &dvb_network_cablecard_class) + return DVB_TYPE_CABLECARD; else if (idc == &dvb_network_isdb_t_class) return DVB_TYPE_ISDB_T; else if (idc == &dvb_network_isdb_c_class) diff --git a/src/input/mpegts/tvhdhomerun/tvhdhomerun.c b/src/input/mpegts/tvhdhomerun/tvhdhomerun.c index 47740a4a0..91ee57396 100644 --- a/src/input/mpegts/tvhdhomerun/tvhdhomerun.c +++ b/src/input/mpegts/tvhdhomerun/tvhdhomerun.c @@ -115,6 +115,7 @@ tvhdhomerun_device_class_override_enum( void * p, const char *lang ) htsmsg_add_str(m, NULL, "DVB-C"); htsmsg_add_str(m, NULL, "ATSC-T"); htsmsg_add_str(m, NULL, "ATSC-C"); + htsmsg_add_str(m, NULL, "CableCARD"); return m; } @@ -316,13 +317,16 @@ static void tvhdhomerun_device_create(struct hdhomerun_discover_device_t *dInfo) override_type = "ATSC-T"; type = dvb_str2type(override_type); if ( ! ( type == DVB_TYPE_C || type == DVB_TYPE_T || - type == DVB_TYPE_ATSC_T || type == DVB_TYPE_ATSC_C ) ) { + type == DVB_TYPE_ATSC_T || type == DVB_TYPE_ATSC_C || + type == DVB_TYPE_CABLECARD ) ) { type = DVB_TYPE_C; } } } else { if (strstr(hd->hd_info.deviceModel, "_atsc")) type = DVB_TYPE_ATSC_T; + if (strstr(hd->hd_info.deviceModel, "_cablecard")) + type = DVB_TYPE_CABLECARD; } hd->hd_override_type = strdup(dvb_type2str(type)); @@ -453,6 +457,7 @@ void tvhdhomerun_init ( void ) idclass_register(&tvhdhomerun_frontend_dvbc_class); idclass_register(&tvhdhomerun_frontend_atsc_t_class); idclass_register(&tvhdhomerun_frontend_atsc_c_class); + idclass_register(&tvhdhomerun_frontend_cablecard_class); TAILQ_INIT(&tvhdhomerun_discoveries); pthread_mutex_init(&tvhdhomerun_discovery_lock, NULL); tvh_cond_init(&tvhdhomerun_discovery_cond); diff --git a/src/input/mpegts/tvhdhomerun/tvhdhomerun.h b/src/input/mpegts/tvhdhomerun/tvhdhomerun.h index bbec1bcfc..80cd130e2 100644 --- a/src/input/mpegts/tvhdhomerun/tvhdhomerun.h +++ b/src/input/mpegts/tvhdhomerun/tvhdhomerun.h @@ -25,6 +25,7 @@ extern const idclass_t tvhdhomerun_frontend_dvbt_class; extern const idclass_t tvhdhomerun_frontend_dvbc_class; extern const idclass_t tvhdhomerun_frontend_atsc_t_class; extern const idclass_t tvhdhomerun_frontend_atsc_c_class; +extern const idclass_t tvhdhomerun_frontend_cablecard_class; void tvhdhomerun_init( void ); void tvhdhomerun_done( void ); diff --git a/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c b/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c index 20ca3492c..2665e63da 100644 --- a/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c +++ b/src/input/mpegts/tvhdhomerun/tvhdhomerun_frontend.c @@ -254,6 +254,19 @@ tvhdhomerun_frontend_monitor_cb( void *aux ) tvhdebug(LS_TVHDHOMERUN, "locked"); hfe->hf_locked = 1; + /* Get CableCARD variables */ + dvb_mux_t *lm = (dvb_mux_t *)mm; + struct hdhomerun_tuner_vstatus_t tuner_vstatus; + char *tuner_vstatus_str; + pthread_mutex_lock(&hfe->hf_hdhomerun_device_mutex); + res = hdhomerun_device_get_tuner_vstatus(hfe->hf_hdhomerun_tuner, + &tuner_vstatus_str, &tuner_vstatus); + pthread_mutex_unlock(&hfe->hf_hdhomerun_device_mutex); + if (res < 1) + tvhwarn(LS_TVHDHOMERUN, "tuner_vstatus (%d)", res); + lm->lm_tuning.dmc_fe_vchan.name = strdup(tuner_vstatus.name); + sscanf(strstr(tuner_status.channel, ":"), ":%u", &lm->lm_tuning.dmc_fe_freq); + /* start input thread */ tvh_pipe(O_NONBLOCK, &hfe->hf_input_thread_pipe); pthread_mutex_lock(&hfe->hf_input_thread_mutex); @@ -308,6 +321,9 @@ static void tvhdhomerun_device_open_pid(tvhdhomerun_frontend_t *hfe, int pid) { char buf[1024]; int res; + if (hfe->hf_type == DVB_TYPE_CABLECARD) + return; + /* a full mux subscription should specificly set the filter */ if (pid == MPEGTS_FULLMUX_PID) { tvhdebug(LS_TVHDHOMERUN, "setting PID filter full mux"); @@ -413,6 +429,14 @@ static int tvhdhomerun_frontend_tune(tvhdhomerun_frontend_t *hfe, mpegts_mux_ins break; } break; + case DVB_TYPE_CABLECARD: + if (!dmc->dmc_fe_vchan.minor) + snprintf(channel_buf, sizeof(channel_buf), "%u", dmc->dmc_fe_vchan.num); + else + snprintf(channel_buf, sizeof(channel_buf), "%u.%u", + dmc->dmc_fe_vchan.num, + dmc->dmc_fe_vchan.minor); + break; default: snprintf(channel_buf, sizeof(channel_buf), "auto:%u", dmc->dmc_fe_freq); break; @@ -427,7 +451,10 @@ static int tvhdhomerun_frontend_tune(tvhdhomerun_frontend_t *hfe, mpegts_mux_ins tvherror(LS_TVHDHOMERUN, "failed to acquire lockkey: %s", perror); return SM_CODE_TUNING_FAILED; } - res = hdhomerun_device_set_tuner_channel(hfe->hf_hdhomerun_tuner, channel_buf); + if (hfe->hf_type == DVB_TYPE_CABLECARD) + res = hdhomerun_device_set_tuner_vchannel(hfe->hf_hdhomerun_tuner, channel_buf); + else + res = hdhomerun_device_set_tuner_channel(hfe->hf_hdhomerun_tuner, channel_buf); pthread_mutex_unlock(&hfe->hf_hdhomerun_device_mutex); if(res < 1) { tvherror(LS_TVHDHOMERUN, "failed to tune to %s", channel_buf); @@ -459,11 +486,13 @@ tvhdhomerun_frontend_start_mux res = tvhdhomerun_frontend_tune(hfe, mmi); /* reset the pfilters */ - pthread_mutex_lock(&hfe->hf_hdhomerun_device_mutex); - r = hdhomerun_device_set_tuner_filter(hfe->hf_hdhomerun_tuner, "0x0000"); - pthread_mutex_unlock(&hfe->hf_hdhomerun_device_mutex); - if(r < 1) - tvherror(LS_TVHDHOMERUN, "failed to reset pfilter: %d", r); + if (hfe->hf_type != DVB_TYPE_CABLECARD) { + pthread_mutex_lock(&hfe->hf_hdhomerun_device_mutex); + r = hdhomerun_device_set_tuner_filter(hfe->hf_hdhomerun_tuner, "0x0000"); + pthread_mutex_unlock(&hfe->hf_hdhomerun_device_mutex); + if(r < 1) + tvherror(LS_TVHDHOMERUN, "failed to reset pfilter: %d", r); + } return res; } @@ -616,6 +645,16 @@ const idclass_t tvhdhomerun_frontend_atsc_c_class = } }; +const idclass_t tvhdhomerun_frontend_cablecard_class = +{ + .ic_super = &tvhdhomerun_frontend_class, + .ic_class = "tvhdhomerun_frontend_cablecard", + .ic_caption = N_("HDHomeRun CableCARD frontend"), + .ic_properties = (const property_t[]){ + {} + } +}; + static mpegts_network_t * tvhdhomerun_frontend_wizard_network ( tvhdhomerun_frontend_t *hfe ) { @@ -704,6 +743,8 @@ tvhdhomerun_frontend_create(tvhdhomerun_device_t *hd, struct hdhomerun_discover_ idc = &tvhdhomerun_frontend_atsc_t_class; else if (type == DVB_TYPE_ATSC_C) idc = &tvhdhomerun_frontend_atsc_c_class; + else if (type == DVB_TYPE_CABLECARD) + idc = &tvhdhomerun_frontend_cablecard_class; else { tvherror(LS_TVHDHOMERUN, "unknown FE type %d", type); return NULL;