diff -Naur tvheadend-orig/src/dvb/dvb_adapter.c tvheadend-patch/src/dvb/dvb_adapter.c --- tvheadend-orig/src/dvb/dvb_adapter.c 2010-11-06 14:37:14.999505279 +0100 +++ tvheadend-patch/src/dvb/dvb_adapter.c 2010-11-06 14:50:26.043504304 +0100 @@ -64,6 +64,19 @@ tda->tda_allpids_dmx_fd = -1; tda->tda_dump_fd = -1; + /* current signal status */ + tda->sig_status = malloc(sizeof(signal_status_t)); + + tda->sig_status->snr = -2; + tda->sig_status->signal = -2; + tda->sig_status->ber = -2; + tda->sig_status->unc = -2; + tda->sig_status->status = -2; + tda->sig_status->status_text = NULL; + tda->sig_status->name = NULL; + + pthread_mutex_init(&tda->sig_status_update_mutex, NULL); + return tda; } diff -Naur tvheadend-orig/src/dvb/dvb_fe.c tvheadend-patch/src/dvb/dvb_fe.c --- tvheadend-orig/src/dvb/dvb_fe.c 2010-11-06 14:37:14.999505279 +0100 +++ tvheadend-patch/src/dvb/dvb_fe.c 2010-11-06 14:50:26.043504304 +0100 @@ -51,7 +51,7 @@ { th_dvb_adapter_t *tda = aux; fe_status_t fe_status; - int status, v, update = 0, vv, i, fec, q; + int status, v, update = 0, vv, i, fec, q, ber, signal, snr; th_dvb_mux_instance_t *tdmi = tda->tda_mux_current; char buf[50]; @@ -112,6 +112,18 @@ } else { status = TDMI_FE_CONSTANT_FEC; } + + /* bit error rate */ + if (ioctl(tda->tda_fe_fd, FE_READ_BER, &ber) == -1) + ber = -2; + + /* signal strength */ + if (ioctl(tda->tda_fe_fd, FE_READ_SIGNAL_STRENGTH, &signal) == -1) + signal = -2; + + /* signal/noise ratio */ + if (ioctl(tda->tda_fe_fd, FE_READ_SNR, &snr) == -1) + snr = -2; } if(status != tdmi->tdmi_fe_status) { @@ -137,6 +149,18 @@ } } + /* update transport status */ + pthread_mutex_lock(&tda->sig_status_update_mutex); + + tda->sig_status->ber = ber; + tda->sig_status->signal = signal; + tda->sig_status->snr = snr; + tda->sig_status->status = fe_status; + tda->sig_status->unc = fec; + tvh_str_update(&tda->sig_status->status_text, dvb_mux_status(tdmi)); + + pthread_mutex_unlock(&tda->sig_status_update_mutex); + if(update) { htsmsg_t *m = htsmsg_create_map(); diff -Naur tvheadend-orig/src/dvb/dvb.h tvheadend-patch/src/dvb/dvb.h --- tvheadend-orig/src/dvb/dvb.h 2010-11-06 14:37:14.999505279 +0100 +++ tvheadend-patch/src/dvb/dvb.h 2010-11-06 14:50:26.043504304 +0100 @@ -200,6 +200,10 @@ int tda_allpids_dmx_fd; int tda_dump_fd; + + pthread_mutex_t sig_status_update_mutex; + signal_status_t *sig_status; /* current signal status */ + } th_dvb_adapter_t; @@ -307,6 +311,8 @@ htsmsg_t *dvb_transport_build_msg(th_transport_t *t); +void dvb_transport_get_signal_status(th_transport_t *current_transport, + signal_status_t *status); /** * DVB Frontend diff -Naur tvheadend-orig/src/dvb/dvb_transport.c tvheadend-patch/src/dvb/dvb_transport.c --- tvheadend-orig/src/dvb/dvb_transport.c 2010-11-06 14:37:14.999505279 +0100 +++ tvheadend-patch/src/dvb/dvb_transport.c 2010-11-06 14:50:26.043504304 +0100 @@ -460,3 +460,31 @@ htsmsg_add_str(m, "adapterId", tdmi->tdmi_adapter->tda_identifier); notify_by_msg("dvbService", m); } + + +/** + * Get the signal status from a DVB transport + */ +void +dvb_transport_get_signal_status(th_transport_t *current_transport, + signal_status_t *status) +{ + if (current_transport && current_transport->tht_dvb_mux_instance && + current_transport->tht_dvb_mux_instance->tdmi_adapter) + { + th_dvb_adapter_t *tda = + current_transport->tht_dvb_mux_instance->tdmi_adapter; + + pthread_mutex_lock(&tda->sig_status_update_mutex); + + status->ber = tda->sig_status->ber; + status->signal = tda->sig_status->signal; + status->snr = tda->sig_status->snr; + status->status = tda->sig_status->status; + status->unc = tda->sig_status->unc; + status->status_text = strdup(tda->sig_status->status_text); + status->name = strdup(tda->tda_displayname); + + pthread_mutex_unlock(&tda->sig_status_update_mutex); + } +} diff -Naur tvheadend-orig/src/htsp.c tvheadend-patch/src/htsp.c --- tvheadend-orig/src/htsp.c 2010-11-06 14:45:50.311506646 +0100 +++ tvheadend-patch/src/htsp.c 2010-11-06 14:50:26.095507576 +0100 @@ -166,6 +166,8 @@ } htsp_subscription_t; +static void htsp_get_signal_status(htsp_subscription_t *hs, signal_status_t *status); + /** * @@ -1392,6 +1394,7 @@ htsp_connection_t *htsp = hs->hs_htsp; int64_t ts; int qlen = hs->hs_q.hmq_payload; + signal_status_t *status = malloc(sizeof(signal_status_t)); if((qlen > 500000 && pkt->pkt_frametype == PKT_B_FRAME) || (qlen > 750000 && pkt->pkt_frametype == PKT_P_FRAME) || @@ -1436,7 +1439,9 @@ htsp_send(htsp, m, pkt->pkt_payload, &hs->hs_q, pktbuf_len(pkt->pkt_payload)); if(hs->hs_last_report != dispatch_clock) { - /* Send a queue status report every second */ + /* Send a queue and signal status report every second */ + + htsp_get_signal_status(hs, status); hs->hs_last_report = dispatch_clock; @@ -1465,6 +1470,18 @@ htsmsg_add_u32(m, "Pdrops", hs->hs_dropstats[PKT_P_FRAME]); htsmsg_add_u32(m, "Idrops", hs->hs_dropstats[PKT_I_FRAME]); + /* add the signal status */ + if (status->status_text != NULL) + htsmsg_add_str(m, "feStatus", status->status_text); + htsmsg_add_u32(m, "feSNR", status->snr); + htsmsg_add_u32(m, "feSignal", status->signal); + htsmsg_add_u32(m, "feBER", status->ber); + htsmsg_add_u32(m, "feUNC", status->unc); + + /* add the tuner name */ + if (status->name != NULL) + htsmsg_add_str(m, "feName", status->name); + /* We use a special queue for queue status message so they're not blocked by anything else */ @@ -1613,3 +1630,25 @@ } streaming_msg_free(sm); } + + +/** + * Adds the signal status of the adapter used by a subscription + */ +static void +htsp_get_signal_status(htsp_subscription_t *hs, signal_status_t *status) +{ + status->status_text = NULL; + status->name = NULL; + status->status = 0; + status->snr = -2; + status->signal = -2; + status->ber = -2; + status->unc = -2; + + // get signal status from the current transport + if (hs->hs_s && hs->hs_s->ths_transport) + { + return get_signal_status_from_transport(hs->hs_s->ths_transport, status); + } +} diff -Naur tvheadend-orig/src/transports.c tvheadend-patch/src/transports.c --- tvheadend-orig/src/transports.c 2010-11-06 14:46:40.579505415 +0100 +++ tvheadend-patch/src/transports.c 2010-11-06 14:51:44.015507336 +0100 @@ -1054,3 +1054,29 @@ return 0; } + +/** + * Get the signal status from a transport + */ +void +get_signal_status_from_transport(th_transport_t *current_transport, + signal_status_t *status) +{ + if (current_transport) + { + // get signal status from the transport + switch (current_transport->tht_type) + { + case TRANSPORT_DVB: + dvb_transport_get_signal_status(current_transport, status); + break; + case TRANSPORT_V4L: + //TODO add signal status from a V4L adapter + break; + case TRANSPORT_IPTV: + //TODO add signal status from an IPTV adapter + break; + } + } +} + diff -Naur tvheadend-orig/src/transports.h tvheadend-patch/src/transports.h --- tvheadend-orig/src/transports.h 2010-11-06 14:45:50.311506646 +0100 +++ tvheadend-patch/src/transports.h 2010-11-06 14:50:26.095507576 +0100 @@ -100,4 +100,7 @@ uint16_t get_encryption_from_transport(th_transport_t *t); +void get_signal_status_from_transport(th_transport_t *current_transport, + signal_status_t *status); + #endif /* TRANSPORTS_H */ diff -Naur tvheadend-orig/src/tvhead.h tvheadend-patch/src/tvhead.h --- tvheadend-orig/src/tvhead.h 2010-11-06 14:37:15.015505279 +0100 +++ tvheadend-patch/src/tvhead.h 2010-11-06 14:50:26.095507576 +0100 @@ -168,6 +168,20 @@ #define SCT_ISVIDEO(t) ((t) == SCT_MPEG2VIDEO || (t) == SCT_H264) #define SCT_ISAUDIO(t) ((t) == SCT_MPEG2AUDIO || (t) == SCT_AC3 || \ (t) == SCT_AAC) + +/** + * The signal status of a tuner + */ +typedef struct signal_status { + char *name; /* adapter name */ + char *status_text; /* adapter status text */ + int status; /* adapter status code */ + uint16_t snr; /* signal/noise ratio */ + uint16_t signal; /* signal strength */ + uint32_t ber; /* bit error rate */ + uint32_t unc; /* uncorrected blocks */ +} signal_status_t; + /** * A streaming pad generates data. * It has one or more streaming targets attached to it.