Skip to content

Commit 6267446

Browse files
authored
Merge pull request #4306 from WXbet/softcsa-fixes
Softcsa fixes
2 parents 09c0337 + ab0f32b commit 6267446

File tree

12 files changed

+121
-55
lines changed

12 files changed

+121
-55
lines changed

lib/dvb/cahandler.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -405,23 +405,24 @@ void eDVBCAHandler::newConnection(int socket)
405405
ePMTClient *client = new ePMTClient(this, client_fd);
406406
clients.push_back(client);
407407

408-
/* Always distribute current CAPMTs first (legacy format, works for all clients) */
409-
distributeCAPMT();
410-
411-
/* Send CLIENT_INFO only when appropriate:
412-
* - Protocol-3 already established (OSCam reconnect): always send
413-
* - First connection ever: send to probe for Protocol-3 support
414-
* - Legacy client detected (no SERVER_INFO after first attempt): skip
415-
* to avoid unnecessary errors in legacy softcam logs */
416408
if (m_protocol3_established)
417409
{
410+
/* Protocol-3 reconnect: complete handshake first, distributeCAPMT()
411+
* will be called from processServerInfoPacket() */
418412
client->sendClientInfo();
419413
}
420414
else if (!m_handshake_attempted)
421415
{
416+
/* First connection: send legacy CAPMTs, then probe for Protocol-3 */
417+
distributeCAPMT();
422418
client->sendClientInfo();
423419
m_handshake_attempted = true;
424420
}
421+
else
422+
{
423+
/* Legacy softcam - send CAPMTs immediately */
424+
distributeCAPMT();
425+
}
425426
}
426427

427428
void eDVBCAHandler::connectionLost(ePMTClient *client)
@@ -569,6 +570,25 @@ int eDVBCAHandler::unregisterService(const eServiceReferenceDVB &ref, int adapte
569570
{
570571
if (!used_demux_slots) // no more used.. so we remove it
571572
{
573+
/*
574+
* Send CMD_NOT_SELECTED to tell the softcam to stop
575+
* descrambling this service before we delete it.
576+
* Without this, switching from an encrypted channel
577+
* to FTA/IPTV would leave the softcam in descrambling
578+
* state (e.g. ecm.info not removed).
579+
*/
580+
if (m_protocol3_established && caservice->getCAPMTVersion() >= 0)
581+
{
582+
for (ePtrList<ePMTClient>::iterator client_it = clients.begin(); client_it != clients.end(); ++client_it)
583+
{
584+
if (client_it->state() == eSocket::Connection)
585+
{
586+
eDebug("[eDVBCAHandler] sending CMD_NOT_SELECTED for service %s", caservice->toString().c_str());
587+
caservice->writeCAPMTObject(*client_it, LIST_UPDATE, CMD_NOT_SELECTED);
588+
}
589+
}
590+
}
591+
572592
delete it->second;
573593
services.erase(it);
574594

lib/dvb/csasession.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,18 @@ void eDVBCSASession::startECMMonitor(iDVBDemux *demux, uint16_t ecm_pid, uint16_
141141

142142
if (info.is_csa_alt && !m_active)
143143
{
144-
eDebug("[eDVBCSASession] ECM Monitor: Activating from cache (CSA-ALT)");
145144
m_ecm_analyzed = true;
146145
m_csa_alt = true;
147-
setActive(true);
146+
if (shouldSuppressActivation && shouldSuppressActivation())
147+
{
148+
eDebug("[eDVBCSASession] ECM Monitor: CSA-ALT cached but activation suppressed (CI module)");
149+
stopECMMonitor();
150+
}
151+
else
152+
{
153+
eDebug("[eDVBCSASession] ECM Monitor: Activating from cache (CSA-ALT)");
154+
setActive(true);
155+
}
148156
}
149157
}
150158

@@ -235,7 +243,15 @@ void eDVBCSASession::ecmDataReceived(const uint8_t *data)
235243
eDebug("[eDVBCSASession] CSA-ALT detected from ECM! Activating software descrambling");
236244
if (!m_active)
237245
{
238-
setActive(true);
246+
if (shouldSuppressActivation && shouldSuppressActivation())
247+
{
248+
eDebug("[eDVBCSASession] Activation suppressed (CI module handles decryption)");
249+
stopECMMonitor();
250+
}
251+
else
252+
{
253+
setActive(true);
254+
}
239255
}
240256
}
241257
else

lib/dvb/csasession.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <lib/dvb/idvb.h>
66
#include <lib/base/ebase.h>
77
#include <sigc++/sigc++.h>
8+
#include <functional>
89

910
class eDVBCSAEngine;
1011
class eDVBCAHandler;
@@ -91,6 +92,10 @@ class eDVBCSASession : public iServiceScrambled, public sigc::trackable
9192
// Signal when first CW is received (for decoder start timing)
9293
sigc::signal<void()> firstCwReceived;
9394

95+
// Optional callback to check if activation should be suppressed
96+
// (e.g. CI module handles decryption). Return true to suppress.
97+
std::function<bool()> shouldSuppressActivation;
98+
9499
private:
95100
eServiceReferenceDVB m_service_ref;
96101
ePtr<eDVBCSAEngine> m_engine;

lib/dvb/cwhandler.cpp

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ void eDVBCWHandler::threadLoop()
257257
const Connection& conn = conns_snapshot[i];
258258

259259
// Softcam → proxy_fd (and intercept CWs)
260+
bool softcam_disconnected = false;
260261
if (pfds[softcam_idx].revents & POLLIN)
261262
{
262263
ssize_t n = ::read(conn.softcam_fd, buf, sizeof(buf));
@@ -283,31 +284,40 @@ void eDVBCWHandler::threadLoop()
283284
written += w;
284285
}
285286
}
287+
else if (n == 0)
288+
{
289+
// EOF - softcam closed the connection
290+
eDebug("[eDVBCWHandler] Softcam EOF on fd %d", conn.softcam_fd);
291+
softcam_disconnected = true;
292+
}
293+
else if (errno != EINTR && errno != EAGAIN)
294+
{
295+
eDebug("[eDVBCWHandler] Softcam read error on fd %d: %m", conn.softcam_fd);
296+
softcam_disconnected = true;
297+
}
286298
}
287299

288300
// Handle softcam disconnect
289-
if (pfds[softcam_idx].revents & (POLLHUP | POLLERR))
301+
if (softcam_disconnected || (pfds[softcam_idx].revents & (POLLHUP | POLLERR)))
290302
{
291-
if (!(pfds[softcam_idx].revents & POLLIN)) // Only if no data pending
303+
eDebug("[eDVBCWHandler] Softcam disconnected on fd %d", conn.softcam_fd);
304+
// Close proxy_fd so ePMTClient gets connectionLost
305+
std::lock_guard<std::mutex> lock(m_connections_mutex);
306+
for (auto it = m_connections.begin(); it != m_connections.end(); ++it)
292307
{
293-
eDebug("[eDVBCWHandler] Softcam disconnected on fd %d", conn.softcam_fd);
294-
// Close proxy_fd so ePMTClient gets connectionLost
295-
std::lock_guard<std::mutex> lock(m_connections_mutex);
296-
for (auto it = m_connections.begin(); it != m_connections.end(); ++it)
308+
if (it->softcam_fd == conn.softcam_fd)
297309
{
298-
if (it->softcam_fd == conn.softcam_fd)
299-
{
300-
::close(it->softcam_fd);
301-
::close(it->proxy_fd);
302-
m_connections.erase(it);
303-
break;
304-
}
310+
::close(it->softcam_fd);
311+
::close(it->proxy_fd);
312+
m_connections.erase(it);
313+
break;
305314
}
306-
continue;
307315
}
316+
continue;
308317
}
309318

310319
// proxy_fd → softcam (CAPMT writes from ePMTClient)
320+
bool proxy_disconnected = false;
311321
if (pfds[proxy_idx].revents & POLLIN)
312322
{
313323
ssize_t n = ::read(conn.proxy_fd, buf, sizeof(buf));
@@ -330,24 +340,31 @@ void eDVBCWHandler::threadLoop()
330340
written += w;
331341
}
332342
}
343+
else if (n == 0)
344+
{
345+
eDebug("[eDVBCWHandler] ePMTClient EOF on proxy_fd %d", conn.proxy_fd);
346+
proxy_disconnected = true;
347+
}
348+
else if (errno != EINTR && errno != EAGAIN)
349+
{
350+
eDebug("[eDVBCWHandler] ePMTClient read error on proxy_fd %d: %m", conn.proxy_fd);
351+
proxy_disconnected = true;
352+
}
333353
}
334354

335355
// Handle ePMTClient disconnect
336-
if (pfds[proxy_idx].revents & (POLLHUP | POLLERR))
356+
if (proxy_disconnected || (pfds[proxy_idx].revents & (POLLHUP | POLLERR)))
337357
{
338-
if (!(pfds[proxy_idx].revents & POLLIN))
358+
eDebug("[eDVBCWHandler] ePMTClient disconnected on proxy_fd %d", conn.proxy_fd);
359+
std::lock_guard<std::mutex> lock(m_connections_mutex);
360+
for (auto it = m_connections.begin(); it != m_connections.end(); ++it)
339361
{
340-
eDebug("[eDVBCWHandler] ePMTClient disconnected on proxy_fd %d", conn.proxy_fd);
341-
std::lock_guard<std::mutex> lock(m_connections_mutex);
342-
for (auto it = m_connections.begin(); it != m_connections.end(); ++it)
362+
if (it->proxy_fd == conn.proxy_fd)
343363
{
344-
if (it->proxy_fd == conn.proxy_fd)
345-
{
346-
::close(it->softcam_fd);
347-
::close(it->proxy_fd);
348-
m_connections.erase(it);
349-
break;
350-
}
364+
::close(it->softcam_fd);
365+
::close(it->proxy_fd);
366+
m_connections.erase(it);
367+
break;
351368
}
352369
}
353370
}

lib/dvb/pmt.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,6 @@ void eDVBServicePMTHandler::PMTready(int error)
182182
{
183183
eDVBCIInterfaces::getInstance()->recheckPMTHandlers();
184184
eDVBCIInterfaces::getInstance()->gotPMT(this);
185-
if (isCiConnected())
186-
serviceEvent(eventCIConnected);
187185
}
188186
}
189187
if (m_ca_servicePtr)

lib/dvb/pmt.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,6 @@ class eDVBServicePMTHandler: public eDVBPMTParser
117117

118118
eventStopped,
119119
eventChannelAllocated,
120-
eventStreamCorrupt,
121-
eventCIConnected, // a CI slot was assigned to this service after recheckPMTHandlers
122120
};
123121
#ifndef SWIG
124122
sigc::signal<void(int)> serviceEvent;
@@ -139,6 +137,7 @@ class eDVBServicePMTHandler: public eDVBPMTParser
139137
void sendEventNoPatEntry();
140138
void getHBBTVUrl(std::string &ret) const { ret = m_HBBTVUrl; }
141139
void setCaDisable(bool disable) { m_ca_disabled = disable; }
140+
bool isCiConnected();
142141
void allocatePVRChannel();
143142

144143
enum serviceType
@@ -167,7 +166,6 @@ class eDVBServicePMTHandler: public eDVBPMTParser
167166
void free();
168167
void addCaHandler();
169168
void removeCaHandler();
170-
bool isCiConnected();
171169
private:
172170
bool m_have_cached_program;
173171
program m_cached_program;

lib/dvb_ci/dvbci.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,6 @@ void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler)
800800
bool eDVBCIInterfaces::isCiConnected(eDVBServicePMTHandler *pmthandler)
801801
{
802802
bool ret = false;
803-
singleLock s(m_pmt_handler_lock);
804803
PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(), m_pmt_handlers.end(), pmthandler);
805804
if (it != m_pmt_handlers.end() && it->cislot)
806805
{

lib/dvb_ci/dvbci.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,6 @@ class eDVBCIInterfaces: public eMainloop, private eThread
215215
void recheckPMTHandlers();
216216
void executeRecheckPMTHandlersInMainloop();
217217
void gotPMT(eDVBServicePMTHandler *pmthandler);
218-
bool isCiConnected(eDVBServicePMTHandler *pmthandler);
219218
void ciRemoved(eDVBCISlot *slot);
220219
int getSlotState(int slot);
221220

@@ -228,6 +227,7 @@ class eDVBCIInterfaces: public eMainloop, private eThread
228227
int answerEnq(int slot, char *value);
229228
int cancelEnq(int slot);
230229
int getMMIState(int slot);
230+
bool isCiConnected(eDVBServicePMTHandler *pmthandler);
231231
int setInputSource(int tunerno, const std::string &source);
232232
int setCIClockRate(int slot, int rate);
233233
void setCIPlusRouting(int slotid);

lib/service/servicedvb.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,14 +1308,6 @@ void eDVBServicePlay::serviceEvent(int event)
13081308
case eDVBServicePMTHandler::eventHBBTVInfo:
13091309
m_event((iPlayableService*)this, evHBBTVInfo);
13101310
break;
1311-
case eDVBServicePMTHandler::eventCIConnected:
1312-
if (m_csa_session && m_csa_session->isActive())
1313-
{
1314-
eDebug("[eDVBServicePlay] CI module connected - deactivating SoftCSA to save resources");
1315-
m_csa_session->stopECMMonitor();
1316-
m_csa_session->forceDeactivate();
1317-
}
1318-
break;
13191311
}
13201312
}
13211313

@@ -4053,12 +4045,18 @@ void eDVBServicePlay::setupSpeculativeDescrambling()
40534045

40544046
// Create SoftDecoder (will start when session activates)
40554047
m_soft_decoder = new eDVBSoftDecoder(m_service_handler, m_dvb_service, m_decoder_index);
4048+
m_soft_decoder->setNoAudio(m_noaudio);
40564049
m_soft_decoder->setSession(m_csa_session);
40574050

40584051
// Connect to SoftDecoder's audio PID selection signal
40594052
m_soft_decoder->m_audio_pid_selected.connect(
40604053
sigc::mem_fun(*this, &eDVBServicePlay::onSoftDecoderAudioPidSelected));
40614054

4055+
// Suppress SoftCSA activation when CI module handles decryption
4056+
m_csa_session->shouldSuppressActivation = [this]() {
4057+
return m_service_handler.isCiConnected();
4058+
};
4059+
40624060
// Connect to session's activated signal for decoder handover
40634061
m_csa_session->activated.connect(
40644062
sigc::mem_fun(*this, &eDVBServicePlay::onSessionActivated));

lib/service/servicedvbfcc.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,11 @@ void eDVBServiceFCCPlay::setupSpeculativeDescrambling()
595595
m_soft_decoder->m_audio_pid_selected.connect(
596596
[this](int pid) { this->onSoftDecoderAudioPidSelected(pid); });
597597

598+
// Suppress SoftCSA activation when CI module handles decryption
599+
m_csa_session->shouldSuppressActivation = [this]() {
600+
return m_service_handler.isCiConnected();
601+
};
602+
598603
// Connect to session's activated signal - use FCC-specific callback!
599604
// This is the key difference from base class: we use onFCCSessionActivated
600605
// which handles FCC decoder stop/start properly

0 commit comments

Comments
 (0)