diff --git a/src/dvb/dvb.h b/src/dvb/dvb.h index 847074a9..6b42de90 100644 --- a/src/dvb/dvb.h +++ b/src/dvb/dvb.h @@ -212,7 +212,7 @@ typedef struct th_dvb_adapter { uint32_t tda_diseqc_version; uint32_t tda_diseqc_repeats; uint32_t tda_disable_pmt_monitor; - uint32_t tda_disable_full_mux_rx; + int32_t tda_full_mux_rx; char *tda_displayname; char *tda_fe_path; @@ -364,7 +364,7 @@ void dvb_adapter_set_diseqc_repeats(th_dvb_adapter_t *tda, void dvb_adapter_set_disable_pmt_monitor(th_dvb_adapter_t *tda, int on); -void dvb_adapter_set_disable_full_mux_rx(th_dvb_adapter_t *tda, int on); +void dvb_adapter_set_full_mux_rx(th_dvb_adapter_t *tda, int r); void dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src); diff --git a/src/dvb/dvb_adapter.c b/src/dvb/dvb_adapter.c index 5a8ccf95..3a971d02 100644 --- a/src/dvb/dvb_adapter.c +++ b/src/dvb/dvb_adapter.c @@ -94,7 +94,7 @@ tda_save(th_dvb_adapter_t *tda) htsmsg_add_u32(m, "extrapriority", tda->tda_extrapriority); htsmsg_add_u32(m, "skip_initialscan", tda->tda_skip_initialscan); htsmsg_add_u32(m, "disable_pmt_monitor", tda->tda_disable_pmt_monitor); - htsmsg_add_u32(m, "disable_full_mux_rx", tda->tda_disable_full_mux_rx); + htsmsg_add_s32(m, "full_mux_rx", tda->tda_full_mux_rx); hts_settings_save(m, "dvbadapters/%s", tda->tda_identifier); htsmsg_destroy(m); } @@ -369,17 +369,23 @@ dvb_adapter_set_disable_pmt_monitor(th_dvb_adapter_t *tda, int on) * */ void -dvb_adapter_set_disable_full_mux_rx(th_dvb_adapter_t *tda, int on) +dvb_adapter_set_full_mux_rx(th_dvb_adapter_t *tda, int on) { - if(tda->tda_disable_full_mux_rx == on) + const char* label[] = { "Auto", "Off", "On" }; + + if (on < -1) on = -1; + if (on > 1) on = 1; + + if(tda->tda_full_mux_rx == on) return; lock_assert(&global_lock); - tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" disabled full MUX receive set to: %s", - tda->tda_displayname, on ? "On" : "Off"); + tvhlog(LOG_NOTICE, "dvb", + "Adapter \"%s\" disabled full MUX receive set to: %s", + tda->tda_displayname, label[on+1]); - tda->tda_disable_full_mux_rx = on; + tda->tda_full_mux_rx = on; tda_save(tda); } @@ -408,12 +414,15 @@ check_full_stream(th_dvb_adapter_t *tda) struct dmx_pes_filter_params dmx_param; int r; - if(tda->tda_disable_full_mux_rx) - return 0; + if(tda->tda_full_mux_rx != -1) + return tda->tda_full_mux_rx; if(tda->tda_hostconnection == HOSTCONNECTION_USB12) return 0; // Don't even bother, device <-> host interface is too slow + if(tda->tda_hostconnection == HOSTCONNECTION_USB480) + return 0; // USB in general appears to have CPU loading issues? + int fd = tvh_open(tda->tda_demux_path, O_RDWR, 0); if(fd == -1) return 0; @@ -462,6 +471,7 @@ tda_add(int adapter_num) tda->tda_fe_path = strdup(fname); tda->tda_fe_fd = -1; tda->tda_dvr_pipe[0] = -1; + tda->tda_full_mux_rx = -1; tda->tda_fe_info = malloc(sizeof(struct dvb_frontend_info)); @@ -506,21 +516,11 @@ tda_add(int adapter_num) TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link); - if(check_full_stream(tda)) { - tvhlog(LOG_INFO, "dvb", "Adapter %s will run in full mux mode", path); - dvb_input_raw_setup(tda); - } else { - tvhlog(LOG_INFO, "dvb", "Adapter %s will run in filtered mode", path); - dvb_input_filtered_setup(tda); - } - - if(tda->tda_sat) - dvb_satconf_init(tda); - gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 1); } + /** * */ @@ -552,6 +552,8 @@ tda_add_from_file(const char *filename) tda->tda_idlescan = 0; tda->tda_sat = 0; + + tda->tda_full_mux_rx = 1; /* Come up with an initial displayname, user can change it and it will be overridden by any stored settings later on */ @@ -559,10 +561,23 @@ tda_add_from_file(const char *filename) tda->tda_displayname = strdup(filename); TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link); - - dvb_input_raw_setup(tda); } +/** + * Initiliase input + */ +static void tda_init_input (th_dvb_adapter_t *tda) +{ + if(tda->tda_type == -1 || check_full_stream(tda)) { + tvhlog(LOG_INFO, "dvb", "Adapter %s will run in full mux mode", tda->tda_rootpath); + dvb_input_raw_setup(tda); + } else { + tvhlog(LOG_INFO, "dvb", "Adapter %s will run in filtered mode", tda->tda_rootpath); + dvb_input_filtered_setup(tda); + } +} + + /** * @@ -629,40 +644,42 @@ dvb_adapter_init(uint32_t adapter_mask, const char *rawfile) htsmsg_field_t *f; const char *name, *s; int i, type; + uint32_t u32; th_dvb_adapter_t *tda; TAILQ_INIT(&dvb_adapters); + /* Initialise hardware */ for(i = 0; i < 32; i++) if ((1 << i) & adapter_mask) tda_add(i); + /* Initialise rawts test file */ if(rawfile) tda_add_from_file(rawfile); - + /* Load configuration */ l = hts_settings_load("dvbadapters"); if(l != NULL) { HTSMSG_FOREACH(f, l) { if((c = htsmsg_get_map_by_field(f)) == NULL) - continue; + continue; name = htsmsg_get_str(c, "displayname"); if((s = htsmsg_get_str(c, "type")) == NULL || - (type = dvb_str_to_adaptertype(s)) < 0) - continue; + (type = dvb_str_to_adaptertype(s)) < 0) + continue; if((tda = dvb_adapter_find_by_identifier(f->hmf_name)) == NULL) { - /* Not discovered by hardware, create it */ - - tda = tda_alloc(); - tda->tda_identifier = strdup(f->hmf_name); - tda->tda_type = type; - TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link); + /* Not discovered by hardware, create it */ + tda = tda_alloc(); + tda->tda_identifier = strdup(f->hmf_name); + tda->tda_type = type; + TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link); } else { - if(type != tda->tda_type) - continue; /* Something is wrong, ignore */ + if(type != tda->tda_type) + continue; /* Something is wrong, ignore */ } free(tda->tda_displayname); @@ -681,13 +698,21 @@ dvb_adapter_init(uint32_t adapter_mask, const char *rawfile) htsmsg_get_u32(c, "extrapriority", &tda->tda_extrapriority); htsmsg_get_u32(c, "skip_initialscan", &tda->tda_skip_initialscan); htsmsg_get_u32(c, "disable_pmt_monitor", &tda->tda_disable_pmt_monitor); - htsmsg_get_u32(c, "disable_full_mux_rx", &tda->tda_disable_full_mux_rx); + if (htsmsg_get_s32(c, "full_mux_rx", &tda->tda_full_mux_rx)) + if (!htsmsg_get_u32(c, "disable_full_mux_rx", &u32) && u32) + tda->tda_full_mux_rx = 0; } htsmsg_destroy(l); } - TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) + TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) { + tda_init_input(tda); + + if(tda->tda_sat) + dvb_satconf_init(tda); + dvb_mux_load(tda); + } } @@ -906,8 +931,16 @@ dvb_adapter_input_dvr(void *aux) if (c < 0) { if (errno == EAGAIN || errno == EINTR) continue; - else + else if (errno == EOVERFLOW) { + tvhlog(LOG_WARNING, "dvb", "\"%s\" read() EOVERFLOW", + tda->tda_identifier); + continue; + } else { + // TODO: should we try to recover? + tvhlog(LOG_ERR, "dvb", "\"%s\" read() error %d", + tda->tda_identifier, errno); break; + } } r += c; @@ -916,7 +949,6 @@ dvb_adapter_input_dvr(void *aux) int wakeup_table_feed = 0; // Just wanna wakeup once - pthread_mutex_lock(&tda->tda_delivery_mutex); if(LIST_FIRST(&tda->tda_streaming_pad.sp_targets) != NULL) { @@ -929,28 +961,26 @@ dvb_adapter_input_dvr(void *aux) pktbuf_ref_dec(pb); } - - /* Process */ while (r >= 188) { /* sync */ if (tsb[i] == 0x47) { + int pid = (tsb[i+1] & 0x1f) << 8 | tsb[i+2]; + if(tda->tda_table_filter[pid]) { + if(!(tsb[i+1] & 0x80)) { // Only dispatch to table parser if not error + dvb_table_feed_t *dtf = malloc(sizeof(dvb_table_feed_t)); + memcpy(dtf->dtf_tsb, tsb + i, 188); + TAILQ_INSERT_TAIL(&tda->tda_table_feed, dtf, dtf_link); + wakeup_table_feed = 1; + } + } else { + LIST_FOREACH(t, &tda->tda_transports, s_active_link) + if(t->s_dvb_mux_instance == tda->tda_mux_current) + ts_recv_packet1(t, tsb + i, NULL); + } - if(!(tsb[i+1] & 0x80)) { // Only dispatch to table parser if not error - int pid = (tsb[i+1] & 0x1f) << 8 | tsb[i+2]; - if(tda->tda_table_filter[pid]) { - dvb_table_feed_t *dtf = malloc(sizeof(dvb_table_feed_t)); - memcpy(dtf->dtf_tsb, tsb + i, 188); - TAILQ_INSERT_TAIL(&tda->tda_table_feed, dtf, dtf_link); - wakeup_table_feed = 1; - } - } - - LIST_FOREACH(t, &tda->tda_transports, s_active_link) - if(t->s_dvb_mux_instance == tda->tda_mux_current) - ts_recv_packet1(t, tsb + i, NULL); i += 188; r -= 188; diff --git a/src/epg.c b/src/epg.c index c123a7b2..eb6a6a88 100644 --- a/src/epg.c +++ b/src/epg.c @@ -746,13 +746,13 @@ static htsmsg_t *epg_episode_num_serialize ( epg_episode_num_t *num ) if (num->e_cnt) htsmsg_add_u32(m, "e_cnt", num->e_cnt); if (num->s_num) - htsmsg_add_u32(m, "s_num", num->e_num); + htsmsg_add_u32(m, "s_num", num->s_num); if (num->s_cnt) - htsmsg_add_u32(m, "s_cnt", num->e_cnt); + htsmsg_add_u32(m, "s_cnt", num->s_cnt); if (num->p_num) - htsmsg_add_u32(m, "p_num", num->e_num); + htsmsg_add_u32(m, "p_num", num->p_num); if (num->p_cnt) - htsmsg_add_u32(m, "p_cnt", num->e_cnt); + htsmsg_add_u32(m, "p_cnt", num->p_cnt); if (num->text) htsmsg_add_str(m, "text", num->text); return m; diff --git a/src/htsp_server.c b/src/htsp_server.c index d1f65f60..b8c75be4 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -1469,24 +1469,30 @@ htsp_write_scheduler(void *aux) r = htsmsg_binary_serialize(hm->hm_msg, &dptr, &dlen, INT32_MAX); -#if 0 - if(hm->hm_pktref) { - usleep(hm->hm_payloadsize * 3); - } -#endif htsp_msg_destroy(hm); - - /* ignore return value */ - r = write(htsp->htsp_fd, dptr, dlen); - if(r != dlen) - tvhlog(LOG_INFO, "htsp", "%s: Write error -- %s", - htsp->htsp_logname, strerror(errno)); - free(dptr); + + void *freeme = dptr; + + while(dlen > 0) { + r = write(htsp->htsp_fd, dptr, dlen); + if(r < 1) { + tvhlog(LOG_INFO, "htsp", "%s: Write error -- %s", + htsp->htsp_logname, strerror(errno)); + break; + } + + dptr += r; + dlen -= r; + } + + free(freeme); pthread_mutex_lock(&htsp->htsp_out_mutex); - if(r != dlen) + if(dlen) break; } + // Shutdown socket to make receive thread terminate entire HTSP connection + shutdown(htsp->htsp_fd, SHUT_RDWR); pthread_mutex_unlock(&htsp->htsp_out_mutex); return NULL; } @@ -1558,6 +1564,17 @@ htsp_serve(int fd, void *opaque, struct sockaddr_in *source, pthread_mutex_unlock(&htsp.htsp_out_mutex); pthread_join(htsp.htsp_writer_thread, NULL); + + htsp_msg_q_t *hmq; + + TAILQ_FOREACH(hmq, &htsp.htsp_active_output_queues, hmq_link) { + htsp_msg_t *hm; + while((hm = TAILQ_FIRST(&hmq->hmq_q)) != NULL) { + TAILQ_REMOVE(&hmq->hmq_q, hm, hm_link); + htsp_msg_destroy(hm); + } + } + close(fd); } diff --git a/src/parser_h264.c b/src/parser_h264.c index 67a82304..0653227f 100644 --- a/src/parser_h264.c +++ b/src/parser_h264.c @@ -355,7 +355,7 @@ h264_decode_slice_header(elementary_stream_t *st, bitstream_t *bs, int *pkttype, int *isfield) { h264_private_t *p; - int slice_type, pps_id, sps_id; + unsigned int slice_type, pps_id, sps_id; if((p = st->es_priv) == NULL) return -1; diff --git a/src/service.c b/src/service.c index c193ef52..6548f104 100644 --- a/src/service.c +++ b/src/service.c @@ -110,18 +110,21 @@ stream_clean(elementary_stream_t *st) st->es_global_data_len = 0; } - /** * */ void -service_stream_destroy(service_t *t, elementary_stream_t *st) +service_stream_destroy(service_t *t, elementary_stream_t *es) { if(t->s_status == SERVICE_RUNNING) - stream_clean(st); - TAILQ_REMOVE(&t->s_components, st, es_link); - free(st->es_nicename); - free(st); + stream_clean(es); + + avgstat_flush(&es->es_rate); + avgstat_flush(&es->es_cc_errors); + + TAILQ_REMOVE(&t->s_components, es, es_link); + free(es->es_nicename); + free(es); } /** @@ -489,17 +492,17 @@ service_destroy(service_t *t) free(t->s_provider); free(t->s_dvb_charset); - while((st = TAILQ_FIRST(&t->s_components)) != NULL) { - TAILQ_REMOVE(&t->s_components, st, es_link); - free(st->es_nicename); - free(st); - } + while((st = TAILQ_FIRST(&t->s_components)) != NULL) + service_stream_destroy(t, st); free(t->s_pat_section); free(t->s_pmt_section); sbuf_free(&t->s_tsbuf); + avgstat_flush(&t->s_cc_errors); + avgstat_flush(&t->s_rate); + service_unref(t); if(ch != NULL) { diff --git a/src/subscriptions.c b/src/subscriptions.c index 1cae0a4f..2f56825b 100644 --- a/src/subscriptions.c +++ b/src/subscriptions.c @@ -79,9 +79,14 @@ subscription_link_service(th_subscription_t *s, service_t *t) pthread_mutex_lock(&t->s_stream_mutex); - if(TAILQ_FIRST(&t->s_components) != NULL) + if(TAILQ_FIRST(&t->s_components) != NULL) { + + if(s->ths_start_message != NULL) + streaming_msg_free(s->ths_start_message); + s->ths_start_message = streaming_msg_create_data(SMT_START, service_build_stream_start(t)); + } // Link to service output streaming_target_connect(&t->s_streaming_pad, &s->ths_input); diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 7ede18ae..10829e2e 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -619,6 +619,7 @@ extjs_epggrab(http_connection_t *hc, const char *remain, void *opaque) if ( str ) save |= epggrab_enable_module_by_id(str, u32); } } + htsmsg_destroy(array); } } if (save) epggrab_save(); diff --git a/src/webui/extjs_dvb.c b/src/webui/extjs_dvb.c index 525ed10e..d1ce5b15 100644 --- a/src/webui/extjs_dvb.c +++ b/src/webui/extjs_dvb.c @@ -157,7 +157,7 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque) htsmsg_add_u32(r, "sidtochan", tda->tda_sidtochan); htsmsg_add_u32(r, "nitoid", tda->tda_nitoid); htsmsg_add_u32(r, "disable_pmt_monitor", tda->tda_disable_pmt_monitor); - htsmsg_add_u32(r, "disable_full_mux_rx", tda->tda_disable_full_mux_rx); + htsmsg_add_u32(r, "full_mux_rx", tda->tda_full_mux_rx+1); htsmsg_add_str(r, "diseqcversion", ((const char *[]){"DiSEqC 1.0 / 2.0", "DiSEqC 1.1 / 2.1"}) @@ -200,8 +200,8 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque) s = http_arg_get(&hc->hc_req_args, "disable_pmt_monitor"); dvb_adapter_set_disable_pmt_monitor(tda, !!s); - s = http_arg_get(&hc->hc_req_args, "disable_full_mux_rx"); - dvb_adapter_set_disable_full_mux_rx(tda, !!s); + s = http_arg_get(&hc->hc_req_args, "full_mux_rx"); + dvb_adapter_set_full_mux_rx(tda, atoi(s)-1); if((s = http_arg_get(&hc->hc_req_args, "nitoid")) != NULL) dvb_adapter_set_nitoid(tda, atoi(s)); diff --git a/src/webui/static/app/dvb.js b/src/webui/static/app/dvb.js index 18a823ba..dcda443a 100644 --- a/src/webui/static/app/dvb.js +++ b/src/webui/static/app/dvb.js @@ -1089,7 +1089,7 @@ tvheadend.dvb_adapter_general = function(adapterData, satConfStore) { }, [ 'name', 'automux', 'skip_initialscan', 'idlescan', 'diseqcversion', 'diseqcrepeats', 'qmon', 'skip_checksubscr', 'poweroff', 'sidtochan', 'nitoid', 'extrapriority', - ,'disable_pmt_monitor', 'disable_full_mux_rx', 'idleclose' ]); + ,'disable_pmt_monitor', 'full_mux_rx', 'idleclose' ]); function saveConfForm() { confform.getForm().submit({ @@ -1135,9 +1135,18 @@ tvheadend.dvb_adapter_general = function(adapterData, satConfStore) { fieldLabel : 'Monitor signal quality', name : 'qmon' }), - new Ext.form.Checkbox({ - fieldLabel : 'Disable full MUX reception', - name : 'disable_full_mux_rx' + new Ext.form.ComboBox({ + fieldLabel : 'Full mux reception', + name : 'full_mux_rx', + hiddenName: 'full_mux_rx', + displayField: 'num', + valueField: 'str', + editable : false, + allowBlank : false, + mode : 'remote', + triggerAction : 'all', + fields: [ 'num', 'str' ], + store : [ [0, 'Auto'], [1, 'Off'], [2, 'On'] ] }), new Ext.form.Checkbox({ fieldLabel : 'Disable PMT monitoring', diff --git a/support/tarball b/support/tarball new file mode 100755 index 00000000..ca65b664 --- /dev/null +++ b/support/tarball @@ -0,0 +1,53 @@ +#!/bin/bash +# +# Build tarball of the current directory +# + +# Exit +function die +{ + echo "ERROR: $*" + exit 1 +} + +# Switch dir +SRCDIR=$(dirname $0)/.. +cd $SRCDIR + +# Arguments +REL=$1 +if [ ! -z "$REL" ]; then + git checkout $REL || die "could not checkout $REL" +fi + +# Clean +git checkout . || die "could not clean git tree" + +# Version +VER=$(./support/version) +echo $VER | grep -q dirty && die "git tree is not clean" +VER1=$(echo $VER | sed 's/~.*//') +echo $VER1 + +# Temp directory +TMPDIR=/tmp/tvhtar-$$ +mkdir -p $TMPDIR +trap "rm -rf $TMPDIR" EXIT + +# Copy +DSTDIR=$TMPDIR/tvheadend-$VER1 +mkdir $DSTDIR +git archive HEAD | tar -x -C $DSTDIR + +# Remove stuff we don't need +rm -rf $DSTDIR/.gitignore + +# Fix changelog (store version) +$DSTDIR/support/changelog $DSTDIR/debian/changelog "" $VER + +# Build tarball +TARFILE=$(cd $SRCDIR/..; pwd)/tvheadend-$VER1.tar.gz +tar -C $TMPDIR -zcf $TARFILE tvheadend-$VER1 + +# Done +echo "Created $TARFILE"