953 lines
22 KiB
C
Executable File
953 lines
22 KiB
C
Executable File
/* Reversed from libcoolstream.so, this comes without any warranty */
|
|
|
|
#define MODULE_LOG_PREFIX "dvbcool"
|
|
|
|
#include "globals.h"
|
|
|
|
#if defined(HAVE_DVBAPI) && (defined(WITH_SU980) || defined(WITH_COOLAPI2) || defined(WITH_COOLAPI))
|
|
#include "extapi/coolapi.h"
|
|
|
|
#include "module-dvbapi.h"
|
|
#include "module-dvbapi-coolapi.h"
|
|
#include "oscam-string.h"
|
|
|
|
|
|
#define MAX_COOL_DMX 4
|
|
|
|
//kronos-Plattform (Coolsterem ZEE)
|
|
//#define MAX_COOL_DMX 3
|
|
|
|
|
|
#define DMX_MAX_FILTERS_PER_CHAN 16
|
|
#define DMX_MAX_CHANNELS_PER_DMX 192
|
|
//#define MAX_COOL_DMX_FILTERS 128
|
|
|
|
struct s_cool_chanhandle;
|
|
|
|
typedef struct s_cool_filter
|
|
{
|
|
int32_t fd;
|
|
struct s_cool_chanhandle *chanhandle;
|
|
void *filter;
|
|
int32_t filter_num;
|
|
uint8_t filter16[16];
|
|
uint8_t mask16[16];
|
|
} S_COOL_FILTER;
|
|
|
|
typedef struct s_cool_chanhandle
|
|
{
|
|
int32_t pid;
|
|
void *buffer1; // filter Cbuf 1
|
|
void *buffer2; // filter Cbuf 2
|
|
void *channel;
|
|
int32_t demux_index;
|
|
struct s_cool_dmxhandle *dmx_handle;
|
|
uint32_t allocated_filters;
|
|
} S_COOL_CHANHANDLE;
|
|
|
|
typedef struct s_cool_dmxhandle
|
|
{
|
|
void *handle;
|
|
uint32_t allocated_channels;
|
|
} S_COOL_DMXHANDLE;
|
|
|
|
struct cool_dmx
|
|
{
|
|
int32_t pid;
|
|
int32_t opened;
|
|
int32_t fd;
|
|
pthread_mutex_t mutex;
|
|
int32_t filter_num;
|
|
int32_t demux_id;
|
|
int32_t type;
|
|
};
|
|
typedef struct cool_dmx dmx_t;
|
|
|
|
typedef struct
|
|
{
|
|
int32_t type;
|
|
uint32_t size;
|
|
#ifdef HAVE_COOLAPI2
|
|
uint32_t ptsbufsize;
|
|
#endif
|
|
int32_t unknown1;
|
|
int16_t unknown2;
|
|
int32_t hwm;
|
|
int32_t lwm;
|
|
int32_t unknown5;
|
|
int32_t unknown6;
|
|
int32_t poolid;
|
|
#ifdef HAVE_COOLAPI2
|
|
uint32_t unit;
|
|
#endif
|
|
} buffer_open_arg_t;
|
|
|
|
typedef struct
|
|
{
|
|
int32_t type;
|
|
int32_t unknown[2];
|
|
} channel_open_arg_t;
|
|
|
|
// Nevis : 13
|
|
// Apollo: 13
|
|
typedef struct
|
|
{
|
|
uint32_t number;
|
|
int32_t unknown1; // channel source
|
|
int32_t unknown2; // mcard cap
|
|
int32_t unknown3; // descrambler type
|
|
int32_t unknown4; // support legacy NDS
|
|
int32_t unknown5;
|
|
int32_t unknown6;
|
|
int32_t unknown[6];
|
|
} device_open_arg_t;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t length;
|
|
uint8_t filter[18]; //strange: initialization with max 18 possible but length limited to 12
|
|
uint8_t mask[18];
|
|
uint8_t nmask[18];
|
|
int8_t fvernum;
|
|
int8_t crcchange;
|
|
int8_t keeprbytes;
|
|
int32_t mode;
|
|
} filter_set_t;
|
|
|
|
|
|
typedef enum
|
|
{
|
|
CONTINUOUS_ACQUIRE = 0,
|
|
ONE_SHOT_ACQUIRE,
|
|
TOGGLE_ACQUIRE
|
|
} DATA_ACQUIRE_MODE;
|
|
|
|
typedef enum
|
|
{
|
|
DATA_ACQUIRED = 1,
|
|
CHANNEL_TIMEOUT,
|
|
CRC_ERROR,
|
|
BUF_OVERFLOW,
|
|
PES_ERROR,
|
|
COPY_DONE,
|
|
CHANNEL_INFO
|
|
} DATA_ACQUIRE_STATUS;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t PTSLow;
|
|
uint32_t PTSHi;
|
|
} DMX_PTS;
|
|
|
|
typedef struct
|
|
{
|
|
void *channel;
|
|
DATA_ACQUIRE_STATUS type;
|
|
//
|
|
DMX_PTS ptssnapshot;
|
|
void *buf;
|
|
uint32_t start;
|
|
//
|
|
DATA_ACQUIRE_MODE mode;
|
|
uint32_t len;
|
|
uint16_t num;
|
|
void *filters[DMX_MAX_FILTERS_PER_CHAN];
|
|
void *tags[DMX_MAX_FILTERS_PER_CHAN];
|
|
} dmx_callback_data_t;
|
|
|
|
/* These functions are implemented in libnxp */
|
|
extern int32_t cnxt_cbuf_open(void **handle, buffer_open_arg_t *arg, void *, void *);
|
|
extern int32_t cnxt_dmx_open(void **device, device_open_arg_t *arg, void *, void *);
|
|
extern int32_t cnxt_dmx_channel_open(void *device, void **channel, channel_open_arg_t *arg, void *callback, void *);
|
|
extern int32_t cnxt_dmx_set_filter(void *handle, filter_set_t *arg, void *);
|
|
extern int32_t cnxt_dmx_channel_suspend(void *handle, int32_t enable);
|
|
|
|
/* Local coolapi functions */
|
|
static int32_t coolapi_read(dmx_t *dmx, dmx_callback_data_t *dataa, uint8_t *buffer);
|
|
|
|
static int8_t dmx_opened;
|
|
int32_t cool_kal_opened = 0;
|
|
|
|
static S_COOL_DMXHANDLE dmx_handles[MAX_COOL_DMX];
|
|
static dmx_t cdemuxes[MAX_COOL_DMX][MAX_FILTER];
|
|
static pthread_mutex_t demux_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
extern void *dvbapi_client;
|
|
|
|
static LLIST *ll_cool_filter = NULL;
|
|
static LLIST *ll_cool_chanhandle = NULL;
|
|
|
|
#define COOLDEMUX_FD(device, num) (('O' << 24) | ('S' << 16) | (device << 8) | num)
|
|
#define COOLDEMUX_DMX_DEV(fd) (((fd) >> 8) & 0xFF)
|
|
#define COOLDEMUX_FLT_IDX(fd) (((fd) >> 0) & 0xFF)
|
|
#define COOLDEMUX_IS_VALID_FD(fd) ((((fd) & 0xFF000000) == ('O' << 24)) && \
|
|
(((fd) & 0x00FF0000) == ('S' << 16)))
|
|
|
|
#define COOLDEMUX_DATA_RECEIVED 1
|
|
#define COOLDEMUX_CHANNEL_TIMEOUT 2
|
|
#define COOLDEMUX_CRC_ERROR 3
|
|
#define COOLDEMUX_BUFF_OVERFLOW 4
|
|
|
|
static dmx_t *find_demux(int32_t fd, int32_t dmx_dev_num)
|
|
{
|
|
if(dmx_dev_num < 0 || dmx_dev_num >= MAX_COOL_DMX)
|
|
{
|
|
cs_log("Invalid demux %d", dmx_dev_num);
|
|
return NULL;
|
|
}
|
|
|
|
dmx_t *dmx;
|
|
int32_t i;
|
|
|
|
if(fd == 0) // DEMUX FILTER ALLOCATE
|
|
{
|
|
for(i = 0; i < MAX_FILTER; i++)
|
|
{
|
|
dmx = &cdemuxes[dmx_dev_num][i];
|
|
if(!dmx->opened)
|
|
{
|
|
dmx->fd = COOLDEMUX_FD(dmx_dev_num, i);
|
|
cs_log_dbg(D_DVBAPI, "opening new fd: %08x", dmx->fd);
|
|
return dmx;
|
|
}
|
|
}
|
|
cs_log_dbg(D_DVBAPI, "ERROR: no free demux found");
|
|
return NULL;
|
|
}
|
|
|
|
if (!COOLDEMUX_IS_VALID_FD(fd))
|
|
{
|
|
cs_log_dbg(D_DVBAPI, "ERROR: invalid FD");
|
|
return NULL;
|
|
}
|
|
|
|
dmx_dev_num = COOLDEMUX_DMX_DEV(fd);
|
|
for(i = 0; i < MAX_FILTER; i++)
|
|
{
|
|
dmx = &cdemuxes[dmx_dev_num][i];
|
|
if(dmx->fd == fd)
|
|
{
|
|
return dmx;
|
|
}
|
|
}
|
|
|
|
cs_log_dbg(D_DVBAPI, "ERROR: CANT FIND Demux %08x", fd);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int32_t coolapi_get_filter_num(int32_t fd)
|
|
{
|
|
if (!COOLDEMUX_IS_VALID_FD(fd))
|
|
{
|
|
cs_log_dbg(D_DVBAPI, "ERROR: invalid FD");
|
|
return -1;
|
|
}
|
|
|
|
return cdemuxes[COOLDEMUX_DMX_DEV(fd)][COOLDEMUX_FLT_IDX(fd)].filter_num;
|
|
}
|
|
|
|
static S_COOL_CHANHANDLE *find_chanhandle(int32_t demux_index, int32_t pid)
|
|
{
|
|
// Find matching channel, if it exists.
|
|
if(ll_count(ll_cool_chanhandle) > 0)
|
|
{
|
|
LL_ITER itr = ll_iter_create(ll_cool_chanhandle);
|
|
S_COOL_CHANHANDLE *handle_item;
|
|
|
|
while((handle_item = ll_iter_next(&itr)))
|
|
{
|
|
if(handle_item->demux_index == demux_index && handle_item->pid == pid)
|
|
{
|
|
return handle_item;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int32_t remove_chanhandle(S_COOL_CHANHANDLE *handle)
|
|
{
|
|
// Find matching channel, if it exists.
|
|
if(ll_count(ll_cool_chanhandle) > 0)
|
|
{
|
|
LL_ITER itr = ll_iter_create(ll_cool_chanhandle);
|
|
S_COOL_CHANHANDLE *handle_item;
|
|
|
|
while((handle_item = ll_iter_next(&itr)))
|
|
{
|
|
if(handle_item == handle)
|
|
{
|
|
ll_iter_remove_data(&itr);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static S_COOL_FILTER *find_filter_by_chanhandle(S_COOL_CHANHANDLE *chanhandle, int32_t filter_num)
|
|
{
|
|
// Find matching channel, if it exists.
|
|
if(ll_count(ll_cool_filter) > 0)
|
|
{
|
|
LL_ITER itr = ll_iter_create(ll_cool_filter);
|
|
S_COOL_FILTER *filter_item;
|
|
|
|
while((filter_item = ll_iter_next(&itr)))
|
|
{
|
|
if(filter_item->chanhandle == chanhandle && filter_item->filter_num == filter_num)
|
|
{
|
|
return filter_item;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static S_COOL_FILTER *find_filter_by_channel(void *channel, int32_t filter_num)
|
|
{
|
|
// Find matching channel, if it exists.
|
|
if(ll_count(ll_cool_filter) > 0)
|
|
{
|
|
LL_ITER itr = ll_iter_create(ll_cool_filter);
|
|
S_COOL_FILTER *filter_item;
|
|
|
|
while((filter_item = ll_iter_next(&itr)))
|
|
{
|
|
if(filter_item->chanhandle &&
|
|
filter_item->chanhandle->channel == channel &&
|
|
filter_item->filter_num == filter_num)
|
|
{
|
|
return filter_item;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int32_t remove_filter(S_COOL_FILTER *filter_handle)
|
|
{
|
|
if(ll_count(ll_cool_filter) > 0)
|
|
{
|
|
LL_ITER itr = ll_iter_create(ll_cool_filter);
|
|
S_COOL_FILTER *filter_item;
|
|
|
|
while((filter_item = ll_iter_next(&itr)))
|
|
{
|
|
if(filter_item == filter_handle)
|
|
{
|
|
ll_iter_remove_data(&itr);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void coolapi_read_data(dmx_t *dmx, dmx_callback_data_t *data)
|
|
{
|
|
if(!dmx)
|
|
{
|
|
cs_log_dbg(D_DVBAPI, "handle is NULL!");
|
|
return;
|
|
}
|
|
|
|
int32_t ret;
|
|
uint8_t buffer[4096];
|
|
|
|
SAFE_SETSPECIFIC(getclient, dvbapi_client);
|
|
SAFE_MUTEX_LOCK(&dmx->mutex);
|
|
memset(buffer, 0, sizeof(buffer));
|
|
ret = coolapi_read(dmx, data, buffer);
|
|
SAFE_MUTEX_UNLOCK(&dmx->mutex);
|
|
|
|
if(ret > -1) {
|
|
uint16_t filters = data->num;
|
|
uint16_t flt;
|
|
|
|
for (flt = 0; flt < filters; flt++) {
|
|
uint32_t n = (uint32_t)data->tags[flt];
|
|
S_COOL_FILTER *filter = find_filter_by_channel(data->channel, n);
|
|
|
|
if (!filter || data->filters[flt] != filter->filter)
|
|
{
|
|
cs_log_dbg(D_DVBAPI, "filter not found in notification!!!!");
|
|
continue;
|
|
}
|
|
|
|
dvbapi_process_input(dmx->demux_id, n, buffer, data->len, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void dmx_callback(void *channel, dmx_t *dmx, int32_t type, dmx_callback_data_t *data)
|
|
{
|
|
if(!dmx)
|
|
{
|
|
cs_log_dbg(D_DVBAPI, "wrong dmx pointer !!!");
|
|
return;
|
|
}
|
|
|
|
if(data == NULL)
|
|
return;
|
|
|
|
if (channel != data->channel)
|
|
return;
|
|
|
|
switch(type)
|
|
{
|
|
#ifdef WITH_COOLAPI2
|
|
case 0x11:
|
|
#else
|
|
case 0x0E:
|
|
#endif
|
|
if(data->type == COOLDEMUX_DATA_RECEIVED && data->len > 0) {
|
|
coolapi_read_data(dmx, data);
|
|
} else if(data->type == COOLDEMUX_CRC_ERROR && data->len > 0) {
|
|
cs_log_dbg(D_DVBAPI, "CRC error !!!");
|
|
cnxt_cbuf_removed_data(data->buf, data->len);
|
|
} else if(data->type == COOLDEMUX_BUFF_OVERFLOW) {
|
|
cs_log_dbg(D_DVBAPI, "OVERFLOW !!!");
|
|
} else {
|
|
cs_log_dbg(D_DVBAPI, "unknown callback data %d len %d", data->type, data->len);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
int32_t coolapi_set_filter(int32_t fd, int32_t num, int32_t pid, uint8_t *flt, uint8_t *mask, int32_t type)
|
|
{
|
|
dmx_t *dmx = find_demux(fd, 0);
|
|
if(!dmx)
|
|
{
|
|
cs_log_dbg(D_DVBAPI, "dmx is NULL!");
|
|
return -1;
|
|
}
|
|
|
|
int32_t result, channel_found;
|
|
SAFE_MUTEX_LOCK(&dmx->mutex);
|
|
|
|
// Find matching channel, if it exists.
|
|
S_COOL_CHANHANDLE *handle_item = find_chanhandle(COOLDEMUX_DMX_DEV(fd), pid);
|
|
if(!handle_item)
|
|
{
|
|
// No channel was found, allocate one
|
|
buffer_open_arg_t bufarg;
|
|
int32_t uBufferSize = 8192 + 64;
|
|
/* Mark that we did not find any open channel on this PID */
|
|
channel_found = 0;
|
|
|
|
if(!cs_malloc(&handle_item, sizeof(S_COOL_CHANHANDLE)))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
memset(&bufarg, 0, sizeof(bufarg));
|
|
|
|
#ifdef HAVE_COOLAPI2
|
|
bufarg.poolid = 5
|
|
#endif
|
|
bufarg.type = 3;
|
|
bufarg.size = uBufferSize;
|
|
bufarg.hwm = (uBufferSize * 7) / 8;
|
|
|
|
result = cnxt_cbuf_open(&handle_item->buffer1, &bufarg, NULL, NULL);
|
|
coolapi_check_error("cnxt_cbuf_open", result);
|
|
bufarg.type = 0;
|
|
|
|
#ifdef HAVE_COOLAPI2
|
|
bufarg.poolid = 0
|
|
#endif
|
|
result = cnxt_cbuf_open(&handle_item->buffer2, &bufarg, NULL, NULL);
|
|
coolapi_check_error("cnxt_cbuf_open", result);
|
|
|
|
channel_open_arg_t chanarg;
|
|
memset(&chanarg, 0, sizeof(channel_open_arg_t));
|
|
|
|
chanarg.type = 4;
|
|
result = cnxt_dmx_channel_open(dmx_handles[COOLDEMUX_DMX_DEV(fd)].handle, &handle_item->channel, &chanarg, dmx_callback, dmx);
|
|
coolapi_check_error("cnxt_dmx_channel_open", result);
|
|
|
|
result = cnxt_dmx_set_channel_buffer(handle_item->channel, 0, handle_item->buffer1);
|
|
coolapi_check_error("cnxt_dmx_set_channel_buffer", result);
|
|
|
|
result = cnxt_dmx_channel_attach(handle_item->channel, 0xB, 0, handle_item->buffer2);
|
|
coolapi_check_error("cnxt_dmx_channel_attach", result);
|
|
|
|
result = cnxt_cbuf_attach(handle_item->buffer2, 2, handle_item->channel);
|
|
coolapi_check_error("cnxt_cbuf_attach", result);
|
|
|
|
result = cnxt_dmx_set_channel_pid(handle_item->channel, pid);
|
|
coolapi_check_error("cnxt_dmx_set_channel_pid", result);
|
|
|
|
result = cnxt_cbuf_flush(handle_item->buffer1, 0);
|
|
coolapi_check_error("cnxt_cbuf_flush", result);
|
|
result = cnxt_cbuf_flush(handle_item->buffer2, 0);
|
|
coolapi_check_error("cnxt_cbuf_flush", result);
|
|
|
|
handle_item->pid = pid;
|
|
handle_item->dmx_handle = &dmx_handles[COOLDEMUX_DMX_DEV(fd)];
|
|
dmx_handles[COOLDEMUX_DMX_DEV(fd)].allocated_channels++;
|
|
ll_append(ll_cool_chanhandle, handle_item);
|
|
|
|
cs_log_dbg(D_DVBAPI, "opened new channel %x", (int32_t) handle_item->channel);;
|
|
}
|
|
else
|
|
{
|
|
channel_found = 1;
|
|
}
|
|
|
|
cs_log_dbg(D_DVBAPI, "setting new filter fd=%08x demux=%d channel=%x num=%d pid=%04x flt=%x mask=%x", fd, COOLDEMUX_DMX_DEV(fd), (int32_t) handle_item->channel, num, pid, flt[0], mask[0]);
|
|
void *filter_handle = NULL;
|
|
filter_set_t filterset;
|
|
int32_t has_filter = 0;
|
|
|
|
S_COOL_FILTER *filter_item = find_filter_by_chanhandle(handle_item, num);
|
|
if (filter_item && type == dmx->type && pid == dmx->pid &&
|
|
(memcmp(flt, filter_item->filter16, 16) || memcmp(mask, filter_item->mask16, 16)))
|
|
{
|
|
cs_log_dbg(D_DVBAPI, "setting new filter fd=%08x demux=%d channel=%x num=%d pid=%04x flt=%x mask=%x, filter exists.. modifying", fd, COOLDEMUX_DMX_DEV(fd), (int32_t) handle_item->channel, num, pid, flt[0], mask[0]);
|
|
filter_handle = filter_item->filter;
|
|
|
|
has_filter = 1;
|
|
|
|
memcpy(filter_item->filter16, flt, 16);
|
|
memcpy(filter_item->mask16, mask, 16);
|
|
}
|
|
else
|
|
{
|
|
dmx->pid = pid;
|
|
dmx->type = type;
|
|
dmx->filter_num = num;
|
|
result = cnxt_dmx_open_filter(dmx_handles[COOLDEMUX_DMX_DEV(fd)].handle, &filter_handle);
|
|
coolapi_check_error("cnxt_dmx_open_filter", result);
|
|
|
|
if(!cs_malloc(&filter_item, sizeof(S_COOL_FILTER)))
|
|
{
|
|
SAFE_MUTEX_UNLOCK(&dmx->mutex);
|
|
return -1;
|
|
}
|
|
|
|
// fill filter item
|
|
filter_item->fd = fd;
|
|
filter_item->filter = filter_handle;
|
|
filter_item->filter_num = num;
|
|
filter_item->chanhandle = handle_item;
|
|
memcpy(filter_item->filter16, flt, 16);
|
|
memcpy(filter_item->mask16, mask, 16);
|
|
|
|
//add filter item
|
|
ll_append(ll_cool_filter, filter_item);
|
|
// increase allocated filters
|
|
handle_item->allocated_filters++;
|
|
}
|
|
|
|
if (has_filter)
|
|
{
|
|
result = cnxt_dmx_channel_suspend(handle_item->channel, 1);
|
|
coolapi_check_error("cnxt_dmx_channel_suspend", result);
|
|
result = cnxt_dmx_channel_detach_filter(handle_item->channel, filter_handle);
|
|
coolapi_check_error("cnxt_dmx_channel_detach_filter", result);
|
|
}
|
|
|
|
memset(&filterset, 0, sizeof(filterset));
|
|
filterset.length = 12;
|
|
memcpy(filterset.filter, flt, 16);
|
|
memcpy(filterset.mask, mask, 16);
|
|
|
|
result = cnxt_dmx_set_filter(filter_handle, &filterset, (void *)num);
|
|
coolapi_check_error("cnxt_dmx_set_filter", result);
|
|
|
|
result = cnxt_dmx_channel_attach_filter(handle_item->channel, filter_handle);
|
|
coolapi_check_error("cnxt_dmx_channel_attach_filter", result);
|
|
|
|
if (has_filter)
|
|
{
|
|
result = cnxt_dmx_channel_suspend(handle_item->channel, 0);
|
|
coolapi_check_error("cnxt_dmx_channel_suspend", result);
|
|
}
|
|
|
|
if(!channel_found)
|
|
{
|
|
// Start channel
|
|
result = cnxt_dmx_channel_ctrl(handle_item->channel, 2, 0);
|
|
coolapi_check_error("cnxt_dmx_channel_ctrl", result);
|
|
}
|
|
|
|
SAFE_MUTEX_UNLOCK(&dmx->mutex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t coolapi_remove_filter(int32_t fd, int32_t num)
|
|
{
|
|
void * channel = NULL;
|
|
void * filter = NULL;
|
|
|
|
dmx_t *dmx = find_demux(fd, 0);
|
|
if(!dmx)
|
|
{
|
|
cs_log_dbg(D_DVBAPI, "dmx is NULL!");
|
|
return -1;
|
|
}
|
|
|
|
if(dmx->pid <= 0)
|
|
{ return -1; }
|
|
|
|
int32_t result;
|
|
|
|
SAFE_MUTEX_LOCK(&dmx->mutex);
|
|
|
|
// Find matching channel, if it exists.
|
|
S_COOL_CHANHANDLE *handle_item = find_chanhandle(COOLDEMUX_DMX_DEV(fd), dmx->pid);
|
|
if (!handle_item)
|
|
{
|
|
SAFE_MUTEX_UNLOCK(&dmx->mutex);
|
|
cs_log_dbg(D_DVBAPI, "removing filter fd=%08x num=%d pid=%04xcfailed, channel does not exist.", fd, num, dmx->pid);
|
|
return -1;
|
|
}
|
|
|
|
channel = handle_item->channel;
|
|
cs_log_dbg(D_DVBAPI, "removing filter fd=%08x num=%d pid=%04x on channel=%p", fd, num, dmx->pid, channel);
|
|
|
|
|
|
S_COOL_FILTER *filter_item = find_filter_by_chanhandle(handle_item, num);
|
|
if(filter_item)
|
|
{
|
|
result = cnxt_dmx_channel_suspend(channel, 1);
|
|
coolapi_check_error("cnxt_dmx_channel_suspend", result);
|
|
result = cnxt_dmx_channel_detach_filter(channel, filter_item->filter);
|
|
coolapi_check_error("cnxt_dmx_channel_detach_filter", result);
|
|
#if 0
|
|
result = cnxt_dmx_close_filter(filter_item->filter);
|
|
coolapi_check_error("cnxt_dmx_close_filter", result);
|
|
#endif
|
|
filter = filter_item->filter;
|
|
remove_filter(filter_item);
|
|
handle_item->allocated_filters--;
|
|
}
|
|
else
|
|
{
|
|
SAFE_MUTEX_UNLOCK(&dmx->mutex);
|
|
cs_log_dbg(D_DVBAPI, "removing filter fd=%08x num=%d pid=%04x on channel=%x failed, channel does not exist.", fd, num, dmx->pid, (int32_t) handle_item->channel);
|
|
return -1;
|
|
}
|
|
|
|
if (!handle_item->allocated_filters)
|
|
{
|
|
result = cnxt_dmx_channel_ctrl(channel, 0, 0);
|
|
coolapi_check_error("cnxt_dmx_channel_ctrl", result);
|
|
cs_log_dbg(D_DVBAPI, "closing channel %x", (int32_t) channel);
|
|
|
|
result = cnxt_dmx_set_channel_pid(channel, 0x1FFF);
|
|
coolapi_check_error("cnxt_dmx_set_channel_pid", result);
|
|
|
|
result = cnxt_cbuf_flush(handle_item->buffer1, 0);
|
|
coolapi_check_error("cnxt_cbuf_flush", result);
|
|
|
|
result = cnxt_cbuf_flush(handle_item->buffer2, 0);
|
|
coolapi_check_error("cnxt_cbuf_flush", result);
|
|
|
|
result = cnxt_cbuf_detach(handle_item->buffer2, 2, channel);
|
|
coolapi_check_error("cnxt_cbuf_detach", result);
|
|
|
|
result = cnxt_dmx_channel_detach(channel, 0xB, 0, handle_item->buffer1);
|
|
coolapi_check_error("cnxt_dmx_channel_detach", result);
|
|
|
|
#if 0
|
|
result = cnxt_dmx_channel_close(channel);
|
|
coolapi_check_error("cnxt_dmx_channel_close", result);
|
|
#endif
|
|
|
|
result = cnxt_cbuf_close(handle_item->buffer2);
|
|
coolapi_check_error("cnxt_cbuf_close", result);
|
|
|
|
result = cnxt_cbuf_close(handle_item->buffer1);
|
|
coolapi_check_error("cnxt_cbuf_close", result);
|
|
handle_item->channel = NULL;
|
|
handle_item->buffer1 = NULL;
|
|
handle_item->buffer2 = NULL;
|
|
remove_chanhandle(handle_item);
|
|
dmx_handles[COOLDEMUX_DMX_DEV(fd)].allocated_channels--;
|
|
dmx->pid = -1;
|
|
} else {
|
|
result = cnxt_dmx_channel_suspend(channel, 0);
|
|
coolapi_check_error("cnxt_dmx_channel_suspend", result);
|
|
channel = NULL;
|
|
}
|
|
|
|
SAFE_MUTEX_UNLOCK(&dmx->mutex);
|
|
if (filter) {
|
|
result = cnxt_dmx_close_filter(filter);
|
|
coolapi_check_error("cnxt_dmx_close_filter", result);
|
|
}
|
|
|
|
// COOLAPI2 - We don't want to close Channel on no ECM Filters (Makes AU / EMMs work)
|
|
if(dmx->type != TYPE_ECM)
|
|
{ return 0; }
|
|
|
|
if (channel) {
|
|
result = cnxt_dmx_channel_close(channel);
|
|
coolapi_check_error("cnxt_dmx_channel_close", result);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t coolapi_open_device(int32_t demux_index, int32_t demux_id)
|
|
{
|
|
dmx_t *dmx;
|
|
|
|
SAFE_MUTEX_LOCK(&demux_lock);
|
|
|
|
dmx = find_demux(0, demux_index);
|
|
if(!dmx)
|
|
{
|
|
SAFE_MUTEX_UNLOCK(&demux_lock);
|
|
cs_log("no free demux found");
|
|
return 0;
|
|
}
|
|
|
|
if(!ll_cool_filter)
|
|
{ ll_cool_filter = ll_create("ll_cool_filter"); }
|
|
|
|
if(!ll_cool_chanhandle)
|
|
{ ll_cool_chanhandle = ll_create("ll_cool_chanhandle"); }
|
|
|
|
dmx->demux_id = demux_id;
|
|
dmx->pid = -1;
|
|
|
|
//dmx->device = dmx_handles[demux_index].handle;
|
|
dmx->opened = 1;
|
|
|
|
pthread_mutexattr_t attr;
|
|
SAFE_MUTEXATTR_INIT(&attr);
|
|
SAFE_MUTEXATTR_SETTYPE(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
|
|
SAFE_MUTEX_INIT(&dmx->mutex, &attr);
|
|
|
|
SAFE_MUTEX_UNLOCK(&demux_lock);
|
|
|
|
return dmx->fd;
|
|
}
|
|
|
|
int32_t coolapi_close_device(int32_t fd)
|
|
{
|
|
dmx_t *dmx = find_demux(fd, 0);
|
|
if(!dmx)
|
|
{
|
|
cs_log_dbg(D_DVBAPI, "dmx is NULL!");
|
|
SAFE_MUTEX_UNLOCK(&demux_lock);
|
|
return -1;
|
|
}
|
|
|
|
cs_log_dbg(D_DVBAPI, "closing fd=%08x", fd);
|
|
dmx->opened = 0;
|
|
pthread_mutex_destroy(&dmx->mutex);
|
|
|
|
memset(dmx, 0, sizeof(dmx_t));
|
|
return 0;
|
|
}
|
|
|
|
/* write cw to all demuxes in mask with passed index */
|
|
int32_t coolapi_write_cw(int32_t mask, uint16_t *STREAMpids, int32_t count, ca_descr_t *ca_descr)
|
|
{
|
|
int32_t i;
|
|
uint32_t idx = ca_descr->index;
|
|
int32_t result;
|
|
void *channel;
|
|
|
|
cs_log_dbg(D_DVBAPI, "cw%d: mask %d index %d pid count %d", ca_descr->parity, mask, idx, count);
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
int32_t pid = STREAMpids[i];
|
|
int32_t j;
|
|
for(j = 0; j < MAX_COOL_DMX; j++)
|
|
{
|
|
if(mask & (1 << j))
|
|
{
|
|
result = cnxt_dmx_get_channel_from_pid(dmx_handles[j].handle, pid, &channel);
|
|
if(result == 0)
|
|
{
|
|
cs_log_dbg(D_DVBAPI, "Found demux %d channel %x for pid %04x", j, (int32_t) channel, pid);
|
|
result = cnxt_dmx_set_channel_key(channel, 0, ca_descr->parity, ca_descr->cw, 8);
|
|
coolapi_check_error("cnxt_dmx_set_channel_key", result);
|
|
if(result != 0)
|
|
{
|
|
cs_log("set_channel_key failed for demux %d pid %04x", j, pid);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int32_t coolapi_read(dmx_t *dmx, dmx_callback_data_t *data, uint8_t *buffer)
|
|
{
|
|
if(!dmx)
|
|
{
|
|
cs_log_dbg(D_DVBAPI, "dmx is NULL!");
|
|
return -1;
|
|
}
|
|
|
|
int32_t result;
|
|
uint32_t done = 0, toread, len = data->len;
|
|
uint32_t bytes_used = 0;
|
|
|
|
//cs_log_dbg(D_DVBAPI, "dmx channel %x pid %x len %d", (int) dmx->channel, dmx->pid, len);
|
|
|
|
result = cnxt_cbuf_get_used(data->buf, &bytes_used);
|
|
coolapi_check_error("cnxt_cbuf_get_used", result);
|
|
if(bytes_used == 0)
|
|
{ return -1; }
|
|
|
|
result = cnxt_cbuf_read_data(data->buf, buffer, 3, &done);
|
|
coolapi_check_error("cnxt_cbuf_read_data", result);
|
|
|
|
if(done != 3)
|
|
{ return -1; }
|
|
|
|
toread = ((buffer[1] << 8) | buffer[2]) & 0xFFF;
|
|
if((toread + 3) > len)
|
|
{ return -1; }
|
|
result = cnxt_cbuf_read_data(data->buf, buffer + 3, toread, &done);
|
|
coolapi_check_error("cnxt_cbuf_read_data", result);
|
|
if(done != toread)
|
|
{ return -1; }
|
|
done += 3;
|
|
|
|
//cs_log_dbg(D_DVBAPI, "bytes read %d\n", done);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void coolapi_dmx_open(void)
|
|
{
|
|
int32_t result = 0;
|
|
device_open_arg_t devarg;
|
|
|
|
if(!dmx_opened)
|
|
{
|
|
int32_t i;
|
|
|
|
cs_log_dbg(D_DVBAPI, "Open Coolstream DMX API");
|
|
|
|
memset(&devarg, 0, sizeof(device_open_arg_t));
|
|
|
|
devarg.unknown1 = 1;
|
|
devarg.unknown3 = 3;
|
|
devarg.unknown6 = 1;
|
|
for(i = 0; i < MAX_COOL_DMX; i++)
|
|
{
|
|
devarg.number = i;
|
|
result = cnxt_dmx_open(&dmx_handles[i].handle, &devarg, NULL, NULL);
|
|
coolapi_check_error("cnxt_dmx_open", result);
|
|
}
|
|
dmx_opened = 1;
|
|
}
|
|
}
|
|
|
|
static void coolapi_dmx_close(void)
|
|
{
|
|
if(dmx_opened)
|
|
{
|
|
int32_t result;
|
|
int32_t i;
|
|
|
|
for(i = 0; i < MAX_COOL_DMX; i++)
|
|
{
|
|
result = cnxt_dmx_close(dmx_handles[i].handle);
|
|
coolapi_check_error("cnxt_dmx_close", result);
|
|
dmx_handles[i].handle = NULL;
|
|
}
|
|
dmx_opened = 0;
|
|
}
|
|
}
|
|
|
|
static void coolapi_start_api(void);
|
|
static void coolapi_stop_api(void);
|
|
|
|
void coolapi_open_all(void)
|
|
{
|
|
SAFE_MUTEX_LOCK(&demux_lock);
|
|
|
|
coolapi_start_api();
|
|
cool_kal_opened = 1;
|
|
coolapi_dmx_open();
|
|
|
|
SAFE_MUTEX_UNLOCK(&demux_lock);
|
|
}
|
|
|
|
void coolapi_close_all(void)
|
|
{
|
|
SAFE_MUTEX_LOCK(&demux_lock);
|
|
|
|
if(!dmx_opened) {
|
|
SAFE_MUTEX_UNLOCK(&demux_lock);
|
|
return;
|
|
}
|
|
|
|
int32_t i, j;
|
|
|
|
for(i = 0; i < MAX_COOL_DMX; i++)
|
|
{
|
|
for(j = 0; j < MAX_FILTER; j++)
|
|
{
|
|
if(cdemuxes[i][j].fd > 0)
|
|
{
|
|
coolapi_remove_filter(cdemuxes[i][j].fd, cdemuxes[i][j].filter_num);
|
|
coolapi_close_device(cdemuxes[i][j].fd);
|
|
}
|
|
}
|
|
}
|
|
|
|
coolapi_dmx_close();
|
|
coolapi_stop_api();
|
|
cool_kal_opened = 0;
|
|
|
|
SAFE_MUTEX_UNLOCK(&demux_lock);
|
|
}
|
|
#endif
|
|
|
|
#if defined(HAVE_DVBAPI) && (defined(WITH_SU980) || defined(WITH_COOLAPI2))
|
|
#include "extapi/coolapi.h"
|
|
extern void cnxt_css_drv_init(void);
|
|
extern void cnxt_css_drv_term(void);
|
|
extern void cnxt_smc_term(void);
|
|
|
|
static void coolapi_start_api(void)
|
|
{
|
|
cnxt_kal_initialize();
|
|
cnxt_css_drv_init();
|
|
cnxt_cbuf_init(NULL);
|
|
cnxt_dmx_init(NULL);
|
|
cnxt_smc_init(NULL);
|
|
}
|
|
|
|
static void coolapi_stop_api(void)
|
|
{
|
|
cnxt_css_drv_term();
|
|
cnxt_kal_terminate();
|
|
}
|
|
#elif defined(HAVE_DVBAPI) && defined(WITH_COOLAPI)
|
|
static void coolapi_start_api(void)
|
|
{
|
|
cnxt_kal_initialize();
|
|
cnxt_drv_init();
|
|
cnxt_smc_init(NULL);
|
|
}
|
|
|
|
static void coolapi_stop_api(void)
|
|
{
|
|
cnxt_kal_terminate();
|
|
cnxt_drv_term();
|
|
}
|
|
#endif
|