From 457098c0817552244347f4ba734ef8df634a97f8 Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Wed, 27 Jun 2012 11:31:51 +0100 Subject: [PATCH 01/11] Simplification of the epggrab api used within the dvb code. --- src/dvb/dvb.h | 7 +++--- src/dvb/dvb_adapter.c | 54 ++++++++++++++++++++--------------------- src/dvb/dvb_fe.c | 4 ++- src/dvb/dvb_multiplex.c | 11 +++------ 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/dvb/dvb.h b/src/dvb/dvb.h index 1f843cfc..1042e5a4 100644 --- a/src/dvb/dvb.h +++ b/src/dvb/dvb.h @@ -115,8 +115,6 @@ typedef struct th_dvb_mux_instance { int tdmi_enabled; - LIST_HEAD(, epggrab_ota_mux) tdmi_epg_grabbers; - time_t tdmi_got_adapter; time_t tdmi_lost_adapter; @@ -147,8 +145,7 @@ typedef struct th_dvb_mux_instance { #define TDA_SCANQ_BAD 0 ///< Bad muxes (monitor quality) #define TDA_SCANQ_OK 1 ///< OK muxes -#define TDA_SCANQ_EPG 2 ///< EPG muxes (TBD) -#define TDA_SCANQ_NUM 3 +#define TDA_SCANQ_NUM 2 typedef struct th_dvb_adapter { @@ -164,6 +161,8 @@ typedef struct th_dvb_adapter { th_dvb_mux_instance_t *tda_mux_current; + th_dvb_mux_instance_t *tda_mux_epg; + int tda_table_epollfd; const char *tda_rootpath; diff --git a/src/dvb/dvb_adapter.c b/src/dvb/dvb_adapter.c index 12e13066..0b6c8d5b 100644 --- a/src/dvb/dvb_adapter.c +++ b/src/dvb/dvb_adapter.c @@ -41,7 +41,7 @@ #include "tsdemux.h" #include "notify.h" #include "service.h" -#include "epggrab/ota.h" +#include "epggrab.h" struct th_dvb_adapter_queue dvb_adapters; struct th_dvb_mux_instance_tree dvb_muxes; @@ -420,7 +420,6 @@ dvb_adapter_init(uint32_t adapter_mask) void dvb_adapter_mux_scanner(void *aux) { - epggrab_ota_mux_t *ota; th_dvb_adapter_t *tda = aux; th_dvb_mux_instance_t *tdmi; int i; @@ -449,15 +448,14 @@ dvb_adapter_mux_scanner(void *aux) return; } - /* Mark any incomplete EPG grabbers as timed out (basically complete) */ - if (tda->tda_mux_current) - LIST_FOREACH(ota, &tda->tda_mux_current->tdmi_epg_grabbers, tdmi_link) { - epggrab_ota_timeout(ota); - } + /* Check EPG */ + if (tda->tda_mux_epg) + tda->tda_mux_epg = NULL; // skip this time + else + tda->tda_mux_epg = epggrab_mux_next(tda); /* Idle or EPG scan enabled */ - idle_epg = tda->tda_idlescan || - TAILQ_FIRST(&tda->tda_scan_queues[TDA_SCANQ_EPG]); + idle_epg = tda->tda_idlescan || tda->tda_mux_epg; /* Idlescan is disabled and no muxes are bad */ if(!idle_epg && TAILQ_FIRST(&tda->tda_scan_queues[TDA_SCANQ_BAD]) == NULL) { @@ -472,27 +470,27 @@ dvb_adapter_mux_scanner(void *aux) return; } - /* Alternate between the three queues (BAD, OK, EPG) */ - for(i = 0; i < TDA_SCANQ_NUM; i++) { - tda->tda_scan_selector++; - if (tda->tda_scan_selector == TDA_SCANQ_NUM) - tda->tda_scan_selector = 0; + /* EPG */ + if (tda->tda_mux_epg) { + int period = epggrab_mux_period(tda->tda_mux_epg); + if (period > 20) + gtimer_arm(&tda->tda_mux_scanner_timer, + dvb_adapter_mux_scanner, tda, period); + dvb_fe_tune(tda->tda_mux_epg, "EPG scan"); + + /* Normal */ + } else { - tdmi = TAILQ_FIRST(&tda->tda_scan_queues[tda->tda_scan_selector]); - if(tdmi != NULL) { - - /* EPG - adjust dwell time */ - if (tda->tda_scan_selector == TDA_SCANQ_EPG) { - epggrab_ota_mux_t *ota; - int period = 20; - LIST_FOREACH(ota, &tdmi->tdmi_epg_grabbers, tdmi_link) { - if (ota->timeout > period) period = ota->timeout; - } - gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, period); + /* Alternate queue */ + for(i = 0; i < TDA_SCANQ_NUM; i++) { + tda->tda_scan_selector++; + if (tda->tda_scan_selector == TDA_SCANQ_NUM) + tda->tda_scan_selector = 0; + tdmi = TAILQ_FIRST(&tda->tda_scan_queues[tda->tda_scan_selector]); + if (tdmi) { + dvb_fe_tune(tdmi, "Autoscan"); + return; } - - dvb_fe_tune(tdmi, scan_string[tda->tda_scan_selector]); - return; } } } diff --git a/src/dvb/dvb_fe.c b/src/dvb/dvb_fe.c index 79087940..aedab5a0 100644 --- a/src/dvb/dvb_fe.c +++ b/src/dvb/dvb_fe.c @@ -230,6 +230,8 @@ dvb_fe_stop(th_dvb_mux_instance_t *tdmi) if(tdmi->tdmi_enabled) { dvb_mux_add_to_scan_queue(tdmi); } + + epggrab_mux_stop(tdmi); time(&tdmi->tdmi_lost_adapter); } @@ -509,7 +511,7 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason) dvb_table_add_default(tdmi); - epggrab_tune(tdmi); + epggrab_mux_start(tdmi); dvb_adapter_notify(tda); return 0; diff --git a/src/dvb/dvb_multiplex.c b/src/dvb/dvb_multiplex.c index 8a4b8882..fd3b7643 100644 --- a/src/dvb/dvb_multiplex.c +++ b/src/dvb/dvb_multiplex.c @@ -44,7 +44,7 @@ #include "dvb_support.h" #include "notify.h" #include "subscriptions.h" -#include "epggrab/ota.h" +#include "epggrab.h" struct th_dvb_mux_instance_tree dvb_muxes; @@ -298,7 +298,6 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc, void dvb_mux_destroy(th_dvb_mux_instance_t *tdmi) { - epggrab_ota_mux_t *ota; th_dvb_adapter_t *tda = tdmi->tdmi_adapter; service_t *t; @@ -332,8 +331,7 @@ dvb_mux_destroy(th_dvb_mux_instance_t *tdmi) if(tdmi->tdmi_table_initial) tda->tda_initial_num_mux--; - while ((ota = LIST_FIRST(&tdmi->tdmi_epg_grabbers))) - epggrab_ota_unregister(ota); + epggrab_mux_delete(tdmi); hts_settings_remove("dvbmuxes/%s", tdmi->tdmi_identifier); @@ -1157,9 +1155,8 @@ void dvb_mux_add_to_scan_queue ( th_dvb_mux_instance_t *tdmi ) { int ti; th_dvb_adapter_t *tda = tdmi->tdmi_adapter; - ti = LIST_FIRST(&tdmi->tdmi_epg_grabbers) ? TDA_SCANQ_EPG - : tdmi->tdmi_quality == 100 ? TDA_SCANQ_OK - : TDA_SCANQ_BAD; + ti = tdmi->tdmi_quality == 100 ? TDA_SCANQ_OK + : TDA_SCANQ_BAD; tdmi->tdmi_scan_queue = &tda->tda_scan_queues[ti]; TAILQ_INSERT_TAIL(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link); } From 9aa3acdd9f0e495234cd141dd469155d77c720a9 Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Wed, 27 Jun 2012 11:32:51 +0100 Subject: [PATCH 02/11] Little bit of tidying up. --- src/dvb/.dvb_adapter.c.swp | Bin 0 -> 32768 bytes src/dvb/dvb_adapter.c | 7 +------ 2 files changed, 1 insertion(+), 6 deletions(-) create mode 100644 src/dvb/.dvb_adapter.c.swp diff --git a/src/dvb/.dvb_adapter.c.swp b/src/dvb/.dvb_adapter.c.swp new file mode 100644 index 0000000000000000000000000000000000000000..35f861f46c9dfac40fd16153eb259050b4a9873c GIT binary patch literal 32768 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 z%u$%72d}awgtda_rootpath == NULL) return; // No hardware @@ -477,7 +472,7 @@ dvb_adapter_mux_scanner(void *aux) gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, period); dvb_fe_tune(tda->tda_mux_epg, "EPG scan"); - + /* Normal */ } else { From 2a371267212345be23cafb07d6622d7e79ac742f Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Wed, 27 Jun 2012 12:00:07 +0100 Subject: [PATCH 03/11] dot file accidentally added. --- src/dvb/.dvb_adapter.c.swp | Bin 32768 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/dvb/.dvb_adapter.c.swp diff --git a/src/dvb/.dvb_adapter.c.swp b/src/dvb/.dvb_adapter.c.swp deleted file mode 100644 index 35f861f46c9dfac40fd16153eb259050b4a9873c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeI5d6XPSdBDfm9D*2#1DMzt%4;OgN-NDCx@^gU)oLY;k#?osm5eP&Gdt6>+h{IL z_v~u1jd8HSgd`9y12)9rFbPK>BoK^qbHf81j+bBp4wu0|LSh>N36T80s_JWwwVdbt zlQ;9;PqWiqRbBPfSLgS2X@2-<{-D~nX)MF%@tMrTH@-jpy0bo=`QRCuOrhb+)d&16 zHa2hF{(zw}nHQ2^?y`FGxZfxg-Q3CfYSCHtbHUQ0TPV4;Qm#-cRQ*;E)N47vS@c&iG1o{%_OQ0`-z682Rpis(W9>w*mWIc`jKV1L+;&GYGo$vv8KX{Lxg6rTUEW6TAUl14m&FMqn*G9UcjffZN%4c?J9~)ZsVaIdBZFfTJ)A({L%A1&@b& z(WkrNJMc;P1c;7Z3E@X6Tt6!Hh3tXpea_VMTz+D5NDbieF~HZjar#it8CdH-XFz$S zimR%vlgcj^YBjI6pnNw_LH%O2)*l!`H&vxxJnj^H-)#ojbqkgHe4*mVwZR>7SE;5O zw3@XY{Oy&qL8-8D7ymett|X~0xkS}#gPAKc36B$pXG9^g!J?DA7pV0lFr>U%pkpr8 zy;4T4&p{@)em#Y}nrF!~{KAqePb4S$f_ZYG71T?fU#u^=%@rk2C!=d5g1OJVMy0S) zD^%SfZmMUff$7?Sx|pwWdBCJ~%Hk8rr62gvh%cRHPZ>%uCo1g!PLfI4*Xn^+Ua>Om zCgr4{6M{s{e$Xtn8d+Zpu-tTY&2&gyl%`i*n5d_&x=mN=u!OQ&Wj6ZSrjh59v0{~s z4Ruw4!NCX6@lM4}l)IP2i}jixsN!Owsn+|0neHmQ82D9x!6~`qu)dP5YRPd?S_e)g z3;ZDpUNvpkI&1kkX_s+PJRH2JGtX^?(Iw47spPcAMs-~GWY8=$nqIx>1uMy@sT;jw zQ&{&z(V;E*UcHu#p1#v7e$5MLzsY#!O0V#xR<+^Ks@zm5mov5aBC%=1z4g02K zuEJ}*;-ng6GGgjRdu(df)L-1^B;zJDsaMQkrQs4K(MaWrL$jB(qfSjO4w44#bM^k( zDjl6{l}2lS6`O7$aGh$QktK~QGjZqIt!p04_yJx|MU_x%HH)e$)V}O3sB*ojf<;#? zcuQ_gS;bBC-DboP9o89+3ZZMcTq0i^N77w-rPA<9zEi56bfWtdb#6R=;INaQ%Fkuj zMXC6OK=NUFldd5=RM2A-lkv$p(Q;d^mVU4FqEP-Z@3}gp6foZjxuwtP? z-DXFIl<&R3tuxrR)s83tqcG#97uKSQA{7z^fH2t&*z-+{VH} zvoODDaUgM#$;gsdbki5j;FZ1>_$8O8r!PvO{8pn;Zw4JV(ib8ZTDhEhzUiUUmv>gY zTI-~7udVXTU2%-Wt#Y$o3-HR7`-uR^kv=~i$qz~ukD@0NYSlb0r>}9rtEVp&rAJ6# za+}RsTc~oe7F5!q{1rdv)r;LOi)M5NmIwKAIZ+rhT}+3yjX{Sr3a3<|QfJ1w>;;P` zkmsvLvrc7KHz}1bE9w(fM}>AS20`QETyA-JdDB9zwW;1*$W^HRn(z9#U7Ju}r7o|x zl)qSSRZ416x}v6AbZK5CRiIaDtf+cfcS-xEj;MWZ&21Jc>QHN*RMY{Jl1wipq23{M zzgDd`(P=j*cop9~`QYTt#QyQAx$)ik1Nphj6@A0r{M^*!?5x^5J)_3eq461};71OO z&!|I3W)4lyPEx*E%0(ZkA35I&)Mfd({nJP0)cDlp>ay{f84|pFhn7s8yRLMk(xrOU zM#ZC4%Y|mMPz$77I*GZ2^b~?*WI>-un6RFSx>#?>BMbBn0SQ+sYTi{X-z~Q)Lt){w z++C@+nyTIi814sEp|+xMadn%@&HzlAB`bTSb>R6+qQk&5#dDcbx>*V4=MQ~5S)7fXrgJZtDgEEW+$ z0oQnHtIBerED7nfCeW6qx3Czf?8KlN9Uk7M#%m?IabJDpb=5-6Jn*Q>OK+$)qCT{F zwdd$=>3H2{84rAhx{R#F`U|{{IM{ zhL6L?;2rRCD8fAKgdK1;+{a$P=iy!ODyYE%Ou*CNzgYAC1N;@d9)1sA4A;O5;c7Sn zPlB(I-y1>J|9fFKjKdI|2U4DMp#SMhpf7>G1o{%_OQ0`-z6AOb=u6-fB_P}Pb_+=M zJY>(JZ7WoE^tmblqoC{+$*;2Our~2!hckf9FRhfBo0jO?Ulk&Y$G1qGZI;UQkgh9DeJ#+v$@mx z`2B3mzJM)(D0(XL{^^|5w;fD6|qE}o*0*yMw_t^Df?d1;)4yr4uhfd*L zz?Or@Vv$d~3@^%!43qV}lM~KG&d4xgy1*;TlExW7ly}JfEV5L)E>T;$M&F*h$j098 zT+~Cx+j84&m~GDX9$~iTw%IUSoozkBY{_l4VYWD1C8NDdHJ00AgN`{{BAnWm<==PjP(dJk{h*QMx0T?bQSVcy(as>Qb$wMQ%h7+&@E{4+}1K(gx|IZ+6|Chi~I0EOwIdB(i`me($;N$S8@Ororo&|Z> z5Bp#Oo(Vf)8$1rqg#To%{~h=&$iBea;cf6zcnKVbJZyul@L2dc>;7-RAH!SWW~f31 zw!>rLba)tuufXrXZ-e**9DptGbFuHk7vODhGu#9#Fa-zU(eU@!_iuqBY=V2R?cWNw zz{}uzxDKXaJ8Xq5uo;HohuHSN0$+wZ;63mz_-&{{3FcrH#^A|tHk=M0#NPh_csVS> z0t~}r;Y<+w|Ft0Y{YzmlOu`tP3qQn8{~h>q_#nI%3h+GG1b3kmUkA~Rzk~O}&2R%0 z;Cb+XA89<&b|brows=YBAy>tm<*;=wp*n(fxz_7am+NB9&$K;d-8yTF*_)r4O&Mbn z#*^4evU_~ba|gvUK-)YRu$0QJSNYIo!0cZZ<}0#&TPv{BSl$#4zd9u$x9+ z2X4h@50_6=4RItrxly^C@{fBB_Bbh4;8i6!BT;O+vk?ZlPVOca-QsbbHhzP!3Nd&ZM9-DM2?qTv$IZq zsfvaSyzJeJDeOecD;}5U;}qR( zXsI>pIK_IE%~jV~c4Z?rVKc*$UGv3m;}5D`YFH~`BITT#3RT6JB3o?vYI$c5qGszncu{brs_$!PMaUk zK`$`jiKQ@Ugi>o~;uwt@UY7cP_-OP6>ai8E02xK$mHOlnu-h$J2hxZ1Q_-7U?cj&#%XYAEqCW?IzO zTd0Y}kIs0Fv`%cD(nCf$(S8>ho1l`>fYEGC=yfp5%FmG>*-ll}Jw-}icVyP2(xqsU zeDZSa?Gu-~ym8lJwd~m9OA-yEsV9!V=E-PpHFcW&a889H`J&WI`>U3+YB zcvhcfzK|VJJ9jE?kX2mhIZ-Y6#|Kr0HDJA&bVnH*)jlZP;$EnW;vA*JBw04&i}eyRPC3Y1OFB9J5QN6Z-a;wv%0l!MtRgc+!)D$ZJM7 zc$0;&P9ALkKs#Ej`{LeIbBnUyGb*iu+#5g3^gZzgTB8QEVLp^HPQ5C-mdVqSSI`c= zN~Rb(XC?_ImR_w~-?&RxGQ~`|W9Fy!PSXGph;g(`Xp>WvX{+CG-EhE`sA0Ym&5u@K zyX)v~>XBg;iEn~9@HV{?T@7}ACLJq8r7tdthqCsMw4Mq0@ak?$X3sLAXf=#S2^N1l z!qZ~do`z+If!m#0x zM+CgrWc|N|Mch5ImSg>Yt6k9D!TSF5@Je_&JRfB3KLlC05Y7eJ3lRJN2jHbJ4GNwH zkB5iD8Ss79@_!3|0AlyQ6i$O5v0ncqdz#$lb^Wh9Q z9X`cc{+;kgAnW`|*aKrQ0>hAl4R9e`08fMaS?k{mUxY8f`{Awd7Pua+gS{{bkAwTy zWHSE_e*w3{o8d)p4K(2dxDdWWP~h+9!WD274uiZ;uny!sf?tE5uy62Vkaq~)1amM0 zhv5)R!xUT!`(OgLz!TssxQ~5=Z^5VG!*Cni0Lw50=fc_WBzPh`3ck($!MET~;N9?B zFbz+EpRjlEZ}21d9J~pxhXZgPJOv&G-)9fu8}L=Q6K;jKfV^Mu`|xIXBisnDh8y4* zTn_u;0yqQiXRqO#a0h%8J_0X?XTxPM3Uc0q=;*gkWzWItaP&oAsz0?>m1V<*4bu6W zg;q38m-T5pm(&X`>29iCIQ%;}%`u8yNmQ0g&wlo^FV;(ZS>_9VrM?{hBaPDzIpX3h zy`Q*8OJ~IdGHR!Z=C1qoE>YqcOfq78)pSI%zABfzB`KKvO+o!7nIa4)u287(O1OY! z=nEvo11!sIz6jmZ8JD3~yvXNUai66l-t?eBO zv;GMOGUKG$s)_$_V(puDQw{s)aOs4NCZ4pW{ddA)6U{jFZz`{K$SgKn;SQpw^!CAMz6`4nP~7b z$uZjN_#Ih9ll=K1)zq6I{42VdUYv&|Wht<6L|a@WgkDi#o5J^S$>Av0<8CmL#fOp9 z)CNUEur9uOC9!cA{>;oRWW61F%*xmj$wY1xTTR|_U?L*Px3{fi!-_XX5TH|Fa0;ajWdUO586z>=!W4mKSTB7L^q})_(Gtu0` zDXsJZr5@WX(X=qR$&zxtPPbR{){|oHqdlL|u`2T;+?dT)i_0`HoPEw7bS9?vOgghi zcF#`C+J@zv&^v82;+^4pJP}+>QGm z6W2`8XC@CKw)C<|k23n7wza!1UA%V{zSSc`otAhgQGWLlsvaHNuNh6HXOpYO z)m{f$y*juXZbjPnEt1QhX!|i)xvLIm>AH-{-@P_zQC7cIqBdzQ=AEaKADD`W1u9cZ|{fb%Zh%tVL_1hRst?JVbBeheWxSBuplhO4OWOYpXr3Bp%UL zd#khtp1X=TP5Jcxtvs`R*k@>!-Tw~R5|l!ATt*D3m(Z-tr7JewaX6fZ-=Shir)EAf zRJB^L#C_&wYr=3)V}>LkFfpzd&|>dh)I9++E3>tdPOe9N$pxry;FG*HD`Rz?u|-{j(3qDXNuPw1X$$XXk8 zzaybfasMPEVWkd@u>uPVb_{coxv#yLHinst@u+HZub*tRAzdsx(O=(T;Yw?q?upPG z+xaN$i=s)=&}f(^T7?SlGLpZGZ2qj8MYSo}uyZG)!nzdHQr^4c@i5FQEluonL=+zsD^yFktbxC7n@uLoJGDEgXUM za6jwj`#|3Bm$mivAh!M&fvmB&!=qshe3kX{d*B*40ad8L1Uv;~UHv`yb9f0H1<{AK zU_P|B4sWax?N+4r9T}h5!@G@hlQT!h4>%(|{c1+EYgK3XUT#(+xe@W9>PUY?{HeNU zXiOZGIwFik&PttyuwF=QaeBJlbPGpb=my%o-4+ihqq(w+i}^U_l`Z9!Cbxy<7zvFw$C z#Rn&o?Z*+w9B-S=9?Z{*o1b$~mJZvW)k7+y-NTPc_|;3=`H-F^?h&*{$@NmC>iP11 zI9UaMaH(9hjX8fQtx@GI2 z6riJTIy`=GBR3_x{Hep4KBF^@kx}**dZoe5FbxUUD~+w2O%h%6u~pm-O+EOikfx}|msah!^D%%km}J@rH1H;=G?_6#bC zYN6u4EPoQPry}%_2=S~UYF+CpQo@8=MxBz&JpuhAqgG91ZG$!xsWDVr|#mp$8n7e)hfxPe{CNdCI4phz8i zc;fgDR)59Cp8KfMp6r8ULs~Xsi7)$nLuyIaRpPFk$g#x4UZ01-@MX^(NQ96LZ3z*0 zK}GLq%QwlyPhsC=siSbw!3{~d+hmE*RwA9aIbX+QB9qv6O7A*J@yu)WVg;Ad4FpT$ z<^&;BCAkPm>_lTtCC};o0Fz30fv47{iR}Q}Wmgk*n>^UWU#T`(ZyhY0BrBa-!R`5a z#gQPKY;m$%Wr*z{OvOtbZW8HMDiu$T6p8C1nHhGQPRs^wqia^=X3MP=SFl*P4cQ=7 zIc-qv(iaOp1KB;jq0Ra!i_egS>X~>X{D!&jPyDTCtDfXjvz%g z!+940*#+*wmb49wM_SS1eXg37N|syEaUv2d(U1~rXdOG5nZ&(tjV_}?y2PO}SR*`n zNgwJHx}RcH6Dx>*NTMiVbZ+T*#>m(!l-(DXQ-h3=j)3Xxg!LpkM=0&bU;-H_nt$o< zw2d#^0!o`RwaF#ghln@9#ptrothXAGHB;>WECIEzx7h#RXIFe*VtxNbxDEagZUs35 z;B9aVyb0a_uYu>mZ@?bd4%^@y_;vU!YyUrhTi~}~1(sn6T5tkt@O*G#0}R3%_yv0d zKZo!=f>-c&5$0hpY=JQt1^#QZ%tlxb>)?F&E_(>_?tu6gd;;D9;!E&GI1F20Gdvld z2%#^*Y5bjm|7I`Yzu>2EKl}*9zu+Bk6TA{$0pf4)Ja8a9hu~-IC&<3TU&Af%3JBjb zxPiaLx8Pd13O2(iJQ1D%vj1==d<9+%J7EX>DrDf7>@EBPeg@(@a4*~qAA%3Ut?+hm z;6ivhTmS>`R5%yThR49Y>`D9^d>uXma!%n};P>Dfcp>b7(;)-$j>2Dq>|xvhQ?MI$ z!6lG|3*j{Q8v7IG^K9OJRJmg^o4 zv%j{UmqVAnW1L>t=yQGIA%$Ft^^*G8H#x^vlel+9 zMX*`MprQNq_Uj0ht!(TYS!?e_#BvUlo?Y7$j(WtNZQd8LUS%| z^jo&lQLptmQmH9#C`Lx!j<9idWbG;f?UJsX1f>nd$&}?{kF=xkovB9|2)IhIVwVSH^aJ*^IghBRa3(?LII)@hoFTH^$zu zCE3tcRg6xWnhj6GN>xErcOuJZexe0StX#=m(uZtWNv@US1rt&=3K#k^V7S0DQ#2xS zq}i+;X=tt;hB9hFLelyvZfw`rF?FtwpPk=F zB27xqACa|qJyTSsYP=8=dVFTNlGbl7L?V)#W@;k>T3gy=8&33)WX81i>2eV5*w)P* z&P7S5&TgWLj+E=L%}ehl^5}j-Yw8sW3Yz+@bEV8D%67t`E73)z;&JR$@}NsCqeQ3q z0LS3!xEw!bPRW$>L`xiwi*Rrd4Nn;5igA1mC+S*M5>xb424tR|x-clc-6{s*^mzH~Or_*B3ytLfFN1K}o)_@q8?cf&=iyYQFfyxfsZBPtDkI z>Oo3>)aNxV<=(M~hx5S=8!-CF$FiupW+dJC-;dy_eKmHJ>*_Pz`DA zq~Fm3GFRJCFWm-AyD$y|=0zUzWd2AC-CScaqt8!$Ah~h^=El0Jxxq633pj6x{Vx?b z%u$%72d}awg Date: Fri, 29 Jun 2012 09:18:38 +0100 Subject: [PATCH 04/11] WIP: this a partially complete restructuring of the epggrab code. But I am having doubts. --- Makefile | 12 +- src/dvb/dvb_adapter.c | 6 +- src/dvb/dvb_fe.c | 2 +- src/epggrab.c | 651 +++--------------------------- src/epggrab.h | 215 ++++++---- src/epggrab/channel.c | 275 +++++++++++++ src/epggrab/eit.h | 27 -- src/epggrab/module.c | 450 +++++++++++++++++++++ src/epggrab/{ => module}/eit.c | 71 ++-- src/epggrab/{ => module}/opentv.c | 565 ++++++++++++++------------ src/epggrab/{ => module}/pyepg.c | 66 ++- src/epggrab/{ => module}/xmltv.c | 65 ++- src/epggrab/opentv.h | 29 -- src/epggrab/ota.c | 130 ------ src/epggrab/ota.h | 76 ---- src/epggrab/otamux.c | 256 ++++++++++++ src/epggrab/private.h | 144 +++++++ src/epggrab/pyepg.h | 27 -- src/epggrab/xmltv.h | 31 -- 19 files changed, 1735 insertions(+), 1363 deletions(-) create mode 100644 src/epggrab/channel.c delete mode 100644 src/epggrab/eit.h create mode 100644 src/epggrab/module.c rename src/epggrab/{ => module}/eit.c (86%) rename src/epggrab/{ => module}/opentv.c (74%) rename src/epggrab/{ => module}/pyepg.c (87%) rename src/epggrab/{ => module}/xmltv.c (87%) delete mode 100644 src/epggrab/opentv.h delete mode 100644 src/epggrab/ota.c delete mode 100644 src/epggrab/ota.h create mode 100644 src/epggrab/otamux.c create mode 100644 src/epggrab/private.h delete mode 100644 src/epggrab/pyepg.h delete mode 100644 src/epggrab/xmltv.h diff --git a/Makefile b/Makefile index 2c8178e9..ec07efd0 100644 --- a/Makefile +++ b/Makefile @@ -74,11 +74,13 @@ SRCS = src/main.c \ src/avc.c \ src/huffman.c \ -SRCS += src/epggrab/pyepg.c\ - src/epggrab/xmltv.c\ - src/epggrab/ota.c \ - src/epggrab/eit.c \ - src/epggrab/opentv.c \ +SRCS += src/epggrab/module.c\ + src/epggrab/channel.c\ + src/epggrab/otamux.c\ + src/epggrab/module/pyepg.c\ + src/epggrab/module/xmltv.c\ + src/epggrab/module/eit.c \ + src/epggrab/module/opentv.c \ SRCS += src/plumbing/tsfix.c \ src/plumbing/globalheaders.c \ diff --git a/src/dvb/dvb_adapter.c b/src/dvb/dvb_adapter.c index 39c690c8..77427bbc 100644 --- a/src/dvb/dvb_adapter.c +++ b/src/dvb/dvb_adapter.c @@ -444,10 +444,12 @@ dvb_adapter_mux_scanner(void *aux) } /* Check EPG */ - if (tda->tda_mux_epg) + if (tda->tda_mux_epg) { + epggrab_mux_stop(tda->tda_mux_epg, 1); // timeout anything not complete tda->tda_mux_epg = NULL; // skip this time - else + } else { tda->tda_mux_epg = epggrab_mux_next(tda); + } /* Idle or EPG scan enabled */ idle_epg = tda->tda_idlescan || tda->tda_mux_epg; diff --git a/src/dvb/dvb_fe.c b/src/dvb/dvb_fe.c index aedab5a0..388fe5ef 100644 --- a/src/dvb/dvb_fe.c +++ b/src/dvb/dvb_fe.c @@ -231,7 +231,7 @@ dvb_fe_stop(th_dvb_mux_instance_t *tdmi) dvb_mux_add_to_scan_queue(tdmi); } - epggrab_mux_stop(tdmi); + epggrab_mux_stop(tdmi, 0); time(&tdmi->tdmi_lost_adapter); } diff --git a/src/epggrab.c b/src/epggrab.c index fb8816e0..213b3af6 100644 --- a/src/epggrab.c +++ b/src/epggrab.c @@ -13,10 +13,7 @@ #include "queue.h" #include "epg.h" #include "epggrab.h" -#include "epggrab/eit.h" -#include "epggrab/xmltv.h" -#include "epggrab/pyepg.h" -#include "epggrab/opentv.h" +#include "epggrab/private.h" #include "channels.h" #include "spawn.h" #include "htsmsg_xml.h" @@ -30,7 +27,7 @@ pthread_cond_t epggrab_cond; /* Config */ uint32_t epggrab_interval; -epggrab_module_t* epggrab_module; +epggrab_module_int_t* epggrab_module; epggrab_module_list_t epggrab_modules; uint32_t epggrab_channel_rename; uint32_t epggrab_channel_renumber; @@ -40,15 +37,20 @@ uint32_t epggrab_channel_reicon; * Helpers * *************************************************************************/ +void epggrab_resched ( void ) +{ +} + /* * Run the parse */ -static void _epggrab_module_parse - ( epggrab_module_t *mod, htsmsg_t *data ) +void epggrab_module_parse + ( void *m, htsmsg_t *data ) { time_t tm1, tm2; int save = 0; epggrab_stats_t stats; + epggrab_module_int_t *mod = m; /* Parse */ memset(&stats, 0, sizeof(stats)); @@ -82,7 +84,7 @@ static void _epggrab_module_parse /* * Grab from module */ -static void _epggrab_module_grab ( epggrab_module_t *mod ) +static void _epggrab_module_grab ( epggrab_module_int_t *mod ) { time_t tm1, tm2; htsmsg_t *data; @@ -95,41 +97,14 @@ static void _epggrab_module_grab ( epggrab_module_t *mod ) /* Process */ if ( data ) { tvhlog(LOG_INFO, mod->id, "grab took %d seconds", tm2 - tm1); - _epggrab_module_parse(mod, data); + epggrab_module_parse(mod, data); } else { tvhlog(LOG_WARNING, mod->id, "grab returned no data"); } } -/* - * Socket handler - */ -static void _epggrab_socket_handler ( epggrab_module_t *mod, int s ) -{ - size_t outlen; - char *outbuf; - time_t tm1, tm2; - htsmsg_t *data = NULL; - - /* Grab/Translate */ - time(&tm1); - outlen = file_readall(s, &outbuf); - if (outlen) data = mod->trans(mod, outbuf); - time(&tm2); - - /* Process */ - if ( data ) { - tvhlog(LOG_INFO, mod->id, "grab took %d seconds", tm2 - tm1); - _epggrab_module_parse(mod, data); - - /* Failed */ - } else { - tvhlog(LOG_ERR, mod->id, "failed to read data"); - } -} - /* ************************************************************************** - * Threads + * Internal Grab Thread * *************************************************************************/ /* @@ -139,7 +114,7 @@ static void* _epggrab_internal_thread ( void* p ) { int err, confver = -1; // force first run struct timespec ts; - epggrab_module_t *mod; + epggrab_module_int_t *mod; /* Setup timeout */ ts.tv_nsec = 0; @@ -169,473 +144,6 @@ static void* _epggrab_internal_thread ( void* p ) return NULL; } -/* - * External (socket) grab thread - */ -static void *_epggrab_socket_thread ( void *p ) -{ - int s; - epggrab_module_t *mod = (epggrab_module_t*)p; - tvhlog(LOG_INFO, mod->id, "external socket enabled"); - - while ( mod->enabled && mod->sock ) { - tvhlog(LOG_DEBUG, mod->id, "waiting for connection"); - s = accept(mod->sock, NULL, NULL); - if (s <= 0) continue; - tvhlog(LOG_DEBUG, mod->id, "got connection %d", s); - _epggrab_socket_handler(mod, s); - } - tvhlog(LOG_DEBUG, mod->id, "terminated"); - return NULL; -} - -/* ************************************************************************** - * Base Module functions - * *************************************************************************/ - -static int _ch_id_cmp ( void *a, void *b ) -{ - return strcmp(((epggrab_channel_t*)a)->id, - ((epggrab_channel_t*)b)->id); -} - -static int _ch_link ( epggrab_channel_t *ec, channel_t *ch ) -{ - service_t *sv; - int match = 0, i; - - if (!ec || !ch) return 0; - if (ec->channel) return 0; - - if (ec->name && !strcmp(ec->name, ch->ch_name)) - match = 1; - else { - LIST_FOREACH(sv, &ch->ch_services, s_ch_link) { - if (ec->sid) { - for (i = 0; i < ec->sid_cnt; i++ ) { - if (sv->s_dvb_service_id == ec->sid[i]) { - match = 1; - break; - } - } - } - if (!match && ec->sname) { - i = 0; - while (ec->sname[i]) { - if (!strcmp(ec->sname[i], sv->s_svcname)) { - match = 1; - break; - } - i++; - } - } - if (match) break; - } - } - - if (match) { - tvhlog(LOG_INFO, ec->mod->id, "linking %s to %s", - ec->id, ch->ch_name); - ec->channel = ch; - if (ec->name && epggrab_channel_rename) - channel_rename(ch, ec->name); - if (ec->icon && epggrab_channel_reicon) - channel_set_icon(ch, ec->icon); - if (ec->number>0 && epggrab_channel_renumber) - channel_set_number(ch, ec->number); - } - - return match; -} - -int epggrab_module_enable_socket ( epggrab_module_t *mod, uint8_t e ) -{ - pthread_t tid; - pthread_attr_t tattr; - struct sockaddr_un addr; - assert(mod->path); - assert(mod->flags & EPGGRAB_MODULE_EXTERNAL); - - /* Ignore */ - if ( mod->enabled == e ) return 0; - - /* Disable */ - if (!e) { - shutdown(mod->sock, SHUT_RDWR); - close(mod->sock); - unlink(mod->path); - mod->sock = 0; - - /* Enable */ - } else { - unlink(mod->path); // just in case! - - mod->sock = socket(AF_UNIX, SOCK_STREAM, 0); - assert(mod->sock); - - memset(&addr, 0, sizeof(struct sockaddr_un)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, mod->path, 100); - if ( bind(mod->sock, (struct sockaddr*)&addr, - sizeof(struct sockaddr_un)) != 0 ) { - tvhlog(LOG_ERR, mod->id, "failed to bind socket"); - close(mod->sock); - mod->sock = 0; - return 0; - } - - if ( listen(mod->sock, 5) != 0 ) { - tvhlog(LOG_ERR, mod->id, "failed to listen on socket"); - close(mod->sock); - mod->sock = 0; - return 0; - } - - tvhlog(LOG_DEBUG, mod->id, "starting socket thread"); - pthread_attr_init(&tattr); - pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); - pthread_create(&tid, &tattr, _epggrab_socket_thread, mod); - } - mod->enabled = e; - return 1; -} - -const char *epggrab_module_socket_path ( const char *id ) -{ - char *ret = malloc(100); - snprintf(ret, 100, "%s/epggrab/%s.sock", - hts_settings_get_root(), id); - return ret; -} - -char *epggrab_module_grab ( epggrab_module_t *mod ) -{ - int outlen; - char *outbuf; - - /* Debug */ - tvhlog(LOG_INFO, mod->id, "grab %s", mod->path); - - /* Grab */ - outlen = spawn_and_store_stdout(mod->path, NULL, &outbuf); - if ( outlen < 1 ) { - tvhlog(LOG_ERR, "pyepg", "no output detected"); - return NULL; - } - - return outbuf; -} - -htsmsg_t *epggrab_module_trans_xml - ( epggrab_module_t *mod, char *c ) -{ - htsmsg_t *ret; - char errbuf[100]; - - if (!c) return NULL; - - /* Extract */ - ret = htsmsg_xml_deserialize(c, errbuf, sizeof(errbuf)); - if (!ret) - tvhlog(LOG_ERR, "pyepg", "htsmsg_xml_deserialize error %s", errbuf); - return ret; -} - -void epggrab_module_channel_save - ( epggrab_module_t *mod, epggrab_channel_t *ch ) -{ - int i; - htsmsg_t *m = htsmsg_create_map(); - htsmsg_t *a; - - if (ch->name) - htsmsg_add_str(m, "name", ch->name); - if (ch->icon) - htsmsg_add_str(m, "icon", ch->icon); - if (ch->channel) - htsmsg_add_u32(m, "channel", ch->channel->ch_id); - if (ch->sid) { - a = htsmsg_create_list(); - for (i = 0; i < ch->sid_cnt; i++ ) { - htsmsg_add_u32(a, NULL, ch->sid[i]); - } - htsmsg_add_msg(m, "sid", a); - } - if (ch->sname) { - a = htsmsg_create_list(); - i = 0; - while (ch->sname[i]) { - htsmsg_add_str(a, NULL, ch->sname[i]); - i++; - } - htsmsg_add_msg(m, "sname", a); - } - if (ch->number) - htsmsg_add_u32(m, "number", ch->number); - - hts_settings_save(m, "epggrab/%s/channels/%s", mod->id, ch->id); -} - -static void epggrab_module_channel_load - ( epggrab_module_t *mod, htsmsg_t *m, const char *id ) -{ - int save = 0, i; - const char *str; - uint32_t u32; - htsmsg_t *a; - htsmsg_field_t *f; - - epggrab_channel_t *ch = epggrab_module_channel_find(mod, id, 1, &save); - - if ((str = htsmsg_get_str(m, "name"))) - ch->name = strdup(str); - if ((str = htsmsg_get_str(m, "icon"))) - ch->icon = strdup(str); - if ((a = htsmsg_get_list(m, "sid"))) { - i = 0; - HTSMSG_FOREACH(f, a) i++; - ch->sid_cnt = i; - ch->sid = calloc(i, sizeof(uint16_t)); - i = 0; - HTSMSG_FOREACH(f, a) { - ch->sid[i] = (uint16_t)f->hmf_s64; - i++; - } - } - if ((a = htsmsg_get_list(m, "sname"))) { - i = 0; - HTSMSG_FOREACH(f, a) i++; - ch->sname = calloc(i+1, sizeof(char*)); - i = 0; - HTSMSG_FOREACH(f, a) { - ch->sname[i] = strdup(f->hmf_str); - i++; - } - } - if(!htsmsg_get_u32(m, "number", &u32)) - ch->number = u32; - - if (!htsmsg_get_u32(m, "channel", &u32)) - ch->channel = channel_find_by_identifier(u32); -} - -void epggrab_module_channels_load ( epggrab_module_t *mod ) -{ - htsmsg_t *m, *e; - htsmsg_field_t *f; - - if ((m = hts_settings_load("epggrab/%s/channels", mod->id))) { - HTSMSG_FOREACH(f, m) { - if ((e = htsmsg_get_map_by_field(f))) - epggrab_module_channel_load(mod, e, f->hmf_name); - } - htsmsg_destroy(m); - } -} - -void epggrab_module_channel_add ( epggrab_module_t *mod, channel_t *ch ) -{ - epggrab_channel_t *egc; - RB_FOREACH(egc, mod->channels, link) { - if (_ch_link(egc, ch) ) { - epggrab_module_channel_save(mod, egc); - break; - } - } -} - -void epggrab_module_channel_rem ( epggrab_module_t *mod, channel_t *ch ) -{ - epggrab_channel_t *egc; - RB_FOREACH(egc, mod->channels, link) { - if (egc->channel == ch) { - egc->channel = NULL; - epggrab_module_channel_save(mod, egc); - break; - } - } -} - -void epggrab_module_channel_mod ( epggrab_module_t *mod, channel_t *ch ) -{ - return epggrab_module_channel_add(mod, ch); -} - - -epggrab_channel_t *epggrab_module_channel_find - ( epggrab_module_t *mod, const char *id, int create, int *save ) -{ - epggrab_channel_t *ec; - static epggrab_channel_t *skel = NULL; - - if (!mod || !mod->channels ) return NULL; - - if ( !skel ) skel = calloc(1, sizeof(epggrab_channel_t)); - skel->id = (char*)id; - skel->mod = mod; - - /* Find */ - if (!create) { - ec = RB_FIND(mod->channels, skel, link, _ch_id_cmp); - - /* Create (if required) */ - } else { - ec = RB_INSERT_SORTED(mod->channels, skel, link, _ch_id_cmp); - if ( ec == NULL ) { - skel->id = strdup(skel->id); - ec = skel; - skel = NULL; - *save = 1; - } - } - - return ec; -} - -/* ************************************************************************** - * Channels - * *************************************************************************/ - -int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name ) -{ - int save = 0; - if (!ec || !name) return 0; - if (!ec->name || strcmp(ec->name, name)) { - if (ec->name) free(ec->name); - ec->name = strdup(name); - if (ec->channel) channel_rename(ec->channel, name); - save = 1; - } - return save; -} - -int epggrab_channel_set_sid - ( epggrab_channel_t *ec, const uint16_t *sid, int num ) -{ - int save = 0, i = 0; - if ( !ec || !sid ) return 0; - if (!ec->sid) save = 1; - else if (ec->sid_cnt != num) save = 1; - else { - for (i = 0; i < num; i++ ) { - if (sid[i] != ec->sid[i]) { - save = 1; - break; - } - } - } - if (save) { - if (ec->sid) free(ec->sid); - ec->sid = calloc(num, sizeof(uint16_t)); - for (i = 0; i < num; i++ ) { - ec->sid[i] = sid[i]; - } - ec->sid_cnt = num; - } - return save; -} - -int epggrab_channel_set_sname ( epggrab_channel_t *ec, const char **sname ) -{ - int save = 0, i = 0; - if ( !ec || !sname ) return 0; - if (!ec->sname) save = 1; - else { - while ( ec->sname[i] && sname[i] ) { - if (strcmp(ec->sname[i], sname[i])) { - save = 1; - break; - } - i++; - } - if (!save && (ec->sname[i] || sname[i])) save = 1; - } - if (save) { - if (ec->sname) { - i = 0; - while (ec->sname[i]) - free(ec->sname[i++]); - free(ec->sname); - } - i = 0; - while (sname[i++]); - ec->sname = calloc(i+1, sizeof(char*)); - i = 0; - while (sname[i]) { - ec->sname[i] = strdup(sname[i]); - i++; - } - } - return save; -} - -int epggrab_channel_set_icon ( epggrab_channel_t *ec, const char *icon ) -{ - int save = 0; - if (!ec->icon || strcmp(ec->icon, icon) ) { - if (!ec | !icon) return 0; - if (ec->icon) free(ec->icon); - ec->icon = strdup(icon); - if (ec->channel) channel_set_icon(ec->channel, icon); - save = 1; - } - return save; -} - -int epggrab_channel_set_number ( epggrab_channel_t *ec, int number ) -{ - int save = 0; - if (!ec || (number <= 0)) return 0; - if (ec->number != number) { - ec->number = number; - if (ec->channel) channel_set_number(ec->channel, number); - save = 1; - } - return save; -} - -void epggrab_channel_link ( epggrab_channel_t *ec ) -{ - channel_t *ch; - - if (!ec) return; - - /* Link */ - if (!ec->channel) { - RB_FOREACH(ch, &channel_name_tree, ch_name_link) { - if (_ch_link(ec, ch)) break; - } - } -} - -void epggrab_channel_updated ( epggrab_channel_t *ec ) -{ - epggrab_channel_link(ec); - epggrab_module_channel_save(ec->mod, ec); -} - -htsmsg_t *epggrab_channel_list ( void ) -{ - char name[100]; - epggrab_module_t *mod; - epggrab_channel_t *ec; - htsmsg_t *e, *m; - m = htsmsg_create_list(); - LIST_FOREACH(mod, &epggrab_modules, link) { - if (mod->enabled && mod->channels) { - RB_FOREACH(ec, mod->channels, link) { - e = htsmsg_create_map(); - htsmsg_add_str(e, "module", mod->id); - htsmsg_add_str(e, "id", ec->id); - sprintf(name, "%s: %s", mod->name, ec->name); - htsmsg_add_str(e, "name", name); - htsmsg_add_msg(m, NULL, e); - } - } - } - return m; -} - /* ************************************************************************** * Configuration * *************************************************************************/ @@ -664,8 +172,12 @@ static void _epggrab_load ( void ) if (old) epggrab_interval *= 3600; htsmsg_get_u32(m, "grab-enabled", &enabled); if (enabled) { - if ( (str = htsmsg_get_str(m, old ? "current-grabber" : "module")) ) - epggrab_module = epggrab_module_find_by_id(str); + if ( (str = htsmsg_get_str(m, old ? "current-grabber" : "module")) ) { + mod = epggrab_module_find_by_id(str); + if (mod && mod->type == EPGGRAB_INT) { + epggrab_module = (epggrab_module_int_t*)mod; + } + } if ( (a = htsmsg_get_map(m, "mod_enabled")) ) { LIST_FOREACH(mod, &epggrab_modules, link) { if (htsmsg_get_u32_or_default(a, mod->id, 0)) { @@ -709,7 +221,7 @@ static void _epggrab_load ( void ) epggrab_interval = 12 * 3600; // hours epggrab_module = NULL; // disabled LIST_FOREACH(m, &epggrab_modules, link) // enable all OTA by default - if (m->flags & EPGGRAB_MODULE_OTA) + if (m->type == EPGGRAB_OTA) epggrab_enable_module(m, 1); } @@ -759,18 +271,18 @@ int epggrab_set_interval ( uint32_t interval ) return save; } -int epggrab_set_module ( epggrab_module_t *mod ) +int epggrab_set_module ( epggrab_module_t *m ) { int save = 0; + epggrab_module_int_t *mod; + if (m && m->type != EPGGRAB_INT) return 0; + mod = (epggrab_module_int_t*)m; if ( epggrab_module != mod ) { - if (epggrab_module) epggrab_enable_module(epggrab_module, 0); - if (mod) { - assert(mod->grab); - assert(mod->trans); - assert(mod->parse); - } - epggrab_module = mod; - if (epggrab_module) epggrab_enable_module(epggrab_module, 1); + if (epggrab_module && epggrab_module->enable) + epggrab_module->enable(epggrab_module, 0); + epggrab_module = (epggrab_module_int_t*)mod; + if (epggrab_module && epggrab_module->enable) + epggrab_module->enable(epggrab_module, 1); save = 1; } return save; @@ -829,75 +341,9 @@ int epggrab_enable_module_by_id ( const char *id, uint8_t e ) } /* ************************************************************************** - * Global Functions + * Module Access * *************************************************************************/ -/* - * Initialise - */ -void epggrab_init ( void ) -{ - /* Initialise modules */ - eit_init(&epggrab_modules); - xmltv_init(&epggrab_modules); - pyepg_init(&epggrab_modules); - opentv_init(&epggrab_modules); - - /* Load config */ - _epggrab_load(); - - /* Start internal grab thread */ - pthread_t tid; - pthread_attr_t tattr; - pthread_attr_init(&tattr); - pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); - pthread_create(&tid, &tattr, _epggrab_internal_thread, NULL); -} - -void epggrab_channel_add ( channel_t *ch ) -{ - epggrab_module_t *m; - LIST_FOREACH(m, &epggrab_modules, link) { - if (m->ch_add) m->ch_add(m, ch); - } -} - -void epggrab_channel_rem ( channel_t *ch ) -{ - epggrab_module_t *m; - LIST_FOREACH(m, &epggrab_modules, link) { - if (m->ch_rem) m->ch_rem(m, ch); - } -} - -void epggrab_channel_mod ( channel_t *ch ) -{ - epggrab_module_t *m; - LIST_FOREACH(m, &epggrab_modules, link) { - if (m->ch_mod) m->ch_mod(m, ch); - } -} - -void epggrab_tune ( th_dvb_mux_instance_t *tdmi ) -{ - epggrab_module_t *m; - epggrab_ota_mux_t *o; - th_dvb_mux_instance_t *t; - - /* Cancel all currently active ota grabs */ - LIST_FOREACH(t, &tdmi->tdmi_adapter->tda_muxes, tdmi_adapter_link) { - if (t == tdmi) continue; - LIST_FOREACH(o, &t->tdmi_epg_grabbers, tdmi_link) { - epggrab_ota_cancel(o); - } - } - - /* Inform all modules */ - LIST_FOREACH(m, &epggrab_modules, link) { - if (m->tune) m->tune(m, tdmi); - } -} - epggrab_module_t* epggrab_module_find_by_id ( const char *id ) { epggrab_module_t *m; @@ -914,11 +360,42 @@ htsmsg_t *epggrab_module_list ( void ) LIST_FOREACH(m, &epggrab_modules, link) { e = htsmsg_create_map(); htsmsg_add_str(e, "id", m->id); - if(m->name) htsmsg_add_str(e, "name", m->name); - if(m->path) htsmsg_add_str(e, "path", m->path); - htsmsg_add_u32(e, "flags", m->flags); + htsmsg_add_u32(e, "type", m->type); htsmsg_add_u32(e, "enabled", m->enabled); + if(m->name) + htsmsg_add_str(e, "name", m->name); + if(m->type == EPGGRAB_EXT) { + epggrab_module_ext_t *ext = (epggrab_module_ext_t*)m; + htsmsg_add_str(e, "path", ext->path); + } htsmsg_add_msg(a, NULL, e); } return a; } + +/* ************************************************************************** + * Initialisation + * *************************************************************************/ + +/* + * Initialise + */ +void epggrab_init ( void ) +{ + /* Initialise modules */ + eit_init(); + xmltv_init(); + pyepg_init(); + opentv_init(); + + /* Load config */ + _epggrab_load(); + + /* Start internal grab thread */ + pthread_t tid; + pthread_attr_t tattr; + pthread_attr_init(&tattr); + pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + pthread_create(&tid, &tattr, _epggrab_internal_thread, NULL); +} + diff --git a/src/epggrab.h b/src/epggrab.h index 7a6cdbb6..ea95ebce 100644 --- a/src/epggrab.h +++ b/src/epggrab.h @@ -1,12 +1,41 @@ +/* + * EPG Grabber - common functions + * Copyright (C) 2012 Adam Sutton + * + * 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 __EPGGRAB_H__ #define __EPGGRAB_H__ -typedef struct epggrab_module epggrab_module_t; - #include -#include "channels.h" -#include "dvb/dvb.h" -#include "epggrab/ota.h" + +/* ************************************************************************** + * Typedefs/Forward decls + * *************************************************************************/ + +struct th_dvb_mux_instance; +struct th_dvb_adapter; + +typedef struct epggrab_module epggrab_module_t; +typedef struct epggrab_module_int epggrab_module_int_t; +typedef struct epggrab_module_ext epggrab_module_ext_t; +typedef struct epggrab_module_ota epggrab_module_ota_t; +typedef struct epggrab_ota_mux epggrab_ota_mux_t; + +LIST_HEAD(epggrab_module_list, epggrab_module); +typedef struct epggrab_module_list epggrab_module_list_t; /* ************************************************************************** * Grabber Stats @@ -41,14 +70,14 @@ typedef struct epggrab_channel epggrab_module_t *mod; ///< Linked module char *id; ///< Grabber's ID + char *name; ///< Channel name - char **sname; ///< Service name's - uint16_t *sid; ///< Service ID's - int sid_cnt; ///< Number of service IDs - char *icon; ///< Channel icon int number; ///< Channel number + char **sname; ///< Service name's + uint16_t *sid; ///< Service ID's + struct channel *channel; ///< Mapped channel } epggrab_channel_t; @@ -67,88 +96,109 @@ htsmsg_t* epggrab_channel_list ( void ); * Mutators */ int epggrab_channel_set_name ( epggrab_channel_t *ch, const char *name ); -int epggrab_channel_set_sid ( epggrab_channel_t *ch, const uint16_t *sid, int num ); -int epggrab_channel_set_sname ( epggrab_channel_t *ch, const char **sname ); int epggrab_channel_set_icon ( epggrab_channel_t *ch, const char *icon ); int epggrab_channel_set_number ( epggrab_channel_t *ch, int number ); - -void epggrab_channel_updated ( epggrab_channel_t *ch ); -void epggrab_channel_link ( epggrab_channel_t *ch ); +int epggrab_channel_set_sname ( epggrab_channel_t *ch, const char **sname ); +int epggrab_channel_set_sid ( epggrab_channel_t *ch, const uint16_t *sid ); /* - * Match the channel + * Updated/link */ +void epggrab_channel_updated ( epggrab_channel_t *ch ); /* ************************************************************************** * Grabber Modules * *************************************************************************/ -/* - * Grabber flags - */ -#define EPGGRAB_MODULE_INTERNAL 0x01 ///< IP based internally run -#define EPGGRAB_MODULE_EXTERNAL 0x02 ///< IP based externally run -#define EPGGRAB_MODULE_OTA 0x04 ///< DVB OTA EPGs - /* * Grabber base class */ struct epggrab_module { - LIST_ENTRY(epggrab_module) link; ///< Global list link + LIST_ENTRY(epggrab_module) link; ///< Global list link + enum { + EPGGRAB_INT, + EPGGRAB_EXT, + EPGGRAB_OTA + } type; ///< Grabber type const char *id; ///< Module identifier const char *name; ///< Module name (for display) - const char *path; ///< Module path (for fixed config) - const uint8_t flags; ///< Mode flag uint8_t enabled; ///< Whether the module is enabled - int sock; ///< Socket descriptor - epggrab_channel_tree_t *channels; ///< Channel list - LIST_HEAD(, epggrab_ota_mux) muxes; ///< Linked muxes /* Enable/Disable */ - int (*enable) ( epggrab_module_t *m, uint8_t e ); - - /* Grab/Translate/Parse */ - char* (*grab) ( epggrab_module_t *m ); - htsmsg_t* (*trans) ( epggrab_module_t *m, char *d ); - int (*parse) ( epggrab_module_t *m, - htsmsg_t *d, epggrab_stats_t *s ); - - /* Channel listings */ - void (*ch_add) ( epggrab_module_t *m, channel_t *ch ); - void (*ch_rem) ( epggrab_module_t *m, channel_t *ch ); - void (*ch_mod) ( epggrab_module_t *m, channel_t *ch ); - - /* Transponder tuning */ - void (*tune) ( epggrab_module_t *m, th_dvb_mux_instance_t *tdmi ); + int (*enable) ( void *m, uint8_t e ); }; /* - * Default module functions + * Internal grabber */ +struct epggrab_module_int +{ + epggrab_module_t ; ///< Parent object -int epggrab_module_enable_socket ( epggrab_module_t *m, uint8_t e ); -const char *epggrab_module_socket_path ( const char *id ); + const char *path; ///< Path for the command + epggrab_channel_tree_t *channels; ///< Channel list -char *epggrab_module_grab ( epggrab_module_t *m ); -htsmsg_t *epggrab_module_trans_xml ( epggrab_module_t *m, char *d ); + /* Handle data */ + char* (*grab) ( void *mod ); + htsmsg_t* (*trans) ( void *mod, char *data ); + int (*parse) ( void *mod, htsmsg_t *data, epggrab_stats_t *stat ); -void epggrab_module_channel_save - ( epggrab_module_t *m, epggrab_channel_t *ch ); -void epggrab_module_channels_load ( epggrab_module_t *m ); -void epggrab_module_channel_add ( epggrab_module_t *m, channel_t *ch ); -void epggrab_module_channel_rem ( epggrab_module_t *m, channel_t *ch ); -void epggrab_module_channel_mod ( epggrab_module_t *m, channel_t *ch ); - -epggrab_channel_t *epggrab_module_channel_find - ( epggrab_module_t *mod, const char *id, int create, int *save ); + /* Channel listings */ + void (*ch_add) ( void *m, struct channel *ch ); + void (*ch_rem) ( void *m, struct channel *ch ); + void (*ch_mod) ( void *m, struct channel *ch ); +}; /* - * Module list + * External grabber */ -LIST_HEAD(epggrab_module_list, epggrab_module); -typedef struct epggrab_module_list epggrab_module_list_t; +struct epggrab_module_ext +{ + epggrab_module_int_t ; ///< Parent object + + int sock; ///< Socket descriptor +}; + +/* + * OTA / mux link + */ +struct epggrab_ota_mux +{ + LIST_ENTRY(epggrab_ota_mux) glob_link; ///< Grabber link + TAILQ_ENTRY(epggrab_ota_mux) reg_link; ///< List of reg'd + struct th_dvb_mux_instance *tdmi; ///< Mux instance + epggrab_module_ota_t *grab; ///< Grab instance + + int timeout; ///< Time out if this long + int interval; ///< Re-grab this often + + int is_reg; ///< Registered with mux + + void *status; ///< Status information + enum { + EPGGRAB_OTA_MUX_IDLE, + EPGGRAB_OTA_MUX_RUNNING, + EPGGRAB_OTA_MUX_TIMEDOUT, + EPGGRAB_OTA_MUX_COMPLETE + } state; ///< Current state + time_t started; ///< Time of last start + time_t completed; ///< Time of last completion + + void (*destroy) (epggrab_ota_mux_t *ota); ///< (Custom) destroy +}; + +/* + * Over the air grabber + */ +struct epggrab_module_ota +{ + epggrab_module_t ; ///< Parent object + + /* Transponder tuning */ + void (*start) ( epggrab_module_ota_t *m, struct th_dvb_mux_instance *tdmi ); +}; /* * Access the Module list @@ -157,38 +207,42 @@ epggrab_module_t* epggrab_module_find_by_id ( const char *id ); htsmsg_t* epggrab_module_list ( void ); /* ************************************************************************** - * Configuration + * Setup/Configuration * *************************************************************************/ /* * Configuration */ -extern pthread_mutex_t epggrab_mutex; -extern uint32_t epggrab_interval; -extern epggrab_module_t* epggrab_module; -extern uint32_t epggrab_channel_rename; -extern uint32_t epggrab_channel_renumber; -extern uint32_t epggrab_channel_reicon; +extern epggrab_module_list_t epggrab_modules; +extern pthread_mutex_t epggrab_mutex; +extern uint32_t epggrab_interval; +extern epggrab_module_int_t* epggrab_module; +extern uint32_t epggrab_channel_rename; +extern uint32_t epggrab_channel_renumber; +extern uint32_t epggrab_channel_reicon; /* - * Update + * Set configuration */ int epggrab_set_interval ( uint32_t interval ); -int epggrab_set_module ( epggrab_module_t *module ); +int epggrab_set_module ( epggrab_module_t *mod ); int epggrab_set_module_by_id ( const char *id ); int epggrab_set_channel_rename ( uint32_t e ); int epggrab_set_channel_renumber ( uint32_t e ); int epggrab_set_channel_reicon ( uint32_t e ); -int epggrab_enable_module ( epggrab_module_t *module, uint8_t e ); +int epggrab_enable_module ( epggrab_module_t *mod, uint8_t e ); int epggrab_enable_module_by_id ( const char *id, uint8_t e ); + +/* + * Load/Save + */ +void epggrab_init ( void ); void epggrab_save ( void ); /* ************************************************************************** * Global Functions * *************************************************************************/ -void epggrab_init ( void ); - /* * Channel handling */ @@ -199,6 +253,21 @@ void epggrab_channel_mod ( struct channel *ch ); /* * Transport handling */ -void epggrab_tune ( th_dvb_mux_instance_t *tdmi ); +void epggrab_mux_start ( struct th_dvb_mux_instance *tdmi ); +void epggrab_mux_stop ( struct th_dvb_mux_instance *tdmi, int timeout ); +void epggrab_mux_delete ( struct th_dvb_mux_instance *tdmi ); +int epggrab_mux_period ( struct th_dvb_mux_instance *tdmi ); +struct th_dvb_mux_instance *epggrab_mux_next ( struct th_dvb_adapter *tda ); + +/* + * Re-schedule + */ +void epggrab_resched ( void ); #endif /* __EPGGRAB_H__ */ + +/* ************************************************************************** + * Editor + * + * vim:sts=2:ts=2:sw=2:et + * *************************************************************************/ diff --git a/src/epggrab/channel.c b/src/epggrab/channel.c new file mode 100644 index 00000000..8b3b21eb --- /dev/null +++ b/src/epggrab/channel.c @@ -0,0 +1,275 @@ +/* + * EPG Grabber - channel functions + * Copyright (C) 2012 Adam Sutton + * + * 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 "tvheadend.h" +#include "settings.h" +#include "htsmsg.h" +#include "channels.h" +#include "service.h" +#include "epg.h" +#include "epggrab.h" +#include "epggrab/private.h" + +#if 0 +static int _ch_id_cmp ( void *a, void *b ) +{ + return strcmp(((epggrab_channel_t*)a)->id, + ((epggrab_channel_t*)b)->id); +} +#endif + +int epggrab_channel_link ( epggrab_channel_t *ec, channel_t *ch ) +{ + service_t *sv; + int match = 0, i; + + if (!ec || !ch) return 0; + if (ec->channel) return 0; + + if (ec->name && !strcmp(ec->name, ch->ch_name)) + match = 1; + else { + LIST_FOREACH(sv, &ch->ch_services, s_ch_link) { + if (ec->sid) { + i = 0; + while (ec->sid[i]) { + if (sv->s_dvb_service_id == ec->sid[i]) { + match = 1; + break; + } + i++; + } + } + if (!match && ec->sname) { + i = 0; + while (ec->sname[i]) { + if (!strcmp(ec->sname[i], sv->s_svcname)) { + match = 1; + break; + } + i++; + } + } + if (match) break; + } + } + + if (match) { + tvhlog(LOG_INFO, ec->mod->id, "linking %s to %s", + ec->id, ch->ch_name); + ec->channel = ch; + if (ec->name && epggrab_channel_rename) + channel_rename(ch, ec->name); + if (ec->icon && epggrab_channel_reicon) + channel_set_icon(ch, ec->icon); + if (ec->number>0 && epggrab_channel_renumber) + channel_set_number(ch, ec->number); + } + + return match; +} + +int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name ) +{ + int save = 0; + if (!ec || !name) return 0; + if (!ec->name || strcmp(ec->name, name)) { + if (ec->name) free(ec->name); + ec->name = strdup(name); + if (ec->channel) channel_rename(ec->channel, name); + save = 1; + } + return save; +} + +int epggrab_channel_set_sid + ( epggrab_channel_t *ec, const uint16_t *sid ) +{ +#if 0 + int save = 0, i = 0, num = 0; + if ( !ec || !sid ) return 0; + if (!ec->sid) save = 1; + else { + + for (i = 0; i < num; i++ ) { + if (sid[i] != ec->sid[i]) { + save = 1; + break; + } + } + } + if (save) { + if (ec->sid) free(ec->sid); + ec->sid = calloc(num, sizeof(uint16_t)); + for (i = 0; i < num; i++ ) { + ec->sid[i] = sid[i]; + } + ec->sid_cnt = num; + } + return save; +#endif + return 0; +} + +int epggrab_channel_set_sname ( epggrab_channel_t *ec, const char **sname ) +{ + int save = 0, i = 0; + if ( !ec || !sname ) return 0; + if (!ec->sname) save = 1; + else { + while ( ec->sname[i] && sname[i] ) { + if (strcmp(ec->sname[i], sname[i])) { + save = 1; + break; + } + i++; + } + if (!save && (ec->sname[i] || sname[i])) save = 1; + } + if (save) { + if (ec->sname) { + i = 0; + while (ec->sname[i]) + free(ec->sname[i++]); + free(ec->sname); + } + i = 0; + while (sname[i++]); + ec->sname = calloc(i+1, sizeof(char*)); + i = 0; + while (sname[i]) { + ec->sname[i] = strdup(sname[i]); + i++; + } + } + return save; +} + +int epggrab_channel_set_icon ( epggrab_channel_t *ec, const char *icon ) +{ + int save = 0; + if (!ec->icon || strcmp(ec->icon, icon) ) { + if (!ec | !icon) return 0; + if (ec->icon) free(ec->icon); + ec->icon = strdup(icon); + if (ec->channel) channel_set_icon(ec->channel, icon); + save = 1; + } + return save; +} + +int epggrab_channel_set_number ( epggrab_channel_t *ec, int number ) +{ + int save = 0; + if (!ec || (number <= 0)) return 0; + if (ec->number != number) { + ec->number = number; + if (ec->channel) channel_set_number(ec->channel, number); + save = 1; + } + return save; +} + + +void epggrab_channel_updated ( epggrab_channel_t *ec ) +{ + //epggrab_channel_link(ec); + epggrab_module_ch_save(ec->mod, ec); +} + +#if 0 +void epggrab_channel_link ( epggrab_channel_t *ec ) +{ + channel_t *ch; + + if (!ec) return; + + /* Link */ + if (!ec->channel) { + RB_FOREACH(ch, &channel_name_tree, ch_name_link) { + if (_ch_link(ec, ch)) break; + } + } +} +#endif + +htsmsg_t *epggrab_channel_list ( void ) +{ +#if 0 + char name[100]; + epggrab_module_t *mod; + epggrab_channel_t *ec; + htsmsg_t *e, *m; + m = htsmsg_create_list(); + LIST_FOREACH(mod, &epggrab_modules, link) { + if (mod->enabled && mod->channels) { + RB_FOREACH(ec, mod->channels, link) { + e = htsmsg_create_map(); + htsmsg_add_str(e, "module", mod->id); + htsmsg_add_str(e, "id", ec->id); + sprintf(name, "%s: %s", mod->name, ec->name); + htsmsg_add_str(e, "name", name); + htsmsg_add_msg(m, NULL, e); + } + } + } + return m; +#endif + return NULL; +} + +void epggrab_channel_add ( channel_t *ch ) +{ +#if 0 + epggrab_module_t *m; + LIST_FOREACH(m, &epggrab_modules, link) { + if (m->ch_add) m->ch_add(m, ch); + } +#endif +} + +void epggrab_channel_rem ( channel_t *ch ) +{ +#if 0 + epggrab_module_t *m; + LIST_FOREACH(m, &epggrab_modules, link) { + if (m->ch_rem) m->ch_rem(m, ch); + } +#endif +} + +void epggrab_channel_mod ( channel_t *ch ) +{ +#if 0 + epggrab_module_t *m; + LIST_FOREACH(m, &epggrab_modules, link) { + if (m->ch_mod) m->ch_mod(m, ch); + } +#endif +} + +epggrab_channel_t *epggrab_channel_find + ( epggrab_channel_tree_t *tree, const char *id, int create, int *save ) +{ + // TODO + return NULL; +} + diff --git a/src/epggrab/eit.h b/src/epggrab/eit.h deleted file mode 100644 index c278718b..00000000 --- a/src/epggrab/eit.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Electronic Program Guide - eit grabber - * Copyright (C) 2012 Adam Sutton - * - * 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 EPGGRAB_EIT_H -#define EPGGRAB_EIT_H - -#include "epggrab.h" - -void eit_init ( epggrab_module_list_t *list ); -void eit_load ( void ); - -#endif diff --git a/src/epggrab/module.c b/src/epggrab/module.c new file mode 100644 index 00000000..092f7d99 --- /dev/null +++ b/src/epggrab/module.c @@ -0,0 +1,450 @@ +/* + * EPG Grabber - module functions + * Copyright (C) 2012 Adam Sutton + * + * 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 "tvheadend.h" +#include "settings.h" +#include "htsmsg.h" +#include "htsmsg_xml.h" +#include "service.h" +#include "channels.h" +#include "spawn.h" +#include "file.h" +#include "epg.h" +#include "epggrab.h" +#include "epggrab/private.h" + +/* ************************************************************************** + * Generic module routines + * *************************************************************************/ + +epggrab_module_t *epggrab_module_create + ( epggrab_module_t *skel, const char *id, const char *name ) +{ + assert(skel); + + /* Setup */ + skel->id = strdup(id); + skel->name = strdup(name); + + /* Insert */ + assert(!epggrab_module_find_by_id(id)); + LIST_INSERT_HEAD(&epggrab_modules, skel, link); + + return skel; +} + +/* ************************************************************************** + * Channel related routines + * *************************************************************************/ + +void epggrab_module_ch_save ( void *_m, epggrab_channel_t *ch ) +{ + int i; + htsmsg_t *m = htsmsg_create_map(); + htsmsg_t *a; + epggrab_module_t *mod = _m; + + if (ch->name) + htsmsg_add_str(m, "name", ch->name); + if (ch->icon) + htsmsg_add_str(m, "icon", ch->icon); + if (ch->channel) + htsmsg_add_u32(m, "channel", ch->channel->ch_id); + if (ch->sid) { + a = htsmsg_create_list(); + i = 0; + while (ch->sid[i]) { + htsmsg_add_u32(a, NULL, ch->sid[i]); + i++; + } + htsmsg_add_msg(m, "sid", a); + } + if (ch->sname) { + a = htsmsg_create_list(); + i = 0; + while (ch->sname[i]) { + htsmsg_add_str(a, NULL, ch->sname[i]); + i++; + } + htsmsg_add_msg(m, "sname", a); + } + if (ch->number) + htsmsg_add_u32(m, "number", ch->number); + + hts_settings_save(m, "epggrab/%s/channels/%s", mod->id, ch->id); +} + +void epggrab_module_ch_add ( void *m, channel_t *ch ) +{ + epggrab_channel_t *egc; + epggrab_module_int_t *mod = m; + RB_FOREACH(egc, mod->channels, link) { + if (epggrab_channel_link(egc, ch)) { + epggrab_module_ch_save(mod, egc); + break; + } + } +} + +void epggrab_module_ch_rem ( void *m, channel_t *ch ) +{ + epggrab_channel_t *egc; + epggrab_module_int_t *mod = m; + RB_FOREACH(egc, mod->channels, link) { + if (egc->channel == ch) { + egc->channel = NULL; + epggrab_module_ch_save(mod, egc); + break; + } + } +} + +void epggrab_module_ch_mod ( void *mod, channel_t *ch ) +{ + return epggrab_module_ch_add(mod, ch); +} + + +#if 0 + +static void epggrab_module_ch_load + ( epggrab_module_t *mod, htsmsg_t *m, const char *id ) +{ + int save = 0, i; + const char *str; + uint32_t u32; + htsmsg_t *a; + htsmsg_field_t *f; + + epggrab_channel_t *ch = epggrab_module_channel_find(mod, id, 1, &save); + + if ((str = htsmsg_get_str(m, "name"))) + ch->name = strdup(str); + if ((str = htsmsg_get_str(m, "icon"))) + ch->icon = strdup(str); + if ((a = htsmsg_get_list(m, "sid"))) { + i = 0; + HTSMSG_FOREACH(f, a) i++; + ch->sid_cnt = i; + ch->sid = calloc(i, sizeof(uint16_t)); + i = 0; + HTSMSG_FOREACH(f, a) { + ch->sid[i] = (uint16_t)f->hmf_s64; + i++; + } + } + if ((a = htsmsg_get_list(m, "sname"))) { + i = 0; + HTSMSG_FOREACH(f, a) i++; + ch->sname = calloc(i+1, sizeof(char*)); + i = 0; + HTSMSG_FOREACH(f, a) { + ch->sname[i] = strdup(f->hmf_str); + i++; + } + } + if(!htsmsg_get_u32(m, "number", &u32)) + ch->number = u32; + + if (!htsmsg_get_u32(m, "channel", &u32)) + ch->channel = channel_find_by_identifier(u32); +} + +void epggrab_module_channels_load ( epggrab_module_t *mod ) +{ + htsmsg_t *m, *e; + htsmsg_field_t *f; + + if ((m = hts_settings_load("epggrab/%s/channels", mod->id))) { + HTSMSG_FOREACH(f, m) { + if ((e = htsmsg_get_map_by_field(f))) + epggrab_module_channel_load(mod, e, f->hmf_name); + } + htsmsg_destroy(m); + } +} + +epggrab_channel_t *epggrab_module_ch_find + ( epggrab_module_t *mod, const char *id, int create, int *save ) +{ + epggrab_channel_t *ec; + static epggrab_channel_t *skel = NULL; + + if (!mod || !mod->channels ) return NULL; + + if ( !skel ) skel = calloc(1, sizeof(epggrab_channel_t)); + skel->id = (char*)id; + skel->mod = mod; + + /* Find */ + if (!create) { + ec = RB_FIND(mod->channels, skel, link, _ch_id_cmp); + + /* Create (if required) */ + } else { + ec = RB_INSERT_SORTED(mod->channels, skel, link, _ch_id_cmp); + if ( ec == NULL ) { + skel->id = strdup(skel->id); + ec = skel; + skel = NULL; + *save = 1; + } + } + + return ec; +} +#endif + +/* ************************************************************************** + * Internal module routines + * *************************************************************************/ + +epggrab_module_int_t *epggrab_module_int_create + ( epggrab_module_int_t *skel, + const char *id, const char *name, const char *path, + char* (*grab) (void*m), + int (*parse) (void *m, htsmsg_t *data, epggrab_stats_t *sta), + htsmsg_t* (*trans) (void *mod, char *data), + epggrab_channel_tree_t *channels ) +{ + /* Allocate data */ + if (!skel) skel = calloc(1, sizeof(epggrab_module_int_t)); + + /* Pass through */ + epggrab_module_create((epggrab_module_t*)skel, id, name); + + /* Int data */ + skel->type = EPGGRAB_INT; + skel->path = strdup(path); + skel->channels = channels; + skel->grab = grab ?: epggrab_module_grab_spawn; + skel->trans = trans ?: epggrab_module_trans_xml; + skel->parse = parse; + if (channels) { + skel->ch_add = epggrab_module_ch_add; + skel->ch_rem = epggrab_module_ch_rem; + skel->ch_mod = epggrab_module_ch_mod; + } + + return skel; +} + +char *epggrab_module_grab_spawn ( void *m ) +{ + int outlen; + char *outbuf; + epggrab_module_int_t *mod = m; + + /* Debug */ + tvhlog(LOG_INFO, mod->id, "grab %s", mod->path); + + /* Grab */ + outlen = spawn_and_store_stdout(mod->path, NULL, &outbuf); + if ( outlen < 1 ) { + tvhlog(LOG_ERR, "pyepg", "no output detected"); + return NULL; + } + + return outbuf; +} + + + +htsmsg_t *epggrab_module_trans_xml ( void *m, char *c ) +{ + htsmsg_t *ret; + char errbuf[100]; + + if (!c) return NULL; + + /* Extract */ + ret = htsmsg_xml_deserialize(c, errbuf, sizeof(errbuf)); + if (!ret) + tvhlog(LOG_ERR, "pyepg", "htsmsg_xml_deserialize error %s", errbuf); + return ret; +} + +/* ************************************************************************** + * External module routines + * *************************************************************************/ + +/* + * Socket handler + */ +static void _epggrab_socket_handler ( epggrab_module_ext_t *mod, int s ) +{ + size_t outlen; + char *outbuf; + time_t tm1, tm2; + htsmsg_t *data = NULL; + + /* Grab/Translate */ + time(&tm1); + outlen = file_readall(s, &outbuf); + if (outlen) data = mod->trans(mod, outbuf); + time(&tm2); + + /* Process */ + if ( data ) { + tvhlog(LOG_INFO, mod->id, "grab took %d seconds", tm2 - tm1); + epggrab_module_parse(mod, data); + + /* Failed */ + } else { + tvhlog(LOG_ERR, mod->id, "failed to read data"); + } +} + + +/* + * External (socket) grab thread + */ +static void *_epggrab_socket_thread ( void *p ) +{ + int s; + epggrab_module_ext_t *mod = (epggrab_module_ext_t*)p; + tvhlog(LOG_INFO, mod->id, "external socket enabled"); + + while ( mod->enabled && mod->sock ) { + tvhlog(LOG_DEBUG, mod->id, "waiting for connection"); + s = accept(mod->sock, NULL, NULL); + if (s <= 0) continue; + tvhlog(LOG_DEBUG, mod->id, "got connection %d", s); + _epggrab_socket_handler(mod, s); + } + tvhlog(LOG_DEBUG, mod->id, "terminated"); + return NULL; +} + +/* + * Enable socket module + */ +int epggrab_module_enable_socket ( void *m, uint8_t e ) +{ + pthread_t tid; + pthread_attr_t tattr; + struct sockaddr_un addr; + epggrab_module_ext_t *mod = (epggrab_module_ext_t*)m; + assert(mod->type == EPGGRAB_EXT); + + /* Ignore */ + if ( mod->enabled == e ) return 0; + + /* Disable */ + if (!e) { + shutdown(mod->sock, SHUT_RDWR); + close(mod->sock); + unlink(mod->path); + mod->sock = 0; + + /* Enable */ + } else { + unlink(mod->path); // just in case! + + mod->sock = socket(AF_UNIX, SOCK_STREAM, 0); + assert(mod->sock); + + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, mod->path, 100); + if ( bind(mod->sock, (struct sockaddr*)&addr, + sizeof(struct sockaddr_un)) != 0 ) { + tvhlog(LOG_ERR, mod->id, "failed to bind socket"); + close(mod->sock); + mod->sock = 0; + return 0; + } + + if ( listen(mod->sock, 5) != 0 ) { + tvhlog(LOG_ERR, mod->id, "failed to listen on socket"); + close(mod->sock); + mod->sock = 0; + return 0; + } + + tvhlog(LOG_DEBUG, mod->id, "starting socket thread"); + pthread_attr_init(&tattr); + pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + pthread_create(&tid, &tattr, _epggrab_socket_thread, mod); + } + mod->enabled = e; + return 1; +} + +/* + * Create a module + */ +epggrab_module_ext_t *epggrab_module_ext_create + ( epggrab_module_ext_t *skel, + const char *id, const char *name, const char *sockid, + int (*parse) (void *m, htsmsg_t *data, epggrab_stats_t *sta), + htsmsg_t* (*trans) (void *mod, char *data), + epggrab_channel_tree_t *channels ) +{ + char path[512]; + + /* Allocate data */ + if (!skel) skel = calloc(1, sizeof(epggrab_module_ext_t)); + + /* Pass through */ + snprintf(path, 512, "%s/epggrab/%s.sock", + hts_settings_get_root(), sockid); + epggrab_module_int_create((epggrab_module_int_t*)skel, + id, name, path, + NULL, parse, trans, + channels); + + /* Local */ + skel->type = EPGGRAB_EXT; + skel->enable = epggrab_module_enable_socket; + + return skel; +} + +/* ************************************************************************** + * OTA module functions + * *************************************************************************/ + +epggrab_module_ota_t *epggrab_module_ota_create + ( epggrab_module_ota_t *skel, + const char *id, const char *name, + void (*start) (epggrab_module_ota_t*m, + struct th_dvb_mux_instance *tdmi), + int (*enable) (void *m, uint8_t e ), + epggrab_channel_tree_t *channels ) +{ + if (!skel) skel = calloc(1, sizeof(epggrab_module_ota_t)); + + /* Pass through */ + epggrab_module_create((epggrab_module_t*)skel, id, name); + + /* Setup */ + skel->type = EPGGRAB_OTA; + skel->enable = enable; + skel->start = start; + + return skel; +} + diff --git a/src/epggrab/eit.c b/src/epggrab/module/eit.c similarity index 86% rename from src/epggrab/eit.c rename to src/epggrab/module/eit.c index 5c182918..502048ed 100644 --- a/src/epggrab/eit.c +++ b/src/epggrab/module/eit.c @@ -23,9 +23,18 @@ #include "dvb/dvb_support.h" #include "service.h" #include "epg.h" -#include "epggrab/eit.h" +#include "epggrab.h" +#include "epggrab/private.h" -static epggrab_module_t _eit_mod; +/* ************************************************************************ + * Status handling + * ***********************************************************************/ + +typedef struct eit_status +{ + int tid; + int sec; +} eit_status_t; /* ************************************************************************ * Processing @@ -112,12 +121,13 @@ static int _eit_callback ( th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, uint8_t tableid, void *opaque ) { - th_dvb_mux_instance_t *otdmi = tdmi; + epggrab_ota_mux_t *ota = (epggrab_ota_mux_t*)opaque; th_dvb_adapter_t *tda; service_t *svc; channel_t *ch; epg_broadcast_t *ebc; epg_episode_t *ee; + eit_status_t *sta; int resched = 0, save = 0, save2 = 0, dllen, dtag, dlen; uint16_t tsid, sid, eid; uint8_t bw, hd, ws, ad, ds, st; @@ -129,14 +139,26 @@ static int _eit_callback char desc[5000]; htsmsg_t *extra; - /* Disabled */ - if(!_eit_mod.enabled) return 0; - /* Invalid */ if(tableid < 0x4e || tableid > 0x6f || len < 11) return -1; - /* Skip */ + /* Already complete */ + if (epggrab_ota_is_complete(ota)) return 0; + + /* Started */ + sta = ota->status; + if (epggrab_ota_begin(ota)) { + sta->tid = tableid; + sta->sec = ptr[3]; + + /* Complete */ + } else if (sta->tid == tableid && sta->sec == ptr[3]) { + epggrab_ota_complete(ota); + return 0; + } + + /* Don't process */ if((ptr[2] & 1) == 0) return 0; @@ -162,12 +184,12 @@ static int _eit_callback /* Ignore (disabled) */ if (!svc->s_dvb_eit_enable) return 0; - /* Register interest */ + /* Register as interesting */ if (tableid < 0x50) - epggrab_ota_register(&_eit_mod, otdmi, 20, 0); + epggrab_ota_register(ota, 20, 0); else - epggrab_ota_register(&_eit_mod, otdmi, 40, 0); - + epggrab_ota_register(ota, 40, 0); + /* Up to date */ #if TODO_INCLUDE_EIT_VER_CHECK ver = ptr[2] >> 1 & 0x1f; @@ -198,7 +220,7 @@ static int _eit_callback continue; } - /* Mark re-schedule detect */ + /* Mark re-schedule detect (only now/next) */ if (save2 && tableid < 0x50) resched = 1; /* Process tags */ @@ -346,9 +368,8 @@ static int _eit_callback } /* Update EPG */ - if (resched) tvhlog(LOG_DEBUG, "eit", "alert grabbers to resched"); - // TODO: handle the reschedule - if (save) epg_updated(); + if (resched) epggrab_resched(); + if (save) epg_updated(); return 0; } @@ -357,19 +378,21 @@ static int _eit_callback * Module Setup * ***********************************************************************/ -static void _eit_tune ( epggrab_module_t *m, th_dvb_mux_instance_t *tdmi ) +static void _eit_start + ( epggrab_module_ota_t *m, th_dvb_mux_instance_t *tdmi ) { - if (_eit_mod.enabled) - tdt_add(tdmi, NULL, _eit_callback, NULL, "eit", TDT_CRC, 0x12, NULL); + epggrab_ota_mux_t *ota; + if (!m->enabled) return; + if (!(ota = epggrab_ota_create(m, tdmi))) return; + if (!ota->status) + ota->status = calloc(1, sizeof(eit_status_t)); + tdt_add(tdmi, NULL, _eit_callback, ota, "eit", TDT_CRC, 0x12, NULL); } -void eit_init ( epggrab_module_list_t *list ) +void eit_init ( void ) { - _eit_mod.id = strdup("eit"); - _eit_mod.name = strdup("EIT: On-Air Grabber"); - _eit_mod.tune = _eit_tune; - *((uint8_t*)&_eit_mod.flags) = EPGGRAB_MODULE_OTA; - LIST_INSERT_HEAD(list, &_eit_mod, link); + epggrab_module_ota_create(NULL, "eit", "EIT: DVB Grabber", + _eit_start, NULL, NULL); } void eit_load ( void ) diff --git a/src/epggrab/opentv.c b/src/epggrab/module/opentv.c similarity index 74% rename from src/epggrab/opentv.c rename to src/epggrab/module/opentv.c index 40b38f4f..71b98222 100644 --- a/src/epggrab/opentv.c +++ b/src/epggrab/module/opentv.c @@ -25,8 +25,8 @@ #include "channels.h" #include "huffman.h" #include "epg.h" -#include "epggrab/ota.h" -#include "epggrab/opentv.h" +#include "epggrab.h" +#include "epggrab/private.h" #include "subscriptions.h" #include "streaming.h" #include "service.h" @@ -35,10 +35,61 @@ static epggrab_channel_tree_t _opentv_channels; -static void _opentv_tune - ( epggrab_module_t *m, th_dvb_mux_instance_t *tdmi ); -static int _opentv_enable - ( epggrab_module_t *m, uint8_t e ); +/* ************************************************************************ + * Status monitoring + * ***********************************************************************/ + +/* Internal event structure */ +typedef struct opentv_event +{ + RB_ENTRY(opentv_event) ev_link; ///< List of partial events + uint16_t cid; ///< Channel ID + uint16_t eid; ///< Events ID + time_t start; ///< Start time + time_t stop; ///< Event stop time + char *title; ///< Event title + char *summary; ///< Event summary + char *desc; ///< Event description + uint8_t cat; ///< Event category + uint16_t series; ///< Series (link) reference + + uint8_t type; ///< 0x1=title, 0x2=summary +} opentv_event_t; + +typedef struct opentv_pid_status +{ + LIST_ENTRY(opentv_pid_status) link; + int pid; + enum { + OPENTV_PID_INIT, + OPENTV_PID_STARTED, + OPENTV_PID_COMPLETE + } state; + uint8_t start[20]; +} opentv_pid_status_t; + +typedef struct opentv_status +{ + int begbat; + int endbat; + LIST_HEAD(, opentv_pid_status) pids; + RB_HEAD(, opentv_event) events; +} opentv_status_t; + +static opentv_pid_status_t *_opentv_get_pid_status + ( opentv_status_t *sta, int pid ) +{ + opentv_pid_status_t *p; + LIST_FOREACH(p, &sta->pids, link) { + if (p->pid == pid) break; + } + if (!p) { + p = calloc(1, sizeof(opentv_pid_status_t)); + p->pid = pid; + LIST_INSERT_HEAD(&sta->pids, p, link); + } + return p; +} /* ************************************************************************ * Data structures @@ -47,19 +98,6 @@ static int _opentv_enable #define OPENTV_SCAN_MAX 600 // 10min max scan period #define OPENTV_SCAN_PER 3600 // 1hour interval -/* Data carousel status */ -typedef struct opentv_status -{ - LIST_ENTRY(opentv_status) link; - int pid; - enum { - OPENTV_STA_INIT, - OPENTV_STA_STARTED, - OPENTV_STA_COMPLETE - } status; - uint8_t start[20]; -} opentv_status_t; - /* Huffman dictionary */ typedef struct opentv_dict { @@ -80,10 +118,6 @@ typedef struct opentv_module_t int *title; int *summary; opentv_dict_t *dict; - - int endbat; - int begbat; - LIST_HEAD(, opentv_status) status; } opentv_module_t; @@ -108,6 +142,7 @@ static opentv_dict_t *_opentv_dict_find ( const char *id ) * Module functions * ***********************************************************************/ +#if 0 static opentv_status_t *_opentv_module_get_status ( opentv_module_t *mod, int pid ) { @@ -121,133 +156,7 @@ static opentv_status_t *_opentv_module_get_status } return sta; } - -/* ************************************************************************ - * Configuration loading - * ***********************************************************************/ - -static int* _pid_list_to_array ( htsmsg_t *m, opentv_module_t *mod ) -{ - int i = 1; - int *ret; - htsmsg_field_t *f; - HTSMSG_FOREACH(f, m) - if (f->hmf_s64) i++; - ret = calloc(i, sizeof(int)); - i = 0; - HTSMSG_FOREACH(f, m) - if (f->hmf_s64) { - ret[i] = (int)f->hmf_s64; - if (mod) (void)_opentv_module_get_status(mod, ret[i]); - i++; - } - return ret; -} - -static int _opentv_dict_load_one ( const char *id, htsmsg_t *m ) -{ - opentv_dict_t *dict = calloc(1, sizeof(opentv_dict_t)); - dict->id = (char*)id; - if (RB_INSERT_SORTED(&_opentv_dicts, dict, h_link, _dict_cmp)) { - tvhlog(LOG_DEBUG, "opentv", "ignore duplicate dictionary %s", id); - free(dict); - return 0; - } else { - dict->codes = huffman_tree_build(m); - if (!dict->codes) { - RB_REMOVE(&_opentv_dicts, dict, h_link); - free(dict); - return -1; - } else { - dict->id = strdup(id); - return 1; - } - } -} - -static void _opentv_dict_load ( htsmsg_t *m ) -{ - int r; - htsmsg_t *e; - htsmsg_field_t *f; - HTSMSG_FOREACH(f, m) { - if ((e = htsmsg_get_list(m, f->hmf_name))) { - if ((r = _opentv_dict_load_one(f->hmf_name, e))) { - if (r > 0) - tvhlog(LOG_INFO, "opentv", "dictionary %s loaded", f->hmf_name); - else - tvhlog(LOG_WARNING, "opentv", "dictionary %s failed", f->hmf_name); - } - } - } - htsmsg_destroy(m); -} - -static int _opentv_prov_load_one - ( const char *id, htsmsg_t *m, epggrab_module_list_t *list ) -{ - char buf[100]; - htsmsg_t *cl, *tl, *sl; - uint32_t tsid, sid, nid; - const char *str, *name; - opentv_dict_t *dict; - static opentv_module_t *mod = NULL; - - /* Check config */ - if (!(name = htsmsg_get_str(m, "name"))) return -1; - if (!(str = htsmsg_get_str(m, "dict"))) return -1; - if (!(dict = _opentv_dict_find(str))) return -1; - if (!(cl = htsmsg_get_list(m, "channel"))) return -1; - if (!(tl = htsmsg_get_list(m, "title"))) return -1; - if (!(sl = htsmsg_get_list(m, "summary"))) return -1; - if (htsmsg_get_u32(m, "nid", &nid)) return -1; - if (htsmsg_get_u32(m, "tsid", &tsid)) return -1; - if (htsmsg_get_u32(m, "sid", &sid)) return -1; - - /* Exists */ - sprintf(buf, "opentv-%s", id); - if (epggrab_module_find_by_id(buf)) return 0; - - /* Create module */ - mod = calloc(1, sizeof(opentv_module_t)); - mod->id = strdup(buf); - sprintf(buf, "OpenTV: %s", name); - mod->name = strdup(buf); - mod->enable = _opentv_enable; - mod->tune = _opentv_tune; - mod->channels = &_opentv_channels; - *((uint8_t*)&mod->flags) = EPGGRAB_MODULE_OTA; - LIST_INSERT_HEAD(list, ((epggrab_module_t*)mod), link); - - /* Add provider details */ - mod->dict = dict; - mod->nid = nid; - mod->tsid = tsid; - mod->sid = sid; - mod->channel = _pid_list_to_array(cl, NULL); - mod->title = _pid_list_to_array(tl, mod); - mod->summary = _pid_list_to_array(sl, mod); - - return 1; -} - -static void _opentv_prov_load ( htsmsg_t *m, epggrab_module_list_t *list ) -{ - int r; - htsmsg_t *e; - htsmsg_field_t *f; - HTSMSG_FOREACH(f, m) { - if ((e = htsmsg_get_map_by_field(f))) { - if ((r = _opentv_prov_load_one(f->hmf_name, e, list))) { - if (r > 0) - tvhlog(LOG_INFO, "opentv", "provider %s loaded", f->hmf_name); - else - tvhlog(LOG_WARNING, "opentv", "provider %s failed", f->hmf_name); - } - } - } - htsmsg_destroy(m); -} +#endif /* ************************************************************************ * EPG Object wrappers @@ -256,9 +165,9 @@ static void _opentv_prov_load ( htsmsg_t *m, epggrab_module_list_t *list ) static epggrab_channel_t *_opentv_find_epggrab_channel ( opentv_module_t *mod, int cid, int create, int *save ) { - char chid[32]; - sprintf(chid, "%s-%d", mod->id, cid); - return epggrab_module_channel_find((epggrab_module_t*)mod, chid, create, save); +// char chid[32]; +// sprintf(chid, "%s-%d", mod->id, cid); + return NULL;//return epggrab_module_channel_find((epggrab_module_t*)mod, chid, create, save); } static epg_season_t *_opentv_find_season @@ -303,26 +212,6 @@ static channel_t *_opentv_find_channel ( int tsid, int sid ) #define OPENTV_TITLE 0x01 #define OPENTV_SUMMARY 0x02 -/* Internal event structure */ -typedef struct opentv_event -{ - RB_ENTRY(opentv_event) ev_link; ///< List of partial events - uint16_t cid; ///< Channel ID - uint16_t eid; ///< Events ID - time_t start; ///< Start time - time_t stop; ///< Event stop time - char *title; ///< Event title - char *summary; ///< Event summary - char *desc; ///< Event description - uint8_t cat; ///< Event category - uint16_t series; ///< Series (link) reference - - uint8_t type; ///< 0x1=title, 0x2=summary -} opentv_event_t; - -/* List of partial events */ -RB_HEAD(, opentv_event) _opentv_events; - /* Event list comparator */ static int _ev_cmp ( void *_a, void *_b ) { @@ -399,7 +288,8 @@ static int _opentv_parse_event_record /* Parse a specific event */ static int _opentv_parse_event - ( opentv_module_t *prov, uint8_t *buf, int len, int cid, time_t mjd, + ( opentv_module_t *prov, opentv_status_t *sta, + uint8_t *buf, int len, int cid, time_t mjd, opentv_event_t *ev, int type ) { int slen = ((int)buf[2] & 0xf << 8) | buf[3]; @@ -410,9 +300,9 @@ static int _opentv_parse_event ev->eid = ((uint16_t)buf[0] << 8) | buf[1]; /* Get existing summary */ - e = RB_FIND(&_opentv_events, ev, ev_link, _ev_cmp); + e = RB_FIND(&sta->events, ev, ev_link, _ev_cmp); if (e) { - RB_REMOVE(&_opentv_events, e, ev_link); + RB_REMOVE(&sta->events, e, ev_link); memcpy(ev, e, sizeof(opentv_event_t)); free(e); } @@ -427,7 +317,8 @@ static int _opentv_parse_event /* Parse an event section */ static int _opentv_parse_event_section - ( opentv_module_t *mod, uint8_t *buf, int len, int type ) + ( opentv_module_t *mod, opentv_status_t *sta, + uint8_t *buf, int len, int type ) { int i, cid, save = 0; time_t mjd; @@ -452,7 +343,7 @@ static int _opentv_parse_event_section i = 7; while (i < len) { memset(&ev, 0, sizeof(opentv_event_t)); - i += _opentv_parse_event(mod, buf+i, len-i, cid, mjd, &ev, type); + i += _opentv_parse_event(mod, sta, buf+i, len-i, cid, mjd, &ev, type); /* Find broadcast */ if (ev.type & OPENTV_TITLE) { @@ -465,7 +356,7 @@ static int _opentv_parse_event_section if (!ebc) { opentv_event_t *skel = malloc(sizeof(opentv_event_t)); memcpy(skel, &ev, sizeof(opentv_event_t)); - assert(!RB_INSERT_SORTED(&_opentv_events, skel, ev_link, _ev_cmp)); + assert(!RB_INSERT_SORTED(&sta->events, skel, ev_link, _ev_cmp)); continue; // don't want to free() anything } } @@ -561,7 +452,7 @@ static int _opentv_parse_ts_desc } static int _opentv_bat_section - ( opentv_module_t *mod, uint8_t *buf, int len ) + ( opentv_module_t *mod, opentv_status_t *sta, uint8_t *buf, int len ) { int i, r; int bdlen, tllen, tdlen; @@ -579,10 +470,10 @@ static int _opentv_bat_section // Note: this is NOT the most robust of approaches, but it works // most of the time i = 0x80000000 | (bid << 8) | sec; - if (!mod->begbat) { - mod->begbat = i; - } else if (mod->begbat == i) { - mod->endbat = 1; + if (!sta->begbat) { + sta->begbat = i; + } else if (sta->begbat == i) { + sta->endbat = 1; return 0; } @@ -621,36 +512,27 @@ static int _opentv_bat_section * Table Callbacks * ***********************************************************************/ -static opentv_module_t *_opentv_table_callback +static epggrab_ota_mux_t *_opentv_table_callback ( th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len, uint8_t tid, void *p ) { th_dvb_table_t *tdt = (th_dvb_table_t*)p; - opentv_module_t *mod = (opentv_module_t*)tdt->tdt_opaque; - epggrab_ota_mux_t *ota; - opentv_status_t *sta; + epggrab_ota_mux_t *ota = tdt->tdt_opaque; + opentv_status_t *sta = ota->status; + opentv_pid_status_t *pid; - /* Ignore BAT not complete */ - if (!mod->endbat) return NULL; - /* Ignore (not enough data) */ if (len < 20) return NULL; - /* Register */ - ota = epggrab_ota_register((epggrab_module_t*)mod, tdmi, - OPENTV_SCAN_MAX, OPENTV_SCAN_PER); - if (!ota) return NULL; - /* Finished / Blocked */ if (epggrab_ota_is_complete(ota)) return NULL; - if (epggrab_ota_is_blocked(ota)) return NULL; /* Begin (reset state) */ if (epggrab_ota_begin(ota)) { opentv_event_t *ev; /* Remove outstanding event data */ - while ((ev = RB_FIRST(&_opentv_events))) { - RB_REMOVE(&_opentv_events, ev, ev_link); + while ((ev = RB_FIRST(&sta->events))) { + RB_REMOVE(&sta->events, ev, ev_link); if (ev->title) free(ev->title); if (ev->desc) free(ev->desc); if (ev->summary) free(ev->summary); @@ -658,34 +540,34 @@ static opentv_module_t *_opentv_table_callback } /* Reset status */ - LIST_FOREACH(sta, &mod->status, link) - sta->status = OPENTV_STA_INIT; + LIST_FOREACH(pid, &sta->pids, link) + pid->state = OPENTV_PID_INIT; } /* Insert/Find */ - sta = _opentv_module_get_status(mod, tdt->tdt_pid); + pid = _opentv_get_pid_status(sta, tdt->tdt_pid); /* Begin PID */ - if (sta->status == OPENTV_STA_INIT) { - sta->status = OPENTV_STA_STARTED; - memcpy(sta->start, buf, 20); - return mod; + if (pid->state == OPENTV_PID_INIT) { + pid->state = OPENTV_PID_STARTED; + memcpy(pid->start, buf, 20); + return ota; /* PID Already complete */ - } else if (sta->status == OPENTV_STA_COMPLETE) { + } else if (pid->state == OPENTV_PID_COMPLETE) { return NULL; /* End PID */ - } else if (!memcmp(sta->start, buf, 20)) { - sta->status = OPENTV_STA_COMPLETE; + } else if (!memcmp(pid->start, buf, 20)) { + pid->state = OPENTV_PID_COMPLETE; /* Check rest */ - LIST_FOREACH(sta, &mod->status, link) - if (sta->status != OPENTV_STA_COMPLETE) return mod; + LIST_FOREACH(pid, &sta->pids, link) + if (pid->state != OPENTV_PID_COMPLETE) return ota; /* PID in progress */ } else { - return mod; + return ota; } /* Mark complete */ @@ -697,91 +579,115 @@ static opentv_module_t *_opentv_table_callback static int _opentv_title_callback ( th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len, uint8_t tid, void *p ) { - opentv_module_t *mod = _opentv_table_callback(tdmi, buf, len, tid, p); - if (mod) - return _opentv_parse_event_section(mod, buf, len, OPENTV_TITLE); + epggrab_ota_mux_t *ota = _opentv_table_callback(tdmi, buf, len, tid, p); + if (ota) + return _opentv_parse_event_section((opentv_module_t*)ota->grab, + (opentv_status_t*)ota->status, + buf, len, OPENTV_TITLE); return 0; } static int _opentv_summary_callback ( th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len, uint8_t tid, void *p ) { - opentv_module_t *mod = _opentv_table_callback(tdmi, buf, len, tid, p); - if (mod) - return _opentv_parse_event_section(mod, buf, len, OPENTV_SUMMARY); + epggrab_ota_mux_t *ota = _opentv_table_callback(tdmi, buf, len, tid, p); + if (ota) + return _opentv_parse_event_section((opentv_module_t*)ota->grab, + (opentv_status_t*)ota->status, + buf, len, OPENTV_SUMMARY); return 0; } static int _opentv_channel_callback ( th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len, uint8_t tid, void *p ) { - opentv_module_t *mod = (opentv_module_t*)p; - if (!mod->endbat) - return _opentv_bat_section(mod, buf, len); + epggrab_ota_mux_t *ota = (epggrab_ota_mux_t*)p; + opentv_status_t *sta = ota->status; + if (!sta->endbat) + return _opentv_bat_section((opentv_module_t*)ota->grab, sta, buf, len); return 0; } /* ************************************************************************ - * Module Setup + * Module callbacks * ***********************************************************************/ -static void _opentv_tune ( epggrab_module_t *m, th_dvb_mux_instance_t *tdmi ) +static void _opentv_ota_destroy ( epggrab_ota_mux_t *ota ) +{ + // TODO +} + +static void _opentv_start + ( epggrab_module_ota_t *m, th_dvb_mux_instance_t *tdmi ) { int *t; struct dmx_sct_filter_params *fp; + epggrab_ota_mux_t *ota; opentv_module_t *mod = (opentv_module_t*)m; + opentv_status_t *sta; + + /* Ignore */ + if (!m->enabled) return; + if (mod->tsid != tdmi->tdmi_transport_stream_id) return; + + /* Create link */ + if (!(ota = epggrab_ota_create(m, tdmi))) return; + if (!ota->status) { + ota->status = calloc(1, sizeof(opentv_status_t)); + ota->destroy = _opentv_ota_destroy; + } + sta = ota->status; + sta->begbat = sta->endbat = 0; + + /* Register interest (we're always interested in this mux) */ + epggrab_ota_register(ota, OPENTV_SCAN_MAX, OPENTV_SCAN_PER); /* Install tables */ - if (m->enabled && (mod->tsid == tdmi->tdmi_transport_stream_id)) { - tvhlog(LOG_INFO, "opentv", "install provider %s tables", mod->id); + tvhlog(LOG_INFO, "opentv", "install provider %s tables", mod->id); - /* Channels */ - t = mod->channel; - while (*t) { - fp = dvb_fparams_alloc(); - fp->filter.filter[0] = 0x4a; - fp->filter.mask[0] = 0xff; - // TODO: what about 0x46 (service description) - tdt_add(tdmi, fp, _opentv_channel_callback, mod, - m->id, TDT_CRC, *t++, NULL); - } + /* Channels */ + t = mod->channel; + while (*t) { + fp = dvb_fparams_alloc(); + fp->filter.filter[0] = 0x4a; + fp->filter.mask[0] = 0xff; + // TODO: what about 0x46 (service description) + tdt_add(tdmi, fp, _opentv_channel_callback, mod, + m->id, TDT_CRC, *t++, NULL); + } - /* Titles */ - t = mod->title; - while (*t) { - fp = dvb_fparams_alloc(); - fp->filter.filter[0] = 0xa0; - fp->filter.mask[0] = 0xfc; - tdt_add(tdmi, fp, _opentv_title_callback, mod, - m->id, TDT_CRC | TDT_TDT, *t++, NULL); - } + /* Titles */ + t = mod->title; + while (*t) { + fp = dvb_fparams_alloc(); + fp->filter.filter[0] = 0xa0; + fp->filter.mask[0] = 0xfc; + tdt_add(tdmi, fp, _opentv_title_callback, mod, + m->id, TDT_CRC | TDT_TDT, *t++, NULL); + } - /* Summaries */ - t = mod->summary; - while (*t) { - fp = dvb_fparams_alloc(); - fp->filter.filter[0] = 0xa8; - fp->filter.mask[0] = 0xfc; - tdt_add(tdmi, fp, _opentv_summary_callback, mod, - m->id, TDT_CRC | TDT_TDT, *t++, NULL); - } - - /* Must rebuild the BAT */ - mod->begbat = mod->endbat = 0; + /* Summaries */ + t = mod->summary; + while (*t) { + fp = dvb_fparams_alloc(); + fp->filter.filter[0] = 0xa8; + fp->filter.mask[0] = 0xfc; + tdt_add(tdmi, fp, _opentv_summary_callback, mod, + m->id, TDT_CRC | TDT_TDT, *t++, NULL); } } -static int _opentv_enable ( epggrab_module_t *m, uint8_t e ) +static int _opentv_enable ( void *m, uint8_t e ) { - th_dvb_adapter_t *tda; - th_dvb_mux_instance_t *tdmi; + //th_dvb_adapter_t *tda; + //th_dvb_mux_instance_t *tdmi; opentv_module_t *mod = (opentv_module_t*)m; - if (m->enabled == e) return 0; + if (mod->enabled == e) return 0; + mod->enabled = e; - m->enabled = e; - - /* Find muxes and enable/disable */ + /* TODO + * Find muxes and enable/disable * TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) { LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) { if (tdmi->tdmi_transport_stream_id != mod->tsid) continue; @@ -792,11 +698,138 @@ static int _opentv_enable ( epggrab_module_t *m, uint8_t e ) } } } +*/ return 1; } -void opentv_init ( epggrab_module_list_t *list ) +/* ************************************************************************ + * Configuration + * ***********************************************************************/ + +static int* _pid_list_to_array ( htsmsg_t *m ) +{ + int i = 1; + int *ret; + htsmsg_field_t *f; + HTSMSG_FOREACH(f, m) + if (f->hmf_s64) i++; + ret = calloc(i, sizeof(int)); + i = 0; + HTSMSG_FOREACH(f, m) + if (f->hmf_s64) { + ret[i] = (int)f->hmf_s64; + i++; + } + return ret; +} + +static int _opentv_dict_load_one ( const char *id, htsmsg_t *m ) +{ + opentv_dict_t *dict = calloc(1, sizeof(opentv_dict_t)); + dict->id = (char*)id; + if (RB_INSERT_SORTED(&_opentv_dicts, dict, h_link, _dict_cmp)) { + tvhlog(LOG_DEBUG, "opentv", "ignore duplicate dictionary %s", id); + free(dict); + return 0; + } else { + dict->codes = huffman_tree_build(m); + if (!dict->codes) { + RB_REMOVE(&_opentv_dicts, dict, h_link); + free(dict); + return -1; + } else { + dict->id = strdup(id); + return 1; + } + } +} + +static void _opentv_dict_load ( htsmsg_t *m ) +{ + int r; + htsmsg_t *e; + htsmsg_field_t *f; + HTSMSG_FOREACH(f, m) { + if ((e = htsmsg_get_list(m, f->hmf_name))) { + if ((r = _opentv_dict_load_one(f->hmf_name, e))) { + if (r > 0) + tvhlog(LOG_INFO, "opentv", "dictionary %s loaded", f->hmf_name); + else + tvhlog(LOG_WARNING, "opentv", "dictionary %s failed", f->hmf_name); + } + } + } + htsmsg_destroy(m); +} + +static int _opentv_prov_load_one ( const char *id, htsmsg_t *m ) +{ + char ibuf[100], nbuf[1000]; + htsmsg_t *cl, *tl, *sl; + uint32_t tsid, sid, nid; + const char *str, *name; + opentv_dict_t *dict; + opentv_module_t *mod; + + /* Check config */ + if (!(name = htsmsg_get_str(m, "name"))) return -1; + if (!(str = htsmsg_get_str(m, "dict"))) return -1; + if (!(dict = _opentv_dict_find(str))) return -1; + if (!(cl = htsmsg_get_list(m, "channel"))) return -1; + if (!(tl = htsmsg_get_list(m, "title"))) return -1; + if (!(sl = htsmsg_get_list(m, "summary"))) return -1; + if (htsmsg_get_u32(m, "nid", &nid)) return -1; + if (htsmsg_get_u32(m, "tsid", &tsid)) return -1; + if (htsmsg_get_u32(m, "sid", &sid)) return -1; + + /* Exists (we expect some duplicates due to config layout) */ + sprintf(ibuf, "opentv-%s", id); + if (epggrab_module_find_by_id(ibuf)) return 0; + + /* Create */ + sprintf(nbuf, "OpenTV: %s", name); + mod = (opentv_module_t*) + epggrab_module_ota_create(calloc(1, sizeof(opentv_module_t)), + ibuf, nbuf, + _opentv_start, _opentv_enable, + &_opentv_channels); + + /* Add provider details */ + mod->dict = dict; + mod->nid = nid; + mod->tsid = tsid; + mod->sid = sid; + mod->channel = _pid_list_to_array(cl); + mod->title = _pid_list_to_array(tl); + mod->summary = _pid_list_to_array(sl); + + return 1; +} + +static void _opentv_prov_load ( htsmsg_t *m ) +{ + int r; + htsmsg_t *e; + htsmsg_field_t *f; + HTSMSG_FOREACH(f, m) { + if ((e = htsmsg_get_map_by_field(f))) { + if ((r = _opentv_prov_load_one(f->hmf_name, e))) { + if (r > 0) + tvhlog(LOG_INFO, "opentv", "provider %s loaded", f->hmf_name); + else + tvhlog(LOG_WARNING, "opentv", "provider %s failed", f->hmf_name); + } + } + } + htsmsg_destroy(m); +} + +/* ************************************************************************ + * Module Setup + * ***********************************************************************/ + +void opentv_init ( void ) { htsmsg_t *m; const char *dr = tvheadend_dataroot(); @@ -810,9 +843,9 @@ void opentv_init ( epggrab_module_list_t *list ) /* Load providers */ if ((m = hts_settings_load("epggrab/opentv/prov"))) - _opentv_prov_load(m, list); + _opentv_prov_load(m); if ((m = hts_settings_load("%sdata/epggrab/opentv/prov", dr))) - _opentv_prov_load(m, list); + _opentv_prov_load(m); tvhlog(LOG_INFO, "opentv", "providers loaded"); } diff --git a/src/epggrab/pyepg.c b/src/epggrab/module/pyepg.c similarity index 87% rename from src/epggrab/pyepg.c rename to src/epggrab/module/pyepg.c index 8207aa4b..167493be 100644 --- a/src/epggrab/pyepg.c +++ b/src/epggrab/module/pyepg.c @@ -24,18 +24,17 @@ #include "htsmsg_xml.h" #include "tvheadend.h" #include "spawn.h" -#include "epg.h" -#include "epggrab/pyepg.h" -#include "epggrab/xmltv.h" #include "channels.h" +#include "epg.h" +#include "epggrab.h" +#include "epggrab/private.h" static epggrab_channel_tree_t _pyepg_channels; -static epggrab_module_t *_pyepg_module; static epggrab_channel_t *_pyepg_channel_find ( const char *id, int create, int *save ) { - return epggrab_module_channel_find(_pyepg_module, id, create, save); + return epggrab_channel_find(&_pyepg_channels, id, create, save); } /* ************************************************************************** @@ -69,7 +68,7 @@ static int _pyepg_parse_channel ( htsmsg_t *data, epggrab_stats_t *stats ) const char *str; uint32_t u32; const char *sname[11]; - uint16_t sid[10]; + uint16_t sid[11]; int sid_idx = 0, sname_idx = 0; if ( data == NULL ) return 0; @@ -108,7 +107,10 @@ static int _pyepg_parse_channel ( htsmsg_t *data, epggrab_stats_t *stats ) } } } - if (sid_idx) save |= epggrab_channel_set_sid(ch, sid, sid_idx); + if (sid_idx) { + sid[sid_idx] = 0; + save |= epggrab_channel_set_sid(ch, sid); + } if (sname_idx) { sname[sname_idx] = NULL; save |= epggrab_channel_set_sname(ch, sname); @@ -412,14 +414,8 @@ static int _pyepg_parse_epg ( htsmsg_t *data, epggrab_stats_t *stats ) return save; } - -/* ************************************************************************ - * Module Setup - * ***********************************************************************/ - - static int _pyepg_parse - ( epggrab_module_t *mod, htsmsg_t *data, epggrab_stats_t *stats ) + ( void *mod, htsmsg_t *data, epggrab_stats_t *stats ) { htsmsg_t *tags, *epg; @@ -432,40 +428,24 @@ static int _pyepg_parse return 0; } -void pyepg_init ( epggrab_module_list_t *list ) -{ - epggrab_module_t *mod; +/* ************************************************************************ + * Module Setup + * ***********************************************************************/ - /* Standard module */ - mod = calloc(1, sizeof(epggrab_module_t)); - mod->id = strdup("pyepg"); - mod->path = strdup("/usr/bin/pyepg"); - mod->name = strdup("PyEPG"); - mod->grab = epggrab_module_grab; - mod->trans = epggrab_module_trans_xml; - mod->parse = _pyepg_parse; - mod->channels = &_pyepg_channels; - mod->ch_add = epggrab_module_channel_add; - mod->ch_rem = epggrab_module_channel_rem; - mod->ch_mod = epggrab_module_channel_mod; - *((uint8_t*)&mod->flags) = EPGGRAB_MODULE_INTERNAL; - LIST_INSERT_HEAD(list, mod, link); - _pyepg_module = mod; +void pyepg_init ( void ) +{ + /* Internal module */ + epggrab_module_int_create(NULL, "pyepg", "PyEPG", "/usr/bin/pyepg", + NULL, _pyepg_parse, NULL, + &_pyepg_channels); /* External module */ - mod = calloc(1, sizeof(epggrab_module_t)); - mod->id = strdup("pyepg_ext"); - mod->path = epggrab_module_socket_path("pyepg"); - mod->name = strdup("PyEPG"); - mod->channels = &_pyepg_channels; - mod->enable = epggrab_module_enable_socket; - mod->trans = epggrab_module_trans_xml; - mod->parse = _pyepg_parse; - *((uint8_t*)&mod->flags) = EPGGRAB_MODULE_EXTERNAL; - LIST_INSERT_HEAD(list, mod, link); + epggrab_module_ext_create(NULL, "pyepg.ext", "PyEPG", "pyepg", + _pyepg_parse, NULL, + &_pyepg_channels); } void pyepg_load ( void ) { - epggrab_module_channels_load(_pyepg_module); + // TODO epggrab_module_channels_load(_pyepg_module); } diff --git a/src/epggrab/xmltv.c b/src/epggrab/module/xmltv.c similarity index 87% rename from src/epggrab/xmltv.c rename to src/epggrab/module/xmltv.c index 442a4993..7b4bfa7e 100644 --- a/src/epggrab/xmltv.c +++ b/src/epggrab/module/xmltv.c @@ -31,19 +31,20 @@ #include "tvheadend.h" #include "channels.h" -#include "epg.h" -#include "xmltv.h" #include "spawn.h" +#include "epg.h" +#include "epggrab.h" +#include "epggrab/private.h" + #define XMLTV_FIND_GRABBERS "/usr/bin/tv_find_grabbers" static epggrab_channel_tree_t _xmltv_channels; -static epggrab_module_t *_xmltv_module; static epggrab_channel_t *_xmltv_channel_find ( const char *id, int create, int *save ) { - return epggrab_module_channel_find(_xmltv_module, id, create, save); + return NULL;//return epggrab_module_channel_find(_xmltv_module, id, create, save); } @@ -442,12 +443,8 @@ _xmltv_parse_tv(htsmsg_t *body, epggrab_stats_t *stats) return save; } -/* ************************************************************************ - * Module Setup - * ***********************************************************************/ - static int _xmltv_parse - ( epggrab_module_t *mod, htsmsg_t *data, epggrab_stats_t *stats ) + ( void *mod, htsmsg_t *data, epggrab_stats_t *stats ) { htsmsg_t *tags, *tv; @@ -460,17 +457,20 @@ static int _xmltv_parse return _xmltv_parse_tv(tv, stats); } -static void _xmltv_load_grabbers ( epggrab_module_list_t *list ) +/* ************************************************************************ + * Module Setup + * ***********************************************************************/ + +static void _xmltv_load_grabbers ( void ) { size_t i, outlen, p, n; char *outbuf; - char errbuf[100]; - epggrab_module_t *mod; + char name[1000]; /* Load data */ outlen = spawn_and_store_stdout(XMLTV_FIND_GRABBERS, NULL, &outbuf); if ( outlen < 1 ) { - tvhlog(LOG_ERR, "xmltv", "%s failed [%s]", XMLTV_FIND_GRABBERS, errbuf); + tvhlog(LOG_ERR, "xmltv", "%s failed", XMLTV_FIND_GRABBERS); return; } @@ -479,16 +479,10 @@ static void _xmltv_load_grabbers ( epggrab_module_list_t *list ) while ( i < outlen ) { if ( outbuf[i] == '\n' || outbuf[i] == '\0' ) { outbuf[i] = '\0'; - mod = calloc(1, sizeof(epggrab_module_t)); - mod->id = mod->path = strdup(&outbuf[p]); - mod->name = malloc(200); - mod->channels = &_xmltv_channels; - sprintf((char*)mod->name, "XMLTV: %s", &outbuf[n]); - *((uint8_t*)&mod->flags) = EPGGRAB_MODULE_INTERNAL; - mod->grab = epggrab_module_grab; - mod->trans = epggrab_module_trans_xml; - mod->parse = _xmltv_parse; - LIST_INSERT_HEAD(list, mod, link); + sprintf(name, "XMLTV: %s", &outbuf[n]); + epggrab_module_int_create(NULL, &outbuf[p], name, &outbuf[p], + NULL, _xmltv_parse, NULL, + &_xmltv_channels); p = n = i + 1; } else if ( outbuf[i] == '|' ) { outbuf[i] = '\0'; @@ -499,31 +493,18 @@ static void _xmltv_load_grabbers ( epggrab_module_list_t *list ) free(outbuf); } -void xmltv_init ( epggrab_module_list_t *list ) +void xmltv_init ( void ) { - epggrab_module_t *mod; - /* External module */ - mod = calloc(1, sizeof(epggrab_module_t)); - mod->id = strdup("xmltv"); - mod->name = strdup("XMLTV"); - mod->path = epggrab_module_socket_path("xmltv"); - mod->enable = epggrab_module_enable_socket; - mod->trans = epggrab_module_trans_xml; - mod->parse = _xmltv_parse; - mod->channels = &_xmltv_channels; - mod->ch_add = epggrab_module_channel_add; - mod->ch_rem = epggrab_module_channel_rem; - mod->ch_mod = epggrab_module_channel_mod; - *((uint8_t*)&mod->flags) = EPGGRAB_MODULE_EXTERNAL; - LIST_INSERT_HEAD(list, mod, link); - _xmltv_module = mod; + epggrab_module_ext_create(NULL, "xmltv", "XMLTV", "xmltv", + _xmltv_parse, NULL, + &_xmltv_channels); /* Standard modules */ - _xmltv_load_grabbers(list); + _xmltv_load_grabbers(); } void xmltv_load ( void ) { - epggrab_module_channels_load(_xmltv_module); + //epggrab_module_channels_load(_xmltv_module); } diff --git a/src/epggrab/opentv.h b/src/epggrab/opentv.h deleted file mode 100644 index e46525d9..00000000 --- a/src/epggrab/opentv.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Electronic Program Guide - opentv - * Copyright (C) 2012 Adam Sutton - * - * 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 __TVH_EPGGRAB_OPENTV_H__ -#define __TVH_EPGGRAB_OPENTV_H__ - -#include "dvb/dvb.h" -#include "epggrab.h" - -void opentv_tune ( th_dvb_mux_instance_t *tdmi ); -void opentv_init ( epggrab_module_list_t *list ); -void opentv_load ( void ); - -#endif /* __TVH_EPGGRAB_OPENTV_H__ */ diff --git a/src/epggrab/ota.c b/src/epggrab/ota.c deleted file mode 100644 index 2dc132d5..00000000 --- a/src/epggrab/ota.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Electronic Program Guide - EPG grabber OTA functions - * Copyright (C) 2012 Adam Sutton - * - * 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 "tvheadend.h" -#include "queue.h" -#include "epg.h" -#include "dvb/dvb.h" -#include "epggrab.h" -#include "epggrab/ota.h" - -LIST_HEAD(,epggrab_ota_mux) ota_muxes; - -epggrab_ota_mux_t *epggrab_ota_register - ( epggrab_module_t *mod, th_dvb_mux_instance_t *tdmi, - int timeout, int interval ) -{ - epggrab_ota_mux_t *ota; - - /* Check for existing */ - LIST_FOREACH(ota, &ota_muxes, glob_link) { - if (ota->grab == mod && ota->tdmi == tdmi) { - ota->timeout = MAX(ota->timeout, timeout); - ota->interval = MIN(ota->interval, interval); - return ota; - } - } - - /* Install new */ - ota = calloc(1, sizeof(epggrab_ota_mux_t)); - ota->grab = mod; - ota->tdmi = tdmi; - ota->timeout = timeout; - ota->interval = interval; - LIST_INSERT_HEAD(&ota_muxes, ota, glob_link); - LIST_INSERT_HEAD(&tdmi->tdmi_epg_grabbers, ota, tdmi_link); - LIST_INSERT_HEAD(&mod->muxes, ota, grab_link); - - /* Re-assign to correct queue */ - if (tdmi->tdmi_scan_queue) - TAILQ_REMOVE(tdmi->tdmi_scan_queue, tdmi, tdmi_scan_link); - dvb_mux_add_to_scan_queue(tdmi); - - return ota; -} - -/* - * Unregister - */ -void epggrab_ota_unregister ( epggrab_ota_mux_t *ota ) -{ - LIST_REMOVE(ota, glob_link); - LIST_REMOVE(ota, tdmi_link); - LIST_REMOVE(ota, grab_link); - free(ota); -} - -void epggrab_ota_unregister_one - ( epggrab_module_t *mod, th_dvb_mux_instance_t *tdmi ) -{ - epggrab_ota_mux_t *ota; - LIST_FOREACH(ota, &ota_muxes, glob_link) { - if (ota->grab == mod && (!tdmi || ota->tdmi == tdmi)) { - epggrab_ota_unregister(ota); - if (tdmi) break; - } - } -} - -void epggrab_ota_unregister_all - ( epggrab_module_t *mod ) -{ - epggrab_ota_unregister_one(mod, NULL); -} - -/* - * Status - */ -int epggrab_ota_begin ( epggrab_ota_mux_t *ota ) -{ - if (ota->status == EPGGRAB_OTA_IDLE) { - ota->status = EPGGRAB_OTA_STARTED; - time(&ota->started); - return 1; - } - return 0; -} - -void epggrab_ota_complete ( epggrab_ota_mux_t *ota ) -{ - if (ota->status != EPGGRAB_OTA_COMPLETED) - time(&ota->completed); - ota->status = EPGGRAB_OTA_COMPLETED; -} - -void epggrab_ota_cancel ( epggrab_ota_mux_t *ota ) -{ - ota->status = EPGGRAB_OTA_IDLE; -} - -void epggrab_ota_timeout ( epggrab_ota_mux_t *ota ) -{ - epggrab_ota_complete(ota); -} - -int epggrab_ota_is_complete ( epggrab_ota_mux_t *ota ) -{ - return ota->status == EPGGRAB_OTA_COMPLETED; -} - -int epggrab_ota_is_blocked ( epggrab_ota_mux_t *ota ) -{ - time_t t; - time(&t); - return t < (ota->completed + ota->interval); -} diff --git a/src/epggrab/ota.h b/src/epggrab/ota.h deleted file mode 100644 index f1220906..00000000 --- a/src/epggrab/ota.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Electronic Program Guide - EPG grabber OTA functions - * Copyright (C) 2012 Adam Sutton - * - * 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 __TVH_EPGGRAB_OTA_H__ -#define __TVH_EPGGRAB_OTA_H__ - -#include "queue.h" -#include - -/* - * Mux to OTA Grabber link - */ -typedef struct epggrab_ota_mux -{ - LIST_ENTRY(epggrab_ota_mux) glob_link; ///< Global list of all instances - LIST_ENTRY(epggrab_ota_mux) grab_link; ///< Grabber's list link - LIST_ENTRY(epggrab_ota_mux) tdmi_link; ///< Mux list link - struct epggrab_module *grab; ///< Grabber module - struct th_dvb_mux_instance *tdmi; ///< Mux instance - - int timeout; ///< Time out if this long - int interval; ///< Re-grab this often - - enum { - EPGGRAB_OTA_IDLE, - EPGGRAB_OTA_STARTED, - EPGGRAB_OTA_COMPLETED - } status; ///< Status of the scan - time_t started; ///< Time of last start - time_t completed; ///< Time of last completion - -} epggrab_ota_mux_t; - -/* - * Register interest (will return existing if already registered) - */ -epggrab_ota_mux_t *epggrab_ota_register - ( struct epggrab_module *mod, struct th_dvb_mux_instance *tdmi, - int timeout, int interval ); - -/* - * Unregister - */ -void epggrab_ota_unregister - ( epggrab_ota_mux_t *ota ); -void epggrab_ota_unregister_one - ( struct epggrab_module *mod, struct th_dvb_mux_instance *tdmi ); -void epggrab_ota_unregister_all - ( struct epggrab_module *mod ); - -/* - * Status - */ -int epggrab_ota_begin ( epggrab_ota_mux_t *ota ); -void epggrab_ota_complete ( epggrab_ota_mux_t *ota ); -void epggrab_ota_cancel ( epggrab_ota_mux_t *ota ); -void epggrab_ota_timeout ( epggrab_ota_mux_t *ota ); -int epggrab_ota_is_complete ( epggrab_ota_mux_t *ota ); -int epggrab_ota_is_blocked ( epggrab_ota_mux_t *ota ); - -#endif /* __TVH_EPGGRAB_OTA_H__ */ diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c new file mode 100644 index 00000000..54487424 --- /dev/null +++ b/src/epggrab/otamux.c @@ -0,0 +1,256 @@ +/* + * Electronic Program Guide - EPG grabber OTA functions + * Copyright (C) 2012 Adam Sutton + * + * 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 . + */ + +/* + * TODO: this current implementation is a bit naff, possibly not as + * efficient as it could be (due to use of the a single list). But generally + * the length of the list will be short and it shouldn't significantly + * impact the overall performance + * + * TODO: currently all muxes are treated independently, this might result + * in the same mux being scanned on multiple adapters, which is + * a bit pointless. + * + * I think that at least _mux_next() and _ota_complete() need + * updating to handle this + */ + +#include "tvheadend.h" +#include "queue.h" +#include "epg.h" +#include "dvb/dvb.h" +#include "epggrab.h" +#include "epggrab/private.h" + +LIST_HEAD(,epggrab_ota_mux) ota_mux_all; +TAILQ_HEAD(, epggrab_ota_mux) ota_mux_reg; + +/* ************************************************************************** + * Global functions (called from DVB code) + * *************************************************************************/ + +void epggrab_mux_start ( th_dvb_mux_instance_t *tdmi ) +{ + epggrab_module_t *m; + epggrab_module_ota_t *mod; + LIST_FOREACH(m, &epggrab_modules, link) { + if (m->type == EPGGRAB_OTA) { + mod = (epggrab_module_ota_t*)m; + mod->start(mod, tdmi); + } + } +} + +void epggrab_mux_stop ( th_dvb_mux_instance_t *tdmi, int timeout ) +{ + epggrab_ota_mux_t *a, *b; + a = LIST_FIRST(&ota_mux_all); + while (a) { + b = LIST_NEXT(a, glob_link); + if (a->tdmi == tdmi) { + if (timeout) + epggrab_ota_timeout(a); + else + epggrab_ota_cancel(a); + } + a = b; + } +} + +void epggrab_mux_delete ( th_dvb_mux_instance_t *tdmi ) +{ + epggrab_ota_mux_t *a, *b; + a = LIST_FIRST(&ota_mux_all); + while (a) { + b = LIST_NEXT(a, glob_link); + if (a->tdmi == tdmi) + epggrab_ota_destroy(a); + a = b; + } +} + +int epggrab_mux_period ( th_dvb_mux_instance_t *tdmi ) +{ + int period = 0; + epggrab_ota_mux_t *ota; + TAILQ_FOREACH(ota, &ota_mux_reg, reg_link) { + if (ota->timeout > period) + period = ota->timeout; + } + return period; +} + +th_dvb_mux_instance_t *epggrab_mux_next ( th_dvb_adapter_t *tda ) +{ + epggrab_ota_mux_t *ota; + TAILQ_FOREACH(ota, &ota_mux_reg, reg_link) { + if (ota->tdmi->tdmi_adapter == tda) break; + } + if (!ota) return NULL; + return ota->tdmi; +} + +/* ************************************************************************** + * OTA Mux link functions + * *************************************************************************/ + +/* + * Comprison of ota_mux instances based on when they can next run + * + * Note: ordering isn't garaunteed to be perfect as we use the current time + */ +static int _ota_time_cmp ( void *_a, void *_b ) +{ + time_t now, wa, wb; + time(&now); + epggrab_ota_mux_t *a = _a; + epggrab_ota_mux_t *b = _b; + wa = a->completed + a->interval; + wb = b->completed + b->interval; + if (wa < now && wb < now) + return a->started - b->started; + else + return wa - wb; +} + +/* + * Create (temporary) or Find (existing) link + */ +epggrab_ota_mux_t *epggrab_ota_create + ( epggrab_module_ota_t *mod, th_dvb_mux_instance_t *tdmi ) +{ + /* Search for existing */ + epggrab_ota_mux_t *ota; + LIST_FOREACH(ota, &ota_mux_all, glob_link) { + if (ota->grab == mod && ota->tdmi == tdmi) break; + } + + /* Create new */ + if (!ota) { + ota = calloc(1, sizeof(epggrab_ota_mux_t)); + ota->grab = mod; + ota->tdmi = tdmi; + LIST_INSERT_HEAD(&ota_mux_all, ota, glob_link); + + } else { + time_t now; + time(&now); + if (ota) ota->state = EPGGRAB_OTA_MUX_IDLE; + + /* Blocked */ + if (epggrab_ota_is_blocked(ota)) ota = NULL; + } + return ota; +} + +/* + * Destrory link (either because it was temporary OR mux deleted) + */ +void epggrab_ota_destroy ( epggrab_ota_mux_t *ota ) +{ + LIST_REMOVE(ota, glob_link); + if (ota->is_reg) TAILQ_REMOVE(&ota_mux_reg, ota, reg_link); + if (ota->destroy) ota->destroy(ota); + else { + if (ota->status) free(ota->status); + free(ota); + } +} + +/* + * Register interest (called when useful data exists on the MUX + * thus inserting it into the EPG scanning queue + */ +void epggrab_ota_register ( epggrab_ota_mux_t *ota, int timeout, int interval ) +{ + // TODO: handle changes to the interval/timeout? + if (!ota->is_reg) { + ota->timeout = timeout; + ota->interval = interval; + ota->is_reg = 1; + TAILQ_INSERT_SORTED(&ota_mux_reg, ota, reg_link, _ota_time_cmp); + } +} + +/* + * State changes + */ + +static void _epggrab_ota_finished ( epggrab_ota_mux_t *ota ) +{ + /* Temporary link - delete it */ + if (!ota->is_reg) + epggrab_ota_destroy(ota); + + /* Reinsert into reg queue */ + else { + TAILQ_REMOVE(&ota_mux_reg, ota, reg_link); + TAILQ_INSERT_SORTED(&ota_mux_reg, ota, reg_link, _ota_time_cmp); + } +} + +int epggrab_ota_begin ( epggrab_ota_mux_t *ota ) +{ + if (ota->state == EPGGRAB_OTA_MUX_IDLE) { + ota->state = EPGGRAB_OTA_MUX_RUNNING; + time(&ota->started); + return 1; + } + return 0; +} + +void epggrab_ota_complete ( epggrab_ota_mux_t *ota ) +{ + if (ota->state != EPGGRAB_OTA_MUX_COMPLETE) { + ota->state = EPGGRAB_OTA_MUX_COMPLETE; + time(&ota->completed); + _epggrab_ota_finished(ota); + + // TODO: need to inform tdmi + } +} + +/* Reset */ +void epggrab_ota_cancel ( epggrab_ota_mux_t *ota ) +{ + ota->state = EPGGRAB_OTA_MUX_IDLE; + _epggrab_ota_finished(ota); +} + +/* Same as complete */ +void epggrab_ota_timeout ( epggrab_ota_mux_t *ota ) +{ + epggrab_ota_complete(ota); +} + +/* + * Check status + */ + +int epggrab_ota_is_complete ( epggrab_ota_mux_t *ota ) +{ + return ota->state == EPGGRAB_OTA_MUX_COMPLETE || + ota->state == EPGGRAB_OTA_MUX_TIMEDOUT; +} + +int epggrab_ota_is_blocked ( epggrab_ota_mux_t *ota ) +{ + time_t t; + time(&t); + return t < (ota->completed + ota->interval); +} diff --git a/src/epggrab/private.h b/src/epggrab/private.h new file mode 100644 index 00000000..bbf10f36 --- /dev/null +++ b/src/epggrab/private.h @@ -0,0 +1,144 @@ +/* + * EPG Grabber - private routines + * Copyright (C) 2012 Adam Sutton + * + * 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 __EPGGRAB_PRIVATE_H__ +#define __EPGGRAB_PRIVATE_H__ + +/* ************************************************************************** + * Generic module routines + * *************************************************************************/ + +epggrab_module_t *epggrab_module_create + ( epggrab_module_t *skel, + const char *id, const char *name ); + +char *epggrab_module_grab_spawn ( void *m ); +htsmsg_t *epggrab_module_trans_xml ( void *m, char *data ); + +void epggrab_module_ch_add ( void *m, struct channel *ch ); +void epggrab_module_ch_rem ( void *m, struct channel *ch ); +void epggrab_module_ch_mod ( void *m, struct channel *ch ); +void epggrab_module_ch_save ( void *m, epggrab_channel_t *ec ); + +int epggrab_module_enable_socket ( void *m, uint8_t e ); + +void epggrab_module_parse ( void *m, htsmsg_t *data ); + +/* ************************************************************************** + * Channel processing + * *************************************************************************/ + +int epggrab_channel_link ( epggrab_channel_t *ec, struct channel *ch ); + +epggrab_channel_t *epggrab_channel_find + ( epggrab_channel_tree_t *chs, const char *id, int create, int *save ); + +/* ************************************************************************** + * Internal module routines + * *************************************************************************/ + +epggrab_module_int_t *epggrab_module_int_create + ( epggrab_module_int_t *skel, + const char *id, const char *name, const char *path, + char* (*grab) (void*m), + int (*parse) (void *m, htsmsg_t *data, epggrab_stats_t *sta), + htsmsg_t* (*trans) (void *mod, char *data), + epggrab_channel_tree_t *channels ); + +/* ************************************************************************** + * External module routines + * *************************************************************************/ + +epggrab_module_ext_t *epggrab_module_ext_create + ( epggrab_module_ext_t *skel, + const char *id, const char *name, const char *sockid, + int (*parse) (void *m, htsmsg_t *data, epggrab_stats_t *sta), + htsmsg_t* (*trans) (void *mod, char *data), + epggrab_channel_tree_t *channels ); + +/* ************************************************************************** + * OTA module routines + * *************************************************************************/ + +epggrab_module_ota_t *epggrab_module_ota_create + ( epggrab_module_ota_t *skel, + const char *id, const char *name, + void (*start) (epggrab_module_ota_t*m, + struct th_dvb_mux_instance *tdmi), + int (*enable) (void *m, uint8_t e ), + epggrab_channel_tree_t *channels ); + +/* ************************************************************************** + * OTA mux link routines + * *************************************************************************/ + +/* + * Create/Find a link (unregistered) + * + * Note: this will return NULL for an already existing link that is currently + * blocked (i.e. has completed within interval period) + */ +epggrab_ota_mux_t *epggrab_ota_create + ( struct epggrab_module_ota *mod, struct th_dvb_mux_instance *tdmi ); + +void epggrab_ota_destroy ( epggrab_ota_mux_t *ota ); + +/* + * Register interest + */ +void epggrab_ota_register + ( epggrab_ota_mux_t *ota, int timeout, int interval ); + +/* + * State change + */ +int epggrab_ota_begin ( epggrab_ota_mux_t *ota ); +void epggrab_ota_complete ( epggrab_ota_mux_t *ota ); +void epggrab_ota_cancel ( epggrab_ota_mux_t *ota ); +void epggrab_ota_timeout ( epggrab_ota_mux_t *ota ); + +/* + * Status + */ +int epggrab_ota_is_complete ( epggrab_ota_mux_t *ota ); +int epggrab_ota_is_blocked ( epggrab_ota_mux_t *ota ); + +/* ************************************************************************** + * Module setup(s) + * *************************************************************************/ + +/* EIT module */ +void eit_init ( void ); +void eit_load ( void ); + +/* OpenTV module */ +void opentv_init ( void ); +void opentv_load ( void ); + +/* PyEPG module */ +void pyepg_init ( void ); +void pyepg_load ( void ); + +/* XMLTV module */ +void xmltv_init ( void ); +void xmltv_load ( void ); + +/* Note: this is reused by pyepg since they share a common format */ +int xmltv_parse_accessibility ( epg_broadcast_t *ebc, htsmsg_t *m ); + +#endif /* __EPGGRAB_PRIVATE_H__ */ diff --git a/src/epggrab/pyepg.h b/src/epggrab/pyepg.h deleted file mode 100644 index 9686c784..00000000 --- a/src/epggrab/pyepg.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Electronic Program Guide - pyepg grabber - * Copyright (C) 2012 Adam Sutton - * - * 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 EPGGRAB_PYEPG_H -#define EPGGRAB_PYEPG_H - -#include "epggrab.h" - -void pyepg_init ( epggrab_module_list_t *list ); -void pyepg_load ( void ); - -#endif diff --git a/src/epggrab/xmltv.h b/src/epggrab/xmltv.h deleted file mode 100644 index 104842a7..00000000 --- a/src/epggrab/xmltv.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Electronic Program Guide - xmltv grabber - * Copyright (C) 2012 Adam Sutton - * - * 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 EPGGRAB_XMLTV_H -#define EPGGRAB_XMLTV_H - -#include "htsmsg.h" -#include "epggrab.h" - -void xmltv_init ( epggrab_module_list_t *list ); -void xmltv_load ( void ); - -// reused by pyepg -int xmltv_parse_accessibility ( epg_broadcast_t *ebc, htsmsg_t *m ); - -#endif From a00b7631e1e5ca6c8bcf12d832b782cc57801b81 Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 29 Jun 2012 13:28:27 +0100 Subject: [PATCH 05/11] Some more tidying up and adding back in missing code. --- src/dvb/dvb.h | 2 +- src/epggrab.c | 90 ++---------------- src/epggrab.h | 24 +++-- src/epggrab/channel.c | 176 +++++++++++++++++++----------------- src/epggrab/module.c | 167 +++++++++++++++++++++------------- src/epggrab/module/eit.c | 24 +++++ src/epggrab/module/opentv.c | 143 +++++++++++++++-------------- src/epggrab/module/pyepg.c | 9 +- src/epggrab/module/xmltv.c | 8 +- src/epggrab/otamux.c | 136 +++++++++++++++++++--------- src/epggrab/private.h | 16 +++- 11 files changed, 429 insertions(+), 366 deletions(-) diff --git a/src/dvb/dvb.h b/src/dvb/dvb.h index 1042e5a4..6f2baf0c 100644 --- a/src/dvb/dvb.h +++ b/src/dvb/dvb.h @@ -130,10 +130,10 @@ typedef struct th_dvb_mux_instance { struct service_list tdmi_transports; /* via s_mux_link */ - TAILQ_ENTRY(th_dvb_mux_instance) tdmi_scan_link; struct th_dvb_mux_instance_queue *tdmi_scan_queue; + TAILQ_HEAD(, epggrab_ota_mux) tdmi_epg_grab; } th_dvb_mux_instance_t; diff --git a/src/epggrab.c b/src/epggrab.c index 213b3af6..643af33b 100644 --- a/src/epggrab.c +++ b/src/epggrab.c @@ -34,53 +34,9 @@ uint32_t epggrab_channel_renumber; uint32_t epggrab_channel_reicon; /* ************************************************************************** - * Helpers + * Internal Grab Thread * *************************************************************************/ -void epggrab_resched ( void ) -{ -} - -/* - * Run the parse - */ -void epggrab_module_parse - ( void *m, htsmsg_t *data ) -{ - time_t tm1, tm2; - int save = 0; - epggrab_stats_t stats; - epggrab_module_int_t *mod = m; - - /* Parse */ - memset(&stats, 0, sizeof(stats)); - pthread_mutex_lock(&global_lock); - time(&tm1); - save |= mod->parse(mod, data, &stats); - time(&tm2); - if (save) epg_updated(); - pthread_mutex_unlock(&global_lock); - htsmsg_destroy(data); - - /* Debug stats */ - tvhlog(LOG_INFO, mod->id, "parse took %d seconds", tm2 - tm1); - tvhlog(LOG_INFO, mod->id, " channels tot=%5d new=%5d mod=%5d", - stats.channels.total, stats.channels.created, - stats.channels.modified); - tvhlog(LOG_INFO, mod->id, " brands tot=%5d new=%5d mod=%5d", - stats.brands.total, stats.brands.created, - stats.brands.modified); - tvhlog(LOG_INFO, mod->id, " seasons tot=%5d new=%5d mod=%5d", - stats.seasons.total, stats.seasons.created, - stats.seasons.modified); - tvhlog(LOG_INFO, mod->id, " episodes tot=%5d new=%5d mod=%5d", - stats.episodes.total, stats.episodes.created, - stats.episodes.modified); - tvhlog(LOG_INFO, mod->id, " broadcasts tot=%5d new=%5d mod=%5d", - stats.broadcasts.total, stats.broadcasts.created, - stats.broadcasts.modified); -} - /* * Grab from module */ @@ -103,10 +59,6 @@ static void _epggrab_module_grab ( epggrab_module_int_t *mod ) } } -/* ************************************************************************** - * Internal Grab Thread - * *************************************************************************/ - /* * Thread (for internal grabbing) */ @@ -340,43 +292,17 @@ int epggrab_enable_module_by_id ( const char *id, uint8_t e ) return epggrab_enable_module(epggrab_module_find_by_id(id), e); } -/* ************************************************************************** - * Module Access - * *************************************************************************/ - -epggrab_module_t* epggrab_module_find_by_id ( const char *id ) -{ - epggrab_module_t *m; - LIST_FOREACH(m, &epggrab_modules, link) { - if ( !strcmp(m->id, id) ) return m; - } - return NULL; -} - -htsmsg_t *epggrab_module_list ( void ) -{ - epggrab_module_t *m; - htsmsg_t *e, *a = htsmsg_create_list(); - LIST_FOREACH(m, &epggrab_modules, link) { - e = htsmsg_create_map(); - htsmsg_add_str(e, "id", m->id); - htsmsg_add_u32(e, "type", m->type); - htsmsg_add_u32(e, "enabled", m->enabled); - if(m->name) - htsmsg_add_str(e, "name", m->name); - if(m->type == EPGGRAB_EXT) { - epggrab_module_ext_t *ext = (epggrab_module_ext_t*)m; - htsmsg_add_str(e, "path", ext->path); - } - htsmsg_add_msg(a, NULL, e); - } - return a; -} - /* ************************************************************************** * Initialisation * *************************************************************************/ +/* + * TODO: implement this + */ +void epggrab_resched ( void ) +{ +} + /* * Initialise */ diff --git a/src/epggrab.h b/src/epggrab.h index ea95ebce..f4d8b019 100644 --- a/src/epggrab.h +++ b/src/epggrab.h @@ -125,9 +125,16 @@ struct epggrab_module const char *id; ///< Module identifier const char *name; ///< Module name (for display) uint8_t enabled; ///< Whether the module is enabled + epggrab_channel_tree_t *channels; ///< Channel list /* Enable/Disable */ int (*enable) ( void *m, uint8_t e ); + + /* Channel listings */ + void (*ch_add) ( void *m, struct channel *ch ); + void (*ch_rem) ( void *m, struct channel *ch ); + void (*ch_mod) ( void *m, struct channel *ch ); + void (*ch_save) ( void *m, epggrab_channel_t *ch ); }; /* @@ -138,17 +145,11 @@ struct epggrab_module_int epggrab_module_t ; ///< Parent object const char *path; ///< Path for the command - epggrab_channel_tree_t *channels; ///< Channel list /* Handle data */ char* (*grab) ( void *mod ); htsmsg_t* (*trans) ( void *mod, char *data ); int (*parse) ( void *mod, htsmsg_t *data, epggrab_stats_t *stat ); - - /* Channel listings */ - void (*ch_add) ( void *m, struct channel *ch ); - void (*ch_rem) ( void *m, struct channel *ch ); - void (*ch_mod) ( void *m, struct channel *ch ); }; /* @@ -166,15 +167,16 @@ struct epggrab_module_ext */ struct epggrab_ota_mux { - LIST_ENTRY(epggrab_ota_mux) glob_link; ///< Grabber link - TAILQ_ENTRY(epggrab_ota_mux) reg_link; ///< List of reg'd + TAILQ_ENTRY(epggrab_ota_mux) glob_link; ///< Grabber link + TAILQ_ENTRY(epggrab_ota_mux) tdmi_link; ///< Link to mux + TAILQ_ENTRY(epggrab_ota_mux) grab_link; ///< Link to grabber struct th_dvb_mux_instance *tdmi; ///< Mux instance epggrab_module_ota_t *grab; ///< Grab instance int timeout; ///< Time out if this long int interval; ///< Re-grab this often - int is_reg; ///< Registered with mux + int is_reg; ///< Permanently registered void *status; ///< Status information enum { @@ -194,7 +196,9 @@ struct epggrab_ota_mux */ struct epggrab_module_ota { - epggrab_module_t ; ///< Parent object + epggrab_module_t ; ///< Parent object + + TAILQ_HEAD(, epggrab_ota_mux) muxes; ///< List of related muxes /* Transponder tuning */ void (*start) ( epggrab_module_ota_t *m, struct th_dvb_mux_instance *tdmi ); diff --git a/src/epggrab/channel.c b/src/epggrab/channel.c index 8b3b21eb..634f5d8c 100644 --- a/src/epggrab/channel.c +++ b/src/epggrab/channel.c @@ -28,14 +28,12 @@ #include "epggrab.h" #include "epggrab/private.h" -#if 0 -static int _ch_id_cmp ( void *a, void *b ) -{ - return strcmp(((epggrab_channel_t*)a)->id, - ((epggrab_channel_t*)b)->id); -} -#endif +/* ************************************************************************** + * EPG Grab Channel functions + * *************************************************************************/ +/* Link epggrab channel to real channel */ +// returns 1 if link made int epggrab_channel_link ( epggrab_channel_t *ec, channel_t *ch ) { service_t *sv; @@ -87,6 +85,7 @@ int epggrab_channel_link ( epggrab_channel_t *ec, channel_t *ch ) return match; } +/* Set name */ int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name ) { int save = 0; @@ -94,41 +93,66 @@ int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name ) if (!ec->name || strcmp(ec->name, name)) { if (ec->name) free(ec->name); ec->name = strdup(name); - if (ec->channel) channel_rename(ec->channel, name); + if (ec->channel && epggrab_channel_rename) + channel_rename(ec->channel, name); save = 1; } return save; } +/* Set icon */ +int epggrab_channel_set_icon ( epggrab_channel_t *ec, const char *icon ) +{ + int save = 0; + if (!ec->icon || strcmp(ec->icon, icon) ) { + if (!ec | !icon) return 0; + if (ec->icon) free(ec->icon); + ec->icon = strdup(icon); + if (ec->channel) channel_set_icon(ec->channel, icon); + save = 1; + } + return save; +} + +/* Set channel number */ +int epggrab_channel_set_number ( epggrab_channel_t *ec, int number ) +{ + int save = 0; + if (!ec || (number <= 0)) return 0; + if (ec->number != number) { + ec->number = number; + if (ec->channel) channel_set_number(ec->channel, number); + save = 1; + } + return save; +} + +/* Set service IDs */ int epggrab_channel_set_sid ( epggrab_channel_t *ec, const uint16_t *sid ) { -#if 0 - int save = 0, i = 0, num = 0; + int save = 0, i; if ( !ec || !sid ) return 0; if (!ec->sid) save = 1; else { - - for (i = 0; i < num; i++ ) { - if (sid[i] != ec->sid[i]) { - save = 1; - break; - } + i = 0; + while ( ec->sid[i] && sid[i] ) { + if ( ec->sid[i] != sid[i] ) break; + i++; } + if (ec->sid[i] || sid[i]) save = 1; } if (save) { + i = 0; + while (ec->sid[i++]); if (ec->sid) free(ec->sid); - ec->sid = calloc(num, sizeof(uint16_t)); - for (i = 0; i < num; i++ ) { - ec->sid[i] = sid[i]; - } - ec->sid_cnt = num; + ec->sid = calloc(i, sizeof(uint16_t)); + memcpy(ec->sid, sid, i * sizeof(uint16_t)); } return save; -#endif - return 0; } +/* Set names */ int epggrab_channel_set_sname ( epggrab_channel_t *ec, const char **sname ) { int save = 0, i = 0; @@ -136,13 +160,10 @@ int epggrab_channel_set_sname ( epggrab_channel_t *ec, const char **sname ) if (!ec->sname) save = 1; else { while ( ec->sname[i] && sname[i] ) { - if (strcmp(ec->sname[i], sname[i])) { - save = 1; - break; - } + if (strcmp(ec->sname[i], sname[i])) break; i++; } - if (!save && (ec->sname[i] || sname[i])) save = 1; + if (ec->sname[i] || sname[i]) save = 1; } if (save) { if (ec->sname) { @@ -163,57 +184,60 @@ int epggrab_channel_set_sname ( epggrab_channel_t *ec, const char **sname ) return save; } -int epggrab_channel_set_icon ( epggrab_channel_t *ec, const char *icon ) -{ - int save = 0; - if (!ec->icon || strcmp(ec->icon, icon) ) { - if (!ec | !icon) return 0; - if (ec->icon) free(ec->icon); - ec->icon = strdup(icon); - if (ec->channel) channel_set_icon(ec->channel, icon); - save = 1; - } - return save; -} - -int epggrab_channel_set_number ( epggrab_channel_t *ec, int number ) -{ - int save = 0; - if (!ec || (number <= 0)) return 0; - if (ec->number != number) { - ec->number = number; - if (ec->channel) channel_set_number(ec->channel, number); - save = 1; - } - return save; -} - - +/* Channel settings updated */ void epggrab_channel_updated ( epggrab_channel_t *ec ) { - //epggrab_channel_link(ec); - epggrab_module_ch_save(ec->mod, ec); -} - -#if 0 -void epggrab_channel_link ( epggrab_channel_t *ec ) -{ channel_t *ch; - if (!ec) return; - /* Link */ - if (!ec->channel) { - RB_FOREACH(ch, &channel_name_tree, ch_name_link) { - if (_ch_link(ec, ch)) break; + /* Find a link */ + if (!ec->channel) + RB_FOREACH(ch, &channel_name_tree, ch_name_link) + if (epggrab_channel_link(ec, ch)) break; + + /* Save */ + if (ec->mod->ch_save) ec->mod->ch_save(ec->mod, ec); +} + +/* ID comparison */ +static int _ch_id_cmp ( void *a, void *b ) +{ + return strcmp(((epggrab_channel_t*)a)->id, + ((epggrab_channel_t*)b)->id); +} + +/* Find/Create channel in the list */ +epggrab_channel_t *epggrab_channel_find + ( epggrab_channel_tree_t *tree, const char *id, int create, int *save ) +{ + epggrab_channel_t *ec; + static epggrab_channel_t *skel = NULL; + if (!skel) skel = calloc(1, sizeof(epggrab_channel_t)); + skel->id = (char*)id; + + /* Find */ + if (!create) { + ec = RB_FIND(tree, skel, link, _ch_id_cmp); + + /* Find/Create */ + } else { + ec = RB_INSERT_SORTED(tree, skel, link, _ch_id_cmp); + if (!ec) { + ec = skel; + skel = NULL; + ec->id = strdup(id); + *save = 1; } } + return ec; } -#endif + +/* ************************************************************************** + * Global routines + * *************************************************************************/ htsmsg_t *epggrab_channel_list ( void ) { -#if 0 char name[100]; epggrab_module_t *mod; epggrab_channel_t *ec; @@ -232,44 +256,28 @@ htsmsg_t *epggrab_channel_list ( void ) } } return m; -#endif - return NULL; } void epggrab_channel_add ( channel_t *ch ) { -#if 0 epggrab_module_t *m; LIST_FOREACH(m, &epggrab_modules, link) { if (m->ch_add) m->ch_add(m, ch); } -#endif } void epggrab_channel_rem ( channel_t *ch ) { -#if 0 epggrab_module_t *m; LIST_FOREACH(m, &epggrab_modules, link) { if (m->ch_rem) m->ch_rem(m, ch); } -#endif } void epggrab_channel_mod ( channel_t *ch ) { -#if 0 epggrab_module_t *m; LIST_FOREACH(m, &epggrab_modules, link) { if (m->ch_mod) m->ch_mod(m, ch); } -#endif } - -epggrab_channel_t *epggrab_channel_find - ( epggrab_channel_tree_t *tree, const char *id, int create, int *save ) -{ - // TODO - return NULL; -} - diff --git a/src/epggrab/module.c b/src/epggrab/module.c index 092f7d99..52f48c9a 100644 --- a/src/epggrab/module.c +++ b/src/epggrab/module.c @@ -35,18 +35,59 @@ #include "epggrab.h" #include "epggrab/private.h" +/* ************************************************************************** + * Module Access + * *************************************************************************/ + +epggrab_module_t* epggrab_module_find_by_id ( const char *id ) +{ + epggrab_module_t *m; + LIST_FOREACH(m, &epggrab_modules, link) { + if ( !strcmp(m->id, id) ) return m; + } + return NULL; +} + +htsmsg_t *epggrab_module_list ( void ) +{ + epggrab_module_t *m; + htsmsg_t *e, *a = htsmsg_create_list(); + LIST_FOREACH(m, &epggrab_modules, link) { + e = htsmsg_create_map(); + htsmsg_add_str(e, "id", m->id); + htsmsg_add_u32(e, "type", m->type); + htsmsg_add_u32(e, "enabled", m->enabled); + if(m->name) + htsmsg_add_str(e, "name", m->name); + if(m->type == EPGGRAB_EXT) { + epggrab_module_ext_t *ext = (epggrab_module_ext_t*)m; + htsmsg_add_str(e, "path", ext->path); + } + htsmsg_add_msg(a, NULL, e); + } + return a; +} + /* ************************************************************************** * Generic module routines * *************************************************************************/ epggrab_module_t *epggrab_module_create - ( epggrab_module_t *skel, const char *id, const char *name ) + ( epggrab_module_t *skel, const char *id, const char *name, + epggrab_channel_tree_t *channels ) { assert(skel); /* Setup */ - skel->id = strdup(id); - skel->name = strdup(name); + skel->id = strdup(id); + skel->name = strdup(name); + skel->channels = channels; + if (channels) { + skel->ch_save = epggrab_module_ch_save; + skel->ch_add = epggrab_module_ch_add; + skel->ch_mod = epggrab_module_ch_mod; + skel->ch_rem = epggrab_module_ch_rem; + } /* Insert */ assert(!epggrab_module_find_by_id(id)); @@ -55,8 +96,48 @@ epggrab_module_t *epggrab_module_create return skel; } +/* + * Run the parse + */ +void epggrab_module_parse + ( void *m, htsmsg_t *data ) +{ + time_t tm1, tm2; + int save = 0; + epggrab_stats_t stats; + epggrab_module_int_t *mod = m; + + /* Parse */ + memset(&stats, 0, sizeof(stats)); + pthread_mutex_lock(&global_lock); + time(&tm1); + save |= mod->parse(mod, data, &stats); + time(&tm2); + if (save) epg_updated(); + pthread_mutex_unlock(&global_lock); + htsmsg_destroy(data); + + /* Debug stats */ + tvhlog(LOG_INFO, mod->id, "parse took %d seconds", tm2 - tm1); + tvhlog(LOG_INFO, mod->id, " channels tot=%5d new=%5d mod=%5d", + stats.channels.total, stats.channels.created, + stats.channels.modified); + tvhlog(LOG_INFO, mod->id, " brands tot=%5d new=%5d mod=%5d", + stats.brands.total, stats.brands.created, + stats.brands.modified); + tvhlog(LOG_INFO, mod->id, " seasons tot=%5d new=%5d mod=%5d", + stats.seasons.total, stats.seasons.created, + stats.seasons.modified); + tvhlog(LOG_INFO, mod->id, " episodes tot=%5d new=%5d mod=%5d", + stats.episodes.total, stats.episodes.created, + stats.episodes.modified); + tvhlog(LOG_INFO, mod->id, " broadcasts tot=%5d new=%5d mod=%5d", + stats.broadcasts.total, stats.broadcasts.created, + stats.broadcasts.modified); +} + /* ************************************************************************** - * Channel related routines + * Module channel routines * *************************************************************************/ void epggrab_module_ch_save ( void *_m, epggrab_channel_t *ch ) @@ -102,7 +183,7 @@ void epggrab_module_ch_add ( void *m, channel_t *ch ) epggrab_module_int_t *mod = m; RB_FOREACH(egc, mod->channels, link) { if (epggrab_channel_link(egc, ch)) { - epggrab_module_ch_save(mod, egc); + if (mod->ch_save) mod->ch_save(mod, egc); break; } } @@ -115,7 +196,7 @@ void epggrab_module_ch_rem ( void *m, channel_t *ch ) RB_FOREACH(egc, mod->channels, link) { if (egc->channel == ch) { egc->channel = NULL; - epggrab_module_ch_save(mod, egc); + if (mod->ch_save) mod->ch_save(mod, egc); break; } } @@ -126,10 +207,7 @@ void epggrab_module_ch_mod ( void *mod, channel_t *ch ) return epggrab_module_ch_add(mod, ch); } - -#if 0 - -static void epggrab_module_ch_load +static void _epggrab_module_channel_load ( epggrab_module_t *mod, htsmsg_t *m, const char *id ) { int save = 0, i; @@ -138,7 +216,7 @@ static void epggrab_module_ch_load htsmsg_t *a; htsmsg_field_t *f; - epggrab_channel_t *ch = epggrab_module_channel_find(mod, id, 1, &save); + epggrab_channel_t *ch = epggrab_channel_find(mod->channels, id, 1, &save); if ((str = htsmsg_get_str(m, "name"))) ch->name = strdup(str); @@ -147,22 +225,23 @@ static void epggrab_module_ch_load if ((a = htsmsg_get_list(m, "sid"))) { i = 0; HTSMSG_FOREACH(f, a) i++; - ch->sid_cnt = i; - ch->sid = calloc(i, sizeof(uint16_t)); - i = 0; - HTSMSG_FOREACH(f, a) { - ch->sid[i] = (uint16_t)f->hmf_s64; - i++; + if (i) { + ch->sid = calloc(i+1, sizeof(uint16_t)); + i = 0; + HTSMSG_FOREACH(f, a) { + ch->sid[i++] = (uint16_t)f->hmf_s64; + } } } if ((a = htsmsg_get_list(m, "sname"))) { i = 0; HTSMSG_FOREACH(f, a) i++; - ch->sname = calloc(i+1, sizeof(char*)); - i = 0; - HTSMSG_FOREACH(f, a) { - ch->sname[i] = strdup(f->hmf_str); - i++; + if (i) { + ch->sname = calloc(i+1, sizeof(char*)); + i = 0; + HTSMSG_FOREACH(f, a) { + ch->sname[i++] = strdup(f->hmf_str); + } } } if(!htsmsg_get_u32(m, "number", &u32)) @@ -176,47 +255,16 @@ void epggrab_module_channels_load ( epggrab_module_t *mod ) { htsmsg_t *m, *e; htsmsg_field_t *f; - + if (!mod || !mod->channels) return; if ((m = hts_settings_load("epggrab/%s/channels", mod->id))) { HTSMSG_FOREACH(f, m) { if ((e = htsmsg_get_map_by_field(f))) - epggrab_module_channel_load(mod, e, f->hmf_name); + _epggrab_module_channel_load(mod, e, f->hmf_name); } htsmsg_destroy(m); } } -epggrab_channel_t *epggrab_module_ch_find - ( epggrab_module_t *mod, const char *id, int create, int *save ) -{ - epggrab_channel_t *ec; - static epggrab_channel_t *skel = NULL; - - if (!mod || !mod->channels ) return NULL; - - if ( !skel ) skel = calloc(1, sizeof(epggrab_channel_t)); - skel->id = (char*)id; - skel->mod = mod; - - /* Find */ - if (!create) { - ec = RB_FIND(mod->channels, skel, link, _ch_id_cmp); - - /* Create (if required) */ - } else { - ec = RB_INSERT_SORTED(mod->channels, skel, link, _ch_id_cmp); - if ( ec == NULL ) { - skel->id = strdup(skel->id); - ec = skel; - skel = NULL; - *save = 1; - } - } - - return ec; -} -#endif - /* ************************************************************************** * Internal module routines * *************************************************************************/ @@ -233,7 +281,7 @@ epggrab_module_int_t *epggrab_module_int_create if (!skel) skel = calloc(1, sizeof(epggrab_module_int_t)); /* Pass through */ - epggrab_module_create((epggrab_module_t*)skel, id, name); + epggrab_module_create((epggrab_module_t*)skel, id, name, channels); /* Int data */ skel->type = EPGGRAB_INT; @@ -242,11 +290,6 @@ epggrab_module_int_t *epggrab_module_int_create skel->grab = grab ?: epggrab_module_grab_spawn; skel->trans = trans ?: epggrab_module_trans_xml; skel->parse = parse; - if (channels) { - skel->ch_add = epggrab_module_ch_add; - skel->ch_rem = epggrab_module_ch_rem; - skel->ch_mod = epggrab_module_ch_mod; - } return skel; } @@ -438,7 +481,7 @@ epggrab_module_ota_t *epggrab_module_ota_create if (!skel) skel = calloc(1, sizeof(epggrab_module_ota_t)); /* Pass through */ - epggrab_module_create((epggrab_module_t*)skel, id, name); + epggrab_module_create((epggrab_module_t*)skel, id, name, channels); /* Setup */ skel->type = EPGGRAB_OTA; diff --git a/src/epggrab/module/eit.c b/src/epggrab/module/eit.c index 502048ed..0f291ae0 100644 --- a/src/epggrab/module/eit.c +++ b/src/epggrab/module/eit.c @@ -36,6 +36,26 @@ typedef struct eit_status int sec; } eit_status_t; +/* ************************************************************************ + * Diagnostics + * ***********************************************************************/ + +// Dump a descriptor tag for debug (looking for new tags etc...) +static void _eit_dtag_dump ( uint8_t dtag, uint8_t dlen, uint8_t *buf ) +{ + int i = 0, j = 0; + char tmp[100]; + tvhlog(LOG_DEBUG, "eit", "dtag 0x%02X len %d\n", dtag, dlen); + while (i < dlen) + while (dlen--) { + j += sprintf(tmp+j, "%02X ", buf[i]); + i++; + if ((i % 8) == 0 || !dlen) { + tvhlog(LOG_DEBUG, "eit", " %s", tmp); + } + } +} + /* ************************************************************************ * Processing * ***********************************************************************/ @@ -182,9 +202,12 @@ static int _eit_callback if (!svc || !svc->s_enabled || !(ch = svc->s_ch)) return 0; /* Ignore (disabled) */ + // TODO: should this be altered? if (!svc->s_dvb_eit_enable) return 0; /* Register as interesting */ + // TODO: do we want to register for now/next? + // TODO: want should the intervals be? if (tableid < 0x50) epggrab_ota_register(ota, 20, 0); else @@ -320,6 +343,7 @@ static int _eit_callback /* Ignore */ default: + _eit_dtag_dump(dtag, dlen, ptr); break; } diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index 71b98222..5874163e 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -56,47 +56,60 @@ typedef struct opentv_event uint8_t type; ///< 0x1=title, 0x2=summary } opentv_event_t; -typedef struct opentv_pid_status +/* PID status (for event PIDs) */ +typedef struct opentv_pid { - LIST_ENTRY(opentv_pid_status) link; - int pid; + LIST_ENTRY(opentv_pid) link; + int pid; enum { OPENTV_PID_INIT, OPENTV_PID_STARTED, OPENTV_PID_COMPLETE - } state; - uint8_t start[20]; -} opentv_pid_status_t; + } state; + uint8_t start[20]; +} opentv_pid_t; +/* Scan status */ typedef struct opentv_status { - int begbat; - int endbat; - LIST_HEAD(, opentv_pid_status) pids; - RB_HEAD(, opentv_event) events; + int begbat; + int endbat; + LIST_HEAD(, opentv_pid) pids; + RB_HEAD(, opentv_event) events; } opentv_status_t; -static opentv_pid_status_t *_opentv_get_pid_status +/* Get a pid entry */ +static opentv_pid_t *_opentv_status_get_pid ( opentv_status_t *sta, int pid ) { - opentv_pid_status_t *p; + opentv_pid_t *p; LIST_FOREACH(p, &sta->pids, link) { if (p->pid == pid) break; } if (!p) { - p = calloc(1, sizeof(opentv_pid_status_t)); + p = calloc(1, sizeof(opentv_pid_t)); p->pid = pid; LIST_INSERT_HEAD(&sta->pids, p, link); } return p; } -/* ************************************************************************ - * Data structures - * ***********************************************************************/ +/* Clear events */ +static void _opentv_status_remove_events ( opentv_status_t *sta ) +{ + opentv_event_t *ev; + while ((ev = RB_FIRST(&sta->events))) { + RB_REMOVE(&sta->events, ev, ev_link); + if (ev->title) free(ev->title); + if (ev->summary) free(ev->summary); + if (ev->desc) free(ev->desc); + free(ev); + } +} -#define OPENTV_SCAN_MAX 600 // 10min max scan period -#define OPENTV_SCAN_PER 3600 // 1hour interval +/* ************************************************************************ + * Module structure + * ***********************************************************************/ /* Huffman dictionary */ typedef struct opentv_dict @@ -138,26 +151,6 @@ static opentv_dict_t *_opentv_dict_find ( const char *id ) return RB_FIND(&_opentv_dicts, &skel, h_link, _dict_cmp); } -/* ************************************************************************ - * Module functions - * ***********************************************************************/ - -#if 0 -static opentv_status_t *_opentv_module_get_status - ( opentv_module_t *mod, int pid ) -{ - opentv_status_t *sta; - LIST_FOREACH(sta, &mod->status, link) - if (sta->pid == pid) break; - if (!sta) { - sta = calloc(1, sizeof(opentv_status_t)); - sta->pid = pid; - LIST_INSERT_HEAD(&mod->status, sta, link); - } - return sta; -} -#endif - /* ************************************************************************ * EPG Object wrappers * ***********************************************************************/ @@ -165,9 +158,9 @@ static opentv_status_t *_opentv_module_get_status static epggrab_channel_t *_opentv_find_epggrab_channel ( opentv_module_t *mod, int cid, int create, int *save ) { -// char chid[32]; -// sprintf(chid, "%s-%d", mod->id, cid); - return NULL;//return epggrab_module_channel_find((epggrab_module_t*)mod, chid, create, save); + char chid[32]; + sprintf(chid, "%s-%d", mod->id, cid); + return epggrab_channel_find(&_opentv_channels, chid, create, save); } static epg_season_t *_opentv_find_season @@ -518,26 +511,22 @@ static epggrab_ota_mux_t *_opentv_table_callback th_dvb_table_t *tdt = (th_dvb_table_t*)p; epggrab_ota_mux_t *ota = tdt->tdt_opaque; opentv_status_t *sta = ota->status; - opentv_pid_status_t *pid; + opentv_pid_t *pid; /* Ignore (not enough data) */ if (len < 20) return NULL; + /* Ignore (don't have BAT) */ + if (!sta->endbat) return NULL; + /* Finished / Blocked */ if (epggrab_ota_is_complete(ota)) return NULL; /* Begin (reset state) */ if (epggrab_ota_begin(ota)) { - opentv_event_t *ev; /* Remove outstanding event data */ - while ((ev = RB_FIRST(&sta->events))) { - RB_REMOVE(&sta->events, ev, ev_link); - if (ev->title) free(ev->title); - if (ev->desc) free(ev->desc); - if (ev->summary) free(ev->summary); - free(ev); - } + _opentv_status_remove_events(sta); /* Reset status */ LIST_FOREACH(pid, &sta->pids, link) @@ -545,7 +534,7 @@ static epggrab_ota_mux_t *_opentv_table_callback } /* Insert/Find */ - pid = _opentv_get_pid_status(sta, tdt->tdt_pid); + pid = _opentv_status_get_pid(sta, tdt->tdt_pid); /* Begin PID */ if (pid->state == OPENTV_PID_INIT) { @@ -614,7 +603,21 @@ static int _opentv_channel_callback static void _opentv_ota_destroy ( epggrab_ota_mux_t *ota ) { - // TODO + opentv_status_t *sta = ota->status; + opentv_pid_t *pid; + + /* Empty the events */ + _opentv_status_remove_events(sta); + + /* Empty pids */ + while ((pid = LIST_FIRST(&sta->pids))) { + LIST_REMOVE(pid, link); + free(pid); + } + + /* Free the rest */ + free(sta); + free(ota); } static void _opentv_start @@ -639,8 +642,8 @@ static void _opentv_start sta = ota->status; sta->begbat = sta->endbat = 0; - /* Register interest (we're always interested in this mux) */ - epggrab_ota_register(ota, OPENTV_SCAN_MAX, OPENTV_SCAN_PER); + /* Register (just in case we missed it on enable somehow) */ + epggrab_ota_register(ota, 600, 3600); // 10min scan every hour /* Install tables */ tvhlog(LOG_INFO, "opentv", "install provider %s tables", mod->id); @@ -652,7 +655,7 @@ static void _opentv_start fp->filter.filter[0] = 0x4a; fp->filter.mask[0] = 0xff; // TODO: what about 0x46 (service description) - tdt_add(tdmi, fp, _opentv_channel_callback, mod, + tdt_add(tdmi, fp, _opentv_channel_callback, ota, m->id, TDT_CRC, *t++, NULL); } @@ -662,7 +665,8 @@ static void _opentv_start fp = dvb_fparams_alloc(); fp->filter.filter[0] = 0xa0; fp->filter.mask[0] = 0xfc; - tdt_add(tdmi, fp, _opentv_title_callback, mod, + _opentv_status_get_pid(sta, *t); + tdt_add(tdmi, fp, _opentv_title_callback, ota, m->id, TDT_CRC | TDT_TDT, *t++, NULL); } @@ -672,33 +676,28 @@ static void _opentv_start fp = dvb_fparams_alloc(); fp->filter.filter[0] = 0xa8; fp->filter.mask[0] = 0xfc; - tdt_add(tdmi, fp, _opentv_summary_callback, mod, + _opentv_status_get_pid(sta, *t); + tdt_add(tdmi, fp, _opentv_summary_callback, ota, m->id, TDT_CRC | TDT_TDT, *t++, NULL); } } static int _opentv_enable ( void *m, uint8_t e ) { - //th_dvb_adapter_t *tda; - //th_dvb_mux_instance_t *tdmi; opentv_module_t *mod = (opentv_module_t*)m; if (mod->enabled == e) return 0; mod->enabled = e; - /* TODO - * Find muxes and enable/disable * - TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) { - LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) { - if (tdmi->tdmi_transport_stream_id != mod->tsid) continue; - if (e) { - epggrab_ota_register(m, tdmi, OPENTV_SCAN_MAX, OPENTV_SCAN_PER); - } else { - epggrab_ota_unregister_one(m, tdmi); - } - } + /* Register interest */ + if (e) { + epggrab_ota_create_and_register_by_id((epggrab_module_ota_t*)mod, + mod->nid, mod->tsid, + 600, 3600); + /* Remove all links */ + } else { + epggrab_ota_destroy_by_module((epggrab_module_ota_t*)mod); } -*/ return 1; } @@ -793,7 +792,7 @@ static int _opentv_prov_load_one ( const char *id, htsmsg_t *m ) epggrab_module_ota_create(calloc(1, sizeof(opentv_module_t)), ibuf, nbuf, _opentv_start, _opentv_enable, - &_opentv_channels); + NULL); /* Add provider details */ mod->dict = dict; diff --git a/src/epggrab/module/pyepg.c b/src/epggrab/module/pyepg.c index 167493be..4dc7268a 100644 --- a/src/epggrab/module/pyepg.c +++ b/src/epggrab/module/pyepg.c @@ -435,17 +435,16 @@ static int _pyepg_parse void pyepg_init ( void ) { /* Internal module */ - epggrab_module_int_create(NULL, "pyepg", "PyEPG", "/usr/bin/pyepg", - NULL, _pyepg_parse, NULL, - &_pyepg_channels); + epggrab_module_int_create(NULL, "/usr/bin/pyepg", "PyEPG", "/usr/bin/pyepg", + NULL, _pyepg_parse, NULL, NULL); /* External module */ - epggrab_module_ext_create(NULL, "pyepg.ext", "PyEPG", "pyepg", + epggrab_module_ext_create(NULL, "pyepg", "PyEPG", "pyepg", _pyepg_parse, NULL, &_pyepg_channels); } void pyepg_load ( void ) { - // TODO epggrab_module_channels_load(_pyepg_module); + epggrab_module_channels_load(epggrab_module_find_by_id("pyepg")); } diff --git a/src/epggrab/module/xmltv.c b/src/epggrab/module/xmltv.c index 7b4bfa7e..546f367a 100644 --- a/src/epggrab/module/xmltv.c +++ b/src/epggrab/module/xmltv.c @@ -44,10 +44,9 @@ static epggrab_channel_tree_t _xmltv_channels; static epggrab_channel_t *_xmltv_channel_find ( const char *id, int create, int *save ) { - return NULL;//return epggrab_module_channel_find(_xmltv_module, id, create, save); + return epggrab_channel_find(&_xmltv_channels, id, create, save); } - /* ************************************************************************** * Parsing * *************************************************************************/ @@ -481,8 +480,7 @@ static void _xmltv_load_grabbers ( void ) outbuf[i] = '\0'; sprintf(name, "XMLTV: %s", &outbuf[n]); epggrab_module_int_create(NULL, &outbuf[p], name, &outbuf[p], - NULL, _xmltv_parse, NULL, - &_xmltv_channels); + NULL, _xmltv_parse, NULL, NULL); p = n = i + 1; } else if ( outbuf[i] == '|' ) { outbuf[i] = '\0'; @@ -506,5 +504,5 @@ void xmltv_init ( void ) void xmltv_load ( void ) { - //epggrab_module_channels_load(_xmltv_module); + epggrab_module_channels_load(epggrab_module_find_by_id("xmltv")); } diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c index 54487424..1166f951 100644 --- a/src/epggrab/otamux.c +++ b/src/epggrab/otamux.c @@ -17,17 +17,8 @@ */ /* - * TODO: this current implementation is a bit naff, possibly not as - * efficient as it could be (due to use of the a single list). But generally - * the length of the list will be short and it shouldn't significantly - * impact the overall performance - * - * TODO: currently all muxes are treated independently, this might result - * in the same mux being scanned on multiple adapters, which is - * a bit pointless. - * - * I think that at least _mux_next() and _ota_complete() need - * updating to handle this + * TODO: currently I don't try to block multiple scans of the same + * tdmi on different adapters */ #include "tvheadend.h" @@ -37,8 +28,7 @@ #include "epggrab.h" #include "epggrab/private.h" -LIST_HEAD(,epggrab_ota_mux) ota_mux_all; -TAILQ_HEAD(, epggrab_ota_mux) ota_mux_reg; +TAILQ_HEAD(, epggrab_ota_mux) ota_mux_all; /* ************************************************************************** * Global functions (called from DVB code) @@ -47,21 +37,21 @@ TAILQ_HEAD(, epggrab_ota_mux) ota_mux_reg; void epggrab_mux_start ( th_dvb_mux_instance_t *tdmi ) { epggrab_module_t *m; - epggrab_module_ota_t *mod; LIST_FOREACH(m, &epggrab_modules, link) { if (m->type == EPGGRAB_OTA) { - mod = (epggrab_module_ota_t*)m; - mod->start(mod, tdmi); + ((epggrab_module_ota_t*)m)->start((epggrab_module_ota_t*)m, tdmi); } } } void epggrab_mux_stop ( th_dvb_mux_instance_t *tdmi, int timeout ) { + // Note: the slightly akward list iteration here is because + // _ota_cancel/delete can remove the object and free() it epggrab_ota_mux_t *a, *b; - a = LIST_FIRST(&ota_mux_all); + a = TAILQ_FIRST(&tdmi->tdmi_epg_grab); while (a) { - b = LIST_NEXT(a, glob_link); + b = TAILQ_NEXT(a, tdmi_link); if (a->tdmi == tdmi) { if (timeout) epggrab_ota_timeout(a); @@ -74,21 +64,15 @@ void epggrab_mux_stop ( th_dvb_mux_instance_t *tdmi, int timeout ) void epggrab_mux_delete ( th_dvb_mux_instance_t *tdmi ) { - epggrab_ota_mux_t *a, *b; - a = LIST_FIRST(&ota_mux_all); - while (a) { - b = LIST_NEXT(a, glob_link); - if (a->tdmi == tdmi) - epggrab_ota_destroy(a); - a = b; - } + epggrab_ota_destroy_by_tdmi(tdmi); } int epggrab_mux_period ( th_dvb_mux_instance_t *tdmi ) { int period = 0; epggrab_ota_mux_t *ota; - TAILQ_FOREACH(ota, &ota_mux_reg, reg_link) { + TAILQ_FOREACH(ota, &tdmi->tdmi_epg_grab, tdmi_link) { + if (!ota->is_reg) break; if (ota->timeout > period) period = ota->timeout; } @@ -98,11 +82,11 @@ int epggrab_mux_period ( th_dvb_mux_instance_t *tdmi ) th_dvb_mux_instance_t *epggrab_mux_next ( th_dvb_adapter_t *tda ) { epggrab_ota_mux_t *ota; - TAILQ_FOREACH(ota, &ota_mux_reg, reg_link) { + TAILQ_FOREACH(ota, &ota_mux_all, glob_link) { + if (!ota->is_reg) break; if (ota->tdmi->tdmi_adapter == tda) break; } - if (!ota) return NULL; - return ota->tdmi; + return ota ? ota->tdmi : NULL; } /* ************************************************************************** @@ -116,10 +100,17 @@ th_dvb_mux_instance_t *epggrab_mux_next ( th_dvb_adapter_t *tda ) */ static int _ota_time_cmp ( void *_a, void *_b ) { + int r; time_t now, wa, wb; time(&now); epggrab_ota_mux_t *a = _a; epggrab_ota_mux_t *b = _b; + + /* Unreg'd always at the end */ + r = a->is_reg - b->is_reg; + if (r) return r; + + /* Check when */ wa = a->completed + a->interval; wb = b->completed + b->interval; if (wa < now && wb < now) @@ -136,7 +127,7 @@ epggrab_ota_mux_t *epggrab_ota_create { /* Search for existing */ epggrab_ota_mux_t *ota; - LIST_FOREACH(ota, &ota_mux_all, glob_link) { + TAILQ_FOREACH(ota, &ota_mux_all, glob_link) { if (ota->grab == mod && ota->tdmi == tdmi) break; } @@ -145,7 +136,9 @@ epggrab_ota_mux_t *epggrab_ota_create ota = calloc(1, sizeof(epggrab_ota_mux_t)); ota->grab = mod; ota->tdmi = tdmi; - LIST_INSERT_HEAD(&ota_mux_all, ota, glob_link); + TAILQ_INSERT_TAIL(&ota_mux_all, ota, glob_link); + TAILQ_INSERT_TAIL(&tdmi->tdmi_epg_grab, ota, tdmi_link); + TAILQ_INSERT_TAIL(&mod->muxes, ota, grab_link); } else { time_t now; @@ -158,13 +151,33 @@ epggrab_ota_mux_t *epggrab_ota_create return ota; } +/* + * Create and register using mux ID + */ +void epggrab_ota_create_and_register_by_id + ( epggrab_module_ota_t *mod, int nid, int tsid, int period, int interval ) +{ + th_dvb_adapter_t *tda; + th_dvb_mux_instance_t *tdmi; + epggrab_ota_mux_t *ota; + TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) { + //TODO: if (tda->nitoid != nid) continue; + LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) { + if (tdmi->tdmi_transport_stream_id != tsid) continue; + ota = epggrab_ota_create(mod, tdmi); + epggrab_ota_register(ota, period, interval); + } + } +} + /* * Destrory link (either because it was temporary OR mux deleted) */ void epggrab_ota_destroy ( epggrab_ota_mux_t *ota ) { - LIST_REMOVE(ota, glob_link); - if (ota->is_reg) TAILQ_REMOVE(&ota_mux_reg, ota, reg_link); + TAILQ_REMOVE(&ota_mux_all, ota, glob_link); + TAILQ_REMOVE(&ota->tdmi->tdmi_epg_grab, ota, tdmi_link); + TAILQ_REMOVE(&ota->grab->muxes, ota, grab_link); if (ota->destroy) ota->destroy(ota); else { if (ota->status) free(ota->status); @@ -172,18 +185,46 @@ void epggrab_ota_destroy ( epggrab_ota_mux_t *ota ) } } +/* + * Destroy by tdmi + */ +void epggrab_ota_destroy_by_tdmi ( th_dvb_mux_instance_t *tdmi ) +{ + epggrab_ota_mux_t *ota; + while ((ota = TAILQ_FIRST(&tdmi->tdmi_epg_grab))) + epggrab_ota_destroy(ota); +} + +/* + * Destroy by module + */ +void epggrab_ota_destroy_by_module ( epggrab_module_ota_t *mod ) +{ + epggrab_ota_mux_t *ota; + while ((ota = TAILQ_FIRST(&mod->muxes))) + epggrab_ota_destroy(ota); +} + /* * Register interest (called when useful data exists on the MUX * thus inserting it into the EPG scanning queue */ void epggrab_ota_register ( epggrab_ota_mux_t *ota, int timeout, int interval ) { - // TODO: handle changes to the interval/timeout? - if (!ota->is_reg) { - ota->timeout = timeout; + int up = 0; + ota->is_reg = 1; + if (timeout > ota->timeout) { + up = 1; + ota->timeout = timeout; + } + if (interval > ota->interval) { + up = 1; ota->interval = interval; - ota->is_reg = 1; - TAILQ_INSERT_SORTED(&ota_mux_reg, ota, reg_link, _ota_time_cmp); + } + + if (up) { + TAILQ_REMOVE(&ota_mux_all, ota, glob_link); + TAILQ_INSERT_SORTED(&ota_mux_all, ota, glob_link, _ota_time_cmp); } } @@ -199,8 +240,8 @@ static void _epggrab_ota_finished ( epggrab_ota_mux_t *ota ) /* Reinsert into reg queue */ else { - TAILQ_REMOVE(&ota_mux_reg, ota, reg_link); - TAILQ_INSERT_SORTED(&ota_mux_reg, ota, reg_link, _ota_time_cmp); + TAILQ_REMOVE(&ota_mux_all, ota, glob_link); + TAILQ_INSERT_SORTED(&ota_mux_all, ota, glob_link, _ota_time_cmp); } } @@ -216,12 +257,23 @@ int epggrab_ota_begin ( epggrab_ota_mux_t *ota ) void epggrab_ota_complete ( epggrab_ota_mux_t *ota ) { + th_dvb_mux_instance_t *tdmi = ota->tdmi; + if (ota->state != EPGGRAB_OTA_MUX_COMPLETE) { ota->state = EPGGRAB_OTA_MUX_COMPLETE; time(&ota->completed); _epggrab_ota_finished(ota); - // TODO: need to inform tdmi + /* Check others */ + TAILQ_FOREACH(ota, &tdmi->tdmi_epg_grab, tdmi_link) { + if (ota->is_reg && ota->state != EPGGRAB_OTA_MUX_RUNNING) break; + } + + /* All complete (bring timer forward) */ + if (!ota) { + gtimer_arm(&tdmi->tdmi_adapter->tda_mux_scanner_timer, + dvb_adapter_mux_scanner, tdmi->tdmi_adapter, 20); + } } } diff --git a/src/epggrab/private.h b/src/epggrab/private.h index bbf10f36..ed1942d9 100644 --- a/src/epggrab/private.h +++ b/src/epggrab/private.h @@ -25,7 +25,7 @@ epggrab_module_t *epggrab_module_create ( epggrab_module_t *skel, - const char *id, const char *name ); + const char *id, const char *name, epggrab_channel_tree_t *channels ); char *epggrab_module_grab_spawn ( void *m ); htsmsg_t *epggrab_module_trans_xml ( void *m, char *data ); @@ -39,6 +39,8 @@ int epggrab_module_enable_socket ( void *m, uint8_t e ); void epggrab_module_parse ( void *m, htsmsg_t *data ); +void epggrab_module_channels_load ( epggrab_module_t *m ); + /* ************************************************************************** * Channel processing * *************************************************************************/ @@ -94,9 +96,17 @@ epggrab_module_ota_t *epggrab_module_ota_create * blocked (i.e. has completed within interval period) */ epggrab_ota_mux_t *epggrab_ota_create - ( struct epggrab_module_ota *mod, struct th_dvb_mux_instance *tdmi ); + ( epggrab_module_ota_t *mod, struct th_dvb_mux_instance *tdmi ); +void epggrab_ota_create_and_register_by_id + ( epggrab_module_ota_t *mod, int nid, int tsid, + int period, int interval ); -void epggrab_ota_destroy ( epggrab_ota_mux_t *ota ); +/* + * Delete + */ +void epggrab_ota_destroy ( epggrab_ota_mux_t *ota ); +void epggrab_ota_destroy_by_module ( epggrab_module_ota_t *mod ); +void epggrab_ota_destroy_by_tdmi ( struct th_dvb_mux_instance *tdmi ); /* * Register interest From cafa9d6cacd31efec4e7699c3ae46942d36c7dd2 Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 29 Jun 2012 13:42:46 +0100 Subject: [PATCH 06/11] Minor tweak. --- src/epggrab/otamux.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c index 1166f951..1d8bf6ef 100644 --- a/src/epggrab/otamux.c +++ b/src/epggrab/otamux.c @@ -81,9 +81,12 @@ int epggrab_mux_period ( th_dvb_mux_instance_t *tdmi ) th_dvb_mux_instance_t *epggrab_mux_next ( th_dvb_adapter_t *tda ) { + time_t now; epggrab_ota_mux_t *ota; + time(&now); TAILQ_FOREACH(ota, &ota_mux_all, glob_link) { - if (!ota->is_reg) break; + if (ota->interval + ota->completed > now) return NULL; + if (!ota->is_reg) return NULL; if (ota->tdmi->tdmi_adapter == tda) break; } return ota ? ota->tdmi : NULL; From 9283974d441c889b79183c3c61da8a9530ce3668 Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 29 Jun 2012 21:16:06 +0100 Subject: [PATCH 07/11] Some minor corrections to new ota code. --- src/dvb/dvb_multiplex.c | 2 ++ src/epggrab.c | 4 ++++ src/epggrab/module.c | 1 + src/epggrab/module/opentv.c | 8 ++++---- src/epggrab/otamux.c | 4 ++-- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/dvb/dvb_multiplex.c b/src/dvb/dvb_multiplex.c index fd3b7643..404e5877 100644 --- a/src/dvb/dvb_multiplex.c +++ b/src/dvb/dvb_multiplex.c @@ -289,6 +289,8 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc, mux_link_initial(tda, tdmi); } + TAILQ_INIT(&tdmi->tdmi_epg_grab); + return tdmi; } diff --git a/src/epggrab.c b/src/epggrab.c index 643af33b..8036d733 100644 --- a/src/epggrab.c +++ b/src/epggrab.c @@ -308,6 +308,10 @@ void epggrab_resched ( void ) */ void epggrab_init ( void ) { + /* Lists */ + extern TAILQ_HEAD(, epggrab_ota_mux) ota_mux_all; + TAILQ_INIT(&ota_mux_all); + /* Initialise modules */ eit_init(); xmltv_init(); diff --git a/src/epggrab/module.c b/src/epggrab/module.c index 52f48c9a..e34f3272 100644 --- a/src/epggrab/module.c +++ b/src/epggrab/module.c @@ -487,6 +487,7 @@ epggrab_module_ota_t *epggrab_module_ota_create skel->type = EPGGRAB_OTA; skel->enable = enable; skel->start = start; + TAILQ_INIT(&skel->muxes); return skel; } diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index 5874163e..0ae4181a 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -122,7 +122,7 @@ typedef struct opentv_dict /* Provider configuration */ typedef struct opentv_module_t { - epggrab_module_t ; ///< Base struct + epggrab_module_ota_t ; ///< Base struct int nid; int tsid; @@ -505,7 +505,7 @@ static int _opentv_bat_section * Table Callbacks * ***********************************************************************/ -static epggrab_ota_mux_t *_opentv_table_callback +static epggrab_ota_mux_t *_opentv_event_callback ( th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len, uint8_t tid, void *p ) { th_dvb_table_t *tdt = (th_dvb_table_t*)p; @@ -568,7 +568,7 @@ static epggrab_ota_mux_t *_opentv_table_callback static int _opentv_title_callback ( th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len, uint8_t tid, void *p ) { - epggrab_ota_mux_t *ota = _opentv_table_callback(tdmi, buf, len, tid, p); + epggrab_ota_mux_t *ota = _opentv_event_callback(tdmi, buf, len, tid, p); if (ota) return _opentv_parse_event_section((opentv_module_t*)ota->grab, (opentv_status_t*)ota->status, @@ -579,7 +579,7 @@ static int _opentv_title_callback static int _opentv_summary_callback ( th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len, uint8_t tid, void *p ) { - epggrab_ota_mux_t *ota = _opentv_table_callback(tdmi, buf, len, tid, p); + epggrab_ota_mux_t *ota = _opentv_event_callback(tdmi, buf, len, tid, p); if (ota) return _opentv_parse_event_section((opentv_module_t*)ota->grab, (opentv_status_t*)ota->status, diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c index 1d8bf6ef..ee4f3956 100644 --- a/src/epggrab/otamux.c +++ b/src/epggrab/otamux.c @@ -72,7 +72,7 @@ int epggrab_mux_period ( th_dvb_mux_instance_t *tdmi ) int period = 0; epggrab_ota_mux_t *ota; TAILQ_FOREACH(ota, &tdmi->tdmi_epg_grab, tdmi_link) { - if (!ota->is_reg) break; + if (!ota->is_reg) continue; if (ota->timeout > period) period = ota->timeout; } @@ -146,7 +146,7 @@ epggrab_ota_mux_t *epggrab_ota_create } else { time_t now; time(&now); - if (ota) ota->state = EPGGRAB_OTA_MUX_IDLE; + ota->state = EPGGRAB_OTA_MUX_IDLE; /* Blocked */ if (epggrab_ota_is_blocked(ota)) ota = NULL; From 76d37cd05d4fbeffb9476ae996148e191daba9af Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 29 Jun 2012 21:41:08 +0100 Subject: [PATCH 08/11] Correct ota completion check. --- src/epggrab/otamux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c index ee4f3956..7a920266 100644 --- a/src/epggrab/otamux.c +++ b/src/epggrab/otamux.c @@ -269,7 +269,7 @@ void epggrab_ota_complete ( epggrab_ota_mux_t *ota ) /* Check others */ TAILQ_FOREACH(ota, &tdmi->tdmi_epg_grab, tdmi_link) { - if (ota->is_reg && ota->state != EPGGRAB_OTA_MUX_RUNNING) break; + if (ota->is_reg && ota->state == EPGGRAB_OTA_MUX_RUNNING) break; } /* All complete (bring timer forward) */ From 406c2353315b9acfa3658c95f748bf4f764e39bc Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 29 Jun 2012 22:02:41 +0100 Subject: [PATCH 09/11] Missing / as a result of a manual merge resolution. --- src/epggrab/module/opentv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index 0ae4181a..5453cc99 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -836,14 +836,14 @@ void opentv_init ( void ) /* Load dictionaries */ if ((m = hts_settings_load("epggrab/opentv/dict"))) _opentv_dict_load(m); - if ((m = hts_settings_load("%sdata/epggrab/opentv/dict", dr))) + if ((m = hts_settings_load("%s/data/epggrab/opentv/dict", dr))) _opentv_dict_load(m); tvhlog(LOG_INFO, "opentv", "dictonaries loaded"); /* Load providers */ if ((m = hts_settings_load("epggrab/opentv/prov"))) _opentv_prov_load(m); - if ((m = hts_settings_load("%sdata/epggrab/opentv/prov", dr))) + if ((m = hts_settings_load("%s/data/epggrab/opentv/prov", dr))) _opentv_prov_load(m); tvhlog(LOG_INFO, "opentv", "providers loaded"); } From 75dd6e351dfa6390fdeeaf31907a4b90e6b549ac Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 29 Jun 2012 22:16:36 +0100 Subject: [PATCH 10/11] Ensure we handle channel deletions. --- src/epggrab/module/opentv.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index 5453cc99..4b609bee 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -795,13 +795,15 @@ static int _opentv_prov_load_one ( const char *id, htsmsg_t *m ) NULL); /* Add provider details */ - mod->dict = dict; - mod->nid = nid; - mod->tsid = tsid; - mod->sid = sid; - mod->channel = _pid_list_to_array(cl); - mod->title = _pid_list_to_array(tl); - mod->summary = _pid_list_to_array(sl); + mod->dict = dict; + mod->nid = nid; + mod->tsid = tsid; + mod->sid = sid; + mod->channel = _pid_list_to_array(cl); + mod->title = _pid_list_to_array(tl); + mod->summary = _pid_list_to_array(sl); + mod->channels = &_opentv_channels; + mod->ch_rem = epggrab_module_ch_rem; return 1; } From af6502d1d6bb3f8282b065917c9eb8415d1f5054 Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 29 Jun 2012 23:02:38 +0100 Subject: [PATCH 11/11] Some fixes to EIT scanner and UI. --- src/epggrab.c | 9 ++++----- src/epggrab/module/eit.c | 9 +++++---- src/epggrab/otamux.c | 2 +- src/webui/static/app/epggrab.js | 16 ++++++++-------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/epggrab.c b/src/epggrab.c index 8036d733..0c52ea6c 100644 --- a/src/epggrab.c +++ b/src/epggrab.c @@ -133,7 +133,7 @@ static void _epggrab_load ( void ) if ( (a = htsmsg_get_map(m, "mod_enabled")) ) { LIST_FOREACH(mod, &epggrab_modules, link) { if (htsmsg_get_u32_or_default(a, mod->id, 0)) { - if (mod->enable) mod->enable(mod, 1); + epggrab_enable_module(mod, 1); } } } @@ -230,11 +230,9 @@ int epggrab_set_module ( epggrab_module_t *m ) if (m && m->type != EPGGRAB_INT) return 0; mod = (epggrab_module_int_t*)m; if ( epggrab_module != mod ) { - if (epggrab_module && epggrab_module->enable) - epggrab_module->enable(epggrab_module, 0); + epggrab_enable_module((epggrab_module_t*)epggrab_module, 0); epggrab_module = (epggrab_module_int_t*)mod; - if (epggrab_module && epggrab_module->enable) - epggrab_module->enable(epggrab_module, 1); + epggrab_enable_module((epggrab_module_t*)epggrab_module, 1); save = 1; } return save; @@ -278,6 +276,7 @@ int epggrab_set_channel_reicon ( uint32_t e ) int epggrab_enable_module ( epggrab_module_t *mod, uint8_t e ) { int save = 0; + if (!mod) return 0; if (mod->enable) { save = mod->enable(mod, e); } else if ( e != mod->enabled ) { diff --git a/src/epggrab/module/eit.c b/src/epggrab/module/eit.c index 0f291ae0..cd017beb 100644 --- a/src/epggrab/module/eit.c +++ b/src/epggrab/module/eit.c @@ -45,13 +45,13 @@ static void _eit_dtag_dump ( uint8_t dtag, uint8_t dlen, uint8_t *buf ) { int i = 0, j = 0; char tmp[100]; - tvhlog(LOG_DEBUG, "eit", "dtag 0x%02X len %d\n", dtag, dlen); - while (i < dlen) - while (dlen--) { + tvhlog(LOG_DEBUG, "eit", " dtag 0x%02X len %d", dtag, dlen); + while (i < dlen) { j += sprintf(tmp+j, "%02X ", buf[i]); i++; if ((i % 8) == 0 || !dlen) { - tvhlog(LOG_DEBUG, "eit", " %s", tmp); + tvhlog(LOG_DEBUG, "eit", " %s", tmp); + j = 0; } } } @@ -201,6 +201,7 @@ static int _eit_callback svc = dvb_transport_find(tdmi, sid, 0, NULL); if (!svc || !svc->s_enabled || !(ch = svc->s_ch)) return 0; + /* Ignore (disabled) */ // TODO: should this be altered? if (!svc->s_dvb_eit_enable) return 0; diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c index 7a920266..6f9a6876 100644 --- a/src/epggrab/otamux.c +++ b/src/epggrab/otamux.c @@ -265,7 +265,6 @@ void epggrab_ota_complete ( epggrab_ota_mux_t *ota ) if (ota->state != EPGGRAB_OTA_MUX_COMPLETE) { ota->state = EPGGRAB_OTA_MUX_COMPLETE; time(&ota->completed); - _epggrab_ota_finished(ota); /* Check others */ TAILQ_FOREACH(ota, &tdmi->tdmi_epg_grab, tdmi_link) { @@ -291,6 +290,7 @@ void epggrab_ota_cancel ( epggrab_ota_mux_t *ota ) void epggrab_ota_timeout ( epggrab_ota_mux_t *ota ) { epggrab_ota_complete(ota); + _epggrab_ota_finished(ota); } /* diff --git a/src/webui/static/app/epggrab.js b/src/webui/static/app/epggrab.js index cc7f399e..42189f39 100644 --- a/src/webui/static/app/epggrab.js +++ b/src/webui/static/app/epggrab.js @@ -7,16 +7,16 @@ tvheadend.epggrab = function() { /* * Module lists (I'm sure there is a better way!) */ - var EPGGRAB_MODULE_INTERNAL = 0x01; - var EPGGRAB_MODULE_EXTERNAL = 0x02; - var EPGGRAB_MODULE_OTA = 0x04; + var EPGGRAB_MODULE_INTERNAL = 0; + var EPGGRAB_MODULE_EXTERNAL = 1; + var EPGGRAB_MODULE_OTA = 2; var moduleStore = new Ext.data.JsonStore({ root : 'entries', url : 'epggrab', baseParams : { op : 'moduleList' }, autoLoad : true, - fields : [ 'id', 'name', 'path', 'flags', 'enabled' ] + fields : [ 'id', 'name', 'path', 'type', 'enabled' ] }); var internalModuleStore = new Ext.data.Store({ recordType: moduleStore.recordType @@ -29,7 +29,7 @@ tvheadend.epggrab = function() { }); moduleStore.on('load', function() { moduleStore.filterBy(function(r) { - return r.get('flags') & EPGGRAB_MODULE_INTERNAL; + return r.get('type') == EPGGRAB_MODULE_INTERNAL; }); r = new internalModuleStore.recordType({ id: '', name : 'Disabled'}); internalModuleStore.add(r); @@ -37,19 +37,19 @@ tvheadend.epggrab = function() { internalModuleStore.add(r.copy()); }); moduleStore.filterBy(function(r) { - return r.get('flags') & EPGGRAB_MODULE_EXTERNAL; + return r.get('type') == EPGGRAB_MODULE_EXTERNAL; }); moduleStore.each(function(r) { externalModuleStore.add(r.copy()); }); moduleStore.filterBy(function(r) { - return r.get('flags') & EPGGRAB_MODULE_OTA; + return r.get('type') == EPGGRAB_MODULE_OTA; }); moduleStore.each(function(r) { otaModuleStore.add(r.copy()); }); moduleStore.filterBy(function(r) { - return r.get('flags') & (EPGGRAB_MODULE_OTA | EPGGRAB_MODULE_EXTERNAL); + return r.get('type') != EPGGRAB_MODULE_INTERNAL; }); });