Registriere dich noch heute kostenlos, um Mitglied zu werden! Sobald du angemeldet bist, kannst du auf unserer Seite aktiv teilnehmen, indem du deine eigenen Themen und Beiträge erstellst und dich über deinen eigenen Posteingang mit anderen Mitgliedern unterhalten kannst! Zudem bekommst du Zutritt zu Bereichen, welche für Gäste verwehrt bleiben
Registriere dich noch heute kostenlos, um Mitglied zu werden! Sobald du angemeldet bist, kannst du auf unserer Seite aktiv teilnehmen, indem du deine eigenen Themen und Beiträge erstellst und dich über deinen eigenen Posteingang mit anderen Mitgliedern unterhalten kannst! Zudem bekommst du Zutritt zu Bereichen, welche für Gäste verwehrt bleiben
diff --git a/ffdecsa/ffdecsa.c b/ffdecsa/ffdecsa.c
index ca6d109..2ca01ff 100644
--- a/ffdecsa/ffdecsa.c
+++ b/ffdecsa/ffdecsa.c
@@ -63,8 +63,7 @@
#define PARALLEL_MODE PARALLEL_128_SSE2
#elif defined(__mips__) || defined(__mips) || defined(__MIPS__)
-//#define PARALLEL_MODE PARALLEL_64_LONG
-#define PARALLEL_MODE PARALLEL_32_INT
+#define PARALLEL_MODE PARALLEL_64_LONG
#elif defined(__sh__) || defined(__SH4__)
#define PARALLEL_MODE PARALLEL_32_INT
@@ -75,7 +74,7 @@
#ifdef WITH_ARM_NEON
#define PARALLEL_MODE PARALLEL_128_NEON
#else
-#define PARALLEL_MODE PARALLEL_32_INT
+#define PARALLEL_MODE PARALLEL_64_LONG
#endif
#else
diff --git a/module-emulator-streamserver.c b/module-emulator-streamserver.c
index e32c244..3d72605 100644
--- a/module-emulator-streamserver.c
+++ b/module-emulator-streamserver.c
@@ -36,7 +36,7 @@ int32_t emu_stream_source_port = 8001;
char *emu_stream_source_auth = NULL;
int32_t emu_stream_relay_port = 17999;
int8_t emu_stream_emm_enabled = 0;
-uint32_t cluster_size = 50;
+uint32_t cluster_size = 50, suggested_cluster_size;
static uint8_t emu_stream_server_mutex_init = 0;
static pthread_mutex_t emu_stream_server_mutex;
@@ -47,6 +47,10 @@ uint16_t emu_stream_cur_srvid[EMU_STREAM_SERVER_MAX_CONNECTIONS];
int8_t stream_server_has_ecm[EMU_STREAM_SERVER_MAX_CONNECTIONS];
pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+pthread_mutex_t emu_send_buffer_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+uint8_t *send_buffer[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+uint32_t send_buffer_length[EMU_STREAM_SERVER_MAX_CONNECTIONS] = {0};
+uint32_t send_buffer_offset[EMU_STREAM_SERVER_MAX_CONNECTIONS] = {0};
emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS];
LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS];
@@ -1237,19 +1241,20 @@ static void DescrambleTsPacketsCompel(emu_stream_client_data *data, uint8_t *str
}
}
-static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
+static uint16_t DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
{
- uint8_t *packetCluster[4];
- uint8_t scrambled_packets = 0, scramblingControl;
- uint32_t i, tsHeader;
- int8_t odd_even = -1, odd_even_count = 1;
+ uint8_t *packetCluster[3];
+ uint16_t retVal = 0; // return 0 if we could not descramble the packets
+
+#ifdef MODULE_RADEGAST
+ uint32_t i;
+ uint32_t tsHeader;
for (i = 0; i < bufLength; i += packetSize)
{
tsHeader = b2i(4, stream_buf + i);
- scramblingControl = (tsHeader & 0xC0) >> 6;
-#ifdef MODULE_RADEGAST
+
uint16_t pid, offset, payloadStart;
pid = (tsHeader & 0x1FFF00) >> 8;
@@ -1272,30 +1277,8 @@ static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *strea
ParseTsData(0x80, 0xFE, 3, &data->have_ecm_data, data->ecm_data, sizeof(data->ecm_data),
&data->ecm_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParseEcmData, data);
}
-#endif // MODULE_RADEGAST
-
- if (scramblingControl == 0)
- {
- continue;
- }
-
- scrambled_packets++;
- scramblingControl &= 0x1;
-
- if (odd_even == -1)
- {
- odd_even = scramblingControl;
- }
-
- if (odd_even != scramblingControl)
- {
- odd_even_count++;
- odd_even = scramblingControl;
- }
}
-
- if (scrambled_packets == 0)
- return;
+#endif // MODULE_RADEGAST
SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[data->connid]);
@@ -1305,14 +1288,12 @@ static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *strea
packetCluster[1] = stream_buf + bufLength;
packetCluster[2] = NULL;
- decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
- if (odd_even_count > 1) // odd and even packets together cannot be decrypted in one step
- {
- decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
- }
+ retVal = decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
}
SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[data->connid]);
+
+ return retVal;
}
static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *stream_path)
@@ -1393,6 +1374,181 @@ static void stream_client_disconnect(emu_stream_client_conn_data *conndata)
NULLFREE(conndata);
}
+int64_t parse_pcr(const uint8_t *tsPacket) {
+ if (tsPacket[0] != 0x47) {
+ return INVALID_PCR;
+ }
+
+ if (!(tsPacket[3] & 0x20)) {
+ return INVALID_PCR;
+ }
+
+ if ((tsPacket[5] & 0x10)) {
+ uint16_t extension = 0;
+ uint64_t base = 0;
+
+ base |= (uint64_t)(tsPacket[6])<<25;
+ base |= (uint64_t)(tsPacket[7])<<(25-8);
+ base |= (uint64_t)(tsPacket[8])<<(25-8-8);
+ base |= (uint64_t)(tsPacket[9])<<(25-8-8-8);
+ base |= (uint16_t)(tsPacket[10] & 128)>>7;
+ extension |= tsPacket[11];
+ extension |= (uint16_t)(tsPacket[10] & 0x01)<<8;
+
+ return base*300 + extension;
+ }
+
+ return INVALID_PCR;
+}
+
+int64_t parse_pcr_unchecked(const uint8_t *tsPacket) {
+ uint16_t extension = 0;
+ uint64_t base = 0;
+
+ base |= (uint64_t)(tsPacket[6])<<25;
+ base |= (uint64_t)(tsPacket[7])<<(25-8);
+ base |= (uint64_t)(tsPacket[8])<<(25-8-8);
+ base |= (uint64_t)(tsPacket[9])<<(25-8-8-8);
+ base |= (uint16_t)(tsPacket[10] & 128)>>7;
+ extension |= tsPacket[11];
+ extension |= (uint16_t)(tsPacket[10] & 0x01)<<8;
+
+ return base*300 + extension;
+}
+
+int8_t has_pcr(const uint8_t *tsPacket) {
+ if (tsPacket[0] != 0x47) {
+ return 0;
+ }
+
+ if (!(tsPacket[3] & 0x20)) {
+ return 0;
+ }
+
+ return (tsPacket[5] & 0x10);
+}
+
+uint8_t is_scrambled(const uint8_t *tsPacket) {
+ return tsPacket[3] & 0x80;
+}
+
+uint8_t has_rai_flag(const uint8_t *tsPacket) {
+ if( ( tsPacket[3] & 0x20 ) && ( tsPacket[4] > 0 ) ) {
+ return tsPacket[5] & 0x40;
+ }
+ return 0;
+}
+
+uint16_t get_pid(const uint8_t *tsPacket) {
+ return ((tsPacket[1] & 0x1f) << 8) | tsPacket[2];
+}
+
+uint64_t find_first_pcr_value(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ uint32_t packetNo;
+ uint64_t pcr = INVALID_PCR;
+ for (packetNo=0;packetNo<numPackets;packetNo++) {
+ pcr = parse_pcr(tsPackets+packetNo*packetSize);
+ if (pcr != INVALID_PCR) {
+ return pcr;
+ }
+ }
+ return INVALID_PCR;
+}
+
+uint8_t *find_next_pcr_packet(uint8_t *tsPackets, uint32_t tsPacketsLen, uint8_t packetSize) {
+ uint32_t packetNo;
+ for (packetNo=0;packetNo*packetSize<tsPacketsLen;packetNo++) {
+ if (has_pcr(tsPackets+packetNo*packetSize)) {
+ return tsPackets+packetNo*packetSize;
+ }
+ }
+ return NULL;
+}
+
+uint64_t find_last_pcr_value(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ uint32_t packetNo;
+ uint64_t pcr = INVALID_PCR;
+ for (packetNo=numPackets;packetNo-->0;) {
+ pcr = parse_pcr(tsPackets+packetNo*packetSize);
+ if (pcr != INVALID_PCR) {
+ return pcr;
+ }
+ }
+ return INVALID_PCR;
+}
+
+uint64_t calc_pcr_timespan(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ return find_last_pcr_value(tsPackets, numPackets, packetSize) - find_first_pcr_value(tsPackets, numPackets, packetSize);
+}
+
+uint8_t has_pusi_flag(const uint8_t *tsPacket) {
+ return tsPacket[1] & 0x40;
+}
+
+
+static void stream_client_sender(void *arg)
+{
+ uint8_t continue_sending = 1;
+ uint8_t packetSize = 188;
+ int32_t connid = ((emu_stream_client_conn_data *) arg)->connid;
+ int32_t connfd = ((emu_stream_client_conn_data *) arg)->connfd;
+
+ cs_log("Stream client %i sender started!", connid);
+ while (continue_sending) {
+ // wait until we have enough packets in send buffer
+ while (continue_sending) {
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ uint8_t *currentPacket = NULL, *descrambled_rai_packet = NULL;
+ uint64_t pcrdiff = 0;
+ uint32_t packetNo = 0;
+ for (currentPacket = send_buffer[connid]+send_buffer_offset[connid]; currentPacket<(send_buffer[connid]+send_buffer_length[connid]);currentPacket+=packetSize) {
+ if (has_rai_flag(currentPacket) && !is_scrambled(currentPacket)) {
+ descrambled_rai_packet = currentPacket;
+ break;
+ }
+ packetNo++;
+ }
+
+ if (descrambled_rai_packet != NULL) {
+ pcrdiff = calc_pcr_timespan(descrambled_rai_packet, (send_buffer[connid]+send_buffer_length[connid]-descrambled_rai_packet) / packetSize, packetSize);
+ }
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ if (pcrdiff > INITIAL_BUFFER_TIME_MS*(PCR_FREQ/1000)) {
+ // printf("we have enough packets in buffer\n");
+ break;
+ } else {
+ // printf("we have a descrambled rai packet\n");
+ }
+ cs_sleepms(5); // 35 ms is a typical timespan between two PCR packets
+ }
+ cs_log("Stream client %i buffer time reached!", connid);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ while (continue_sending) {
+ uint16_t packetsToSend = (send_buffer_length[connid]-send_buffer_offset[connid]) / packetSize;
+ if (packetsToSend > 80) {
+ // limit bitrate to ~30mbit/s
+ packetsToSend = 80;
+ }
+
+ ssize_t bytesSent = send(connfd, send_buffer[connid]+send_buffer_offset[connid], packetsToSend*packetSize, 0);
+ if (bytesSent == -1) {
+ cs_log_dbg(0, "Stream client %i could not send. Stopping sender!", connid);
+ continue_sending = 0;
+ break;
+ } else if (bytesSent != packetsToSend*188) {
+ cs_log("Stream client %i sent only %d bytes", connid, bytesSent);
+ }
+
+ send_buffer_offset[connid]+=packetsToSend*188;
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ cs_sleepms(5);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ }
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ }
+ cs_log("Stream client %i sender stopped!", connid);
+}
+
static void *stream_client_handler(void *arg)
{
emu_stream_client_conn_data *conndata = (emu_stream_client_conn_data *)arg;
@@ -1410,6 +1566,15 @@ static void *stream_client_handler(void *arg)
uint16_t packetCount = 0, packetSize = 0, startOffset = 0;
uint32_t remainingDataPos, remainingDataLength, tmp_pids[4];
+ uint64_t last_pcr = INVALID_PCR;
+ uint16_t packets_since_last_pcr;
+
+ struct timeb now, postPublish = {.time = 0};
+
+ uint64_t recved_since_last_long_poll = 0;
+
+ pthread_t sender_thread;
+
struct pollfd pfd[2];
int ret;
@@ -1428,10 +1593,19 @@ static void *stream_client_handler(void *arg)
return NULL;
}
+ if (!cs_malloc(&send_buffer[conndata->connid], EMU_SEND_BUFFER_SIZE))
+ {
+ NULLFREE(http_buf);
+ NULLFREE(stream_buf);
+ stream_client_disconnect(conndata);
+ return NULL;
+ }
+
if (!cs_malloc(&data, sizeof(emu_stream_client_data)))
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
stream_client_disconnect(conndata);
return NULL;
}
@@ -1441,6 +1615,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1451,6 +1626,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1485,6 +1661,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1527,6 +1704,11 @@ static void *stream_client_handler(void *arg)
streamStatus = 0;
bytesRead = 0;
+ send_buffer_length[conndata->connid] = 0;
+ send_buffer_offset[conndata->connid] = 0;
+
+ start_thread("emu stream client sender", stream_client_sender, conndata, &sender_thread, 0, 0);
+
while (!exit_oscam && clientStatus != -1 && streamStatus != -1
&& streamConnectErrorCount < 3 && streamDataErrorCount < 15)
{
@@ -1537,8 +1719,8 @@ static void *stream_client_handler(void *arg)
}
else if (emu_fixed_key_data[conndata->connid].icam_csa_used)
{
- cur_dvb_buffer_size = 188 * cluster_size;
- cur_dvb_buffer_wait = 188 * (cluster_size - 3);
+ cur_dvb_buffer_size = 188 * suggested_cluster_size;
+ cur_dvb_buffer_wait = 188 * suggested_cluster_size;
}
else
{
@@ -1551,7 +1733,15 @@ static void *stream_client_handler(void *arg)
pfd[1].fd = conndata->connfd;
pfd[1].events = POLLRDHUP | POLLHUP;
+ struct timeb preMeasure, postMeasure;
+ cs_ftimeus(&preMeasure);
ret = poll(pfd, 2, 2000);
+ cs_ftimeus(&postMeasure);
+ int64_t measured_time = comp_timebus(&postMeasure, &preMeasure);
+ if (measured_time > 2000) {
+ // printf("%7"PRIu64"\t%"PRId32"\t%"PRIu64"\n", measured_time, bytesRead, recved_since_last_long_poll);
+ recved_since_last_long_poll = 0;
+ }
if (ret < 0) // poll error
{
@@ -1571,6 +1761,7 @@ static void *stream_client_handler(void *arg)
if (pfd[0].revents & POLLIN) // new incoming data
{
streamStatus = recv(streamfd, stream_buf + bytesRead, cur_dvb_buffer_size - bytesRead, MSG_DONTWAIT);
+ recved_since_last_long_poll += streamStatus;
}
if ((pfd[0].revents & POLLHUP) || (pfd[0].revents & POLLRDHUP)) // incoming connection closed
{
@@ -1601,7 +1792,6 @@ static void *stream_client_handler(void *arg)
{
cs_log_dbg(0, "WARNING: stream client %i non-full buffer from stream source", conndata->connid);
streamDataErrorCount++;
- cs_sleepms(100);
}
}
else
@@ -1612,7 +1802,7 @@ static void *stream_client_handler(void *arg)
streamConnectErrorCount = 0;
bytesRead += streamStatus;
- if (bytesRead >= cur_dvb_buffer_wait)
+ if ((emu_fixed_key_data[data->connid].icam_csa_used && emu_fixed_key_data[data->connid].icam_csa_ks != NULL && bytesRead >= packetSize) || bytesRead >= cur_dvb_buffer_wait)
{
startOffset = 0;
@@ -1622,9 +1812,9 @@ static void *stream_client_handler(void *arg)
SearchTsPackets(stream_buf, bytesRead, &packetSize, &startOffset);
}
- if (packetSize == 0)
+ if (packetSize == 0) // no ts packets found yet
{
- bytesRead = 0;
+ bytesRead = 0; // discard buffer
}
else
{
@@ -1649,7 +1839,18 @@ static void *stream_client_handler(void *arg)
}
else if (caid_is_icam(data->caid)) //ICAM
{
- DescrambleTsPacketsICam(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
+ //struct timeb preDescramble, postDescramble;
+ //cs_ftimeus(&preDescramble);
+ packetCount = DescrambleTsPacketsICam(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
+ cs_sleepms(1);
+ // printf("descrambled %3"PRIu16" of %3"PRIu16" packets\n", packetCount, (bytesRead - startOffset) / packetSize);
+ //cs_ftimeus(&postDescramble);
+ //printf("%7"PRId64"\n",comp_timebus(&postDescramble, &preDescramble));
+ if (packetCount == 0) {
+ // we could not descramble packets yet (probably b/c of missing cws)
+ // just copy all scrambled packets to sendbuffer
+ packetCount = ((bytesRead - startOffset) / packetSize);
+ }
}
}
else
@@ -1663,7 +1864,22 @@ static void *stream_client_handler(void *arg)
ParseTsPackets(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
}
- clientStatus = send(conndata->connfd, stream_buf + startOffset, packetCount * packetSize, 0);
+ struct timeb preMeasure, postMeasure;
+
+ // cs_ftimeus(&preMeasure);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[conndata->connid]);
+ if (send_buffer_length[conndata->connid] + packetCount * packetSize > EMU_SEND_BUFFER_SIZE) {
+ // reorganize sendbuffer
+ cs_log("reorganize send_buffer");
+ memmove(send_buffer[conndata->connid], send_buffer[conndata->connid] + send_buffer_offset[conndata->connid], send_buffer_length[conndata->connid] - send_buffer_offset[conndata->connid]);
+ send_buffer_length[conndata->connid] = send_buffer_length[conndata->connid] - send_buffer_offset[conndata->connid];
+ send_buffer_offset[conndata->connid] = 0;
+ }
+ memcpy(send_buffer[conndata->connid] + send_buffer_length[conndata->connid], stream_buf + startOffset, packetCount * packetSize);
+ send_buffer_length[conndata->connid] += packetCount * packetSize;
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[conndata->connid]);
+
+ clientStatus = packetCount * packetSize;
remainingDataPos = startOffset + (packetCount * packetSize);
remainingDataLength = bytesRead - remainingDataPos;
@@ -1685,8 +1901,12 @@ static void *stream_client_handler(void *arg)
close(streamfd);
}
+ // wait for sender thread to finish
+ pthread_join(sender_thread, NULL);
+
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
for (i = 0; i < 8; i++)
{
@@ -1695,10 +1915,6 @@ static void *stream_client_handler(void *arg)
free_key_struct(data->key.pvu_csa_ks[i]);
}
}
- if (data->key.icam_csa_ks)
- {
- free_key_struct(data->key.icam_csa_ks);
- }
#ifdef MODULE_RADEGAST
icam_reset(data->connid);
#endif
@@ -1717,7 +1933,8 @@ void *stream_server(void *UNUSED(a))
emu_stream_client_conn_data *conndata;
cluster_size = get_internal_parallelism();
- cs_log("INFO: FFDecsa parallel mode = %d", cluster_size);
+ suggested_cluster_size = get_suggested_cluster_size();
+ cs_log("INFO: FFDecsa parallel mode = %d (suggested cluster size: %d packets)", cluster_size, suggested_cluster_size);
if (!emu_stream_server_mutex_init)
{
diff --git a/module-emulator-streamserver.h b/module-emulator-streamserver.h
index 5b76d0d..580e699 100644
--- a/module-emulator-streamserver.h
+++ b/module-emulator-streamserver.h
@@ -13,6 +13,15 @@
#define EMU_DVB_BUFFER_WAIT_DES 188*29
#define EMU_DVB_BUFFER_SIZE EMU_DVB_BUFFER_SIZE_CSA
+#define EMU_SEND_BUFFER_SIZE 188*204*208*2 // might implement ring buffer in future
+
+#define INVALID_PCR (uint64_t) 0xFFFFFFFFFFFFFFFF
+#define PCR_FREQ 27000000
+#define PCR_SCALE ((uint64_t)1 << 33) * 300
+
+// miliseconds of mpeg-ts to buffer
+#define INITIAL_BUFFER_TIME_MS 2500
+
typedef struct
{
uint32_t pvu_des_ks[8][2][32];
@@ -85,6 +94,8 @@ extern pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTION
extern emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS];
extern LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+extern pthread_mutex_t emu_send_buffer_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+
void *stream_key_delayer(void *arg);
bool stream_write_cw(ECM_REQUEST *er);
diff --git a/module-emulator.c b/module-emulator.c
index 0cdb915..ce6630e 100644
--- a/module-emulator.c
+++ b/module-emulator.c
@@ -735,6 +735,7 @@ static int32_t emu_reader_init(struct s_reader *UNUSED(reader))
for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
{
SAFE_MUTEX_INIT(&emu_fixed_key_data_mutex[i], NULL);
+ SAFE_MUTEX_INIT(&emu_send_buffer_mutex[i], NULL);
ll_emu_stream_delayed_keys[i] = ll_create("ll_emu_stream_delayed_keys");
memset(&emu_fixed_key_data[i], 0, sizeof(emu_stream_client_key_data));
}
diff --git a/oscam-time.c b/oscam-time.c
index 0fceed5..7bb50b6 100644
--- a/oscam-time.c
+++ b/oscam-time.c
@@ -261,6 +261,22 @@ void add_ms_to_timeb(struct timeb *tb, int32_t ms)
}
}
+void add_us_to_timeb(struct timeb *tb, uint64_t us)
+{
+ if (us >= 1000000){
+ tb->time += us / 1000000;
+ tb->millitm += (us % 1000000);
+ }
+ else{
+ tb->millitm += us;
+ }
+ if(tb->millitm >= 1000000)
+ {
+ tb->millitm %= 1000000;
+ tb->time++;
+ }
+}
+
int64_t add_ms_to_timeb_diff(struct timeb *tb, int32_t ms)
{
struct timeb tb_now;
diff --git a/oscam-time.h b/oscam-time.h
index d04f64b..138142c 100644
--- a/oscam-time.h
+++ b/oscam-time.h
@@ -19,6 +19,7 @@ void cs_sleepus(uint32_t usec);
void add_ms_to_timespec(struct timespec *timeout, int32_t msec);
void add_ms_to_timeb(struct timeb *tb, int32_t ms);
+void add_us_to_timeb(struct timeb *tb, uint64_t us);
int64_t add_ms_to_timeb_diff(struct timeb *tb, int32_t ms);
time_t cs_walltime(struct timeb *tp);
diff --git a/ffdecsa/ffdecsa.c b/ffdecsa/ffdecsa.c
index ca6d109..2ca01ff 100644
--- a/ffdecsa/ffdecsa.c
+++ b/ffdecsa/ffdecsa.c
@@ -63,8 +63,7 @@
#define PARALLEL_MODE PARALLEL_128_SSE2
#elif defined(__mips__) || defined(__mips) || defined(__MIPS__)
-//#define PARALLEL_MODE PARALLEL_64_LONG
-#define PARALLEL_MODE PARALLEL_32_INT
+#define PARALLEL_MODE PARALLEL_64_LONG
#elif defined(__sh__) || defined(__SH4__)
#define PARALLEL_MODE PARALLEL_32_INT
@@ -75,7 +74,7 @@
#ifdef WITH_ARM_NEON
#define PARALLEL_MODE PARALLEL_128_NEON
#else
-#define PARALLEL_MODE PARALLEL_32_INT
+#define PARALLEL_MODE PARALLEL_64_LONG
#endif
#else
diff --git a/module-emulator-streamserver.c b/module-emulator-streamserver.c
index e32c244..70851cc 100644
--- a/module-emulator-streamserver.c
+++ b/module-emulator-streamserver.c
@@ -36,7 +36,7 @@ int32_t emu_stream_source_port = 8001;
char *emu_stream_source_auth = NULL;
int32_t emu_stream_relay_port = 17999;
int8_t emu_stream_emm_enabled = 0;
-uint32_t cluster_size = 50;
+uint32_t cluster_size = 50, suggested_cluster_size;
static uint8_t emu_stream_server_mutex_init = 0;
static pthread_mutex_t emu_stream_server_mutex;
@@ -47,6 +47,10 @@ uint16_t emu_stream_cur_srvid[EMU_STREAM_SERVER_MAX_CONNECTIONS];
int8_t stream_server_has_ecm[EMU_STREAM_SERVER_MAX_CONNECTIONS];
pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+pthread_mutex_t emu_send_buffer_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+uint8_t *send_buffer[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+uint32_t send_buffer_length[EMU_STREAM_SERVER_MAX_CONNECTIONS] = {0};
+uint32_t send_buffer_offset[EMU_STREAM_SERVER_MAX_CONNECTIONS] = {0};
emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS];
LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS];
@@ -1237,19 +1241,20 @@ static void DescrambleTsPacketsCompel(emu_stream_client_data *data, uint8_t *str
}
}
-static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
+static uint16_t DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
{
- uint8_t *packetCluster[4];
- uint8_t scrambled_packets = 0, scramblingControl;
- uint32_t i, tsHeader;
- int8_t odd_even = -1, odd_even_count = 1;
+ uint8_t *packetCluster[3];
+ uint16_t retVal = bufLength / packetSize;
+
+#ifdef MODULE_RADEGAST
+ uint32_t i;
+ uint32_t tsHeader;
for (i = 0; i < bufLength; i += packetSize)
{
tsHeader = b2i(4, stream_buf + i);
- scramblingControl = (tsHeader & 0xC0) >> 6;
-#ifdef MODULE_RADEGAST
+
uint16_t pid, offset, payloadStart;
pid = (tsHeader & 0x1FFF00) >> 8;
@@ -1272,30 +1277,8 @@ static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *strea
ParseTsData(0x80, 0xFE, 3, &data->have_ecm_data, data->ecm_data, sizeof(data->ecm_data),
&data->ecm_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParseEcmData, data);
}
-#endif // MODULE_RADEGAST
-
- if (scramblingControl == 0)
- {
- continue;
- }
-
- scrambled_packets++;
- scramblingControl &= 0x1;
-
- if (odd_even == -1)
- {
- odd_even = scramblingControl;
- }
-
- if (odd_even != scramblingControl)
- {
- odd_even_count++;
- odd_even = scramblingControl;
- }
}
-
- if (scrambled_packets == 0)
- return;
+#endif // MODULE_RADEGAST
SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[data->connid]);
@@ -1305,14 +1288,12 @@ static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *strea
packetCluster[1] = stream_buf + bufLength;
packetCluster[2] = NULL;
- decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
- if (odd_even_count > 1) // odd and even packets together cannot be decrypted in one step
- {
- decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
- }
+ retVal = decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
}
SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[data->connid]);
+
+ return retVal;
}
static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *stream_path)
@@ -1393,6 +1374,179 @@ static void stream_client_disconnect(emu_stream_client_conn_data *conndata)
NULLFREE(conndata);
}
+int64_t parse_pcr(const uint8_t *tsPacket) {
+ if (tsPacket[0] != 0x47) {
+ return INVALID_PCR;
+ }
+
+ if (!(tsPacket[3] & 0x20)) {
+ return INVALID_PCR;
+ }
+
+ if ((tsPacket[5] & 0x10)) {
+ uint16_t extension = 0;
+ uint64_t base = 0;
+
+ base |= (uint64_t)(tsPacket[6])<<25;
+ base |= (uint64_t)(tsPacket[7])<<(25-8);
+ base |= (uint64_t)(tsPacket[8])<<(25-8-8);
+ base |= (uint64_t)(tsPacket[9])<<(25-8-8-8);
+ base |= (uint16_t)(tsPacket[10] & 128)>>7;
+ extension |= tsPacket[11];
+ extension |= (uint16_t)(tsPacket[10] & 0x01)<<8;
+
+ return base*300 + extension;
+ }
+
+ return INVALID_PCR;
+}
+
+int64_t parse_pcr_unchecked(const uint8_t *tsPacket) {
+ uint16_t extension = 0;
+ uint64_t base = 0;
+
+ base |= (uint64_t)(tsPacket[6])<<25;
+ base |= (uint64_t)(tsPacket[7])<<(25-8);
+ base |= (uint64_t)(tsPacket[8])<<(25-8-8);
+ base |= (uint64_t)(tsPacket[9])<<(25-8-8-8);
+ base |= (uint16_t)(tsPacket[10] & 128)>>7;
+ extension |= tsPacket[11];
+ extension |= (uint16_t)(tsPacket[10] & 0x01)<<8;
+
+ return base*300 + extension;
+}
+
+int8_t has_pcr(const uint8_t *tsPacket) {
+ if (tsPacket[0] != 0x47) {
+ return 0;
+ }
+
+ if (!(tsPacket[3] & 0x20)) {
+ return 0;
+ }
+
+ return (tsPacket[5] & 0x10);
+}
+
+uint8_t is_scrambled(const uint8_t *tsPacket) {
+ return tsPacket[3] & 0x80;
+}
+
+uint8_t has_rai_flag(const uint8_t *tsPacket) {
+ if( ( tsPacket[3] & 0x20 ) && ( tsPacket[4] > 0 ) ) {
+ return tsPacket[5] & 0x40;
+ }
+ return 0;
+}
+
+uint16_t get_pid(const uint8_t *tsPacket) {
+ return ((tsPacket[1] & 0x1f) << 8) | tsPacket[2];
+}
+
+uint64_t find_first_pcr_value(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ uint32_t packetNo;
+ uint64_t pcr = INVALID_PCR;
+ for (packetNo=0;packetNo<numPackets;packetNo++) {
+ pcr = parse_pcr(tsPackets+packetNo*packetSize);
+ if (pcr != INVALID_PCR) {
+ return pcr;
+ }
+ }
+ return INVALID_PCR;
+}
+
+uint8_t *find_next_pcr_packet(uint8_t *tsPackets, uint32_t tsPacketsLen, uint8_t packetSize) {
+ uint32_t packetNo;
+ for (packetNo=0;packetNo*packetSize<tsPacketsLen;packetNo++) {
+ if (has_pcr(tsPackets+packetNo*packetSize)) {
+ return tsPackets+packetNo*packetSize;
+ }
+ }
+ return NULL;
+}
+
+uint64_t find_last_pcr_value(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ uint32_t packetNo;
+ uint64_t pcr = INVALID_PCR;
+ for (packetNo=numPackets;packetNo-->0;) {
+ pcr = parse_pcr(tsPackets+packetNo*packetSize);
+ if (pcr != INVALID_PCR) {
+ return pcr;
+ }
+ }
+ return INVALID_PCR;
+}
+
+uint64_t calc_pcr_timespan(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ return find_last_pcr_value(tsPackets, numPackets, packetSize) - find_first_pcr_value(tsPackets, numPackets, packetSize);
+}
+
+uint8_t has_pusi_flag(const uint8_t *tsPacket) {
+ return tsPacket[1] & 0x40;
+}
+
+
+static void stream_client_sender(void *arg)
+{
+ uint8_t continue_sending = 1;
+ uint8_t packetSize = 188;
+ int32_t connid = ((emu_stream_client_conn_data *) arg)->connid;
+ int32_t connfd = ((emu_stream_client_conn_data *) arg)->connfd;
+
+ cs_log("Stream client %i sender started!", connid);
+ while (continue_sending) {
+ // wait until we have enough packets in send buffer
+ while (continue_sending) {
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ uint8_t *currentPacket = NULL, *descrambled_rai_packet = NULL;
+ uint64_t pcrdiff = 0;
+ uint32_t packetNo = 0;
+ for (currentPacket = send_buffer[connid]+send_buffer_offset[connid]; currentPacket<(send_buffer[connid]+send_buffer_length[connid]);currentPacket+=packetSize) {
+ if (has_rai_flag(currentPacket) && !is_scrambled(currentPacket)) {
+ descrambled_rai_packet = currentPacket;
+ break;
+ }
+ packetNo++;
+ }
+
+ if (descrambled_rai_packet != NULL) {
+ pcrdiff = calc_pcr_timespan(descrambled_rai_packet, (send_buffer[connid]+send_buffer_length[connid]-descrambled_rai_packet) / packetSize, packetSize);
+ }
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ if (pcrdiff > INITIAL_BUFFER_TIME_MS*(PCR_FREQ/1000)) {
+ break;
+ } else {
+ }
+ cs_sleepms(35); // 35 ms is a typical timespan between two PCR packets
+ }
+ cs_log("Stream client %i buffer time reached!", connid);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ while (continue_sending) {
+ uint16_t packetsToSend = (send_buffer_length[connid]-send_buffer_offset[connid]) / packetSize;
+ if (packetsToSend > 80) {
+ // limit bitrate to ~30mbit/s
+ packetsToSend = 80;
+ }
+
+ ssize_t bytesSent = send(connfd, send_buffer[connid]+send_buffer_offset[connid], packetsToSend*packetSize, 0);
+ if (bytesSent == -1) {
+ cs_log_dbg(0, "Stream client %i could not send. Stopping sender!", connid);
+ continue_sending = 0;
+ break;
+ } else if (bytesSent != packetsToSend*188) {
+ cs_log("Stream client %i sent only %d bytes", connid, bytesSent);
+ }
+
+ send_buffer_offset[connid]+=packetsToSend*188;
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ cs_sleepms(5);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ }
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ }
+ cs_log("Stream client %i sender stopped!", connid);
+}
+
static void *stream_client_handler(void *arg)
{
emu_stream_client_conn_data *conndata = (emu_stream_client_conn_data *)arg;
@@ -1410,6 +1564,15 @@ static void *stream_client_handler(void *arg)
uint16_t packetCount = 0, packetSize = 0, startOffset = 0;
uint32_t remainingDataPos, remainingDataLength, tmp_pids[4];
+ uint64_t last_pcr = INVALID_PCR;
+ uint16_t packets_since_last_pcr;
+
+ struct timeb now, postPublish = {.time = 0};
+
+ uint64_t recved_since_last_long_poll = 0;
+
+ pthread_t sender_thread;
+
struct pollfd pfd[2];
int ret;
@@ -1428,10 +1591,19 @@ static void *stream_client_handler(void *arg)
return NULL;
}
+ if (!cs_malloc(&send_buffer[conndata->connid], EMU_SEND_BUFFER_SIZE))
+ {
+ NULLFREE(http_buf);
+ NULLFREE(stream_buf);
+ stream_client_disconnect(conndata);
+ return NULL;
+ }
+
if (!cs_malloc(&data, sizeof(emu_stream_client_data)))
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
stream_client_disconnect(conndata);
return NULL;
}
@@ -1441,6 +1613,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1451,6 +1624,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1485,6 +1659,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1527,6 +1702,11 @@ static void *stream_client_handler(void *arg)
streamStatus = 0;
bytesRead = 0;
+ send_buffer_length[conndata->connid] = 0;
+ send_buffer_offset[conndata->connid] = 0;
+
+ start_thread("emu stream client sender", stream_client_sender, conndata, &sender_thread, 0, 0);
+
while (!exit_oscam && clientStatus != -1 && streamStatus != -1
&& streamConnectErrorCount < 3 && streamDataErrorCount < 15)
{
@@ -1537,8 +1717,8 @@ static void *stream_client_handler(void *arg)
}
else if (emu_fixed_key_data[conndata->connid].icam_csa_used)
{
- cur_dvb_buffer_size = 188 * cluster_size;
- cur_dvb_buffer_wait = 188 * (cluster_size - 3);
+ cur_dvb_buffer_size = 188 * suggested_cluster_size;
+ cur_dvb_buffer_wait = 188 * suggested_cluster_size;
}
else
{
@@ -1546,12 +1726,15 @@ static void *stream_client_handler(void *arg)
cur_dvb_buffer_wait = EMU_DVB_BUFFER_WAIT_DES;
}
+ uint8_t packets_left_in_buffer = (packetSize > 0) ? bytesRead/packetSize:0;
+ uint8_t descrambling = data->have_pat_data == 1 && data->have_pmt_data == 1;
+
pfd[0].fd = streamfd;
pfd[0].events = POLLIN | POLLRDHUP | POLLHUP;
pfd[1].fd = conndata->connfd;
pfd[1].events = POLLRDHUP | POLLHUP;
- ret = poll(pfd, 2, 2000);
+ ret = poll(pfd, 2, (packets_left_in_buffer > 0 && descrambling) ? 5:2000);
if (ret < 0) // poll error
{
@@ -1562,9 +1745,14 @@ static void *stream_client_handler(void *arg)
}
else if (ret == 0) // timeout
{
- cs_log("WARNING: stream client %i no data from stream source", conndata->connid);
- streamDataErrorCount++; // 2 sec timeout * 15 = 30 seconds no data -> close
- continue;
+ if (packets_left_in_buffer > 0 && descrambling) {
+ // was fast timeout
+ streamStatus = 0; // act like we received 0 new bytes
+ } else {
+ cs_log("WARNING: stream client %i no data from stream source", conndata->connid);
+ streamDataErrorCount++; // 2 sec timeout * 15 = 30 seconds no data -> close
+ continue;
+ }
}
else
{
@@ -1601,7 +1789,6 @@ static void *stream_client_handler(void *arg)
{
cs_log_dbg(0, "WARNING: stream client %i non-full buffer from stream source", conndata->connid);
streamDataErrorCount++;
- cs_sleepms(100);
}
}
else
@@ -1612,7 +1799,7 @@ static void *stream_client_handler(void *arg)
streamConnectErrorCount = 0;
bytesRead += streamStatus;
- if (bytesRead >= cur_dvb_buffer_wait)
+ if (bytesRead >= cur_dvb_buffer_wait || (packets_left_in_buffer > 0 && descrambling))
{
startOffset = 0;
@@ -1622,9 +1809,9 @@ static void *stream_client_handler(void *arg)
SearchTsPackets(stream_buf, bytesRead, &packetSize, &startOffset);
}
- if (packetSize == 0)
+ if (packetSize == 0) // no ts packets found yet
{
- bytesRead = 0;
+ bytesRead = 0; // discard buffer
}
else
{
@@ -1649,7 +1836,8 @@ static void *stream_client_handler(void *arg)
}
else if (caid_is_icam(data->caid)) //ICAM
{
- DescrambleTsPacketsICam(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
+ packetCount = DescrambleTsPacketsICam(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
+ cs_sleepus(1500);
}
}
else
@@ -1663,7 +1851,18 @@ static void *stream_client_handler(void *arg)
ParseTsPackets(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
}
- clientStatus = send(conndata->connfd, stream_buf + startOffset, packetCount * packetSize, 0);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[conndata->connid]);
+ if (send_buffer_length[conndata->connid] + packetCount * packetSize > EMU_SEND_BUFFER_SIZE) {
+ // reorganize sendbuffer
+ memmove(send_buffer[conndata->connid], send_buffer[conndata->connid] + send_buffer_offset[conndata->connid], send_buffer_length[conndata->connid] - send_buffer_offset[conndata->connid]);
+ send_buffer_length[conndata->connid] = send_buffer_length[conndata->connid] - send_buffer_offset[conndata->connid];
+ send_buffer_offset[conndata->connid] = 0;
+ }
+ memcpy(send_buffer[conndata->connid] + send_buffer_length[conndata->connid], stream_buf + startOffset, packetCount * packetSize);
+ send_buffer_length[conndata->connid] += packetCount * packetSize;
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[conndata->connid]);
+
+ clientStatus = packetCount * packetSize;
remainingDataPos = startOffset + (packetCount * packetSize);
remainingDataLength = bytesRead - remainingDataPos;
@@ -1685,8 +1884,12 @@ static void *stream_client_handler(void *arg)
close(streamfd);
}
+ // wait for sender thread to finish
+ pthread_join(sender_thread, NULL);
+
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
for (i = 0; i < 8; i++)
{
@@ -1695,10 +1898,6 @@ static void *stream_client_handler(void *arg)
free_key_struct(data->key.pvu_csa_ks[i]);
}
}
- if (data->key.icam_csa_ks)
- {
- free_key_struct(data->key.icam_csa_ks);
- }
#ifdef MODULE_RADEGAST
icam_reset(data->connid);
#endif
@@ -1717,7 +1916,8 @@ void *stream_server(void *UNUSED(a))
emu_stream_client_conn_data *conndata;
cluster_size = get_internal_parallelism();
- cs_log("INFO: FFDecsa parallel mode = %d", cluster_size);
+ suggested_cluster_size = get_suggested_cluster_size();
+ cs_log("INFO: FFDecsa parallel mode = %d (suggested cluster size: %d packets)", cluster_size, suggested_cluster_size);
if (!emu_stream_server_mutex_init)
{
diff --git a/module-emulator-streamserver.h b/module-emulator-streamserver.h
index 5b76d0d..580e699 100644
--- a/module-emulator-streamserver.h
+++ b/module-emulator-streamserver.h
@@ -13,6 +13,15 @@
#define EMU_DVB_BUFFER_WAIT_DES 188*29
#define EMU_DVB_BUFFER_SIZE EMU_DVB_BUFFER_SIZE_CSA
+#define EMU_SEND_BUFFER_SIZE 188*204*208*2 // might implement ring buffer in future
+
+#define INVALID_PCR (uint64_t) 0xFFFFFFFFFFFFFFFF
+#define PCR_FREQ 27000000
+#define PCR_SCALE ((uint64_t)1 << 33) * 300
+
+// miliseconds of mpeg-ts to buffer
+#define INITIAL_BUFFER_TIME_MS 2500
+
typedef struct
{
uint32_t pvu_des_ks[8][2][32];
@@ -85,6 +94,8 @@ extern pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTION
extern emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS];
extern LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+extern pthread_mutex_t emu_send_buffer_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+
void *stream_key_delayer(void *arg);
bool stream_write_cw(ECM_REQUEST *er);
diff --git a/module-emulator.c b/module-emulator.c
index 0cdb915..ce6630e 100644
--- a/module-emulator.c
+++ b/module-emulator.c
@@ -735,6 +735,7 @@ static int32_t emu_reader_init(struct s_reader *UNUSED(reader))
for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
{
SAFE_MUTEX_INIT(&emu_fixed_key_data_mutex[i], NULL);
+ SAFE_MUTEX_INIT(&emu_send_buffer_mutex[i], NULL);
ll_emu_stream_delayed_keys[i] = ll_create("ll_emu_stream_delayed_keys");
memset(&emu_fixed_key_data[i], 0, sizeof(emu_stream_client_key_data));
}
svn export https://svn.streamboard.tv/oscam/trunk oscam
pushd oscam || cd oscam
patch -i ../oscam-emu.patch -p0
patch -i ../oscam_emu_icam_dvbapi_radegast_v9.patch.txt -p1
patch -i ../buffer.patch -p1
popd || cd ..
Die für 11725 gabs hier nicht glaube nicht. 11724 war die letzte soweit ich weiss. Und die für 11725, die habe ich auch vom streamboard.Bash:svn export https://svn.streamboard.tv/oscam/trunk oscam pushd oscam || cd oscam patch -i ../oscam-emu.patch -p0 patch -i ../oscam_emu_icam_dvbapi_radegast_v9.patch.txt -p 1 patch -i ../buffer.patch -p1 popd || cd ..
weiß gerade nur nicht, wo ich den oscam-emu.patch für 11725 bezogen habe. ich meine das war im streamboard
patch -p0 < oscam-emu.patch
patch -p1 < oscam_emu_icam_dvbapi_radegast_v9.patch
patch -p1 < buffer.patch
Folge dem Video um zu sehen, wie unsere Website als Web-App auf dem Startbildschirm installiert werden kann.
Anmerkung: Diese Funktion ist in einigen Browsern möglicherweise nicht verfügbar.
Das Digital Eliteboard ist ein kostenloses Forum und ist auf Spenden angewiesen, um sich auch in Zukunft selbst zu finanzieren. Wenn auch du mit dem Digital Eliteboard zufrieden bist, würden wir uns über jede Unterstützung freuen.
Hier kannst du uns unterstützen SPENDEN