@@ -86,8 +86,8 @@ bool csa_load_library()
8686}
8787
8888eDVBCSAEngine::eDVBCSAEngine ()
89- : m_key_even( nullptr )
90- , m_key_odd( nullptr )
89+ : m_key_even{ nullptr , nullptr }
90+ , m_key_odd{ nullptr , nullptr }
9191 , m_batch_size(0 )
9292{
9393}
@@ -96,15 +96,18 @@ eDVBCSAEngine::~eDVBCSAEngine()
9696{
9797 if (g_csa_api.available && g_csa_api.key_free )
9898 {
99- if (m_key_even )
99+ for ( int i = 0 ; i < 2 ; ++i )
100100 {
101- g_csa_api.key_free (m_key_even);
102- m_key_even = nullptr ;
103- }
104- if (m_key_odd)
105- {
106- g_csa_api.key_free (m_key_odd);
107- m_key_odd = nullptr ;
101+ if (m_key_even[i])
102+ {
103+ g_csa_api.key_free (m_key_even[i]);
104+ m_key_even[i] = nullptr ;
105+ }
106+ if (m_key_odd[i])
107+ {
108+ g_csa_api.key_free (m_key_odd[i]);
109+ m_key_odd[i] = nullptr ;
110+ }
108111 }
109112 }
110113}
@@ -118,13 +121,16 @@ bool eDVBCSAEngine::init()
118121 }
119122
120123 m_batch_size = g_csa_api.batch_size ();
121- m_key_even = g_csa_api.key_alloc ();
122- m_key_odd = g_csa_api.key_alloc ();
123124
124- if (!m_key_even || !m_key_odd )
125+ for ( int i = 0 ; i < 2 ; ++i )
125126 {
126- eWarning (" [eDVBCSAEngine] init: key_alloc failed" );
127- return false ;
127+ m_key_even[i] = g_csa_api.key_alloc ();
128+ m_key_odd[i] = g_csa_api.key_alloc ();
129+ if (!m_key_even[i] || !m_key_odd[i])
130+ {
131+ eWarning (" [eDVBCSAEngine] init: key_alloc failed" );
132+ return false ;
133+ }
128134 }
129135
130136 // Pre-allocate batch arrays
@@ -201,7 +207,7 @@ void eDVBCSAEngine::setKey(int parity, uint8_t ecm_mode, const uint8_t* cw)
201207{
202208 if (!cw)
203209 return ;
204- if (!m_key_even || !m_key_odd)
210+ if (!m_key_even[ 0 ] || !m_key_even[ 1 ] || ! m_key_odd[ 0 ] || !m_key_odd[ 1 ] )
205211 return ;
206212 if (!g_csa_api.available || !g_csa_api.key_set_ecm )
207213 return ;
@@ -211,16 +217,24 @@ void eDVBCSAEngine::setKey(int parity, uint8_t ecm_mode, const uint8_t* cw)
211217 BYTE_HEX (cw[0 ]), BYTE_HEX (cw[1 ]), BYTE_HEX (cw[2 ]), BYTE_HEX (cw[3 ]),
212218 BYTE_HEX (cw[4 ]), BYTE_HEX (cw[5 ]), BYTE_HEX (cw[6 ]), BYTE_HEX (cw[7 ]));
213219
214- // Lock-free key update
220+ // Double-buffered key update: write to inactive slot, then swap index.
221+ // descramble() on the recorder thread reads the active slot via atomic index,
222+ // so it never sees a partially-written key schedule.
215223 if (parity == 0 ) // even
216224 {
217- g_csa_api.key_set_ecm (ecm_mode, cw, m_key_even);
218- m_key_even_set = true ;
225+ int active = m_key_even_idx.load (std::memory_order_relaxed);
226+ int inactive = 1 - active;
227+ g_csa_api.key_set_ecm (ecm_mode, cw, m_key_even[inactive]);
228+ m_key_even_idx.store (inactive, std::memory_order_release);
229+ m_key_even_set.store (true , std::memory_order_release);
219230 }
220231 else // odd
221232 {
222- g_csa_api.key_set_ecm (ecm_mode, cw, m_key_odd);
223- m_key_odd_set = true ;
233+ int active = m_key_odd_idx.load (std::memory_order_relaxed);
234+ int inactive = 1 - active;
235+ g_csa_api.key_set_ecm (ecm_mode, cw, m_key_odd[inactive]);
236+ m_key_odd_idx.store (inactive, std::memory_order_release);
237+ m_key_odd_set.store (true , std::memory_order_release);
224238 }
225239
226240 if (g_csa_api.get_ecm_table )
@@ -273,13 +287,21 @@ void eDVBCSAEngine::descramble(unsigned char* packets, int len)
273287{
274288 if (!packets || len <= 0 )
275289 return ;
276- if (!m_key_even || !m_key_odd || m_batch_size <= 0 )
290+ if (m_batch_size <= 0 )
277291 return ;
278292 if (!g_csa_api.available || !g_csa_api.decrypt )
279293 return ;
280294 if (m_batch_even.empty () || m_batch_odd.empty ())
281295 return ;
282296
297+ // Snapshot active key state and indices once for this entire buffer.
298+ // setKey() on the CWHandler thread may swap the index at any time,
299+ // but we consistently use the snapshot throughout this call.
300+ const bool even_set = m_key_even_set.load (std::memory_order_acquire);
301+ const bool odd_set = m_key_odd_set.load (std::memory_order_acquire);
302+ dvbcsa_bs_key_t * key_even = even_set ? m_key_even[m_key_even_idx.load (std::memory_order_acquire)] : nullptr ;
303+ dvbcsa_bs_key_t * key_odd = odd_set ? m_key_odd[m_key_odd_idx.load (std::memory_order_acquire)] : nullptr ;
304+
283305 int i = 0 ;
284306 int even_cnt = 0 ;
285307 int odd_cnt = 0 ;
@@ -290,9 +312,6 @@ void eDVBCSAEngine::descramble(unsigned char* packets, int len)
290312
291313 CSA_LOG (" [eDVBCSAEngine] descramble: len=%d batch_size=%d" , len, m_batch_size);
292314
293- const bool even_set = m_key_even_set;
294- const bool odd_set = m_key_odd_set;
295-
296315 while (i < len)
297316 {
298317 unsigned char *pkt = packets + i;
@@ -308,7 +327,7 @@ void eDVBCSAEngine::descramble(unsigned char* packets, int len)
308327
309328 if (scrambled == 2 ) // even
310329 {
311- if (even_set )
330+ if (key_even )
312331 {
313332 // Key available: descramble and clear TSC
314333 clearTSC (pkt);
@@ -326,7 +345,7 @@ void eDVBCSAEngine::descramble(unsigned char* packets, int len)
326345 }
327346 else if (scrambled == 3 ) // odd
328347 {
329- if (odd_set )
348+ if (key_odd )
330349 {
331350 // Key available: descramble and clear TSC
332351 clearTSC (pkt);
@@ -347,8 +366,7 @@ void eDVBCSAEngine::descramble(unsigned char* packets, int len)
347366 if (even_cnt == m_batch_size)
348367 {
349368 pcks_even[even_cnt].data = NULL ;
350- if (even_set)
351- g_csa_api.decrypt (m_key_even, pcks_even, 184 );
369+ g_csa_api.decrypt (key_even, pcks_even, 184 );
352370 CSA_LOG (" [eDVBCSAEngine] decrypt even batch (%d)" , m_batch_size);
353371 even_cnt = 0 ;
354372 }
@@ -357,8 +375,7 @@ void eDVBCSAEngine::descramble(unsigned char* packets, int len)
357375 if (odd_cnt == m_batch_size)
358376 {
359377 pcks_odd[odd_cnt].data = NULL ;
360- if (odd_set)
361- g_csa_api.decrypt (m_key_odd, pcks_odd, 184 );
378+ g_csa_api.decrypt (key_odd, pcks_odd, 184 );
362379 CSA_LOG (" [eDVBCSAEngine] decrypt odd batch (%d)" , m_batch_size);
363380 odd_cnt = 0 ;
364381 }
@@ -370,17 +387,15 @@ void eDVBCSAEngine::descramble(unsigned char* packets, int len)
370387 if (even_cnt > 0 )
371388 {
372389 pcks_even[even_cnt].data = NULL ;
373- if (even_set)
374- g_csa_api.decrypt (m_key_even, pcks_even, 184 );
390+ g_csa_api.decrypt (key_even, pcks_even, 184 );
375391 CSA_LOG (" [eDVBCSAEngine] decrypt remaining even packets=%d" , even_cnt);
376392 }
377393
378394 // flush remaining odd
379395 if (odd_cnt > 0 )
380396 {
381397 pcks_odd[odd_cnt].data = NULL ;
382- if (odd_set)
383- g_csa_api.decrypt (m_key_odd, pcks_odd, 184 );
398+ g_csa_api.decrypt (key_odd, pcks_odd, 184 );
384399 CSA_LOG (" [eDVBCSAEngine] decrypt remaining odd packets=%d" , odd_cnt);
385400 }
386401
0 commit comments