4 #include <lib/dvb/cahandler.h>
5 #include <lib/base/eerror.h>
6 #include <lib/system/init.h>
7 #include <lib/system/init_num.h>
8 #include <lib/system/info.h>
10 ePMTClient::ePMTClient(eDVBCAHandler
*handler
, int socket
)
11 : eUnixDomainSocket(socket
, 1, eApp
), parent(handler
)
13 CONNECT(connectionClosed_
, ePMTClient::connectionLost
);
16 void ePMTClient::connectionLost()
18 if (parent
) parent
->connectionLost(this);
21 eDVBCAHandler::eDVBCAHandler()
22 : eServerSocket(PMT_SERVER_SOCKET
, eApp
), serviceLeft(eApp
)
24 services
.setAutoDelete(true);
25 clients
.setAutoDelete(true);
26 CONNECT( eDVB::getInstance()->leaveTransponder
, eDVBCAHandler::leaveTransponder
);
27 CONNECT(serviceLeft
.timeout
, eDVBCAHandler::serviceGone
);
28 eDVBCaPMTClientHandler::registerCaPMTClient(this); // static method...
31 eDVBCAHandler::~eDVBCAHandler()
33 eDVBCaPMTClientHandler::unregisterCaPMTClient(this); // static method...
36 void eDVBCAHandler::newConnection(int socket
)
38 ePMTClient
*client
= new ePMTClient(this, socket
);
39 clients
.push_back(client
);
41 /* inform the new client about our current services, if we have any */
45 void eDVBCAHandler::connectionLost(ePMTClient
*client
)
47 ePtrList
<ePMTClient
>::iterator it
= std::find(clients
.begin(), clients
.end(), client
);
48 if (it
!= clients
.end())
54 void eDVBCAHandler::leaveTransponder( eTransponder
* t
)
58 const char *msg
= "\x9f\x80\x3f\x04\x83\x02\x03\x01";
60 /* send msg to the listening client */
61 eUnixDomainSocket
socket(eApp
);
62 socket
.connectToPath(PMT_CLIENT_SOCKET
);
63 if (socket
.state() == eSocket::Connection
) socket
.writeBlock(msg
, strlen(msg
));
67 void eDVBCAHandler::enterService( const eServiceReferenceDVB
&service
)
69 ePtrList
<CAService
>::iterator it
=
70 std::find(services
.begin(), services
.end(), service
);
71 if ( it
== services
.end() )
74 services
.push_back(new CAService( service
));
78 * our servicelist has changed, but we have to wait till we receive PMT data
79 * for this service, before we distribute a new list of CAPMT objects to our clients.
83 void eDVBCAHandler::leaveService( const eServiceReferenceDVB
&service
)
85 ePtrList
<CAService
>::iterator it
=
86 std::find(services
.begin(), services
.end(), service
);
87 if ( it
!= services
.end() )
89 serviceLeft
.startLongTimer(2);
93 /* our servicelist has changed, distribute the list of CAPMT objects to all our clients */
97 void eDVBCAHandler::serviceGone()
105 void eDVBCAHandler::distributeCAPMT()
108 * write the list of CAPMT objects to each connected client, if it's not empty
110 if (services
.empty()) return;
112 ePtrList
<ePMTClient
>::iterator client_it
= clients
.begin();
113 for ( ; client_it
!= clients
.end(); ++client_it
)
115 if (client_it
->state() == eSocket::Connection
)
117 unsigned char list_management
= LIST_FIRST
;
118 ePtrList
<CAService
>::iterator it
= services
.begin();
119 for ( ; it
!= services
.end(); )
121 CAService
*current
= it
;
123 if (it
== services
.end()) list_management
|= LIST_LAST
;
124 current
->writeCAPMTObject(*client_it
, list_management
);
125 list_management
= LIST_MORE
;
131 void eDVBCAHandler::handlePMT( const eServiceReferenceDVB
&service
, PMT
*pmt
)
133 ePtrList
<CAService
>::iterator it
= std::find(services
.begin(), services
.end(), service
);
134 if (it
!= services
.end())
136 /* we found the service in our list */
137 if (it
->getCAPMTVersion() == pmt
->version
)
139 eDebug("[eDVBCAHandler] dont send the self pmt version");
143 bool isUpdate
= (it
->getCAPMTVersion() >= 0);
145 /* prepare the data */
148 /* send the data to the listening client */
153 /* this is a PMT update, we should distribute the new CAPMT object to all our connected clients */
154 ePtrList
<ePMTClient
>::iterator client_it
= clients
.begin();
155 for ( ; client_it
!= clients
.end(); ++client_it
)
157 if (client_it
->state() == eSocket::Connection
)
159 it
->writeCAPMTObject(*client_it
, LIST_UPDATE
);
166 * this is PMT information for a new service, so we can now distribute
167 * the CAPMT objects to all our connected clients
174 CAService::CAService( const eServiceReferenceDVB
&service
)
175 : eUnixDomainSocket(eApp
), lastPMTVersion(-1), me(service
), capmt(NULL
), retry(eApp
)
177 int socketReconnect
= 0;
178 eConfig::getInstance()->getKey("/elitedvb/extra/cahandlerReconnect", socketReconnect
);
181 CONNECT(connectionClosed_
, CAService::connectionLost
);
183 CONNECT(retry
.timeout
, CAService::sendCAPMT
);
184 // eDebug("[eDVBCAHandler] new service %s", service.toString().c_str() );
187 void CAService::connectionLost()
189 /* reconnect in 1s */
190 retry
.startLongTimer(1);
193 void CAService::buildCAPMT( PMT
*pmt
)
196 capmt
= new unsigned char[1024];
198 memcpy(capmt
,"\x9f\x80\x32\x82\x00\x00", 6);
200 capmt
[6]=lastPMTVersion
==-1 ? LIST_ONLY
: LIST_UPDATE
;
201 capmt
[7]=(unsigned char)((pmt
->program_number
>>8) & 0xff); //prg-nr
202 capmt
[8]=(unsigned char)(pmt
->program_number
& 0xff); //prg-nr
204 capmt
[9]=pmt
->version
; //reserved - version - current/next
205 capmt
[10]=0x00; //reserved - prg-info len
206 capmt
[11]=0x00; //prg-info len
208 capmt
[12]=CMD_OK_DESCRAMBLING
; // ca pmt command id
209 capmt
[13]=0x81; // private descr.. dvbnamespace
211 capmt
[15]=me
.getDVBNamespace().get()>>24;
212 capmt
[16]=(me
.getDVBNamespace().get()>>16)&0xFF;
213 capmt
[17]=(me
.getDVBNamespace().get()>>8)&0xFF;
214 capmt
[18]=me
.getDVBNamespace().get()&0xFF;
215 capmt
[19]=me
.getTransportStreamID().get()>>8;
216 capmt
[20]=me
.getTransportStreamID().get()&0xFF;
217 capmt
[21]=me
.getOriginalNetworkID().get()>>8;
218 capmt
[22]=me
.getOriginalNetworkID().get()&0xFF;
220 capmt
[23]=0x82; // demuxer kram..
223 switch(eSystemInfo::getInstance()->getHwType())
225 case eSystemInfo::DM7000
:
226 case eSystemInfo::DM7020
:
227 capmt
[25]=0x03; // descramble on demux0 and demux1
228 capmt
[26]=0x01; // get section data from demux1
230 case eSystemInfo::DM500PLUS
:
231 case eSystemInfo::DM600PVR
:
232 capmt
[25]=0x01; // descramble on demux0 // demux 1 is just a fake demux 0
233 capmt
[26]=0x01; // get section data from demux1
236 capmt
[25]=0x01; // only descramble on demux0
237 capmt
[26]=0x00; // get section data from demux0
241 capmt
[27]=0x84; // pmt pid
243 capmt
[29]=pmt
->pid
>>8;
244 capmt
[30]=pmt
->pid
&0xFF;
246 lastPMTVersion
=pmt
->version
;
253 for (ePtrList
<Descriptor
>::const_iterator
i(pmt
->program_info
);
254 i
!= pmt
->program_info
.end(); ++i
)
256 if (i
->Tag()==9) // CADescriptor
258 CADescriptor
*ca
=(CADescriptor
*)*i
;
259 memcpy(capmt
+wp
, ca
->data
, ca
->data
[1]+2);
265 for (ePtrList
<PMTEntry
>::iterator
i(pmt
->streams
); i
!= pmt
->streams
.end(); ++i
)
270 capmt
[lenpos
]=((len
& 0xf00)>>8);
271 capmt
[lenpos
+1]=(len
& 0xff);
275 capmt
[wp
++]=(pe
->stream_type
& 0xffff);
276 capmt
[wp
++]=((pe
->elementary_PID
>> 8) & 0xff);
277 capmt
[wp
++]=(pe
->elementary_PID
& 0xff);
280 switch (pe
->stream_type
)
282 case 1: // ISO/IEC 11172 Video
283 case 2: // ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or ISO/IEC 11172-2 constrained parameter video stream
284 case 3: // ISO/IEC 11172 Audio
285 case 4: // ISO/IEC 13818-3 Audio
286 case 6: // private stream ( ttx or AC3 or DTS )
287 for (ePtrList
<Descriptor
>::const_iterator
i(pe
->ES_info
);
288 i
!= pe
->ES_info
.end(); ++i
)
290 if (i
->Tag()==9) // CADescriptor
292 CADescriptor
*ca
=(CADescriptor
*)*i
;
296 capmt
[wp
++]=0x01; //ca_pmt_command_id
299 memcpy(capmt
+wp
, ca
->data
, ca
->data
[1]+2);
308 capmt
[lenpos
]=((len
& 0xf00)>>8);
309 capmt
[lenpos
+1]=(len
& 0xff);
311 capmt
[4]=((wp
-6)>>8) & 0xff;
312 capmt
[5]=(wp
-6) & 0xff;
315 void CAService::sendCAPMT()
317 if (state() == Idle
|| state() == Invalid
)
319 /* we're not connected yet */
320 connectToPath(PMT_CLIENT_SOCKET
);
323 if (state() == Connection
)
326 * Send the CAPMT object which we just constructed, with unmodified list_management field.
327 * This should work in case of a new service, as well as for an updated service.
329 writeCAPMTObject(this, -1);
333 /* we're not connected, try again in 5s */
334 retry
.startLongTimer(5);
338 int CAService::writeCAPMTObject(eSocket
*socket
, int list_management
)
342 if (!capmt
) return 0;
344 if (list_management
>= 0) capmt
[6] = (unsigned char)list_management
;
350 return socket
->writeBlock((const char*)capmt
, wp
);
353 eAutoInitP0
<eDVBCAHandler
> init_eDVBCAHandler(eAutoInitNumbers::osd
-2, "eDVBCAHandler");