for people and it's only useful if you have complex setups with
multiple adapters, etc.
+ * Improve logging when subscriptions fail to start
+
hts-tvheadend (2.7) hts; urgency=low
* Added support for DVB subtitles. Currently only forwarded over HTSP
/**
* DVB Frontend
*/
-void dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason);
+int dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason);
void dvb_fe_stop(th_dvb_mux_instance_t *tdmi);
#include "dvb_support.h"
#include "diseqc.h"
#include "notify.h"
+#include "transports.h"
/**
/**
*
*/
-void
+int
dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
{
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
lock_assert(&global_lock);
if(tda->tda_mux_current == tdmi)
- return;
+ return 0;
if(tdmi->tdmi_scan_queue != NULL) {
TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link);
tvhlog(LOG_ERR, "dvb", "\"%s\" tuning to \"%s\""
" -- Front configuration failed -- %s, frequency: %ld",
tda->tda_rootpath, buf, strerror(errno), p->frequency);
+ return TRANSPORT_NOSTART_TUNING_FAILED;
}
tda->tda_mux_current = tdmi;
dvb_table_add_default(tdmi);
dvb_adapter_notify(tda);
+ return 0;
}
static int
dvb_transport_start(th_transport_t *t, unsigned int weight, int force_start)
{
- int w;
+ int w, r;
th_dvb_adapter_t *tda = t->tht_dvb_mux_instance->tdmi_adapter;
th_dvb_mux_instance_t *tdmi = tda->tda_mux_current;
lock_assert(&global_lock);
if(tda->tda_rootpath == NULL)
- return 1; /* hardware not present */
+ return TRANSPORT_NOSTART_NO_HARDWARE;
- if(tdmi && !tdmi->tdmi_enabled)
- return 1; /* Mux is disabled */
+ if(t->tht_dvb_mux_instance && !t->tht_dvb_mux_instance->tdmi_enabled)
+ return TRANSPORT_NOSTART_MUX_NOT_ENABLED; /* Mux is disabled */
/* Check if adapter is idle, or already tuned */
w = transport_compute_weight(&tdmi->tdmi_adapter->tda_transports);
if(w >= weight)
- return 1; /* We are outranked by weight, cant use it */
+ /* We are outranked by weight, cant use it */
+ return TRANSPORT_NOSTART_NOT_FREE;
dvb_adapter_clean(tda);
}
- dvb_transport_open_demuxers(tda, t);
-
pthread_mutex_lock(&tda->tda_delivery_mutex);
- LIST_INSERT_HEAD(&tda->tda_transports, t, tht_active_link);
- dvb_fe_tune(t->tht_dvb_mux_instance, "Transport start");
+ r = dvb_fe_tune(t->tht_dvb_mux_instance, "Transport start");
+ if(!r)
+ LIST_INSERT_HEAD(&tda->tda_transports, t, tht_active_link);
pthread_mutex_unlock(&tda->tda_delivery_mutex);
- return 0;
+
+ if(!r)
+ dvb_transport_open_demuxers(tda, t);
+
+ return r;
}
lock_assert(&global_lock);
- return tdmi->tdmi_enabled ? tdmi->tdmi_quality : 0;
+ return tdmi->tdmi_adapter->tda_qmon ? tdmi->tdmi_quality : 100;
}
vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
va_end(ap);
- tvhlog(LOG_ERR, "pvr", "%s: %s", de->de_filename, msgbuf);
+ tvhlog(LOG_ERR, "pvr",
+ "Recording error: \"%s\": %s",
+ de->de_filename ?: de->de_title, msgbuf);
}
case SMT_NOSOURCE:
dvr_rec_fatal_error(de,
- "No source transport available, automatic retry");
+ "Unable to start -- %s",
+ transport_nostart2txt(sm->sm_code));
break;
case SMT_MPEGTS:
break;
case SMT_NOSOURCE:
- htsp_subscription_status(hs, "No available sources");
+ htsp_subscription_status(hs, transport_nostart2txt(sm->sm_code));
break;
case SMT_MPEGTS:
case SMT_STOP:
case SMT_TRANSPORT_STATUS:
+ case SMT_NOSOURCE:
dst->sm_code = src->sm_code;
break;
th_subscription_t *s;
th_transport_t *t;
streaming_message_t *sm;
-
+ char buf[128];
+ int errorcode;
lock_assert(&global_lock);
gtimer_arm(&subscription_reschedule_timer, subscription_reschedule, NULL, 2);
if(s->ths_channel == NULL)
continue; /* stale entry, channel has been destroyed */
- t = transport_find(s->ths_channel, s->ths_weight);
+ snprintf(buf, sizeof(buf), "Subscription \"%s\"", s->ths_title);
+ t = transport_find(s->ths_channel, s->ths_weight, buf, &errorcode);
if(t == NULL) {
/* No transport available */
- sm = streaming_msg_create(SMT_NOSOURCE);
+ sm = streaming_msg_create_code(SMT_NOSOURCE, errorcode);
streaming_target_deliver(s->ths_output, sm);
continue;
}
static void transport_data_timeout(void *aux);
+/**
+ *
+ */
+const char *
+transport_nostart2txt(int code)
+{
+ switch(code) {
+ case TRANSPORT_NOSTART_NO_HARDWARE: return "No hardware present";
+ case TRANSPORT_NOSTART_MUX_NOT_ENABLED: return "No mux enabled";
+ case TRANSPORT_NOSTART_NOT_FREE: return "Adapter in use by other subscription";
+ case TRANSPORT_NOSTART_TUNING_FAILED: return "Tuning failed";
+ case TRANSPORT_NOSTART_SVC_NOT_ENABLED: return "No service enabled";
+ case TRANSPORT_NOSTART_BAD_SIGNAL: return "Too bad signal quality";
+ }
+ return "Unknown error";
+}
+
/**
*
transport_start(th_transport_t *t, unsigned int weight, int force_start)
{
th_stream_t *st;
+ int r;
lock_assert(&global_lock);
t->tht_dts_start = AV_NOPTS_VALUE;
t->tht_pcr_drift = 0;
- if(t->tht_start_feed(t, weight, force_start))
- return -1;
+ if((r = t->tht_start_feed(t, weight, force_start)))
+ return r;
pthread_mutex_lock(&t->tht_stream_mutex);
*
*/
th_transport_t *
-transport_find(channel_t *ch, unsigned int weight)
+transport_find(channel_t *ch, unsigned int weight, const char *loginfo,
+ int *errorp)
{
th_transport_t *t, **vec;
- int cnt = 0, i;
-
+ int cnt = 0, i, r;
+ int error = 0;
+
lock_assert(&global_lock);
/* First, sort all transports in order */
LIST_FOREACH(t, &ch->ch_transports, tht_ch_link)
- if(t->tht_enabled && t->tht_quality_index(t) > 10)
- cnt++;
+ cnt++;
vec = alloca(cnt * sizeof(th_transport_t *));
- i = 0;
- LIST_FOREACH(t, &ch->ch_transports, tht_ch_link)
- if(t->tht_enabled && t->tht_quality_index(t) > 10)
- vec[i++] = t;
+ cnt = 0;
+ LIST_FOREACH(t, &ch->ch_transports, tht_ch_link) {
+
+ if(!t->tht_enabled) {
+ error = TRANSPORT_NOSTART_SVC_NOT_ENABLED;
+ if(loginfo != NULL) {
+ tvhlog(LOG_NOTICE, "Transport", "%s: Skipping \"%s\" -- not enabled",
+ loginfo, transport_nicename(t));
+ }
+ continue;
+ }
- assert(i == cnt);
+ if(t->tht_quality_index(t) < 10) {
+ error = TRANSPORT_NOSTART_BAD_SIGNAL;
+ if(loginfo != NULL) {
+ tvhlog(LOG_NOTICE, "Transport",
+ "%s: Skipping \"%s\" -- Quality below 10%",
+ loginfo, transport_nicename(t));
+ }
+ continue;
+ }
+ vec[cnt++] = t;
+ }
/* Sort transports, lower priority should come come earlier in the vector
(i.e. it will be more favoured when selecting a transport */
for(i = 0; i < cnt; i++) {
t = vec[i];
- if(!transport_start(t, weight, 0))
+ if((r = transport_start(t, weight, 0)) == 0)
return t;
+ error = r;
+ if(loginfo != NULL)
+ tvhlog(LOG_NOTICE, "Transport",
+ "%s: Skipping \"%s\" -- %s",
+ loginfo, transport_nicename(t), transport_nostart2txt(r));
}
+ if(errorp != NULL)
+ *errorp = error;
return NULL;
}
#include "htsmsg.h"
#include "subscriptions.h"
+#define TRANSPORT_NOSTART_NO_HARDWARE 1
+#define TRANSPORT_NOSTART_MUX_NOT_ENABLED 2
+#define TRANSPORT_NOSTART_NOT_FREE 3
+#define TRANSPORT_NOSTART_TUNING_FAILED 4
+#define TRANSPORT_NOSTART_SVC_NOT_ENABLED 5
+#define TRANSPORT_NOSTART_BAD_SIGNAL 6
+
void transport_init(void);
unsigned int transport_compute_weight(struct th_transport_list *head);
void transport_map_channel(th_transport_t *t, channel_t *ch, int save);
-th_transport_t *transport_find(channel_t *ch, unsigned int weight);
+th_transport_t *transport_find(channel_t *ch, unsigned int weight,
+ const char *loginfo, int *errorp);
th_stream_t *transport_stream_find(th_transport_t *t, int pid);
const char *transport_component_nicename(th_stream_t *st);
+const char *transport_nostart2txt(int code);
+
#endif /* TRANSPORTS_H */