From ff70e88880626b7276be465c01a54c7ceb3ab951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Wed, 16 Apr 2008 05:23:03 +0000 Subject: [PATCH] Add AJAX mailboxes for updating content asynchornously on the web ui. --- Makefile | 5 +- ajaxui/ajaxui.c | 25 ++- ajaxui/ajaxui.h | 5 +- ajaxui/ajaxui_config_dvb.c | 15 +- ajaxui/ajaxui_mailbox.c | 307 +++++++++++++++++++++++++++++++++++++ ajaxui/ajaxui_mailbox.h | 28 ++++ dvb.c | Bin 12461 -> 12652 bytes dvb_fe.c | 7 +- dvb_tables.c | 8 +- http.c | 12 ++ http.h | 3 + notify.c | 47 ++++++ notify.h | 28 ++++ tvhead.h | 1 + 14 files changed, 474 insertions(+), 17 deletions(-) create mode 100644 ajaxui/ajaxui_mailbox.c create mode 100644 ajaxui/ajaxui_mailbox.h create mode 100644 notify.c create mode 100644 notify.h diff --git a/Makefile b/Makefile index f94b2e4b..8e339c9f 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,8 @@ SRCS = main.c dispatch.c channels.c transports.c teletext.c psi.c \ subscriptions.c mux.c tsdemux.c buffer.c tcp.c \ - resolver.c tsmux.c parsers.c bitstream.c parser_h264.c spawn.c + resolver.c tsmux.c parsers.c bitstream.c parser_h264.c spawn.c \ + notify.c SRCS += http.c @@ -33,7 +34,7 @@ SRCS += FFdecsa.c # VPATH += ajaxui -SRCS += ajaxui.c ajaxui_channels.c \ +SRCS += ajaxui.c ajaxui_mailbox.c ajaxui_channels.c \ ajaxui_config.c ajaxui_config_channels.c ajaxui_config_dvb.c \ ajaxui_config_transport.c diff --git a/ajaxui/ajaxui.c b/ajaxui/ajaxui.c index 5cb68d15..bda67cb1 100644 --- a/ajaxui/ajaxui.c +++ b/ajaxui/ajaxui.c @@ -26,6 +26,7 @@ #include "tvhead.h" #include "http.h" #include "ajaxui.h" +#include "dispatch.h" #include "obj/ajaxui.cssh" @@ -93,7 +94,7 @@ ajax_table_header(http_connection_t *hc, tcp_queue_t *tq, */ void ajax_table_row(tcp_queue_t *tq, const char *cells[], int columnsizes[], - int *bgptr) + int *bgptr, const char *idprefix[], const char *idpostfix) { int i = 0; @@ -103,7 +104,13 @@ ajax_table_row(tcp_queue_t *tq, const char *cells[], int columnsizes[], *bgptr = !*bgptr; while(cells[i]) { - tcp_qprintf(tq, "
%s
", + tcp_qprintf(tq, + "
%s
", + idprefix && idprefix[i] ? "id=\"" : "", + idprefix && idprefix[i] ? idprefix[i] : "", + idprefix && idprefix[i] && idpostfix ? "_" : "", + idprefix && idprefix[i] && idpostfix ? idpostfix : "", + idprefix && idprefix[i] ? "\" " : "", columnsizes[i], cells[i]); i++; } @@ -399,21 +406,29 @@ ajax_page_root(http_connection_t *hc, http_reply_t *hr, ""); + tcp_qprintf(tq, "
"); + + tcp_qprintf(tq, "
"); + ajax_box_begin(tq, AJAX_BOX_FILLED, "topmenu", NULL, NULL); ajax_box_end(tq, AJAX_BOX_FILLED); tcp_qprintf(tq, "
"); ajax_js(tq, "switchtab('top', '0')"); +#if 0 + tcp_qprintf(tq, "
"); - tcp_qprintf(tq, ""); + ajax_box_begin(tq, AJAX_BOX_SIDEBOX, "statusbox", NULL, "System status"); + ajax_box_end(tq, AJAX_BOX_SIDEBOX); +#endif + tcp_qprintf(tq, "
"); http_output_html(hc, hr); return 0; } - /** * AJAX user interface */ @@ -425,7 +440,6 @@ ajaxui_start(void) http_path_add("/ajax/topmenu", NULL, ajax_page_titlebar); http_path_add("/ajax/toptab", NULL, ajax_page_tab); - /* Stylesheet */ http_resource_add("/ajax/ajaxui.css", embedded_ajaxui, sizeof(embedded_ajaxui), "text/css", "gzip"); @@ -463,6 +477,7 @@ ajaxui_start(void) http_resource_add("/gfx/mapped.png", embedded_mapped, sizeof(embedded_mapped), "image/png", NULL); + ajax_mailbox_init(); ajax_channels_init(); ajax_config_init(); ajax_config_transport_init(); diff --git a/ajaxui/ajaxui.h b/ajaxui/ajaxui.h index 61b4813d..cb4f4801 100644 --- a/ajaxui/ajaxui.h +++ b/ajaxui/ajaxui.h @@ -19,7 +19,6 @@ #ifndef AJAXUI_H_ #define AJAXUI_H_ - typedef enum { AJAX_BOX_FILLED, AJAX_BOX_SIDEBOX, @@ -46,6 +45,8 @@ TAILQ_HEAD(ajax_menu_entry_queue, ajax_menu_entry); void ajaxui_start(void); void ajax_channels_init(void); void ajax_config_init(void); +void ajax_mailbox_init(void); +int ajax_mailbox_create(char *subscriptionid); void ajax_menu_bar_from_array(tcp_queue_t *tq, const char *name, @@ -74,6 +75,6 @@ void ajax_table_header(http_connection_t *hc, tcp_queue_t *tq, int scrollbar, int columnsizes[]); void ajax_table_row(tcp_queue_t *tq, const char *cells[], int columnsizes[], - int *bgptr); + int *bgptr, const char *idprefix[], const char *idpostfix); #endif /* AJAXUI_H_ */ diff --git a/ajaxui/ajaxui_config_dvb.c b/ajaxui/ajaxui_config_dvb.c index 0d73dbaf..50f437ac 100644 --- a/ajaxui/ajaxui_config_dvb.c +++ b/ajaxui/ajaxui_config_dvb.c @@ -223,7 +223,7 @@ ajax_adaptereditor(http_connection_t *hc, http_reply_t *hr, ajax_js(tq, "new Ajax.Updater('dvbmuxlist%s', " - "'/ajax/dvbadaptermuxlist/%s', {method: 'get'}) ", + "'/ajax/dvbadaptermuxlist/%s', {method: 'get', evalScripts: true})", tda->tda_identifier, tda->tda_identifier); tcp_qprintf(tq, "
"); @@ -516,7 +516,7 @@ ajax_adaptercreatemux(http_connection_t *hc, http_reply_t *hr, ajax_js(tq, "new Ajax.Updater('dvbmuxlist%s', " - "'/ajax/dvbadaptermuxlist/%s', {method: 'get'}) ", + "'/ajax/dvbadaptermuxlist/%s', {method: 'get', evalScripts: true})", tda->tda_identifier, tda->tda_identifier); http_output_html(hc, hr); @@ -586,9 +586,10 @@ ajax_adaptermuxlist(http_connection_t *hc, http_reply_t *hr, "'/ajax/dvbmuxeditor/%s', {method: 'get', evalScripts: true})\"" ">%s", tdmi->tdmi_identifier, buf); + cells[0] = buf2; cells[1] = dvb_mux_status(tdmi); - + switch(tdmi->tdmi_state) { case TDMI_IDLE: txt = "Idle"; break; case TDMI_IDLESCAN: txt = "Scanning"; break; @@ -597,7 +598,7 @@ ajax_adaptermuxlist(http_connection_t *hc, http_reply_t *hr, } cells[2] = txt; - + txt = tdmi->tdmi_network; if(txt == NULL) txt = "Unknown"; @@ -614,10 +615,14 @@ ajax_adaptermuxlist(http_connection_t *hc, http_reply_t *hr, cells[4] = buf3; cells[5] = NULL; - ajax_table_row(tq, cells, csize, &o); + ajax_table_row(tq, cells, csize, &o, + (const char *[]){NULL, "status", "state", "name", NULL}, + tdmi->tdmi_identifier); } tcp_qprintf(tq, "
"); + ajax_js(tq, "new Ajax.Request('/ajax/mailbox/%d')", + ajax_mailbox_create(tda->tda_identifier)); http_output_html(hc, hr); return 0; diff --git a/ajaxui/ajaxui_mailbox.c b/ajaxui/ajaxui_mailbox.c new file mode 100644 index 00000000..843a92ad --- /dev/null +++ b/ajaxui/ajaxui_mailbox.c @@ -0,0 +1,307 @@ +/* + * tvheadend, AJAX / HTML Mailboxes + * Copyright (C) 2008 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "tvhead.h" +#include "dispatch.h" +#include "http.h" +#include "ajaxui.h" + +#define MAILBOX_UNUSED_TIMEOUT 15 +#define MAILBOX_EMPTY_REPLY_TIMEOUT 10 + + +static LIST_HEAD(, ajaxui_mailbox) mailboxes; + +int mailbox_tally; + +TAILQ_HEAD(ajaxui_letter_queue, ajaxui_letter); + +typedef struct ajaxui_letter { + TAILQ_ENTRY(ajaxui_letter) al_link; + char *al_payload; +} ajaxui_letter_t; + + +typedef struct ajaxui_mailbox { + LIST_ENTRY(ajaxui_mailbox) amb_link; + + uint32_t amb_boxid; + char *amb_subscriptionid; + + dtimer_t amb_timer; + + http_reply_t *amb_hr; /* Pending request */ + + struct ajaxui_letter_queue amb_letters; + +} ajaxui_mailbox_t; + + +/** + * + */ +static void +al_destroy(ajaxui_mailbox_t *amb, ajaxui_letter_t *al) +{ + TAILQ_REMOVE(&amb->amb_letters, al, al_link); + free(al); +} + + +/** + * + */ +static void +amb_destroy(ajaxui_mailbox_t *amb) +{ + ajaxui_letter_t *al; + + while((al = TAILQ_FIRST(&amb->amb_letters)) != NULL) + al_destroy(amb, al); + + LIST_REMOVE(amb, amb_link); + + dtimer_disarm(&amb->amb_timer); + + free(amb->amb_subscriptionid); + free(amb); +} + + + +/** + * + */ +static void +ajax_mailbox_unused(void *opaque, int64_t now) +{ + ajaxui_mailbox_t *amb = opaque; + assert(amb->amb_hr == NULL); + amb_destroy(amb); +} + +/** + * + */ +static void +ajax_mailbox_connection_lost(http_reply_t *hr, void *opaque) +{ + ajaxui_mailbox_t *amb = opaque; + assert(hr == amb->amb_hr); + amb_destroy(amb); +} + + + +/** + * + */ +int +ajax_mailbox_create(char *subscriptionid) +{ + ajaxui_mailbox_t *amb = calloc(1, sizeof(ajaxui_mailbox_t)); + + mailbox_tally++; + + amb->amb_boxid = mailbox_tally; + amb->amb_subscriptionid = strdup(subscriptionid); + + LIST_INSERT_HEAD(&mailboxes, amb, amb_link); + + TAILQ_INIT(&amb->amb_letters); + + dtimer_arm(&amb->amb_timer, ajax_mailbox_unused, amb, + MAILBOX_UNUSED_TIMEOUT); + return amb->amb_boxid; +} + + +/** + * + */ +static void +ajax_mailbox_reply(ajaxui_mailbox_t *amb, http_reply_t *hr) +{ + ajaxui_letter_t *al; + + while((al = TAILQ_FIRST(&amb->amb_letters)) != NULL) { + tcp_qprintf(&hr->hr_tq, "%s", al->al_payload); + al_destroy(amb, al); + } + + tcp_qprintf(&hr->hr_tq, "new Ajax.Request('/ajax/mailbox/%d');\r\n", + amb->amb_boxid); + + http_output(hr->hr_connection, hr, "text/javascript", NULL, 0); + amb->amb_hr = NULL; + + dtimer_arm(&amb->amb_timer, ajax_mailbox_unused, amb, + MAILBOX_UNUSED_TIMEOUT); +} + + +static void +ajax_mailbox_empty_reply(void *opaque, int64_t now) +{ + ajaxui_mailbox_t *amb = opaque; + http_reply_t *hr = amb->amb_hr; + + ajax_mailbox_reply(amb, hr); + http_continue(hr->hr_connection); +} + + +/** + * Poll callback + * + * Prepare the mailbox for reply + */ +static int +ajax_mailbox_poll(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) +{ + uint32_t boxid; + ajaxui_mailbox_t *amb; + + if(remain == NULL) + return HTTP_STATUS_NOT_FOUND; + + boxid = atoi(remain); + LIST_FOREACH(amb, &mailboxes, amb_link) + if(amb->amb_boxid == boxid) + break; + if(amb == NULL) + return HTTP_STATUS_NOT_FOUND; + + if(amb->amb_hr != NULL) + return 409; + + if(TAILQ_FIRST(&amb->amb_letters) != NULL) { + /* Pending letters, direct reply */ + ajax_mailbox_reply(amb, hr); + return 0; + } + + amb->amb_hr = hr; + + hr->hr_opaque = amb; + hr->hr_destroy = ajax_mailbox_connection_lost; + + dtimer_arm(&amb->amb_timer, ajax_mailbox_empty_reply, amb, + MAILBOX_EMPTY_REPLY_TIMEOUT); + return 0; +} + + +/** + * + */ +void +ajax_mailbox_init(void) +{ + http_path_add("/ajax/mailbox", NULL, ajax_mailbox_poll); +} + + +/** + * + */ +static void +ajax_mailbox_add_to_subscription(const char *subscription, const char *content) +{ + ajaxui_mailbox_t *amb; + ajaxui_letter_t *al; + http_connection_t *hc; + + LIST_FOREACH(amb, &mailboxes, amb_link) { + if(strcmp(subscription, amb->amb_subscriptionid)) + continue; + + al = malloc(sizeof(ajaxui_letter_t)); + al->al_payload = strdup(content); + TAILQ_INSERT_TAIL(&amb->amb_letters, al, al_link); + + if(amb->amb_hr != NULL) { + hc = amb->amb_hr->hr_connection; + ajax_mailbox_reply(amb, amb->amb_hr); + http_continue(hc); + } + } +} + + + +/** + * + */ +static void +ajax_mailbox_update_div(const char *subscription, const char *prefix, + const char *postfix, const char *content) +{ + char buf[1000]; + + snprintf(buf, sizeof(buf), + "document.getElementById('%s_%s').innerHTML='%s';\r\n", + prefix, postfix, content); + + ajax_mailbox_add_to_subscription(subscription, buf); +} + + + +void +ajax_mailbox_tdmi_state_change(th_dvb_mux_instance_t *tdmi) +{ + const char *txt; + + switch(tdmi->tdmi_state) { + case TDMI_IDLE: txt = "Idle"; break; + case TDMI_IDLESCAN: txt = "Scanning"; break; + case TDMI_RUNNING: txt = "Running"; break; + default: txt = "???"; break; + } + + + ajax_mailbox_update_div(tdmi->tdmi_adapter->tda_identifier, + "state", tdmi->tdmi_identifier, + txt); +} + +void +ajax_mailbox_tdmi_name_change(th_dvb_mux_instance_t *tdmi) +{ + ajax_mailbox_update_div(tdmi->tdmi_adapter->tda_identifier, + "name", tdmi->tdmi_identifier, + tdmi->tdmi_network ?: ""); +} + + +void +ajax_mailbox_tdmi_status_change(th_dvb_mux_instance_t *tdmi) +{ + ajax_mailbox_update_div(tdmi->tdmi_adapter->tda_identifier, + "status", tdmi->tdmi_identifier, + tdmi->tdmi_last_status); +} diff --git a/ajaxui/ajaxui_mailbox.h b/ajaxui/ajaxui_mailbox.h new file mode 100644 index 00000000..661c9337 --- /dev/null +++ b/ajaxui/ajaxui_mailbox.h @@ -0,0 +1,28 @@ +/* + * tvheadend, AJAX user interface + * Copyright (C) 2007 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef AJAXUI_MAILBOX_H_ +#define AJAXUI_MAILBOX_H_ + +void ajax_mailbox_tdmi_state_change(th_dvb_mux_instance_t *tdmi); + +void ajax_mailbox_tdmi_name_change(th_dvb_mux_instance_t *tdmi); + +void ajax_mailbox_tdmi_status_change(th_dvb_mux_instance_t *tdmi); + +#endif /* AJAXUI_MAILBOX_H_ */ diff --git a/dvb.c b/dvb.c index 2ab6f983f82340db21b9d01f3b4e86b7141d035d..ee4dca5fce4cdb3734c10e7f82966ea87c4b03b9 100644 GIT binary patch delta 213 zcmZ3R_$FzC603l6W?phmX-cYsQeJ*ZW?JQDIo4G?LJA7W`FX`93dtFXMG9KQ)?8eZ zq{Syc5cHjVUQCXSOFrfHWE@0<5Ez_Ow%Yy$<0(yv{mp6_3=?qQ&ZSnCRD;S NdA0%9<_6I>(f}u=5>fyF diff --git a/dvb_fe.c b/dvb_fe.c index 48276c1d..1c3e4d0d 100644 --- a/dvb_fe.c +++ b/dvb_fe.c @@ -39,6 +39,7 @@ #include "dvb.h" #include "dvb_support.h" #include "diseqc.h" +#include "notify.h" typedef struct dvb_fe_cmd { TAILQ_ENTRY(dvb_fe_cmd) link; @@ -200,6 +201,7 @@ tdmi_stop(th_dvb_mux_instance_t *tdmi) pthread_mutex_unlock(&tdmi->tdmi_table_lock); tdmi->tdmi_state = TDMI_IDLE; + notify_tdmi_state_change(tdmi); time(&tdmi->tdmi_lost_adapter); } @@ -214,7 +216,10 @@ dvb_tune_tdmi(th_dvb_mux_instance_t *tdmi, int maylog, tdmi_state_t state) th_dvb_adapter_t *tda = tdmi->tdmi_adapter; char buf[100]; - tdmi->tdmi_state = state; + if(tdmi->tdmi_state != state) { + tdmi->tdmi_state = state; + notify_tdmi_state_change(tdmi); + } if(tda->tda_mux_current == tdmi) return; diff --git a/dvb_tables.c b/dvb_tables.c index aaa94f8f..c59e56e9 100644 --- a/dvb_tables.c +++ b/dvb_tables.c @@ -41,6 +41,7 @@ #include "transports.h" #include "channels.h" #include "psi.h" +#include "notify.h" #define TDT_NOW 0x1 @@ -614,8 +615,11 @@ dvb_nit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, if(dvb_get_string(networkname, sizeof(networkname), ptr, tlen, "UTF8")) return; - free((void *)tdmi->tdmi_network); - tdmi->tdmi_network = strdup(networkname); + if(strcmp(tdmi->tdmi_network ?: "", networkname)) { + free((void *)tdmi->tdmi_network); + tdmi->tdmi_network = strdup(networkname); + notify_tdmi_name_change(tdmi); + } break; } diff --git a/http.c b/http.c index 6704c5da..85e612aa 100644 --- a/http.c +++ b/http.c @@ -253,6 +253,15 @@ http_xmit_queue(http_connection_t *hc) } +/** + * Continue HTTP session, called by deferred replies + */ +void +http_continue(http_connection_t *hc) +{ + if(http_xmit_queue(hc)) + tcp_disconnect(&hc->hc_tcp_session, 0); +} /** * Send HTTP error back @@ -286,6 +295,7 @@ void http_output(http_connection_t *hc, http_reply_t *hr, const char *content, const char *encoding, int maxage) { + hr->hr_destroy = NULL; hr->hr_encoding = encoding; hr->hr_content = content; hr->hr_maxage = maxage; @@ -297,6 +307,7 @@ http_output(http_connection_t *hc, http_reply_t *hr, const char *content, void http_output_html(http_connection_t *hc, http_reply_t *hr) { + hr->hr_destroy = NULL; hr->hr_content = "text/html; charset=UTF-8"; } @@ -340,6 +351,7 @@ http_exec(http_connection_t *hc, http_path_t *hp, char *remain, int err) TAILQ_INSERT_TAIL(&hc->hc_replies, hr, hr_link); tcp_init_queue(&hr->hr_tq, -1); + hr->hr_connection = hc; hr->hr_version = hc->hc_version; hr->hr_keep_alive = hc->hc_keep_alive; diff --git a/http.h b/http.h index b8aaf754..55b6cd0e 100644 --- a/http.h +++ b/http.h @@ -51,6 +51,7 @@ typedef struct http_reply { void (*hr_destroy)(struct http_reply *hr, void *opaque); + struct http_connection *hr_connection; int hr_version; /* HTTP version */ int hr_keep_alive; @@ -136,6 +137,8 @@ void http_output(http_connection_t *hc, http_reply_t *hr, void http_output_html(http_connection_t *hc, http_reply_t *hr); +void http_continue(http_connection_t *hc); + void http_redirect(http_connection_t *hc, http_reply_t *hr, const char *location); diff --git a/notify.c b/notify.c new file mode 100644 index 00000000..c181e6d7 --- /dev/null +++ b/notify.c @@ -0,0 +1,47 @@ +/* + * tvheadend, Notification framework + * Copyright (C) 2008 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "tvhead.h" +#include "ajaxui/ajaxui_mailbox.h" + +void +notify_tdmi_state_change(th_dvb_mux_instance_t *tdmi) +{ + ajax_mailbox_tdmi_state_change(tdmi); +} + + +void +notify_tdmi_name_change(th_dvb_mux_instance_t *tdmi) +{ + ajax_mailbox_tdmi_name_change(tdmi); +} + + + +void +notify_tdmi_status_change(th_dvb_mux_instance_t *tdmi) +{ + ajax_mailbox_tdmi_status_change(tdmi); +} diff --git a/notify.h b/notify.h new file mode 100644 index 00000000..70fe7164 --- /dev/null +++ b/notify.h @@ -0,0 +1,28 @@ +/* + * tvheadend, Notification framework + * Copyright (C) 2008 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef NOTIFY_H_ +#define NOTIFY_H_ + +void notify_tdmi_state_change(th_dvb_mux_instance_t *tdmi); + +void notify_tdmi_name_change(th_dvb_mux_instance_t *tdmi); + +void notify_tdmi_status_change(th_dvb_mux_instance_t *tdmi); + +#endif /* NOTIFY_H_ */ diff --git a/tvhead.h b/tvhead.h index abac49ae..afc02125 100644 --- a/tvhead.h +++ b/tvhead.h @@ -167,6 +167,7 @@ typedef struct th_dvb_mux_instance { dtimer_t tdmi_initial_scan_timer; const char *tdmi_status; + const char *tdmi_last_status; /* For notification updates */ time_t tdmi_got_adapter; time_t tdmi_lost_adapter;