From 3d49692a9faa7092d6c968da0b42657fd1be609a Mon Sep 17 00:00:00 2001 From: max_10 Date: Sun, 27 Apr 2014 01:52:05 +0200 Subject: [PATCH] add libduckbox Origin commit data ------------------ Branch: master Commit: https://github.com/neutrino-images/ni-libstb-hal/commit/4dc1171253b9a50d7c538b516867f3b7184821f8 Author: max_10 Date: 2014-04-27 (Sun, 27 Apr 2014) ------------------ No further description and justification available within origin commit message! ------------------ This commit was generated by Migit --- Makefile.am | 8 + acinclude.m4 | 83 +- common/Makefile.am | 16 +- common/ca.h | 19 +- common/ca_ci.cpp | 1098 +++++++++++++++++ common/ca_ci.h | 283 +++++ configure.ac | 2 + include/audio_td.h | 3 + include/cs_api.h | 2 + include/cs_frontpanel.h | 184 +++ include/cs_vfd.h | 178 +++ include/dmx_td.h | 2 + include/hardware_caps.h | 1 + include/lt_debug.h | 8 - include/mmi.h | 24 + include/playback_td.h | 6 + include/pwrmngr.h | 2 + include/record_td.h | 2 + include/video_td.h | 2 + libduckbox/Makefile.am | 26 + libduckbox/audio.cpp | 1 + libduckbox/audio_lib.h | 1 + libduckbox/audio_mixer.cpp | 1 + libduckbox/audio_mixer.h | 1 + libduckbox/cs_api.h | 30 + libduckbox/dmx.cpp | 1 + libduckbox/dmx_cs.h | 1 + libduckbox/dmx_lib.h | 1 + libduckbox/hardware_caps.c | 158 +++ libduckbox/init.cpp | 55 + libduckbox/init_cs.h | 1 + libduckbox/init_lib.h | 1 + libduckbox/playback_libeplayer3.cpp | 1 + libduckbox/playback_libeplayer3.h | 1 + libduckbox/pwrmngr.cpp | 1 + libduckbox/pwrmngr.h | 1 + libduckbox/record.cpp | 1 + libduckbox/record_lib.h | 1 + libduckbox/video.cpp | 1 + libduckbox/video_lib.h | 1 + libdvbci/Makefile.am | 17 + libdvbci/Makefile.in | 632 ++++++++++ libdvbci/dvbci_appmgr.cpp | 104 ++ libdvbci/dvbci_appmgr.h | 24 + libdvbci/dvbci_camgr.cpp | 81 ++ libdvbci/dvbci_camgr.h | 24 + libdvbci/dvbci_datetimemgr.cpp | 59 + libdvbci/dvbci_datetimemgr.h | 18 + libdvbci/dvbci_mmi.cpp | 282 +++++ libdvbci/dvbci_mmi.h | 24 + libdvbci/dvbci_resmgr.cpp | 91 ++ libdvbci/dvbci_resmgr.h | 20 + libdvbci/dvbci_session.cpp | 348 ++++++ libdvbci/dvbci_session.h | 46 + libspark/Makefile.am | 4 +- libspark/audio_lib.h | 34 +- libspark/hardware_caps.c | 1 + libspark/mmi.h | 23 - libspark/playback.cpp | 1466 ----------------------- libspark/playback_lib.h | 125 -- libspark/playback_libeplayer3.cpp | 24 +- libspark/playback_libeplayer3.h | 4 +- libspark/pwrmngr.cpp | 4 +- libspark/record.cpp | 11 + libspark/td-compat/td-audio-compat.h | 38 - libspark/td-compat/td-demux-compat.h | 45 - libspark/td-compat/td-frontend-compat.h | 120 -- libspark/td-compat/td-value-compat.h | 93 -- libspark/td-compat/td-video-compat.h | 46 - libspark/video.cpp | 31 +- libspark/video_lib.h | 8 +- libtriple/Makefile.am | 1 + libtriple/mmi.h | 23 - 73 files changed, 4050 insertions(+), 2030 deletions(-) create mode 100644 common/ca_ci.cpp create mode 100644 common/ca_ci.h create mode 100644 include/cs_frontpanel.h create mode 100644 include/cs_vfd.h delete mode 100644 include/lt_debug.h create mode 100644 libduckbox/Makefile.am create mode 120000 libduckbox/audio.cpp create mode 120000 libduckbox/audio_lib.h create mode 120000 libduckbox/audio_mixer.cpp create mode 120000 libduckbox/audio_mixer.h create mode 100644 libduckbox/cs_api.h create mode 120000 libduckbox/dmx.cpp create mode 120000 libduckbox/dmx_cs.h create mode 120000 libduckbox/dmx_lib.h create mode 100644 libduckbox/hardware_caps.c create mode 100644 libduckbox/init.cpp create mode 120000 libduckbox/init_cs.h create mode 120000 libduckbox/init_lib.h create mode 120000 libduckbox/playback_libeplayer3.cpp create mode 120000 libduckbox/playback_libeplayer3.h create mode 120000 libduckbox/pwrmngr.cpp create mode 120000 libduckbox/pwrmngr.h create mode 120000 libduckbox/record.cpp create mode 120000 libduckbox/record_lib.h create mode 120000 libduckbox/video.cpp create mode 120000 libduckbox/video_lib.h create mode 100644 libdvbci/Makefile.am create mode 100644 libdvbci/Makefile.in create mode 100644 libdvbci/dvbci_appmgr.cpp create mode 100644 libdvbci/dvbci_appmgr.h create mode 100644 libdvbci/dvbci_camgr.cpp create mode 100644 libdvbci/dvbci_camgr.h create mode 100644 libdvbci/dvbci_datetimemgr.cpp create mode 100644 libdvbci/dvbci_datetimemgr.h create mode 100644 libdvbci/dvbci_mmi.cpp create mode 100644 libdvbci/dvbci_mmi.h create mode 100644 libdvbci/dvbci_resmgr.cpp create mode 100644 libdvbci/dvbci_resmgr.h create mode 100644 libdvbci/dvbci_session.cpp create mode 100644 libdvbci/dvbci_session.h delete mode 100644 libspark/mmi.h delete mode 100644 libspark/playback.cpp delete mode 100644 libspark/playback_lib.h delete mode 100644 libspark/td-compat/td-audio-compat.h delete mode 100644 libspark/td-compat/td-demux-compat.h delete mode 100644 libspark/td-compat/td-frontend-compat.h delete mode 100644 libspark/td-compat/td-value-compat.h delete mode 100644 libspark/td-compat/td-video-compat.h delete mode 100644 libtriple/mmi.h diff --git a/Makefile.am b/Makefile.am index 36e8f10..e5e1615 100644 --- a/Makefile.am +++ b/Makefile.am @@ -40,3 +40,11 @@ libstb_hal_la_LIBADD += \ libspark/libspark.la \ libeplayer3/libeplayer3.la endif +if BOXTYPE_DUCKBOX +libstb_hal_test_LDADD += -lasound +SUBDIRS += libduckbox libeplayer3 libdvbci +libstb_hal_la_LIBADD += \ + libduckbox/libduckbox.la \ + libeplayer3/libeplayer3.la \ + libdvbci/libdvbci.la +endif diff --git a/acinclude.m4 b/acinclude.m4 index 64db50e..f9b8dca 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -278,22 +278,51 @@ _TUXBOX_APPS_LIB_SYMBOL($1,$2,$3,WARN) AC_DEFUN([TUXBOX_BOXTYPE],[ AC_ARG_WITH(boxtype, - [ --with-boxtype valid values: dbox2,tripledragon,dreambox,ipbox,coolstream,spark,azbox,generic], + [ --with-boxtype valid values: dbox2,tripledragon,dreambox,ipbox,coolstream,spark,azbox,generic,duckbox,spark7162], [case "${withval}" in dbox2|dreambox|ipbox|tripledragon|coolstream|spark|azbox|generic) BOXTYPE="$withval" ;; + spark7162) + BOXTYPE="spark" + BOXMODEL="$withval" + ;; dm*) BOXTYPE="dreambox" BOXMODEL="$withval" ;; + ufs*) + BOXTYPE="duckbox" + BOXMODEL="$withval" + ;; + atevio*) + BOXTYPE="duckbox" + BOXMODEL="$withval" + ;; + fortis*) + BOXTYPE="duckbox" + BOXMODEL="$withval" + ;; + octagon*) + BOXTYPE="duckbox" + BOXMODEL="$withval" + ;; + cuberevo*) + BOXTYPE="duckbox" + BOXMODEL="$withval" + ;; + tf*) + BOXTYPE="duckbox" + BOXMODEL="$withval" + ;; *) AC_MSG_ERROR([bad value $withval for --with-boxtype]) ;; esac], [BOXTYPE="generic"]) AC_ARG_WITH(boxmodel, [ --with-boxmodel valid for dreambox: dm500, dm500plus, dm600pvr, dm56x0, dm7000, dm7020, dm7025 - valid for ipbox: ip200, ip250, ip350, ip400], + valid for ipbox: ip200, ip250, ip350, ip400 + valid for duckbox: ufs910, ufs912, ufs913, ufs922, atevio7500, fortis_hdbox, octagon1008, cuberevo, cuberevo_mini2, cuberevo_2000hd, tf7700], [case "${withval}" in dm500|dm500plus|dm600pvr|dm56x0|dm7000|dm7020|dm7025) if test "$BOXTYPE" = "dreambox"; then @@ -309,6 +338,13 @@ AC_ARG_WITH(boxmodel, AC_MSG_ERROR([unknown model $withval for boxtype $BOXTYPE]) fi ;; + ufs910|ufs912|ufs913|ufs922|atevio7500|fortis_hdbox|octagon1008|cuberevo|cuberevo_mini2|cuberevo_2000hd|tf7700) + if test "$BOXTYPE" = "duckbox"; then + BOXMODEL="$withval" + else + AC_MSG_ERROR([unknown model $withval for boxtype $BOXTYPE]) + fi + ;; raspi) if test "$BOXTYPE" = "generic"; then BOXMODEL="$withval" @@ -335,6 +371,7 @@ AM_CONDITIONAL(BOXTYPE_DREAMBOX, test "$BOXTYPE" = "dreambox") AM_CONDITIONAL(BOXTYPE_IPBOX, test "$BOXTYPE" = "ipbox") AM_CONDITIONAL(BOXTYPE_COOL, test "$BOXTYPE" = "coolstream") AM_CONDITIONAL(BOXTYPE_GENERIC, test "$BOXTYPE" = "generic") +AM_CONDITIONAL(BOXTYPE_DUCKBOX, test "$BOXTYPE" = "duckbox") AM_CONDITIONAL(BOXMODEL_DM500,test "$BOXMODEL" = "dm500") AM_CONDITIONAL(BOXMODEL_DM500PLUS,test "$BOXMODEL" = "dm500plus") @@ -347,6 +384,22 @@ AM_CONDITIONAL(BOXMODEL_IP250,test "$BOXMODEL" = "ip250") AM_CONDITIONAL(BOXMODEL_IP350,test "$BOXMODEL" = "ip350") AM_CONDITIONAL(BOXMODEL_IP400,test "$BOXMODEL" = "ip400") +AM_CONDITIONAL(BOXMODEL_UFS910, test "$BOXMODEL" = "ufs910") +AM_CONDITIONAL(BOXMODEL_UFS912,test "$BOXMODEL" = "ufs912") +AM_CONDITIONAL(BOXMODEL_UFS913,test "$BOXMODEL" = "ufs913") +AM_CONDITIONAL(BOXMODEL_UFS922,test "$BOXMODEL" = "ufs922") + +AM_CONDITIONAL(BOXMODEL_SPARK7162,test "$BOXMODEL" = "spark7162") + +AM_CONDITIONAL(BOXMODEL_ATEVIO7500, test "$BOXMODEL" = "atevio7500") +AM_CONDITIONAL(BOXMODEL_FORTIS_HDBOX,test "$BOXMODEL" = "fortis_hdbox") +AM_CONDITIONAL(BOXMODEL_OCTAGON1008,test "$BOXMODEL" = "octagon1008") +AM_CONDITIONAL(BOXMODEL_CUBEREVO,test "$BOXMODEL" = "cuberevo") +AM_CONDITIONAL(BOXMODEL_CUBEREVO_MINI2,test "$BOXMODEL" = "cuberevo_mini2") +AM_CONDITIONAL(BOXMODEL_CUBEREVO_2000HD,test "$BOXMODEL" = "cuberevo_2000hd") +AM_CONDITIONAL(BOXMODEL_TF7700,test "$BOXMODEL" = "tf7700") + + AM_CONDITIONAL(BOXMODEL_RASPI,test "$BOXMODEL" = "raspi") if test "$BOXTYPE" = "dbox2"; then @@ -365,6 +418,8 @@ elif test "$BOXTYPE" = "coolstream"; then AC_DEFINE(HAVE_COOL_HARDWARE, 1, [building for a coolstream]) elif test "$BOXTYPE" = "generic"; then AC_DEFINE(HAVE_GENERIC_HARDWARE, 1, [building for a generic device like a standard PC]) +elif test "$BOXTYPE" = "duckbox"; then + AC_DEFINE(HAVE_DUCKBOX_HARDWARE, 1, [building for a duckbox]) fi # TODO: do we need more defines? @@ -378,6 +433,30 @@ elif test "$BOXMODEL" = "ip350"; then AC_DEFINE(BOXMODEL_IP350, 1, [ipbox 350]) elif test "$BOXMODEL" = "ip400"; then AC_DEFINE(BOXMODEL_IP400, 1, [ipbox 400]) +elif test "$BOXMODEL" = "ufs910"; then + AC_DEFINE(BOXMODEL_UFS910, 1, [ufs910]) +elif test "$BOXMODEL" = "ufs912"; then + AC_DEFINE(BOXMODEL_UFS912, 1, [ufs912]) +elif test "$BOXMODEL" = "ufs913"; then + AC_DEFINE(BOXMODEL_UFS913, 1, [ufs913]) +elif test "$BOXMODEL" = "ufs922"; then + AC_DEFINE(BOXMODEL_UFS922, 1, [ufs922]) +elif test "$BOXMODEL" = "spark7162"; then + AC_DEFINE(BOXMODEL_SPARK7162, 1, [spark7162]) +elif test "$BOXMODEL" = "atevio7500"; then + AC_DEFINE(BOXMODEL_ATEVIO7500, 1, [atevio7500]) +elif test "$BOXMODEL" = "fortis_hdbox"; then + AC_DEFINE(BOXMODEL_FORTIS_HDBOX, 1, [fortis_hdbox]) +elif test "$BOXMODEL" = "octagon1008"; then + AC_DEFINE(BOXMODEL_OCTAGON1008, 1, [octagon1008]) +elif test "$BOXMODEL" = "cuberevo"; then + AC_DEFINE(BOXMODEL_CUBEREVO, 1, [cuberevo]) +elif test "$BOXMODEL" = "cuberevo_mini2"; then + AC_DEFINE(BOXMODEL_CUBEREVO_MINI2, 1, [cuberevo_mini2]) +elif test "$BOXMODEL" = "cuberevo_2000hd"; then + AC_DEFINE(BOXMODEL_CUBEREVO_2000HD, 1, [cuberevo_2000hd]) +elif test "$BOXMODEL" = "tf7700"; then + AC_DEFINE(BOXMODEL_TF7700, 1, [tf7700]) elif test "$BOXMODEL" = "raspi"; then AC_DEFINE(BOXMODEL_RASPI, 1, [Raspberry pi]) fi diff --git a/common/Makefile.am b/common/Makefile.am index f44757c..200d2f5 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -1,8 +1,22 @@ noinst_LTLIBRARIES = libcommon.la AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing +AM_LDFLAGS = -lpthread +if BOXTYPE_DUCKBOX +AM_CXXFLAGS += \ + -I $(top_srcdir)/include \ + -I $(top_srcdir)/libdvbci +endif + +if BOXTYPE_DUCKBOX libcommon_la_SOURCES = \ - ca.cpp \ + ca_ci.cpp +else +libcommon_la_SOURCES = \ + ca.cpp +endif + +libcommon_la_SOURCES += \ lt_debug.cpp \ proc_tools.c diff --git a/common/ca.h b/common/ca.h index bcb1f76..bfbfc32 100644 --- a/common/ca.h +++ b/common/ca.h @@ -1,18 +1,22 @@ /* * dummy functions to implement ca_cs.h interface */ +#if HAVE_DUCKBOX_HARDWARE +#include "ca_ci.h" +#else #ifndef __CA_LIBTRIPLE_H_ #define __CA_LIBTRIPLE_H_ #include #include "cs_types.h" #include +#include typedef std::vector CaIdVector; typedef std::vector::iterator CaIdVectorIterator; typedef std::vector::const_iterator CaIdVectorConstIterator; enum CA_INIT_MASK { - CA_INIT_SC = 1, + CA_INIT_SC = 1, CA_INIT_CI, CA_INIT_BOTH }; @@ -20,7 +24,7 @@ enum CA_INIT_MASK { enum CA_SLOT_TYPE { CA_SLOT_TYPE_SMARTCARD, CA_SLOT_TYPE_CI, - CA_SLOT_TYPE_ALL, + CA_SLOT_TYPE_ALL }; enum CA_MESSAGE_FLAGS { @@ -63,13 +67,18 @@ enum CA_MESSAGE_MSGID { CA_MESSAGE_MSG_MMI_CLOSE, CA_MESSAGE_MSG_INTERNAL, CA_MESSAGE_MSG_PMT_ARRIVED, + CA_MESSAGE_MSG_CAPMT_ARRIVED, CA_MESSAGE_MSG_CAT_ARRIVED, CA_MESSAGE_MSG_ECM_ARRIVED, CA_MESSAGE_MSG_EMM_ARRIVED, CA_MESSAGE_MSG_CHANNEL_CHANGE, - CA_MESSAGE_MSG_EXIT, + CA_MESSAGE_MSG_GUI_READY, + CA_MESSAGE_MSG_EXIT }; +typedef std::set ca_map_t; +typedef ca_map_t::iterator ca_map_iterator_t; + typedef struct CA_MESSAGE { uint32_t MsgId; enum CA_SLOT_TYPE SlotType; @@ -91,7 +100,8 @@ public: uint32_t GetNumberSmartCardSlots(void); static cCA *GetInstance(void); bool SendPMT(int Unit, unsigned char *Data, int Len, CA_SLOT_TYPE SlotType = CA_SLOT_TYPE_ALL); - bool SendCAPMT(u64 /*Source*/, u8 /*DemuxSource*/, u8 /*DemuxMask*/, const unsigned char * /*CAPMT*/, u32 /*CAPMTLen*/, const unsigned char * /*RawPMT*/, u32 /*RawPMTLen*/) { return true; }; +// bool SendCAPMT(u64 /*Source*/, u8 /*DemuxSource*/, u8 /*DemuxMask*/, const unsigned char * /*CAPMT*/, u32 /*CAPMTLen*/, const unsigned char * /*RawPMT*/, u32 /*RawPMTLen*/) { return true; }; + bool SendCAPMT(u64 /*Source*/, u8 /*DemuxSource*/, u8 /*DemuxMask*/, const unsigned char * /*CAPMT*/, u32 /*CAPMTLen*/, const unsigned char * /*RawPMT*/, u32 /*RawPMTLen*/, unsigned char /*scrambled = 0*/, ca_map_t /*camap = std::set()*/, int /*mode = 0*/, bool /*enabled = false*/) { return true; }; bool SendMessage(const CA_MESSAGE *Msg); void SetInitMask(enum CA_INIT_MASK InitMask); int GetCAIDS(CaIdVector & /*Caids*/) { return 0; }; @@ -110,3 +120,4 @@ public: }; #endif // __CA_LIBTRIPLE_H_ +#endif // HAVE_DUCKBOX_HARDWARE diff --git a/common/ca_ci.cpp b/common/ca_ci.cpp new file mode 100644 index 0000000..65033e5 --- /dev/null +++ b/common/ca_ci.cpp @@ -0,0 +1,1098 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ca_ci.h" +#include "lt_debug.h" +#include +#include + +#include +#include +#include +#include + +/* for some debug > set to 1 */ +#define x_debug 1 +#define y_debug 0 + +#define TAG_MENU_ANSWER 0x9f880b +#define TAG_ENTER_MENU 0x9f8022 + +#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_CA, this, args) + +static const char * FILENAME = "[ca.cpp]"; + +/* für callback */ +/* nur diese Message wird vom CI aus neutrinoMessages.h benutzt */ +/* für den CamMsgHandler, darum hier einfach mal definiert */ +/* die Feinheiten werden ja in CA_MESSAGE verpackt */ +uint32_t EVT_CA_MESSAGE = 0x80000000 + 60; + +static cs_messenger cam_messenger; + +void cs_register_messenger(cs_messenger messenger) +{ + cam_messenger = messenger; + return; +} + +bool cCA::checkQueueSize(tSlot* slot) +{ + return (slot->sendqueue.size() > 0); +} + +/* for temporary testing */ +void cCA::Test(int slot, CaIdVector caids) +{ + char buf[255]; + char mname[200]; + char fname[20]; + int count, cx, cy, i; + snprintf(fname, sizeof(fname), "/tmp/ci-slot%d" , slot); + ModuleName(CA_SLOT_TYPE_CI, slot, mname); + FILE* fd = fopen(fname, "w"); + if (fd == NULL) return; + snprintf(buf, sizeof(buf), "%s\n" , mname); + fputs(buf, fd); + if (caids.size() > 40) + count = 40; + else + count = caids.size(); + cx = snprintf(buf, sizeof(buf), "Anzahl Caids: %d Slot: %d > ", count, slot); + for (i = 0; i < count; i++) + { + cy = snprintf(buf + cx, sizeof(buf) - cx, "%04x ", caids[i]); + cx += cy; + } + snprintf(buf + cx, sizeof(buf) - cx, "\n"); + fputs(buf, fd); + fclose(fd); +} + +void cCA::DelTest(int slot) +{ + char fname[20]; + snprintf(fname, sizeof(fname), "/tmp/ci-slot%d" , slot); + if (access(fname, F_OK) == 0) remove(fname); +} + +/* helper function to call the cpp thread loop */ +void* execute_thread(void *c) +{ + tSlot* slot = (tSlot*) c; + cCA *obj = (cCA*)slot->pClass; + obj->slot_pollthread(c); + return NULL; +} + +/* from dvb-apps */ +int asn_1_decode(uint16_t * length, unsigned char * asn_1_array, uint32_t asn_1_array_len) +{ + uint8_t length_field; + + if (asn_1_array_len < 1) + return -1; + length_field = asn_1_array[0]; + + if (length_field < 0x80) + { + // there is only one word + *length = length_field & 0x7f; + return 1; + } + else if (length_field == 0x81) + { + if (asn_1_array_len < 2) + return -1; + + *length = asn_1_array[1]; + return 2; + } + else if (length_field == 0x82) + { + if (asn_1_array_len < 3) + return -1; + + *length = (asn_1_array[1] << 8) | asn_1_array[2]; + return 3; + } + + return -1; +} + +//wait for a while for some data und read it if some +eData waitData(int fd, unsigned char* buffer, int* len) +{ + int retval; + struct pollfd fds; + fds.fd = fd; + fds.events = POLLOUT | POLLPRI | POLLIN; + retval = poll(&fds, 1, 100); + if (retval < 0) + { + printf("%s data error\n", FILENAME); + return eDataError; + } + else if (retval == 0) + { + return eDataTimeout; + } + else if (retval > 0) + { + if (fds.revents & POLLIN) + { + int n = read (fd, buffer, *len); + if (n > 0) + { + *len = n; + return eDataReady; + } + *len = 0; + return eDataError; + } + else if (fds.revents & POLLOUT) + { + return eDataWrite; + } + else if (fds.revents & POLLPRI) + { + return eDataStatusChanged; + } + } + return eDataError; +} + +//send some data on an fd, for a special slot and connection_id +eData sendData(tSlot* slot, unsigned char* data, int len) +{ + unsigned char *d = (unsigned char*) malloc(len + 5); + + // only poll connection if we are not awaiting an answer + slot->pollConnection = false; + + /* should we send a data last ? */ + if (data != NULL) + { + if ((data[2] >= T_SB) && (data[2] <= T_NEW_T_C)) + { + memcpy(d, data, len); + } + else + { + //send data_last and data + memcpy(d + 5, data, len); + d[0] = slot->slot; + d[1] = slot->connection_id; + d[2] = T_DATA_LAST; + if (len > 127) + d[3] = 4; + else + d[3] = len + 1; + d[4] = slot->connection_id; + len += 5; + } + } + else + { + //send a data last only + d[0] = slot->slot; + d[1] = slot->connection_id; + d[2] = T_DATA_LAST; + d[3] = len + 1; + d[4] = slot->connection_id; + len = 5; + } +#ifdef direct_write + int res = write(slot->fd, d, len); + + free(d); + if (res < 0 || res != len) + { + printf("error writing data to fd %d, slot %d: %m\n", slot->fd, slot->slot); + return eDataError; + } +#else + slot->sendqueue.push(queueData(d, len)); +#endif + return eDataReady; +} + +//send a transport connection create request +bool sendCreateTC(tSlot* slot) +{ + unsigned char* data = (unsigned char*) malloc(sizeof(char) * 5); + data[0] = slot->slot; + data[1] = slot->slot + 1; /* conid */ + data[2] = T_CREATE_T_C; + data[3] = 1; + data[4] = slot->slot + 1 /* conid */; + sendData(slot, data, 5); + return true; +} + +void cCA::process_tpdu(tSlot* slot, unsigned char tpdu_tag, __u8* data, int asn_data_length, int con_id) +{ + switch (tpdu_tag) + { + case T_C_T_C_REPLY: + printf("%s %s Got CTC Replay (slot %d, con %d)\n", FILENAME, __FUNCTION__, slot->slot, slot->connection_id); + //answer with data last (and if we have with data) + sendData(slot, NULL, 0); + break; + case T_DELETE_T_C: + //FIXME: close sessions etc; slot->reset ? + //we must answer here with t_c_replay + printf("%s %s Got \"Delete Transport Connection\" from module ->currently not handled!\n", FILENAME, __FUNCTION__); + break; + case T_D_T_C_REPLY: + printf("%s %s Got \"Delete Transport Connection Replay\" from module!\n", FILENAME, __FUNCTION__); + break; + case T_REQUEST_T_C: + printf("%s %s Got \"Request Transport Connection\" from Module ->currently not handled!\n", FILENAME, __FUNCTION__); + break; + case T_DATA_MORE: + { + int new_data_length = slot->receivedLen + asn_data_length; + printf("%s %s Got \"Data More\" from Module\n", FILENAME, __FUNCTION__); + __u8 *new_data_buffer = (__u8*) realloc(slot->receivedData, new_data_length); + slot->receivedData = new_data_buffer; + memcpy(slot->receivedData + slot->receivedLen, data, asn_data_length); + slot->receivedLen = new_data_length; + break; + } + case T_DATA_LAST: + /* single package */ + if (slot->receivedData == NULL) + { + printf("%s -> single package\n", FILENAME); +#if x_debug + printf("%s -> calling receiveData with data (len %d)\n", FILENAME, asn_data_length); + for (int i = 0; i < asn_data_length; i++) + printf("%02x ", data[i]); + printf("\n"); +#endif + eDVBCISession::receiveData(slot, data, asn_data_length); + eDVBCISession::pollAll(); + } + else + { + /* chained package */ + int new_data_length = slot->receivedLen + asn_data_length; + printf("%s -> chained data\n", FILENAME); + __u8 *new_data_buffer = (__u8*) realloc(slot->receivedData, new_data_length); + slot->receivedData = new_data_buffer; + memcpy(slot->receivedData + slot->receivedLen, data, asn_data_length); + slot->receivedLen = new_data_length; +#if x_debug + printf("%s -> calling receiveData with data (len %d)\n", FILENAME, asn_data_length); + for (int i = 0; i < slot->receivedLen; i++) + printf("%02x ", slot->receivedData[i]); + printf("\n"); +#endif + eDVBCISession::receiveData(slot, slot->receivedData, slot->receivedLen); + eDVBCISession::pollAll(); + + free(slot->receivedData); + slot->receivedData = NULL; + slot->receivedLen = 0; + } + break; + case T_SB: + { + if (data[0] & 0x80) + { + /* we now wait for an answer so dont poll */ + slot->pollConnection = false; + + /* send the RCV and ask for the data */ + unsigned char send_data[5]; + send_data[0] = slot->slot; + send_data[1] = slot->connection_id; + send_data[2] = T_RCV; + send_data[3] = 1; + send_data[4] = slot->connection_id; + write(slot->fd, send_data, 5); + } + else + { + //if the queue is not empty we dont need to send + // a polling to the module. + //if (checkQueueSize(slot) == false) + // slot->pollConnection = true; + } + break; + } + default: + printf("%s unhandled tpdu_tag 0x%0x\n", FILENAME, tpdu_tag); + } +} + +bool cCA::SendMessage(const CA_MESSAGE *msg) +{ + lt_debug("%s\n", __func__); + cam_messenger(EVT_CA_MESSAGE, (uint32_t) msg); +#if y_debug + printf("*******Message\n"); + printf("msg: %p\n", msg); + printf("MSGID: %x\n", msg->MsgId); + printf("SlotType: %x\n", msg->SlotType); + printf("Slot: %x\n", msg->Slot); +#endif + return true; +} + +void cCA::MenuEnter(enum CA_SLOT_TYPE, uint32_t bSlotIndex) +{ + printf("%s %s bSlotIndex: %d\n", FILENAME, __FUNCTION__, bSlotIndex); + + std::list::iterator it; + + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { +#if 0 + if ((strstr((*it)->name, "unknown module") != NULL) && ((*it)->slot == bSlotIndex)) + { + //the module has no real name, this is the matter if something while initializing went wrong + //so let this take as a reset action for the module so we do not need to add a reset + //feature to the neutrino menu + ModuleReset(SlotType, bSlotIndex); + + return; + } +#endif + if ((*it)->slot == bSlotIndex) + { + if ((*it)->hasAppManager) + (*it)->appSession->startMMI(); + break; + } + } +} + +void cCA::MenuAnswer(enum CA_SLOT_TYPE, uint32_t bSlotIndex, uint32_t choice) +{ + printf("%s %s bSlotIndex: %d choice: %c\n", FILENAME, __FUNCTION__, bSlotIndex, choice); + + std::list::iterator it; + + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { + if ((*it)->slot == bSlotIndex) + { + if ((*it)->hasMMIManager) + (*it)->mmiSession->answerText((int) choice); + } + } +} + +void cCA::InputAnswer(enum CA_SLOT_TYPE, uint32_t bSlotIndex, uint8_t * pBuffer, int nLength) +{ + printf("%s %s bSlotIndex: %d\n", FILENAME, __FUNCTION__, bSlotIndex); + + std::list::iterator it; + + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { + if ((*it)->slot == bSlotIndex) + { + if ((*it)->hasMMIManager) + (*it)->mmiSession->answerEnq((char*) pBuffer, nLength); + break; + } + } +} + +void cCA::MenuClose(enum CA_SLOT_TYPE, uint32_t bSlotIndex) +{ + printf("%s %s bSlotIndex: %d\n", FILENAME, __FUNCTION__, bSlotIndex); + std::list::iterator it; + + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { + if ((*it)->slot == bSlotIndex) + { + if ((*it)->hasMMIManager) + (*it)->mmiSession->stopMMI(); + break; + } + } +} + +uint32_t cCA::GetNumberCISlots(void) +{ + printf("%s %s\n", FILENAME, __FUNCTION__); + return num_slots; +} + +uint32_t cCA::GetNumberSmartCardSlots(void) +{ + printf("%s %s\n", FILENAME, __FUNCTION__); + return 0; +} + +void cCA::ModuleName(enum CA_SLOT_TYPE, uint32_t slot, char * Name) +{ + std::list::iterator it; + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { + if ((*it)->slot == slot) + { + strcpy(Name, (*it)->name); + break; + } + } +} + +bool cCA::ModulePresent(enum CA_SLOT_TYPE, uint32_t slot) +{ + std::list::iterator it; + + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { + if ((*it)->slot == slot) + { + return (*it)->camIsReady; + break; + } + } + return false; +} + +void cCA::ModuleReset(enum CA_SLOT_TYPE, uint32_t slot) +{ + std::list::iterator it; + bool haveFound = false; + + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { + if ((*it)->slot == slot) + { + haveFound = true; + break; + } + } + if (haveFound) + { + (*it)->status = eStatusReset; + usleep(200000); + eDVBCISession::deleteSessions((tSlot*)(*it)); + (*it)->mmiSession = NULL; + (*it)->hasMMIManager = false; + (*it)->hasCAManager = false; + (*it)->hasDateTime = false; + (*it)->hasAppManager = false; + (*it)->mmiOpened = false; + (*it)->camIsReady = false; + (*it)->counter = 0; + (*it)->init = false; + (*it)->pollConnection = false; + sprintf((*it)->name, "unknown module %d", (*it)->slot); + (*it)->cam_caids.clear(); + + (*it)->newCapmt = false; + (*it)->inUse = false; + (*it)->tpid = 0; + (*it)->pmtlen = 0; + (*it)->source = TUNER_A; + (*it)->camask = 0; + memset((*it)->pmtdata, 0, sizeof((*it)->pmtdata)); + + while((*it)->sendqueue.size()) + { + delete [] (*it)->sendqueue.top().data; + (*it)->sendqueue.pop(); + } + + if (ioctl((*it)->fd, CA_RESET, (*it)->slot) < 0) + printf("IOCTL CA_RESET failed for slot %d\n", slot); + usleep(200000); + (*it)->status = eStatusNone; + } +} + +int cCA::GetCAIDS(CaIdVector &Caids) +{ + std::list::iterator it; + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { + if ((*it)->camIsReady) + { + for (int i = 0; i < (*it)->cam_caids.size(); i++) + Caids.push_back((*it)->cam_caids[i]); + } + } + return 0; +} + +bool cCA::StopRecordCI( u64 tpid, u8 source, u32 calen) +{ + printf("%s:%s\n", FILENAME, __func__); + std::list::iterator it; + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { + if ((*it)->inUse && (*it)->tpid == tpid && (*it)->source == source && !calen) + { + (*it)->inUse = false; + return true; + } + } + return false; +} + +SlotIt cCA::FindFreeSlot(ca_map_t camap, unsigned char scrambled) +{ + printf("%s:%s\n", FILENAME, __func__); + std::list::iterator it; + ca_map_iterator_t caIt; + int i; + for (it = slot_data.begin(); it != slot_data.end(); ++it) + { + if ((*it)->camIsReady && (*it)->hasCAManager && (*it)->hasAppManager && !(*it)->inUse) + { +#if x_debug + printf("Slot Caids: %d > ", (*it)->cam_caids.size()); + for (i = 0; i < (*it)->cam_caids.size(); i++) + printf("%04x ", (*it)->cam_caids[i]); + printf("\n"); +#endif + if (scrambled) + { + for (i = 0; i < (*it)->cam_caids.size(); i++) + { + caIt = camap.find((*it)->cam_caids[i]); + if (caIt != camap.end()) + { + printf("Found: %04x\n", *caIt); + return it; + } + } + } + else + { + return it; + } + } + + } + return it; +} + +/* erstmal den capmt wie er von Neutrino kommt in den Slot puffern */ +bool cCA::SendCAPMT(u64 tpid, u8 source_demux, u8 camask, const unsigned char * cabuf, u32 calen, const unsigned char * rawpmt, u32 rawlen, unsigned char scrambled, ca_map_t cm, int mode, bool enabled) +{ + printf("%s:%s\n", FILENAME, __func__); + if (!num_slots) return true; /* stb's without ci-slots */ +#if x_debug + printf("TPID: %llX\n", tpid); + printf("SOURCE_DEMUX: %X\n", source_demux); + printf("CA_MASK: %X\n", camask); + printf("CALEN: %d\n", calen); + printf("Scrambled: %d\n", scrambled); + printf("Mode: %d\n", mode); + printf("Enabled: %s\n", enabled ? "START" : "STOP"); +#endif + if (mode && scrambled && !enabled) + { + if (StopRecordCI(tpid, source_demux, calen)) + printf("CI set free\n"); + } + + if (calen == 0) + return true; + SlotIt It = FindFreeSlot(cm, scrambled); + + if ((*It)) + { + printf("Slot: %d\n", (*It)->slot); + if (scrambled || (!scrambled && (*It)->source == source_demux)) + { + if ((*It)->tpid != tpid) + { + (*It)->tpid = tpid; + (*It)->source = source_demux; + (*It)->pmtlen = calen; + for(int i = 0; i < calen; i++) + (*It)->pmtdata[i] = cabuf[i]; + (*It)->newCapmt = true; + } + if (mode && scrambled && enabled) + (*It)->inUse = true; + } + } + else + { + printf("No free ci-slot\n"); + } +#if x_debug + if (!cm.empty()) + { + printf("Service Caids: "); + for(ca_map_iterator_t it = cm.begin(); it != cm.end(); ++it) + { + printf("%04x ", (*it)); + } + printf("\n"); + } + else + { + printf("CaMap Empty\n"); + } +#endif + return true; +} + +cCA::cCA(int Slots) +{ + printf("%s %s %d\n", FILENAME, __FUNCTION__, Slots); + + int fd, i; + char filename[128]; + num_slots = Slots; + + for (i = 0; i < Slots; i++) + { + sprintf(filename, "/dev/dvb/adapter0/ci%d", i); + fd = open(filename, O_RDWR | O_NONBLOCK); + if (fd < 0) + { + printf("failed to open %s ->%m", filename); + } + tSlot* slot = (tSlot*) malloc(sizeof(tSlot)); + slot->slot = i; + slot->fd = fd; + slot->connection_id = 0; + slot->status = eStatusNone; + slot->receivedLen = 0; + slot->receivedData = NULL; + slot->pClass = this; + slot->pollConnection = false; + slot->camIsReady = false; + slot->hasMMIManager = false; + slot->hasCAManager = false; + slot->hasDateTime = false; + slot->hasAppManager = false; + slot->mmiOpened = false; + + slot->newCapmt = false; + slot->inUse = false; + slot->tpid = 0; + slot->pmtlen = 0; + slot->source = TUNER_A; + slot->camask = 0; + memset(slot->pmtdata, 0, sizeof(slot->pmtdata)); + + slot->counter = 0; + slot->init = false; + sprintf(slot->name, "unknown module %d", i); + slot_data.push_back(slot); + /* now reset the slot so the poll pri can happen in the thread */ + if (ioctl(fd, CA_RESET, i) < 0) + printf("IOCTL CA_RESET failed for slot %d\n", slot); + /* create a thread for each slot */ + if (fd > 0) + { + if (pthread_create(&slot->slot_thread, 0, execute_thread, (void*)slot)) + { + printf("pthread_create"); + } + } + } +} + +cCA::~cCA() +{ + printf("%s %s\n", FILENAME, __FUNCTION__); +} + +static cCA* pcCAInstance = NULL; + +cCA * cCA::GetInstance() +{ + printf("%s %s\n", FILENAME, __FUNCTION__); + + if (pcCAInstance == NULL) + { + hw_caps_t *caps = get_hwcaps(); + pcCAInstance = new cCA(caps->has_CI); + } + return pcCAInstance; +} + +cCA::cCA(void) +{ + printf("%s %s\n", FILENAME, __FUNCTION__); +} + +void cCA::setSource(tSlot* slot) +{ + char buf[64]; + snprintf(buf, 64, "/proc/stb/tsmux/ci%d_input", slot->slot); + FILE *ci = fopen(buf, "wb"); + + if(ci > 0) + { + switch(slot->source) + { + case TUNER_A: + fprintf(ci, "A"); + break; + case TUNER_B: + fprintf(ci, "B"); + break; + case TUNER_C: + fprintf(ci, "C"); + break; + case TUNER_D: + fprintf(ci, "D"); + break; + } + fclose(ci); + } +} + +void cCA::slot_pollthread(void *c) +{ + ca_slot_info_t info; + unsigned char data[1024]; + tSlot* slot = (tSlot*) c; + + while (1) + { + int len = 1024; + unsigned char* d; + eData status; + + switch (slot->status) + { + case eStatusReset: + while (slot->status == eStatusReset) + { + usleep(1000); + } + break; + case eStatusNone: + { + if (slot->camIsReady) + { + if (sendCreateTC(slot)) + { + slot->status = eStatusWait; + slot->camIsReady = true; + } + else + { + usleep(100000); + } + } + else + { + /* wait for pollpri */ + status = waitData(slot->fd, data, &len); + if (status == eDataStatusChanged) + { + info.num = slot->slot; + + if (ioctl(slot->fd, CA_GET_SLOT_INFO, &info) < 0) + printf("IOCTL CA_GET_SLOT_INFO failed for slot %d\n", slot->slot); + + printf("flags %d %d %d ->slot %d\n", info.flags, CA_CI_MODULE_READY, info.flags & CA_CI_MODULE_READY, slot->slot); + + if (info.flags & CA_CI_MODULE_READY) + { + printf("1. cam (%d) status changed ->cam now present\n", slot->slot); + + slot->mmiSession = NULL; + slot->hasMMIManager = false; + slot->hasCAManager = false; + slot->hasDateTime = false; + slot->hasAppManager = false; + slot->mmiOpened = false; + slot->init = false; + sprintf(slot->name, "unknown module %d", slot->slot); + slot->status = eStatusNone; + + /* Send a message to Neutrino cam_menu handler */ + CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); + memset(pMsg, 0, sizeof(CA_MESSAGE)); + pMsg->MsgId = CA_MESSAGE_MSG_INSERTED; + pMsg->SlotType = CA_SLOT_TYPE_CI; + pMsg->Slot = slot->slot; + SendMessage(pMsg); + + slot->camIsReady = true; + //setSource(slot); + } + else + { + //noop + } + } + } + } /* case statusnone */ + break; + case eStatusWait: + { + status = waitData(slot->fd, data, &len); + if (status == eDataReady) + { + slot->pollConnection = false; + d = data; + /* taken from the dvb-apps */ + int data_length = len - 2; + d += 2; /* remove leading slot and connection id */ + while (data_length > 0) + { + unsigned char tpdu_tag = d[0]; + unsigned short asn_data_length; + int length_field_len; + if ((length_field_len = asn_1_decode(&asn_data_length, d + 1, data_length - 1)) < 0) + { + printf("Received data with invalid asn from module on slot %02x\n", slot->slot); + break; + } + + if ((asn_data_length < 1) || (asn_data_length > (data_length - (1 + length_field_len)))) + { + printf("Received data with invalid length from module on slot %02x\n", slot->slot); + break; + } + slot->connection_id = d[1 + length_field_len]; + //printf("Setting connection_id from received data to %d\n", slot->connection_id); + d += 1 + length_field_len + 1; + data_length -= (1 + length_field_len + 1); + asn_data_length--; + process_tpdu(slot, tpdu_tag, d, asn_data_length, slot->connection_id); + // skip over the consumed data + d += asn_data_length; + data_length -= asn_data_length; + } // while (data_length) + } /*if data ready */ + else if (status == eDataWrite) + { + if (!slot->sendqueue.empty()) + { + const queueData &qe = slot->sendqueue.top(); + int res = write(slot->fd, qe.data, qe.len); + if (res >= 0 && (unsigned int)res == qe.len) + { + delete [] qe.data; + slot->sendqueue.pop(); + } + else + { + printf("r = %d, %m\n", res); + } + } + else + { + //printf("sendqueue emtpy\n"); + if ((checkQueueSize(slot) == false) && ((!slot->hasCAManager) || (slot->mmiOpened) || (slot->counter < 30))) + slot->pollConnection = true; + if (slot->hasCAManager && !slot->mmiOpened) + slot->counter++; + if (slot->mmiOpened) + slot->counter = 0; + } + } + else if (status == eDataStatusChanged) + { + info.num = slot->slot; + + if (ioctl(slot->fd, CA_GET_SLOT_INFO, &info) < 0) + printf("IOCTL CA_GET_SLOT_INFO failed for slot %d\n", slot->slot); + + printf("flags %d %d %d ->slot %d\n", info.flags, CA_CI_MODULE_READY, info.flags & CA_CI_MODULE_READY, slot->slot); + + if ((slot->camIsReady == false) && (info.flags & CA_CI_MODULE_READY)) + { + printf("2. cam (%d) status changed ->cam now present\n", slot->slot); + + slot->mmiSession = NULL; + slot->hasMMIManager = false; + slot->hasCAManager = false; + slot->hasDateTime = false; + slot->hasAppManager = false; + slot->mmiOpened = false; + slot->init = false; + sprintf(slot->name, "unknown module %d", slot->slot); + slot->status = eStatusNone; + + /* Send a message to Neutrino cam_menu handler */ + CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); + memset(pMsg, 0, sizeof(CA_MESSAGE)); + pMsg->MsgId = CA_MESSAGE_MSG_INSERTED; + pMsg->SlotType = CA_SLOT_TYPE_CI; + pMsg->Slot = slot->slot; + SendMessage(pMsg); + + slot->camIsReady = true; + } + else if ((slot->camIsReady == true) && (!(info.flags & CA_CI_MODULE_READY))) + { + printf("cam (%d) status changed ->cam now _not_ present\n", slot->slot); + eDVBCISession::deleteSessions(slot); + slot->mmiSession = NULL; + slot->hasMMIManager = false; + slot->hasCAManager = false; + slot->hasDateTime = false; + slot->hasAppManager = false; + slot->mmiOpened = false; + slot->init = false; + slot->counter = 0; + slot->pollConnection = false; + sprintf(slot->name, "unknown module %d", slot->slot); + slot->status = eStatusNone; + slot->cam_caids.clear(); + + slot->newCapmt = false; + slot->inUse = false; + slot->tpid = 0; + slot->pmtlen = 0; + slot->source = TUNER_A; + slot->camask = 0; + memset(slot->pmtdata, 0, sizeof(slot->pmtdata)); + + /* temporary : delete testfile */ + DelTest(slot->slot); + /* Send a message to Neutrino cam_menu handler */ + CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); + memset(pMsg, 0, sizeof(CA_MESSAGE)); + pMsg->MsgId = CA_MESSAGE_MSG_REMOVED; + pMsg->SlotType = CA_SLOT_TYPE_CI; + pMsg->Slot = slot->slot; + SendMessage(pMsg); + + while(slot->sendqueue.size()) + { + delete [] slot->sendqueue.top().data; + slot->sendqueue.pop(); + } + slot->camIsReady = false; + usleep(100000); + } + } + if (!checkQueueSize(slot) && slot->pollConnection) + { + //printf("****poll1\n"); + sendData(slot, NULL, 0); + } + } + break; + default: + printf("unknown state %d\n", slot->status); + break; + } + + if (slot->hasCAManager && slot->hasAppManager && !slot->init) + { + slot->init = true; + + slot->cam_caids = slot->camgrSession->getCAIDs(); + + printf("Anzahl Caids: %d Slot: %d > ", slot->cam_caids.size(), slot->slot); + for (int i = 0; i < slot->cam_caids.size(); i++) + { + printf("%04x ", slot->cam_caids[i]); + + } + printf("\n"); + + /* temporary : write testfile */ + Test(slot->slot, slot->cam_caids); + + /* Send a message to Neutrino cam_menu handler */ + CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); + memset(pMsg, 0, sizeof(CA_MESSAGE)); + pMsg->MsgId = CA_MESSAGE_MSG_INIT_OK; + pMsg->SlotType = CA_SLOT_TYPE_CI; + pMsg->Slot = slot->slot; + SendMessage(pMsg); + /* resend a capmt if we have one. this is not very proper but I cant any mechanism in + neutrino currently. so if a cam is inserted a pmt is not resend */ + + SendCaPMT(slot); + } + if (slot->hasCAManager && slot->hasAppManager && slot->newCapmt) + { + SendCaPMT(slot); + slot->newCapmt = false; + } + } +} + +cCA *CA = cCA::GetInstance(); + +bool cCA::SendCaPMT(tSlot* slot) +{ + printf("%s:%s\n", FILENAME, __func__); + if ((slot->fd > 0) && (slot->camIsReady)) + { + if (slot->hasCAManager) + { +#if x_debug + printf("buffered capmt(0x%X): > \n", slot->pmtlen); + for(int i = 0; i < slot->pmtlen; i++) + printf("%02X ", slot->pmtdata[i]); + printf("\n"); +#endif + if (slot->pmtlen == 0) + return true; + slot->camgrSession->sendSPDU(0x90, 0, 0, slot->pmtdata, slot->pmtlen); + } + } + + if (slot->fd > 0) + { + setSource(slot); + slot->counter = 0; + } + return true; +} + +bool cCA::Init(void) +{ + printf("%s %s\n", FILENAME, __FUNCTION__); + return true; +} + +bool cCA::SendDateTime(void) +{ + printf("%s %s\n", FILENAME, __FUNCTION__); + return false; +} + +bool cCA::Start(void) +{ + printf("%s %s\n", FILENAME, __FUNCTION__); + return true; +} + +void cCA::Stop(void) +{ + printf("%s %s\n", FILENAME, __FUNCTION__); +} + +void cCA::Ready(bool p) +{ + printf("%s %s param:%d\n", FILENAME, __FUNCTION__, (int)p); +} + +void cCA::SetInitMask(enum CA_INIT_MASK p) +{ + printf("%s %s param:%d\n", FILENAME, __FUNCTION__, (int)p); +} diff --git a/common/ca_ci.h b/common/ca_ci.h new file mode 100644 index 0000000..1c4952f --- /dev/null +++ b/common/ca_ci.h @@ -0,0 +1,283 @@ +#ifndef __CA_H_ +#define __CA_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "mmi.h" +#include "cs_types.h" +#include "cs_api.h" + +/* constants taken from dvb-apps */ +#define T_SB 0x80 // sb primitive h<--m +#define T_RCV 0x81 // receive primitive h-->m +#define T_CREATE_T_C 0x82 // create transport connection primitive h-->m +#define T_C_T_C_REPLY 0x83 // ctc reply primitive h<--m +#define T_DELETE_T_C 0x84 // delete tc primitive h<->m +#define T_D_T_C_REPLY 0x85 // dtc reply primitive h<->m +#define T_REQUEST_T_C 0x86 // request transport connection primitive h<--m +#define T_NEW_T_C 0x87 // new tc / reply to t_request primitive h-->m +#define T_T_C_ERROR 0x77 // error creating tc primitive h-->m +#define T_DATA_LAST 0xA0 // convey data from higher constructed h<->m +#define T_DATA_MORE 0xA1 // convey data from higher constructed h<->m + +enum CA_INIT_MASK { + CA_INIT_SC = 1, + CA_INIT_CI, + CA_INIT_BOTH +}; + +enum CA_SLOT_TYPE { + CA_SLOT_TYPE_SMARTCARD, + CA_SLOT_TYPE_CI, + CA_SLOT_TYPE_ALL +}; + +enum CA_MESSAGE_FLAGS { + CA_MESSAGE_EMPTY = (1 << 0), + CA_MESSAGE_HAS_PARAM1_DATA = (1 << 1), /// Free after use! + CA_MESSAGE_HAS_PARAM1_INT = (1 << 2), + CA_MESSAGE_HAS_PARAM1_PTR = (1 << 3), + CA_MESSAGE_HAS_PARAM2_INT = (1 << 4), + CA_MESSAGE_HAS_PARAM2_PTR = (1 << 5), + CA_MESSAGE_HAS_PARAM2_DATA = (1 << 6), + CA_MESSAGE_HAS_PARAM3_DATA = (1 << 7), /// Free after use! + CA_MESSAGE_HAS_PARAM3_INT = (1 << 8), + CA_MESSAGE_HAS_PARAM3_PTR = (1 << 9), + CA_MESSAGE_HAS_PARAM4_INT = (1 << 10), + CA_MESSAGE_HAS_PARAM4_PTR = (1 << 11), + CA_MESSAGE_HAS_PARAM4_DATA = (1 << 12), + CA_MESSAGE_HAS_PARAM5_INT = (1 << 13), + CA_MESSAGE_HAS_PARAM5_PTR = (1 << 14), + CA_MESSAGE_HAS_PARAM5_DATA = (1 << 15), + CA_MESSAGE_HAS_PARAM6_INT = (1 << 16), + CA_MESSAGE_HAS_PARAM6_PTR = (1 << 17), + CA_MESSAGE_HAS_PARAM6_DATA = (1 << 18), + CA_MESSAGE_HAS_PARAM1_LONG = (1 << 19), + CA_MESSAGE_HAS_PARAM2_LONG = (1 << 20), + CA_MESSAGE_HAS_PARAM3_LONG = (1 << 21), + CA_MESSAGE_HAS_PARAM4_LONG = (1 << 22) +}; + +enum CA_MESSAGE_MSGID { + CA_MESSAGE_MSG_INSERTED, + CA_MESSAGE_MSG_REMOVED, + CA_MESSAGE_MSG_INIT_OK, + CA_MESSAGE_MSG_INIT_FAILED, + CA_MESSAGE_MSG_MMI_MENU, + CA_MESSAGE_MSG_MMI_MENU_ENTER, + CA_MESSAGE_MSG_MMI_MENU_ANSWER, + CA_MESSAGE_MSG_MMI_LIST, + CA_MESSAGE_MSG_MMI_TEXT, + CA_MESSAGE_MSG_MMI_REQ_INPUT, + CA_MESSAGE_MSG_MMI_CLOSE, + CA_MESSAGE_MSG_INTERNAL, + CA_MESSAGE_MSG_PMT_ARRIVED, + CA_MESSAGE_MSG_CAPMT_ARRIVED, + CA_MESSAGE_MSG_CAT_ARRIVED, + CA_MESSAGE_MSG_ECM_ARRIVED, + CA_MESSAGE_MSG_EMM_ARRIVED, + CA_MESSAGE_MSG_CHANNEL_CHANGE, + CA_MESSAGE_MSG_GUI_READY, + CA_MESSAGE_MSG_EXIT +}; + +typedef struct CA_MESSAGE { + uint32_t MsgId; + enum CA_SLOT_TYPE SlotType; + int Slot; + uint32_t Flags; + union { + uint8_t *Data[4]; + uint32_t Param[4]; + void *Ptr[4]; + uint64_t ParamLong[4]; + } Msg; +} CA_MESSAGE; + +typedef std::set ca_map_t; +typedef ca_map_t::iterator ca_map_iterator_t; + +typedef std::vector CaIdVector; +typedef std::vector::iterator CaIdVectorIterator; +typedef std::vector::const_iterator CaIdVectorConstIterator; + +#define CA_MESSAGE_SIZE sizeof(CA_MESSAGE) +#define CA_MESSAGE_ENTRIES 256 +#define CA_MESSAGE_ENTRIES_CI 128 +#define CA_MESSAGE_ENTRIES_SC 64 + +#ifndef CS_CA_PDATA +#define CS_CA_PDATA void +#endif + +typedef enum { + TUNER_A, + TUNER_B, + TUNER_C, + TUNER_D +} source_t; + +typedef enum { + eDataTimeout, + eDataError, + eDataReady, + eDataWrite, + eDataStatusChanged +} eData; + +typedef enum { + eStatusNone, + eStatusWait, + eStatusReset +} eStatus; + +struct queueData +{ + __u8 prio; + unsigned char *data; + unsigned int len; + queueData(unsigned char *_data, unsigned int _len, __u8 _prio = 0) + :prio(_prio), data(_data), len(_len) + { + + } + bool operator < ( const struct queueData &a ) const + { + return prio < a.prio; + } +}; + +class eDVBCIMMISession; +class eDVBCIApplicationManagerSession; +class eDVBCICAManagerSession; + +typedef struct +{ + pthread_t slot_thread; + int slot; + int fd; + int connection_id; + eStatus status; + + int receivedLen; + unsigned char* receivedData; + + void* pClass; + + bool pollConnection; + bool camIsReady; + + eDVBCIMMISession* mmiSession; + eDVBCIApplicationManagerSession* appSession; + eDVBCICAManagerSession* camgrSession; + + bool hasAppManager; + bool hasMMIManager; + bool hasCAManager; + bool hasDateTime; + bool mmiOpened; + bool init; + + char name[512]; + + bool newCapmt; + bool inUse; + u64 tpid; + u32 pmtlen; + u8 source; + u8 camask; + unsigned char pmtdata[1024]; + + int counter; + CaIdVector cam_caids; + std::priority_queue sendqueue; +} tSlot; + +eData sendData(tSlot *slot, unsigned char* data, int len); + +typedef std::list::iterator SlotIt; + +/// CA module class +class cCA { +private: + /// Static instance of the CA module +// static cCA *inst; + /// Private constructor (singleton method) + cCA(void); + /// Private data for the CA module + CS_CA_PDATA *privateData; + enum CA_INIT_MASK initMask; + int num_slots; + bool init; + void SendPMT(); + pthread_mutex_t ciMutex; + std::list slot_data; + pthread_t slot_thread; + +public: + bool Init(void); + cCA(int Slots); + /// Returns the number of CI slots + uint32_t GetNumberCISlots(void); + /// Returns the number of Smartcard slots + uint32_t GetNumberSmartCardSlots(void); + /// Singleton + static cCA *GetInstance(void); + /// Send PMT to a individual or to all available modules (DEPRECATED) + bool SendPMT(int Unit, unsigned char *Data, int Len, enum CA_SLOT_TYPE SlotType = CA_SLOT_TYPE_ALL); + /// Sends a message to the CA thread + bool SendMessage(const CA_MESSAGE *Msg); + /// Sets which modules to initialize. It is only + /// possible to change this once! + void SetInitMask(enum CA_INIT_MASK InitMask); + /// Sets the frequency (in Hz) of the TS stream input (only valid for CI) + void SetTSClock(u32 /*Speed*/) { return; }; + /// Start the CA module + bool Start(void); + /// Stops the CA module + void Stop(void); + /// Notify that the GUI is ready to receive messages + /// (CA messages coming from a module) + void Ready(bool Set); + /// Resets a module (if possible) + void ModuleReset(enum CA_SLOT_TYPE, uint32_t Slot); + /// Checks if a module is present + bool ModulePresent(enum CA_SLOT_TYPE, uint32_t Slot); + /// Returns the module name in array Name + void ModuleName(enum CA_SLOT_TYPE, uint32_t Slot, char *Name); + /// Notify the module we want to enter menu + void MenuEnter(enum CA_SLOT_TYPE, uint32_t Slot); + /// Notify the module with our answer (choice nr) + void MenuAnswer(enum CA_SLOT_TYPE, uint32_t Slot, uint32_t choice); + /// Notify the module with our answer (binary) + void InputAnswer(enum CA_SLOT_TYPE, uint32_t Slot, uint8_t * Data, int Len); + /// Notify the module we closed the menu + void MenuClose(enum CA_SLOT_TYPE, uint32_t Slot); + /// Get the supported CAIDs + int GetCAIDS(CaIdVector &Caids); + /// Send a CA-PMT object and Raw unparsed PMT to the CA layer + bool SendCAPMT(u64 /*Source*/, u8 /*DemuxSource*/, u8 /*DemuxMask*/, const unsigned char * /*CAPMT*/, u32 /*CAPMTLen*/, const unsigned char * /*RawPMT*/, u32 /*RawPMTLen*/, + unsigned char scrambled = 0, ca_map_t camap = std::set(), int mode = 0, bool enabled = false); + + bool StopRecordCI( u64 tpid, u8 source, u32 calen); + SlotIt FindFreeSlot(ca_map_t camap, unsigned char scrambled); + bool SendDateTime(void); + bool SendCaPMT(tSlot* slot); + void slot_pollthread(void *c); + void setSource(tSlot* slot); + bool checkQueueSize(tSlot* slot); + void process_tpdu(tSlot* slot, unsigned char tpdu_tag, __u8* data, int asn_data_length, int con_id); + + void Test(int slot, CaIdVector caids); + void DelTest(int slot); + /// Virtual destructor + virtual ~cCA(); +}; + +#endif // __CA_H_ diff --git a/configure.ac b/configure.ac index e92283c..cd79036 100644 --- a/configure.ac +++ b/configure.ac @@ -37,6 +37,8 @@ common/Makefile libeplayer3/Makefile azbox/Makefile generic-pc/Makefile +libduckbox/Makefile +libdvbci/Makefile libtriple/Makefile libspark/Makefile raspi/Makefile diff --git a/include/audio_td.h b/include/audio_td.h index 9cb74a1..984f2ef 100644 --- a/include/audio_td.h +++ b/include/audio_td.h @@ -1,6 +1,9 @@ #include #if HAVE_TRIPLEDRAGON #include "../libtriple/audio_td.h" +#elif HAVE_DUCKBOX_HARDWARE +#include "../libduckbox/audio_lib.h" +#include "../libduckbox/audio_mixer.h" #elif HAVE_SPARK_HARDWARE #include "../libspark/audio_lib.h" #include "../libspark/audio_mixer.h" diff --git a/include/cs_api.h b/include/cs_api.h index fff64d5..7364bff 100644 --- a/include/cs_api.h +++ b/include/cs_api.h @@ -1,6 +1,8 @@ #include #if HAVE_TRIPLEDRAGON #include "../libtriple/cs_api.h" +#elif HAVE_DUCKBOX_HARDWARE +#include "../libduckbox/cs_api.h" #elif HAVE_SPARK_HARDWARE #include "../libspark/cs_api.h" #elif HAVE_AZBOX_HARDWARE diff --git a/include/cs_frontpanel.h b/include/cs_frontpanel.h new file mode 100644 index 0000000..c196ebc --- /dev/null +++ b/include/cs_frontpanel.h @@ -0,0 +1,184 @@ +#ifndef __DUCKBOX_VFD__ +#define __DUCKBOX_VFD__ + +#define VFDDISPLAYCHARS 0xc0425a00 +#define VFDWRITECGRAM 0x40425a01 +#define VFDBRIGHTNESS 0xc0425a03 +#define VFDPWRLED 0xc0425a04 +#define VFDDRIVERINIT 0xc0425a08 +#define VFDICONDISPLAYONOFF 0xc0425a0a +#define VFDDISPLAYWRITEONOFF 0xc0425a05 + +#define VFDCLEARICONS 0xc0425af6 +#define VFDSETRF 0xc0425af7 +#define VFDSETFAN 0xc0425af8 +#define VFDGETWAKEUPMODE 0xc0425af9 +#define VFDGETTIME 0xc0425afa +#define VFDSETTIME 0xc0425afb +#define VFDSTANDBY 0xc0425afc +#define VFDREBOOT 0xc0425afd +#define VFDSETLED 0xc0425afe +#define VFDSETMODE 0xc0425aff + +#define VFDGETWAKEUPTIME 0xc0425b00 +#define VFDGETVERSION 0xc0425b01 +#define VFDSETDISPLAYTIME 0xc0425b02 +#define VFDSETTIMEMODE 0xc0425b03 +#define VFDDISPLAYCLR 0xc0425b00 + +typedef enum { +#if defined(BOXMODEL_OCTAGON1008) + ICON_DTS, + ICON_VIDEO, + ICON_AUDIO, + ICON_LINK, + ICON_HDD, + ICON_DISC, + ICON_DVB, + FP_ICON_USB = 0x27, + FP_ICON_HD = 0x27, + FP_ICON_HDD = ICON_HDD, + FP_ICON_LOCK = 0x27, + FP_ICON_BT = 0x27, + FP_ICON_MP3 = 0x27, + FP_ICON_MUSIC = 0x27, + FP_ICON_DD = 0x27, + FP_ICON_MAIL = 0x27, + FP_ICON_MUTE = 0x27, + FP_ICON_PLAY = 0x27, + FP_ICON_PAUSE = 0x27, + FP_ICON_FF = 0x27, + FP_ICON_FR = 0x27, + FP_ICON_REC = 0x27, + FP_ICON_CLOCK = 0x27, +#elif defined(BOXMODEL_FORTIS_HDBOX) + ICON_STANDBY = 0x10, + ICON_SAT, + ICON_REC, + ICON_TIMESHIFT, + ICON_TIMER, + ICON_HD, + ICON_USB, + ICON_SCRAMBLED, + ICON_DOLBY, + ICON_MUTE, + ICON_TUNER1, + ICON_TUNER2, + ICON_MP3, + ICON_REPEAT, + ICON_Play, + FP_ICON_PAUSE, + ICON_TER, + ICON_FILE, + ICON_480i, + ICON_480p, + ICON_576i, + ICON_576p, + ICON_720p, + ICON_1080i, + ICON_1080p, + ICON_Play_1, + FP_ICON_USB = ICON_USB, + FP_ICON_REC = ICON_REC, + FP_ICON_CLOCK = ICON_TIMER, + FP_ICON_HD = ICON_HD, + FP_ICON_LOCK = ICON_SCRAMBLED, + FP_ICON_DD = ICON_DOLBY, + FP_ICON_MUTE = ICON_MUTE, + FP_ICON_MP3 = ICON_MP3, + FP_ICON_PLAY = ICON_Play, + FP_ICON_HDD, + FP_ICON_MUSIC, + FP_ICON_MAIL, + FP_ICON_FF, + FP_ICON_FR, +#elif defined(BOXMODEL_UFS910) + FP_ICON_USB = 0x10, + FP_ICON_HD, + FP_ICON_HDD, + FP_ICON_LOCK, + FP_ICON_BT, + FP_ICON_MP3, + FP_ICON_MUSIC, + FP_ICON_DD, + FP_ICON_MAIL, + FP_ICON_MUTE, + FP_ICON_PLAY, + FP_ICON_PAUSE, + FP_ICON_FF, + FP_ICON_FR, + FP_ICON_REC, + FP_ICON_CLOCK, +#else + FP_ICON_USB = 0x10, + FP_ICON_HD, + FP_ICON_HDD, + FP_ICON_LOCK, + FP_ICON_BT, + FP_ICON_MP3, + FP_ICON_MUSIC, + FP_ICON_DD, + FP_ICON_MAIL, + FP_ICON_MUTE, + FP_ICON_PLAY, + FP_ICON_PAUSE, + FP_ICON_FF, + FP_ICON_FR, + FP_ICON_REC, + FP_ICON_CLOCK, +#endif + FP_ICON_RECORD, + FP_ICON_DOWNLOAD, + FP_ICON_TIMESHIFT, + FP_ICON_MAX +} fp_icon; + +typedef enum { + FP_FLAG_NONE = 0x00, + FP_FLAG_SCROLL_ON = 0x01, /* switch scrolling on */ + FP_FLAG_SCROLL_LTR = 0x02, /* scroll from left to rightinstead of default right to left direction (i.e. for arabic text) */ + FP_FLAG_SCROLL_SIO = 0x04, /* start/stop scrolling with empty screen (scroll in/out) */ + FP_FLAG_SCROLL_DELAY = 0x08, /* delayed scroll start */ + FP_FLAG_ALIGN_LEFT = 0x10, /* align the text in display from the left (default) */ + FP_FLAG_ALIGN_RIGHT = 0x20, /* align the text in display from the right (arabic) */ + FP_FLAG_UPDATE_SCROLL_POS = 0x40, /* update the current position for scrolling */ +} fp_flag; + +typedef struct { + unsigned char brightness; + unsigned char flags; + unsigned char current_hour; + unsigned char current_minute; + unsigned char timer_minutes_hi; + unsigned char timer_minutes_lo; +} fp_standby_data_t; + +typedef struct { + unsigned char source; + unsigned char time_minutes_hi; + unsigned char time_minutes_lo; +} fp_wakeup_data_t; + +typedef enum { + FP_LED_1_ON = 0x81, + FP_LED_2_ON = 0x82, + FP_LED_3_ON = 0x83, + FP_LED_1_OFF = 0x01, + FP_LED_2_OFF = 0x02, + FP_LED_3_OFF = 0x03, +} fp_led_ctrl_t; + +typedef enum { + FP_WAKEUP_SOURCE_TIMER = 0x01, + FP_WAKEUP_SOURCE_BUTTON = 0x02, + FP_WAKEUP_SOURCE_REMOTE = 0x04, + FP_WAKEUP_SOURCE_PWLOST = 0x7F, + FP_WAKEUP_SOURCE_POWER = 0xFF +} fp_wakeup_source; + +typedef struct { + unsigned short addr; + unsigned short cmd; +} fp_standby_cmd_data_t; + +#endif /* __DUCKBOX_VFD__ */ diff --git a/include/cs_vfd.h b/include/cs_vfd.h new file mode 100644 index 0000000..7ee3b70 --- /dev/null +++ b/include/cs_vfd.h @@ -0,0 +1,178 @@ +#ifndef __DUCKBOX_VFD__ +#define __DUCKBOX_VFD__ + +#define VFDDISPLAYCHARS 0xc0425a00 +#define VFDWRITECGRAM 0x40425a01 +#define VFDBRIGHTNESS 0xc0425a03 +#define VFDPWRLED 0xc0425a04 +#define VFDDRIVERINIT 0xc0425a08 +#define VFDICONDISPLAYONOFF 0xc0425a0a +#define VFDDISPLAYWRITEONOFF 0xc0425a05 + +#define VFDCLEARICONS 0xc0425af6 +#define VFDSETRF 0xc0425af7 +#define VFDSETFAN 0xc0425af8 +#define VFDGETWAKEUPMODE 0xc0425af9 +#define VFDGETTIME 0xc0425afa +#define VFDSETTIME 0xc0425afb +#define VFDSTANDBY 0xc0425afc +#define VFDREBOOT 0xc0425afd +#define VFDSETLED 0xc0425afe +#define VFDSETMODE 0xc0425aff + +#define VFDGETWAKEUPTIME 0xc0425b00 +#define VFDGETVERSION 0xc0425b01 +#define VFDSETDISPLAYTIME 0xc0425b02 +#define VFDSETTIMEMODE 0xc0425b03 +#define VFDDISPLAYCLR 0xc0425b00 + +typedef enum { +#if defined(BOXMODEL_OCTAGON1008) + ICON_DTS, + ICON_VIDEO, + ICON_AUDIO, + ICON_LINK, + ICON_HDD, + ICON_DISC, + ICON_DVB, + VFD_ICON_USB = 0x27, + VFD_ICON_HD = 0x27, + VFD_ICON_HDD = ICON_HDD, + VFD_ICON_LOCK = 0x27, + VFD_ICON_BT = 0x27, + VFD_ICON_MP3 = 0x27, + VFD_ICON_MUSIC = 0x27, + VFD_ICON_DD = 0x27, + VFD_ICON_MAIL = 0x27, + VFD_ICON_MUTE = 0x27, + VFD_ICON_PLAY = 0x27, + VFD_ICON_PAUSE = 0x27, + VFD_ICON_FF = 0x27, + VFD_ICON_FR = 0x27, + VFD_ICON_REC = 0x27, + VFD_ICON_CLOCK = 0x27, +#elif defined(BOXMODEL_FORTIS_HDBOX) + ICON_STANDBY = 0x10, + ICON_SAT, + ICON_REC, + ICON_TIMESHIFT, + ICON_TIMER, + ICON_HD, + ICON_USB, + ICON_SCRAMBLED, + ICON_DOLBY, + ICON_MUTE, + ICON_TUNER1, + ICON_TUNER2, + ICON_MP3, + ICON_REPEAT, + ICON_Play, + VFD_ICON_PAUSE, + ICON_TER, + ICON_FILE, + ICON_480i, + ICON_480p, + ICON_576i, + ICON_576p, + ICON_720p, + ICON_1080i, + ICON_1080p, + ICON_Play_1, + VFD_ICON_USB = ICON_USB, + VFD_ICON_REC = ICON_REC, + VFD_ICON_CLOCK = ICON_TIMER, + VFD_ICON_HD = ICON_HD, + VFD_ICON_LOCK = ICON_SCRAMBLED, + VFD_ICON_DD = ICON_DOLBY, + VFD_ICON_MUTE = ICON_MUTE, + VFD_ICON_MP3 = ICON_MP3, + VFD_ICON_PLAY = ICON_Play, + VFD_ICON_HDD, + VFD_ICON_MUSIC, + VFD_ICON_MAIL, + VFD_ICON_FF, + VFD_ICON_FR, +#elif defined(BOXMODEL_UFS910) + VFD_ICON_USB = 0x10, + VFD_ICON_HD, + VFD_ICON_HDD, + VFD_ICON_LOCK, + VFD_ICON_BT, + VFD_ICON_MP3, + VFD_ICON_MUSIC, + VFD_ICON_DD, + VFD_ICON_MAIL, + VFD_ICON_MUTE, + VFD_ICON_PLAY, + VFD_ICON_PAUSE, + VFD_ICON_FF, + VFD_ICON_FR, + VFD_ICON_REC, + VFD_ICON_CLOCK, +#else + VFD_ICON_USB = 0x10, + VFD_ICON_HD, + VFD_ICON_HDD, + VFD_ICON_LOCK, + VFD_ICON_BT, + VFD_ICON_MP3, + VFD_ICON_MUSIC, + VFD_ICON_DD, + VFD_ICON_MAIL, + VFD_ICON_MUTE, + VFD_ICON_PLAY, + VFD_ICON_PAUSE, + VFD_ICON_FF, + VFD_ICON_FR, + VFD_ICON_REC, + VFD_ICON_CLOCK, +#endif + VFD_ICON_MAX +} vfd_icon; + +typedef enum +{ + VFD_FLAG_NONE = 0x00, + VFD_FLAG_SCROLL_ON = 0x01, /* switch scrolling on */ + VFD_FLAG_SCROLL_LTR = 0x02, /* scroll from left to rightinstead of default right to left direction (i.e. for arabic text) */ + VFD_FLAG_SCROLL_SIO = 0x04, /* start/stop scrolling with empty screen (scroll in/out) */ + VFD_FLAG_SCROLL_DELAY = 0x08, /* delayed scroll start */ + VFD_FLAG_ALIGN_LEFT = 0x10, /* align the text in display from the left (default) */ + VFD_FLAG_ALIGN_RIGHT = 0x20, /* align the text in display from the right (arabic) */ + VFD_FLAG_UPDATE_SCROLL_POS = 0x40, /* update the current position for scrolling */ +} vfd_flag; + +typedef struct { + unsigned char brightness; + unsigned char flags; + unsigned char current_hour; + unsigned char current_minute; + unsigned char timer_minutes_hi; + unsigned char timer_minutes_lo; +} standby_data_t; + +typedef struct { + unsigned char source; + unsigned char time_minutes_hi; + unsigned char time_minutes_lo; +} wakeup_data_t; + +typedef enum { + VFD_LED_1_ON = 0x81, + VFD_LED_2_ON = 0x82, + VFD_LED_3_ON = 0x83, + VFD_LED_1_OFF = 0x01, + VFD_LED_2_OFF = 0x02, + VFD_LED_3_OFF = 0x03, +} vfd_led_ctrl_t; + +typedef enum +{ + WAKEUP_SOURCE_TIMER = 0x01, + WAKEUP_SOURCE_BUTTON = 0x02, + WAKEUP_SOURCE_REMOTE = 0x04, + WAKEUP_SOURCE_PWLOST = 0x7F, + WAKEUP_SOURCE_POWER = 0xFF +} wakeup_source; + +#endif /* __DUCKBOX_VFD__ */ diff --git a/include/dmx_td.h b/include/dmx_td.h index b2b3751..db4330f 100644 --- a/include/dmx_td.h +++ b/include/dmx_td.h @@ -1,6 +1,8 @@ #include #if HAVE_TRIPLEDRAGON #include "../libtriple/dmx_td.h" +#elif HAVE_DUCKBOX_HARDWARE +#include "../libduckbox/dmx_lib.h" #elif HAVE_SPARK_HARDWARE #include "../libspark/dmx_lib.h" #elif HAVE_AZBOX_HARDWARE diff --git a/include/hardware_caps.h b/include/hardware_caps.h index 641ed88..d4e48a9 100644 --- a/include/hardware_caps.h +++ b/include/hardware_caps.h @@ -36,6 +36,7 @@ typedef struct hw_caps char boxvendor[64]; char boxname[64]; int boxtype; + int has_CI; } hw_caps_t; hw_caps_t *get_hwcaps(void); diff --git a/include/lt_debug.h b/include/lt_debug.h deleted file mode 100644 index 513f17d..0000000 --- a/include/lt_debug.h +++ /dev/null @@ -1,8 +0,0 @@ -#include -#if HAVE_TRIPLEDRAGON -#include "../libtriple/playback_td.h" -#elif HAVE_SPARK_HARDWARE -#include "../libspark/playback_lib.h" -#else -#error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined -#endif diff --git a/include/mmi.h b/include/mmi.h index 3fec80f..4f89482 100644 --- a/include/mmi.h +++ b/include/mmi.h @@ -5,7 +5,30 @@ #define MAX_MMI_TEXT_LEN 255 #define MAX_MMI_CHOICE_TEXT_LEN 255 +typedef enum { + MMI_TOP_MENU_SUBS = 1, + MMI_TOP_MENU_EVENTS, + MMI_TOP_MENU_TOKENS, + MMI_TOP_MENU_PIN, + MMI_TOP_MENU_MATURE, + MMI_TOP_MENU_ABOUT +} MMI_MENU_CURRENT; + +typedef enum { + MMI_MENU_LEVEL_MAIN = 0, + MMI_MENU_LEVEL_MATURE, + MMI_MENU_LEVEL_ASK_PIN_MATURE +} MMI_MENU_LEVEL; + +typedef enum { + MMI_PIN_LEVEL_ASK_OLD = 0, + MMI_PIN_LEVEL_CHECK_CURRENT, + MMI_PIN_LEVEL_ASK_REPEAT, + MMI_PIN_LEVEL_CHECK_AND_CHANGE +} MMI_PIN_LEVEL; + typedef struct { + int slot; int choice_nb; char title[MAX_MMI_TEXT_LEN]; char subtitle[MAX_MMI_TEXT_LEN]; @@ -14,6 +37,7 @@ typedef struct { } MMI_MENU_LIST_INFO; typedef struct { + int slot; int blind; int answerlen; char enquiryText[MAX_MMI_TEXT_LEN]; diff --git a/include/playback_td.h b/include/playback_td.h index 301b6c8..82ec96a 100644 --- a/include/playback_td.h +++ b/include/playback_td.h @@ -1,6 +1,8 @@ #include #if HAVE_TRIPLEDRAGON #include "../libtriple/playback_td.h" +#elif HAVE_DUCKBOX_HARDWARE +#include "../libduckbox/playback_libeplayer3.h" #elif HAVE_SPARK_HARDWARE #include "../libspark/playback_libeplayer3.h" #elif HAVE_AZBOX_HARDWARE @@ -9,8 +11,12 @@ #if BOXMODEL_RASPI #include "../raspi/playback.h" #else +#if ENABLE_GSTREAMER +#include "../generic-pc/playback_gst.h" +#else #include "../generic-pc/playback.h" #endif +#endif #else #error neither HAVE_TRIPLEDRAGON nor HAVE_SPARK_HARDWARE defined #endif diff --git a/include/pwrmngr.h b/include/pwrmngr.h index 3b3dcfe..dea558f 100644 --- a/include/pwrmngr.h +++ b/include/pwrmngr.h @@ -1,6 +1,8 @@ #include #if HAVE_TRIPLEDRAGON #include "../libtriple/pwrmngr.h" +#elif HAVE_DUCKBOX_HARDWARE +#include "../libduckbox/pwrmngr.h" #elif HAVE_SPARK_HARDWARE #include "../libspark/pwrmngr.h" #elif HAVE_AZBOX_HARDWARE diff --git a/include/record_td.h b/include/record_td.h index 0b63c66..e4467b5 100644 --- a/include/record_td.h +++ b/include/record_td.h @@ -1,6 +1,8 @@ #include #if HAVE_TRIPLEDRAGON #include "../libtriple/record_td.h" +#elif HAVE_DUCKBOX_HARDWARE +#include "../libduckbox/record_lib.h" #elif HAVE_SPARK_HARDWARE #include "../libspark/record_lib.h" #elif HAVE_AZBOX_HARDWARE diff --git a/include/video_td.h b/include/video_td.h index 479d230..ec63331 100644 --- a/include/video_td.h +++ b/include/video_td.h @@ -1,6 +1,8 @@ #include #if HAVE_TRIPLEDRAGON #include "../libtriple/video_td.h" +#elif HAVE_DUCKBOX_HARDWARE +#include "../libduckbox/video_lib.h" #elif HAVE_SPARK_HARDWARE #include "../libspark/video_lib.h" #elif HAVE_AZBOX_HARDWARE diff --git a/libduckbox/Makefile.am b/libduckbox/Makefile.am new file mode 100644 index 0000000..189cb98 --- /dev/null +++ b/libduckbox/Makefile.am @@ -0,0 +1,26 @@ +noinst_LTLIBRARIES = libduckbox.la + +AM_CPPFLAGS = -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS +AM_CPPFLAGS += \ + -I$(top_srcdir)/common \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/libeplayer3/include + +AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing + +AM_LDFLAGS = -lpthread -lasound -lass -lrt \ + @AVFORMAT_LIBS@ \ + @AVUTIL_LIBS@ \ + @AVCODEC_LIBS@ \ + @SWRESAMPLE_LIBS@ + +libduckbox_la_SOURCES = \ + hardware_caps.c \ + dmx.cpp \ + video.cpp \ + audio.cpp \ + audio_mixer.cpp \ + init.cpp \ + playback_libeplayer3.cpp \ + pwrmngr.cpp \ + record.cpp diff --git a/libduckbox/audio.cpp b/libduckbox/audio.cpp new file mode 120000 index 0000000..cb92e8e --- /dev/null +++ b/libduckbox/audio.cpp @@ -0,0 +1 @@ +../libspark/audio.cpp \ No newline at end of file diff --git a/libduckbox/audio_lib.h b/libduckbox/audio_lib.h new file mode 120000 index 0000000..17da9d9 --- /dev/null +++ b/libduckbox/audio_lib.h @@ -0,0 +1 @@ +../libspark/audio_lib.h \ No newline at end of file diff --git a/libduckbox/audio_mixer.cpp b/libduckbox/audio_mixer.cpp new file mode 120000 index 0000000..468eb7d --- /dev/null +++ b/libduckbox/audio_mixer.cpp @@ -0,0 +1 @@ +../libspark/audio_mixer.cpp \ No newline at end of file diff --git a/libduckbox/audio_mixer.h b/libduckbox/audio_mixer.h new file mode 120000 index 0000000..0701d55 --- /dev/null +++ b/libduckbox/audio_mixer.h @@ -0,0 +1 @@ +../libspark/audio_mixer.h \ No newline at end of file diff --git a/libduckbox/cs_api.h b/libduckbox/cs_api.h new file mode 100644 index 0000000..8ac8d93 --- /dev/null +++ b/libduckbox/cs_api.h @@ -0,0 +1,30 @@ +/* compatibility header for tripledragon. I'm lazy, so I just left it + as "cs_api.h" so that I don't need too many ifdefs in the code */ + +#ifndef __CS_API_H_ +#define __CS_API_H_ + +#include "init_lib.h" +typedef void (*cs_messenger) (unsigned int msg, unsigned int data); + +inline void cs_api_init() +{ + init_td_api(); +}; + +inline void cs_api_exit() +{ + shutdown_td_api(); +}; + +#define cs_malloc_uncached malloc +#define cs_free_uncached free + +// Callback function helpers +void cs_register_messenger(cs_messenger messenger); +static inline void cs_deregister_messenger(void) { return; }; + +/* compat... HD1 seems to be version 6. everything newer ist > 6... */ +static inline unsigned int cs_get_revision(void) { return 1; }; +extern int cnxt_debug; +#endif //__CS_API_H_ diff --git a/libduckbox/dmx.cpp b/libduckbox/dmx.cpp new file mode 120000 index 0000000..ca94210 --- /dev/null +++ b/libduckbox/dmx.cpp @@ -0,0 +1 @@ +../libspark/dmx.cpp \ No newline at end of file diff --git a/libduckbox/dmx_cs.h b/libduckbox/dmx_cs.h new file mode 120000 index 0000000..ff27353 --- /dev/null +++ b/libduckbox/dmx_cs.h @@ -0,0 +1 @@ +../libspark/dmx_cs.h \ No newline at end of file diff --git a/libduckbox/dmx_lib.h b/libduckbox/dmx_lib.h new file mode 120000 index 0000000..a04eec1 --- /dev/null +++ b/libduckbox/dmx_lib.h @@ -0,0 +1 @@ +../libspark/dmx_lib.h \ No newline at end of file diff --git a/libduckbox/hardware_caps.c b/libduckbox/hardware_caps.c new file mode 100644 index 0000000..7ba32d1 --- /dev/null +++ b/libduckbox/hardware_caps.c @@ -0,0 +1,158 @@ +/* + * determine the capabilities of the hardware. + * part of libstb-hal + * + * (C) 2010-2012 Stefan Seyfried + * + * License: GPL v2 or later + */ + +#include +#include +#include +#include +#include +#include +#include + +static int initialized = 0; +static hw_caps_t caps; + +hw_caps_t *get_hwcaps(void) +{ + if (initialized) + return ∩︀ + + memset(&caps, 0, sizeof(hw_caps_t)); + + initialized = 1; + const char *tmp; + char buf[64]; + int len = -1; + int fd = open("/proc/stb/info/model", O_RDONLY); + if (fd != -1) { + len = read(fd, buf, sizeof(buf) - 1); + close(fd); + } + if (len > 0) { + buf[len] = 0; + if (!strncmp(buf, "atevio7500", 10)) { + strcpy(caps.boxvendor, "DUCKBOX"); + strcpy(caps.boxname, buf); + caps.can_shutdown = 1; + caps.has_HDMI = 1; + caps.has_SCART = 1; + caps.can_cec = 1; + caps.has_fan = 0; + caps.has_CI = 2; + } + else if (!strncmp(buf, "ufs912", 6)) { + strcpy(caps.boxvendor, "DUCKBOX"); + strcpy(caps.boxname, buf); + caps.can_shutdown = 1; + caps.has_HDMI = 1; + caps.has_SCART = 1; + caps.can_cec = 1; + caps.has_fan = 0; + caps.has_CI = 2; + } + else if (!strncmp(buf, "ufs913", 6)) { + strcpy(caps.boxvendor, "DUCKBOX"); + strcpy(caps.boxname, buf); + caps.can_shutdown = 1; + caps.has_HDMI = 1; + caps.has_SCART = 1; + caps.can_cec = 1; + caps.has_fan = 0; + caps.has_CI = 2; + } + else if (!strncmp(buf, "ufs922", 6)) { + strcpy(caps.boxvendor, "DUCKBOX"); + strcpy(caps.boxname, buf); + caps.can_shutdown = 1; + caps.has_HDMI = 1; + caps.has_SCART = 1; + caps.can_cec = 0; + caps.has_fan = 1; + caps.has_CI = 2; + } + else if (!strncmp(buf, "ufs910", 6)) { + strcpy(caps.boxvendor, "DUCKBOX"); + strcpy(caps.boxname, buf); + caps.can_shutdown = 1; + caps.has_HDMI = 1; + caps.has_SCART = 1; + caps.can_cec = 0; + caps.has_fan = 0; + caps.has_CI = 2; + } + else if (!strncmp(buf, "hdbox", 5)) { + strcpy(caps.boxvendor, "DUCKBOX"); + strcpy(caps.boxname, buf); + caps.can_shutdown = 1; + caps.has_HDMI = 1; + caps.has_SCART = 1; + caps.can_cec = 0; + caps.has_fan = 0; + caps.has_CI = 2; + } + else if (!strncmp(buf, "octagon1008", 11)) { + strcpy(caps.boxvendor, "DUCKBOX"); + strcpy(caps.boxname, buf); + caps.can_shutdown = 1; + caps.has_HDMI = 1; + caps.has_SCART = 1; + caps.can_cec = 0; + caps.has_fan = 0; + caps.has_CI = 2; + } + else if (!strncmp(buf, "cuberevo", 8)) { + strcpy(caps.boxvendor, "DUCKBOX"); + strcpy(caps.boxname, buf); + caps.can_shutdown = 1; + caps.has_HDMI = 1; + caps.has_SCART = 1; + caps.can_cec = 0; + caps.has_fan = 0; + caps.has_CI = 2; + } + else if (!strncmp(buf, "cuberevo-mini2", 14)) { + strcpy(caps.boxvendor, "DUCKBOX"); + strcpy(caps.boxname, buf); + caps.can_shutdown = 1; + caps.has_HDMI = 1; + caps.has_SCART = 1; + caps.can_cec = 0; + caps.has_fan = 0; + caps.has_CI = 2; + } + else if (!strncmp(buf, "cuberevo-2000hd", 15)) { + strcpy(caps.boxvendor, "DUCKBOX"); + strcpy(caps.boxname, buf); + caps.can_shutdown = 1; + caps.has_HDMI = 1; + caps.has_SCART = 1; + caps.can_cec = 0; + caps.has_fan = 0; + caps.has_CI = 0; + } + else if (!strncmp(buf, "tf7700", 6)) { + strcpy(caps.boxvendor, "DUCKBOX"); + strcpy(caps.boxname, buf); + caps.can_shutdown = 1; + caps.has_HDMI = 1; + caps.has_SCART = 1; + caps.can_cec = 0; + caps.has_fan = 0; + caps.has_CI = 2; + } + else { + strcpy(caps.boxvendor, "unknown"); + strcpy(caps.boxname, "unknown model"); + } + } + else + strcpy(caps.boxname, "(unknown model)"); + + return ∩︀ +} diff --git a/libduckbox/init.cpp b/libduckbox/init.cpp new file mode 100644 index 0000000..41358e5 --- /dev/null +++ b/libduckbox/init.cpp @@ -0,0 +1,55 @@ +#include + +#include "init_lib.h" +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "pwrmngr.h" + +#include "lt_debug.h" +#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_INIT, NULL, args) +#define lt_info(args...) _lt_info(TRIPLE_DEBUG_INIT, NULL, args) + +static bool initialized = false; + +void init_td_api() +{ + if (!initialized) + lt_debug_init(); + lt_info("%s begin, initialized=%d, debug=0x%02x\n", __FUNCTION__, (int)initialized, debuglevel); + if (!initialized) + { + /* this is a strange hack: the drivers seem to only work correctly after + * demux0 has been used once. After that, we can use demux1,2,... */ + struct dmx_pes_filter_params p; + int dmx = open("/dev/dvb/adapter0/demux0", O_RDWR|O_CLOEXEC); + if (dmx < 0) + lt_info("%s: ERROR open /dev/dvb/adapter0/demux0 (%m)\n", __func__); + else + { + memset(&p, 0, sizeof(p)); + p.output = DMX_OUT_DECODER; + p.input = DMX_IN_FRONTEND; + p.flags = DMX_IMMEDIATE_START; + p.pes_type = DMX_PES_VIDEO; + ioctl(dmx, DMX_SET_PES_FILTER, &p); + ioctl(dmx, DMX_STOP); + close(dmx); + } + } + initialized = true; + lt_info("%s end\n", __FUNCTION__); +} + +void shutdown_td_api() +{ + lt_info("%s, initialized = %d\n", __FUNCTION__, (int)initialized); + initialized = false; +} diff --git a/libduckbox/init_cs.h b/libduckbox/init_cs.h new file mode 120000 index 0000000..359b1d6 --- /dev/null +++ b/libduckbox/init_cs.h @@ -0,0 +1 @@ +../libspark/init_cs.h \ No newline at end of file diff --git a/libduckbox/init_lib.h b/libduckbox/init_lib.h new file mode 120000 index 0000000..8726e66 --- /dev/null +++ b/libduckbox/init_lib.h @@ -0,0 +1 @@ +../libspark/init_lib.h \ No newline at end of file diff --git a/libduckbox/playback_libeplayer3.cpp b/libduckbox/playback_libeplayer3.cpp new file mode 120000 index 0000000..375de84 --- /dev/null +++ b/libduckbox/playback_libeplayer3.cpp @@ -0,0 +1 @@ +../libspark/playback_libeplayer3.cpp \ No newline at end of file diff --git a/libduckbox/playback_libeplayer3.h b/libduckbox/playback_libeplayer3.h new file mode 120000 index 0000000..449d0a8 --- /dev/null +++ b/libduckbox/playback_libeplayer3.h @@ -0,0 +1 @@ +../libspark/playback_libeplayer3.h \ No newline at end of file diff --git a/libduckbox/pwrmngr.cpp b/libduckbox/pwrmngr.cpp new file mode 120000 index 0000000..cee9acb --- /dev/null +++ b/libduckbox/pwrmngr.cpp @@ -0,0 +1 @@ +../libspark/pwrmngr.cpp \ No newline at end of file diff --git a/libduckbox/pwrmngr.h b/libduckbox/pwrmngr.h new file mode 120000 index 0000000..e63e97b --- /dev/null +++ b/libduckbox/pwrmngr.h @@ -0,0 +1 @@ +../libspark/pwrmngr.h \ No newline at end of file diff --git a/libduckbox/record.cpp b/libduckbox/record.cpp new file mode 120000 index 0000000..4daae8d --- /dev/null +++ b/libduckbox/record.cpp @@ -0,0 +1 @@ +../libspark/record.cpp \ No newline at end of file diff --git a/libduckbox/record_lib.h b/libduckbox/record_lib.h new file mode 120000 index 0000000..1ec9332 --- /dev/null +++ b/libduckbox/record_lib.h @@ -0,0 +1 @@ +../libspark/record_lib.h \ No newline at end of file diff --git a/libduckbox/video.cpp b/libduckbox/video.cpp new file mode 120000 index 0000000..c30d002 --- /dev/null +++ b/libduckbox/video.cpp @@ -0,0 +1 @@ +../libspark/video.cpp \ No newline at end of file diff --git a/libduckbox/video_lib.h b/libduckbox/video_lib.h new file mode 120000 index 0000000..7a57b9c --- /dev/null +++ b/libduckbox/video_lib.h @@ -0,0 +1 @@ +../libspark/video_lib.h \ No newline at end of file diff --git a/libdvbci/Makefile.am b/libdvbci/Makefile.am new file mode 100644 index 0000000..a1d4c82 --- /dev/null +++ b/libdvbci/Makefile.am @@ -0,0 +1,17 @@ +noinst_LTLIBRARIES = libdvbci.la + +AM_CPPFLAGS = \ + -I$(top_srcdir)/common \ + -I$(top_srcdir)/include + +AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing +AM_LDFLAGS = -lpthread + +libdvbci_la_SOURCES = \ + dvbci_session.cpp \ + dvbci_mmi.cpp \ + dvbci_camgr.cpp \ + dvbci_appmgr.cpp \ + dvbci_datetimemgr.cpp \ + dvbci_resmgr.cpp + diff --git a/libdvbci/Makefile.in b/libdvbci/Makefile.in new file mode 100644 index 0000000..5a45e96 --- /dev/null +++ b/libdvbci/Makefile.in @@ -0,0 +1,632 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = libdvbci +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/depcomp +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libdvbci_la_LIBADD = +am_libdvbci_la_OBJECTS = dvbci_session.lo dvbci_mmi.lo dvbci_camgr.lo \ + dvbci_appmgr.lo dvbci_datetimemgr.lo dvbci_resmgr.lo +libdvbci_la_OBJECTS = $(am_libdvbci_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(libdvbci_la_SOURCES) +DIST_SOURCES = $(libdvbci_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AVCODEC_CFLAGS = @AVCODEC_CFLAGS@ +AVCODEC_LIBS = @AVCODEC_LIBS@ +AVFORMAT_CFLAGS = @AVFORMAT_CFLAGS@ +AVFORMAT_LIBS = @AVFORMAT_LIBS@ +AVUTIL_CFLAGS = @AVUTIL_CFLAGS@ +AVUTIL_LIBS = @AVUTIL_LIBS@ +AWK = @AWK@ +BOXMODEL = @BOXMODEL@ +BOXTYPE = @BOXTYPE@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONFIGDIR = @CONFIGDIR@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIR = @DATADIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DIRECTFB_CFLAGS = @DIRECTFB_CFLAGS@ +DIRECTFB_LIBS = @DIRECTFB_LIBS@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FONTDIR = @FONTDIR@ +GAMESDIR = @GAMESDIR@ +GREP = @GREP@ +GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@ +GSTREAMER_INTERFACES_CFLAGS = @GSTREAMER_INTERFACES_CFLAGS@ +GSTREAMER_INTERFACES_LIBS = @GSTREAMER_INTERFACES_LIBS@ +GSTREAMER_LIBS = @GSTREAMER_LIBS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBDIR = @LIBDIR@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +PLUGINDIR = @PLUGINDIR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SWRESAMPLE_CFLAGS = @SWRESAMPLE_CFLAGS@ +SWRESAMPLE_LIBS = @SWRESAMPLE_LIBS@ +SWSCALE_CFLAGS = @SWSCALE_CFLAGS@ +SWSCALE_LIBS = @SWSCALE_LIBS@ +TARGET_CONFIGDIR = @TARGET_CONFIGDIR@ +TARGET_DATADIR = @TARGET_DATADIR@ +TARGET_FONTDIR = @TARGET_FONTDIR@ +TARGET_GAMESDIR = @TARGET_GAMESDIR@ +TARGET_LIBDIR = @TARGET_LIBDIR@ +TARGET_PLUGINDIR = @TARGET_PLUGINDIR@ +TARGET_THEMESDIR = @TARGET_THEMESDIR@ +TARGET_UCODEDIR = @TARGET_UCODEDIR@ +THEMESDIR = @THEMESDIR@ +UCODEDIR = @UCODEDIR@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = libdvbci.la +AM_CPPFLAGS = \ + -I$(top_srcdir)/common \ + -I$(top_srcdir)/include + +AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing +AM_LDFLAGS = -lpthread +libdvbci_la_SOURCES = \ + dvbci_session.cpp \ + dvbci_mmi.cpp \ + dvbci_camgr.cpp \ + dvbci_appmgr.cpp \ + dvbci_datetimemgr.cpp \ + dvbci_resmgr.cpp + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libdvbci/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign libdvbci/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libdvbci.la: $(libdvbci_la_OBJECTS) $(libdvbci_la_DEPENDENCIES) $(EXTRA_libdvbci_la_DEPENDENCIES) + $(AM_V_CXXLD)$(CXXLINK) $(libdvbci_la_OBJECTS) $(libdvbci_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvbci_appmgr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvbci_camgr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvbci_datetimemgr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvbci_mmi.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvbci_resmgr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvbci_session.Plo@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libdvbci/dvbci_appmgr.cpp b/libdvbci/dvbci_appmgr.cpp new file mode 100644 index 0000000..033a1f2 --- /dev/null +++ b/libdvbci/dvbci_appmgr.cpp @@ -0,0 +1,104 @@ +/* DVB CI Application Manager */ +#include +#include + +#include "dvbci_appmgr.h" + +static const char * FILENAME = "[dvbci_appmgr]"; + +eDVBCIApplicationManagerSession::eDVBCIApplicationManagerSession(tSlot *tslot) +{ + slot = tslot; + slot->hasAppManager = true; + slot->appSession = this; +} + +eDVBCIApplicationManagerSession::~eDVBCIApplicationManagerSession() +{ + slot->hasAppManager = false; + slot->appSession = NULL; +} + +int eDVBCIApplicationManagerSession::receivedAPDU(const unsigned char *tag, const void *data, int len) +{ + printf("SESSION(%d)/APP %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); + for (int i = 0; i < len; i++) + printf("%02x ", ((const unsigned char*)data)[i]); + printf("\n"); + + if ((tag[0] == 0x9f) && (tag[1] == 0x80)) + { + switch (tag[2]) + { + case 0x21: + { + int dl; + printf("application info:\n"); + printf(" len: %d\n", len); + printf(" application_type: %d\n", ((unsigned char*)data)[0]); + printf(" application_manufacturer: %02x %02x\n", ((unsigned char*)data)[2], ((unsigned char*)data)[1]); + printf(" manufacturer_code: %02x %02x\n", ((unsigned char*)data)[4], ((unsigned char*)data)[3]); + printf(" menu string: \n"); + dl = ((unsigned char*)data)[5]; + if ((dl + 6) > len) + { + printf("warning, invalid length (%d vs %d)\n", dl + 6, len); + dl = len - 6; + } + char str[dl + 1]; + memcpy(str, ((char*)data) + 6, dl); + str[dl] = '\0'; + for (int i = 0; i < dl; ++i) + printf("%c", ((unsigned char*)data)[i + 6]); + printf("\n"); + + strcpy(slot->name, str); + printf("%s set cam name %s on slot %d, %p\n", FILENAME, slot->name, slot->slot, slot); + break; + } + default: + printf("%s unknown APDU tag 9F 80 %02x\n", FILENAME, tag[2]); + break; + } + } + return 0; +} + +int eDVBCIApplicationManagerSession::doAction() +{ + switch (state) + { + case stateStarted: + { + const unsigned char tag[3] = {0x9F, 0x80, 0x20}; + sendAPDU(tag); + state = stateFinal; + return 1; + } + case stateFinal: + printf("in final state."); + wantmenu = 0; + if (wantmenu) + { + printf("%s wantmenu: sending Tenter_menu\n", FILENAME); + const unsigned char tag[3] = {0x9F, 0x80, 0x22}; + sendAPDU(tag); + wantmenu = 0; + return 0; + } + else + return 0; + default: + return 0; + } +} + +int eDVBCIApplicationManagerSession::startMMI() +{ + printf("%s -> %s\n", FILENAME, __func__); + const unsigned char tag[3] = {0x9F, 0x80, 0x22}; + sendAPDU(tag); + slot->mmiOpened = true; + return 0; +} + diff --git a/libdvbci/dvbci_appmgr.h b/libdvbci/dvbci_appmgr.h new file mode 100644 index 0000000..f996c6e --- /dev/null +++ b/libdvbci/dvbci_appmgr.h @@ -0,0 +1,24 @@ +#ifndef __dvbci_dvbci_appmgr_h +#define __dvbci_dvbci_appmgr_h + +#include "dvbci_session.h" + +class eDVBCIApplicationManagerSession: public eDVBCISession +{ + enum { + stateFinal=statePrivate + }; + + tSlot *slot; + + int wantmenu; + int receivedAPDU(const unsigned char *tag, const void *data, int len); + int doAction(); +public: + eDVBCIApplicationManagerSession(tSlot *tslot); + ~eDVBCIApplicationManagerSession(); + int enterMenu(); + int startMMI(); +}; + +#endif diff --git a/libdvbci/dvbci_camgr.cpp b/libdvbci/dvbci_camgr.cpp new file mode 100644 index 0000000..8bfdef1 --- /dev/null +++ b/libdvbci/dvbci_camgr.cpp @@ -0,0 +1,81 @@ +/* DVB CI CA Manager */ +#include +#include + +#include "dvbci_camgr.h" + +#include + +eDVBCICAManagerSession::eDVBCICAManagerSession(tSlot *tslot) +{ + slot = tslot; +} + +eDVBCICAManagerSession::~eDVBCICAManagerSession() +{ + slot->hasCAManager = false; + slot->camgrSession = NULL; +} + +int eDVBCICAManagerSession::receivedAPDU(const unsigned char *tag, const void *data, int len) +{ + printf("SESSION(%d)/CA %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); + for (int i = 0; i < len; i++) + printf("%02x ", ((const unsigned char*)data)[i]); + printf("\n"); + + if ((tag[0] == 0x9f) && (tag[1] == 0x80)) + { + switch (tag[2]) + { + case 0x31: + { + printf("ca info:\n"); + for (int i = 0; i < len; i += 2) + { + printf("%04x ", (((const unsigned char*)data)[i] << 8) | (((const unsigned char*)data)[i + 1])); + caids.push_back((((const unsigned char*)data)[i] << 8) | (((const unsigned char*)data)[i + 1])); + } + sort(caids.begin(), caids.end()); + printf("\n"); + + slot->pollConnection = false; + slot->hasCAManager = true; + slot->camgrSession = this; + } + break; + default: + printf("unknown APDU tag 9F 80 %02x\n", tag[2]); + break; + } + } + return 0; +} + +int eDVBCICAManagerSession::doAction() +{ + switch (state) + { + case stateStarted: + { + const unsigned char tag[3] = {0x9F, 0x80, 0x30}; // ca info enq + sendAPDU(tag); + state = stateFinal; + return 0; + } + case stateFinal: + printf("stateFinal und action! kann doch garnicht sein ;)\n"); + default: + return 0; + } +} + +int eDVBCICAManagerSession::sendCAPMT(unsigned char *data, int len) +{ + const unsigned char tag[3] = {0x9F, 0x80, 0x32}; // ca_pmt + + sendAPDU(tag, data, len); + + return 0; +} + diff --git a/libdvbci/dvbci_camgr.h b/libdvbci/dvbci_camgr.h new file mode 100644 index 0000000..44c9f98 --- /dev/null +++ b/libdvbci/dvbci_camgr.h @@ -0,0 +1,24 @@ +#ifndef __dvbci_dvbci_camgr_h +#define __dvbci_dvbci_camgr_h + +#include + +#include "dvbci_session.h" + +class eDVBCICAManagerSession: public eDVBCISession +{ + enum { + stateFinal=statePrivate + }; + std::vector caids; + int receivedAPDU(const unsigned char *tag, const void *data, int len); + int doAction(); +public: + eDVBCICAManagerSession(tSlot *tslot); + ~eDVBCICAManagerSession(); + + const std::vector &getCAIDs() const { return caids; } + int sendCAPMT(unsigned char *pmt, int len); +}; + +#endif diff --git a/libdvbci/dvbci_datetimemgr.cpp b/libdvbci/dvbci_datetimemgr.cpp new file mode 100644 index 0000000..481864e --- /dev/null +++ b/libdvbci/dvbci_datetimemgr.cpp @@ -0,0 +1,59 @@ +/* DVB CI DateTime Manager */ +#include + +#include "dvbci_datetimemgr.h" + +eDVBCIDateTimeSession::eDVBCIDateTimeSession(tSlot *tslot) +{ + slot = tslot; + slot->hasDateTime = true; + slot->pollConnection = true; +} + +eDVBCIDateTimeSession::~eDVBCIDateTimeSession() +{ + slot->hasDateTime = false; +} + +int eDVBCIDateTimeSession::receivedAPDU(const unsigned char *tag, const void *data, int len) +{ + printf("SESSION(%d)/DATETIME %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); + for (int i = 0; i < len; i++) + printf("%02x ", ((const unsigned char*)data)[i]); + printf("\n"); + + if ((tag[0] == 0x9f) && (tag[1] == 0x84)) + { + switch (tag[2]) + { + case 0x40: + state = stateSendDateTime; + return 1; + break; + default: + printf("unknown APDU tag 9F 84 %02x\n", tag[2]); + break; + } + } + return 0; +} + +int eDVBCIDateTimeSession::doAction() +{ + switch (state) + { + case stateStarted: + return 0; + case stateSendDateTime: + { + unsigned char tag[3] = {0x9f, 0x84, 0x41}; // date_time_response + unsigned char msg[7] = {0, 0, 0, 0, 0, 0, 0}; + sendAPDU(tag, msg, 7); + return 0; + } + case stateFinal: + printf("stateFinal und action! kann doch garnicht sein ;)\n"); + default: + return 0; + } +} diff --git a/libdvbci/dvbci_datetimemgr.h b/libdvbci/dvbci_datetimemgr.h new file mode 100644 index 0000000..3cb12a2 --- /dev/null +++ b/libdvbci/dvbci_datetimemgr.h @@ -0,0 +1,18 @@ +#ifndef __dvbci_dvbci_datetimemgr_h +#define __dvbci_dvbci_datetimemgr_h + +#include "dvbci_session.h" + +class eDVBCIDateTimeSession: public eDVBCISession +{ + enum { + stateFinal=statePrivate, stateSendDateTime + }; + int receivedAPDU(const unsigned char *tag, const void *data, int len); + int doAction(); +public: + eDVBCIDateTimeSession(tSlot *tslot); + ~eDVBCIDateTimeSession(); +}; + +#endif diff --git a/libdvbci/dvbci_mmi.cpp b/libdvbci/dvbci_mmi.cpp new file mode 100644 index 0000000..a79e118 --- /dev/null +++ b/libdvbci/dvbci_mmi.cpp @@ -0,0 +1,282 @@ +/* DVB CI MMI */ +#include +#include +#include +#include + +#include "dvbci_mmi.h" +#include + +static const char * FILENAME = "[dvbci_mmi]"; + +eDVBCIMMISession::eDVBCIMMISession(tSlot *tslot) +{ + printf("%s:%s\n", FILENAME, __func__); + slot = tslot; + slot->hasMMIManager = true; + slot->mmiSession = this; +} + +eDVBCIMMISession::~eDVBCIMMISession() +{ + /* Send a message to Neutrino cam_menu handler */ + CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); + memset(pMsg, 0, sizeof(CA_MESSAGE)); + + pMsg->MsgId = CA_MESSAGE_MSG_MMI_CLOSE; + pMsg->SlotType = CA_SLOT_TYPE_CI; + pMsg->Slot = slot->slot; + cCA::GetInstance()->SendMessage(pMsg); + + slot->hasMMIManager = false; + slot->mmiSession = NULL; + slot->mmiOpened = false; +} + +int eDVBCIMMISession::receivedAPDU(const unsigned char *tag, const void *data, int len) +{ + printf("SESSION(%d)/MMI %02x %02x %02x: ", session_nb, tag[0], tag[1], tag[2]); + for (int i = 0; i < len; i++) + printf("%02x ", ((const unsigned char*)data)[i]); + printf("\n"); + + if ((tag[0] == 0x9f) && (tag[1] == 0x88)) + { + /* from e2 mmi_ui.cpp */ + switch (tag[2]) + { + case 0x00: /* close */ + { + /* Send a message to Neutrino cam_menu handler */ + CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); + memset(pMsg, 0, sizeof(CA_MESSAGE)); + + pMsg->MsgId = CA_MESSAGE_MSG_MMI_CLOSE; + pMsg->SlotType = CA_SLOT_TYPE_CI; + pMsg->Slot = slot->slot; + cCA::GetInstance()->SendMessage(pMsg); + } + break; + case 0x01: /* display control */ + state = stateDisplayReply; + return 1; + break; + case 0x07: /* menu enq */ + { + MMI_ENQUIRY_INFO* enquiry = (MMI_ENQUIRY_INFO*) malloc(sizeof(MMI_ENQUIRY_INFO)); + memset(enquiry, 0, sizeof(MMI_ENQUIRY_INFO)); + unsigned char *d = (unsigned char*)data; + unsigned char *max = ((unsigned char*)d) + len; + + int textlen = len - 2; + if ((d + 2) > max) + break; + + int blind = *d++ & 1; + int alen = *d++; + printf("%d bytes text\n", textlen); + if ((d + textlen) > max) + break; + + char str[textlen + 1]; + memcpy(str, ((char*)d), textlen); + str[textlen] = '\0'; + printf("enq-text: %s", str); + enquiry->slot = slot->slot; + enquiry->blind = blind; + enquiry->answerlen = alen; + strcpy(enquiry->enquiryText, str); + + /* Send a message to Neutrino cam_menu handler */ + CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); + memset(pMsg, 0, sizeof(CA_MESSAGE)); + + pMsg->MsgId = CA_MESSAGE_MSG_MMI_REQ_INPUT; + pMsg->SlotType = CA_SLOT_TYPE_CI; + pMsg->Slot = slot->slot; + pMsg->Flags = CA_MESSAGE_HAS_PARAM1_DATA; + pMsg->Msg.Data[0] = (uint8_t*)enquiry; + cCA::GetInstance()->SendMessage(pMsg); + + slot->mmiOpened = true; + } + break; + case 0x09: /* menu last */ + case 0x0c: /* list last */ + { + MMI_MENU_LIST_INFO* listInfo = (MMI_MENU_LIST_INFO*) malloc(sizeof(MMI_MENU_LIST_INFO)); + memset(listInfo, 0, sizeof(MMI_MENU_LIST_INFO)); + + listInfo->slot = slot->slot; + listInfo->choice_nb = 0; + + unsigned char *d = (unsigned char*)data; + unsigned char *max = ((unsigned char*)d) + len; + int pos = 0; + + if (tag[2] == 0x09) + printf("menu_last\n"); + else + printf("list_last\n"); + + if (d > max) + break; + + int n = *d++; + + if (n == 0xFF) + n = 0; + else + n++; + + for (int i = 0; i < (n + 3); ++i) + { + int textlen; + if ((d + 3) > max) + break; + + printf("text tag: %02x %02x %02x\n", d[0], d[1], d[2]); + d += 3; + d += eDVBCISession::parseLengthField(d, textlen); + + printf("%d bytes text", textlen); + if ((d + textlen) > max) + break; + + char str[textlen + 1]; + memcpy(str, ((char*)d), textlen); + str[textlen] = '\0'; + + int type = pos++; + + if (type == 0) /* title */ + strcpy(listInfo->title, str); + else if (type == 1) /* subtitle */ + strcpy(listInfo->subtitle, str); + else if (type == 2) /* bottom */ + strcpy(listInfo->bottom, str); + else /* text */ + { + strcpy(listInfo->choice_item[listInfo->choice_nb], str); + listInfo->choice_nb++; + printf("%d. %s\n", listInfo->choice_nb, listInfo->choice_item[listInfo->choice_nb - 1]); + } + while (textlen--) + printf("%c", *d++); + printf("\n"); + } + + if (tag[2] == 0x09) + { + /* Send a message to Neutrino cam_menu handler */ + CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); + memset(pMsg, 0, sizeof(CA_MESSAGE)); + + pMsg->MsgId = CA_MESSAGE_MSG_MMI_MENU; + pMsg->SlotType = CA_SLOT_TYPE_CI; + pMsg->Slot = slot->slot; + pMsg->Flags = CA_MESSAGE_HAS_PARAM1_DATA; + pMsg->Msg.Data[0] = (uint8_t*)listInfo; + cCA::GetInstance()->SendMessage(pMsg); + } + else + { + /* Send a message to Neutrino cam_menu handler */ + CA_MESSAGE* pMsg = (CA_MESSAGE*) malloc(sizeof(CA_MESSAGE)); + memset(pMsg, 0, sizeof(CA_MESSAGE)); + + pMsg->MsgId = CA_MESSAGE_MSG_MMI_LIST; + pMsg->SlotType = CA_SLOT_TYPE_CI; + pMsg->Slot = slot->slot; + pMsg->Flags = CA_MESSAGE_HAS_PARAM1_DATA; + pMsg->Msg.Data[0] = (uint8_t*)listInfo; + cCA::GetInstance()->SendMessage(pMsg); + } + } + break; + default: + break; + } + } + return 0; +} + +int eDVBCIMMISession::doAction() +{ + switch (state) + { + case stateStarted: + state = stateIdle; + break; + case stateDisplayReply: + { + unsigned char tag[] = {0x9f, 0x88, 0x02}; + unsigned char data[] = {0x01, 0x01}; + sendAPDU(tag, data, 2); + state = stateIdle; + break; + } + case stateFakeOK: + { + unsigned char tag[] = {0x9f, 0x88, 0x0b}; + unsigned char data[] = {5}; + sendAPDU(tag, data, 1); + state = stateIdle; + break; + } + case stateIdle: + break; + default: + break; + } + return 0; +} + +int eDVBCIMMISession::stopMMI() +{ + unsigned char tag[] = {0x9f, 0x88, 0x00}; + unsigned char data[] = {0x00}; + sendAPDU(tag, data, 1); + + slot->mmiOpened = false; + return 0; +} + +int eDVBCIMMISession::answerText(int answer) +{ + printf("eDVBCIMMISession::answerText(%d)\n", answer); + + unsigned char tag[] = {0x9f, 0x88, 0x0B}; + unsigned char data[] = {0x00}; + data[0] = answer & 0xff; + sendAPDU(tag, data, 1); + + return 0; +} + +int eDVBCIMMISession::answerEnq(char * answer, int len) +{ + printf("eDVBCIMMISession::answerEnq(%d bytes)\n", len); + + unsigned char data[len + 1]; + data[0] = 0x01; // answer ok + memcpy(data + 1, answer, len); + + unsigned char tag[] = {0x9f, 0x88, 0x08}; + sendAPDU(tag, data, len + 1); + + return 0; +} + +int eDVBCIMMISession::cancelEnq() +{ + printf("eDVBCIMMISession::cancelEnq()\n"); + + unsigned char tag[] = {0x9f, 0x88, 0x08}; + unsigned char data[] = {0x00}; // canceled + sendAPDU(tag, data, 1); + slot->mmiOpened = false; + + return 0; +} + diff --git a/libdvbci/dvbci_mmi.h b/libdvbci/dvbci_mmi.h new file mode 100644 index 0000000..9132697 --- /dev/null +++ b/libdvbci/dvbci_mmi.h @@ -0,0 +1,24 @@ +#ifndef __dvbci_dvbci_mmi_h +#define __dvbci_dvbci_mmi_h + +#include "dvbci_session.h" + +class eDVBCIMMISession: public eDVBCISession +{ + enum { + stateDisplayReply=statePrivate, stateFakeOK, stateIdle + }; + + int receivedAPDU(const unsigned char *tag, const void *data, int len); + int doAction(); + tSlot *slot; +public: + eDVBCIMMISession(tSlot *tslot); + ~eDVBCIMMISession(); + int stopMMI(); + int answerText(int answer); + int answerEnq(char *answer, int len); + int cancelEnq(); +}; + +#endif diff --git a/libdvbci/dvbci_resmgr.cpp b/libdvbci/dvbci_resmgr.cpp new file mode 100644 index 0000000..c7706b0 --- /dev/null +++ b/libdvbci/dvbci_resmgr.cpp @@ -0,0 +1,91 @@ +/* DVB CI Resource Manager */ +#include +#include "dvbci_resmgr.h" + +static const char * FILENAME = "[dvbci_resmgr]"; + +int eDVBCIResourceManagerSession::receivedAPDU(const unsigned char *tag, const void *data, int len) +{ + printf("SESSION(%d) %02x %02x %02x (len = %d): \n", session_nb, tag[0], tag[1], tag[2], len); + for (int i = 0; i < len; i++) + printf("%02x ", ((const unsigned char*)data)[i]); + printf("\n"); + if ((tag[0] == 0x9f) && (tag[1] == 0x80)) + { + switch (tag[2]) + { + case 0x10: // profile enquiry + printf("cam fragt was ich kann."); + state = stateProfileEnquiry; + return 1; + break; + case 0x11: // Tprofile + printf("mein cam kann: "); + if (!len) + printf("nichts\n"); + else + for (int i = 0; i < len; i++) + printf("%02x ", ((const unsigned char*)data)[i]); + printf("\n"); + + if (state == stateFirstProfileEnquiry) + { + // profile change + return 1; + } + state = stateFinal; + break; + default: + printf("%s %s unknown APDU tag 9F 80 %02x\n", tag[2], FILENAME, __FUNCTION__); + } + } + return 0; +} + +int eDVBCIResourceManagerSession::doAction() +{ + switch (state) + { + case stateStarted: + { + const unsigned char tag[3] = {0x9F, 0x80, 0x10}; // profile enquiry + sendAPDU(tag); + state = stateFirstProfileEnquiry; + return 0; + } + case stateFirstProfileEnquiry: + { + const unsigned char tag[3] = {0x9F, 0x80, 0x12}; // profile change + sendAPDU(tag); + state = stateProfileChange; + return 0; + } + case stateProfileChange: + { + printf("bla kaputt\n"); + break; + } + case stateProfileEnquiry: + { + const unsigned char tag[3] = {0x9F, 0x80, 0x11}; + const unsigned char data[][4] = + { + {0x00, 0x01, 0x00, 0x41}, + {0x00, 0x02, 0x00, 0x41}, + {0x00, 0x03, 0x00, 0x41}, +// {0x00, 0x20, 0x00, 0x41}, // host control + {0x00, 0x40, 0x00, 0x41}, + {0x00, 0x24, 0x00, 0x41} +// {0x00, 0x10, 0x00, 0x41} // auth. + }; + sendAPDU(tag, data, sizeof(data)); + state = stateFinal; + return 0; + } + case stateFinal: + printf("stateFinal und action! kann doch garnicht sein ;)\n"); + default: + break; + } + return 0; +} diff --git a/libdvbci/dvbci_resmgr.h b/libdvbci/dvbci_resmgr.h new file mode 100644 index 0000000..85f4589 --- /dev/null +++ b/libdvbci/dvbci_resmgr.h @@ -0,0 +1,20 @@ +#ifndef __dvbci_dvbci_resmgr_h +#define __dvbci_dvbci_resmgr_h + +#include "dvbci_session.h" + +class eDVBCIResourceManagerSession: public eDVBCISession +{ + enum { + stateFirstProfileEnquiry=statePrivate, + stateProfileChange, + stateProfileEnquiry, + stateFinal + }; + int receivedAPDU(const unsigned char *tag, const void *data, int len); + int doAction(); +public: + +}; + +#endif diff --git a/libdvbci/dvbci_session.cpp b/libdvbci/dvbci_session.cpp new file mode 100644 index 0000000..31fcdba --- /dev/null +++ b/libdvbci/dvbci_session.cpp @@ -0,0 +1,348 @@ +/* DVB CI Transport Connection */ +#include +#include +#include +#include +#include "dvbci_session.h" +#include "dvbci_resmgr.h" +#include "dvbci_appmgr.h" +#include "dvbci_camgr.h" +#include "dvbci_datetimemgr.h" +#include "dvbci_mmi.h" + +static const char * FILENAME = "[dvbci_session]"; + +eDVBCISession* eDVBCISession::sessions[SLMS]; + +int eDVBCISession::buildLengthField(unsigned char *pkt, int len) +{ + if (len < 127) + { + *pkt++ = len; + return 1; + } + else if (len < 256) + { + *pkt++ = 0x81; + *pkt++ = len; + return 2; + } + else if (len < 65535) + { + *pkt++ = 0x82; + *pkt++ = len >> 8; + *pkt++ = len; + return 3; + } + else + { + printf("too big length\n"); + exit(0); + } +} + +int eDVBCISession::parseLengthField(const unsigned char *pkt, int &len) +{ + len = 0; + if (!(*pkt & 0x80)) + { + len = *pkt; + return 1; + } + for (int i = 0; i < (pkt[0] & 0x7F); ++i) + { + len <<= 8; + len |= pkt[i + 1]; + } + return (pkt[0] & 0x7F) + 1; +} + +void eDVBCISession::sendAPDU(const unsigned char *tag, const void *data, int len) +{ + unsigned char pkt[len + 3 + 4]; + int l; + memcpy(pkt, tag, 3); + l = buildLengthField(pkt + 3, len); + if (data) + memcpy(pkt + 3 + l, data, len); + sendSPDU(0x90, 0, 0, pkt, len + 3 + l); +} + +void eDVBCISession::sendSPDU(unsigned char tag, const void *data, int len, const void *apdu, int alen) +{ + sendSPDU(slot, tag, data, len, session_nb, apdu, alen); +} + +void eDVBCISession::sendSPDU(tSlot *slot, unsigned char tag, const void *data, int len, unsigned short session_nb, const void *apdu, int alen) +{ + unsigned char pkt[4096]; + unsigned char *ptr = pkt; + + *ptr++ = tag; + ptr += buildLengthField(ptr, len + 2); + if (data) + memcpy(ptr, data, len); + ptr += len; + *ptr++ = session_nb >> 8; + *ptr++ = session_nb; + + if (apdu) + memcpy(ptr, apdu, alen); + ptr += alen; + sendData(slot, pkt, ptr - pkt); +} + +void eDVBCISession::sendOpenSessionResponse(tSlot *slot, unsigned char session_status, const unsigned char *resource_identifier, unsigned short session_nb) +{ + char pkt[6]; + pkt[0] = session_status; + memcpy(pkt + 1, resource_identifier, 4); + sendSPDU(slot, 0x92, pkt, 5, session_nb); +} + +void eDVBCISession::recvCreateSessionResponse(const unsigned char *data) +{ + status = data[0]; + state = stateStarted; + action = 1; + printf("create Session Response, status %x\n", status); +} + +void eDVBCISession::recvCloseSessionRequest(const unsigned char *data) +{ + state = stateInDeletion; + action = 1; + printf("close Session Request\n"); +} + +void eDVBCISession::deleteSessions(const tSlot *slot) +{ + for (unsigned short session_nb = 0; session_nb < SLMS; ++session_nb) + { + if (sessions[session_nb] && sessions[session_nb]->slot == slot) + sessions[session_nb] = 0; + } +} + +eDVBCISession* eDVBCISession::createSession(tSlot *slot, const unsigned char *resource_identifier, unsigned char &status) +{ + unsigned long tag; + unsigned short session_nb; + + for (session_nb = 1; session_nb < SLMS; ++session_nb) + if (!sessions[session_nb - 1]) + break; + + printf("use session_nb = %d\n", session_nb); + if (session_nb == SLMS) + { + status = 0xF3; + return NULL; + } + + tag = resource_identifier[0] << 24; + tag |= resource_identifier[1] << 16; + tag |= resource_identifier[2] << 8; + tag |= resource_identifier[3]; + + printf("Tag: %08X\n", tag); + + switch (tag) + { + case 0x00010041: + sessions[session_nb - 1] = new eDVBCIResourceManagerSession; + printf("RESOURCE MANAGER\n"); + break; + case 0x00020041: + sessions[session_nb - 1] = new eDVBCIApplicationManagerSession(slot); + printf("APPLICATION MANAGER\n"); + break; + case 0x00030041: + sessions[session_nb - 1] = new eDVBCICAManagerSession(slot); + printf("CA MANAGER\n"); + break; + case 0x00240041: + sessions[session_nb - 1] = new eDVBCIDateTimeSession(slot); + printf("DATE-TIME\n"); + break; + case 0x00400041: + sessions[session_nb - 1] = new eDVBCIMMISession(slot); + printf("MMI - create session\n"); + break; + case 0x00100041: +// session=new eDVBCIAuthSession; + printf("AuthSession\n"); +// break; + case 0x00200041: + default: + printf("unknown resource type %02x %02x %02x %02x\n", resource_identifier[0], resource_identifier[1], resource_identifier[2], resource_identifier[3]); + sessions[session_nb - 1] = 0; + status = 0xF0; + } + + if (!sessions[session_nb - 1]) + { + printf("unknown session.. expect crash\n"); + return NULL; + } + + printf("new session nb %d %p\n", session_nb, sessions[session_nb - 1]); + sessions[session_nb - 1]->session_nb = session_nb; + + if (sessions[session_nb - 1]) + { + sessions[session_nb - 1]->slot = slot; + status = 0; + } + sessions[session_nb - 1]->state = stateInCreation; + return sessions[session_nb - 1]; +} + +void eDVBCISession::handleClose() +{ + printf("%s %s\n", FILENAME, __FUNCTION__); + + unsigned char data[1] = {0x00}; + sendSPDU(0x96, data, 1, 0, 0); +} + +int eDVBCISession::pollAll() +{ + for (int session_nb = 1; session_nb < SLMS; ++session_nb) + { + if (sessions[session_nb - 1]) + { + int r; + if (sessions[session_nb - 1]->state == stateInDeletion) + { + sessions[session_nb - 1]->handleClose(); + sessions[session_nb - 1] = 0; + r = 1; + } + else + r = sessions[session_nb - 1]->poll(); + + if (r) + { + printf("%s <\n", __func__); + return 1; + } + } + } + return 0; +} + +void eDVBCISession::receiveData(tSlot *slot, const unsigned char *ptr, size_t len) +{ + printf("slot: %p\n", slot); + + for(unsigned int i = 0; i < len; i++) + printf("%02x ", ptr[i]); + printf("\n"); + + if ((ptr[0] == 0x90 || ptr[0] == 0x95) && (ptr[3] == 0 )) + { + printf("****Mist: %02x %02x %02x %02x\n", ptr[0], ptr[1], ptr[2], ptr[3]); + } + const unsigned char *pkt = (const unsigned char*)ptr; + unsigned char tag = *pkt++; + int llen, hlen; + + + llen = parseLengthField(pkt, hlen); + pkt += llen; + + eDVBCISession* session = NULL; + + if(tag == 0x91) + { + unsigned char status; + + session = createSession(slot, pkt, status); + sendOpenSessionResponse(slot, status, pkt, session ? session->session_nb : 0); + + if (session) + { + session->state = stateStarted; + session->action = 1; + } + } + else + { + unsigned session_nb; + printf("hlen = %d, %d, %d\n", hlen, pkt[hlen - 2], pkt[hlen - 1]); + session_nb = pkt[hlen - 2] << 8; + session_nb |= pkt[hlen - 1] & 0xFF; + + if ((!session_nb) || (session_nb >= SLMS)) + { + printf("PROTOCOL: illegal session number %x\n", session_nb); + return; + } + + session = sessions[session_nb - 1]; + if (!session) + { + printf("PROTOCOL: data on closed session %x\n", session_nb); + return; + } + + switch (tag) + { + case 0x90: + break; + case 0x94: + session->recvCreateSessionResponse(pkt); + break; + case 0x95: + session->recvCloseSessionRequest(pkt); + break; + default: + printf("INTERNAL: nyi, tag %02x.\n", tag); + return; + } + } + + hlen += llen + 1; // lengthfield and tag + + pkt = ((const unsigned char*)ptr) + hlen; + len -= hlen; + + if (session) + { + printf("len %d\n", len); + while (len > 0) + { + int alen; + const unsigned char *tag = pkt; + pkt += 3; // tag + len -= 3; + hlen = parseLengthField(pkt, alen); + pkt += hlen; + len -= hlen; + + printf("len = %d, hlen = %d, alen = %d\n", len, hlen, alen); + + if (((len - alen) > 0) && ((len - alen) < 3)) + { + printf("WORKAROUND: applying work around MagicAPDULength\n"); + alen = len; + } + + printf("1. Call receivedAPDU tag = 0x%2x, len = %d\n", (int) tag, alen); + + if (session->receivedAPDU(tag, pkt, alen)) + session->action = 1; + pkt += alen; + len -= alen; + } + } + if (len) + printf("PROTOCOL: warning, TL-Data has invalid length\n"); +} + +eDVBCISession::~eDVBCISession() +{ +// printf("destroy %p", this); +} + diff --git a/libdvbci/dvbci_session.h b/libdvbci/dvbci_session.h new file mode 100644 index 0000000..d2bb90c --- /dev/null +++ b/libdvbci/dvbci_session.h @@ -0,0 +1,46 @@ +#ifndef __dvbci_dvbci_tc_h +#define __dvbci_dvbci_tc_h + +#include + +#define SLMS 256 + +class eDVBCISession +{ + static eDVBCISession* sessions[SLMS]; + static eDVBCISession* createSession(tSlot *slot, const unsigned char *resource_identifier, unsigned char &status); + static void sendSPDU(tSlot *slot, unsigned char tag,const void *data, int len, unsigned short session_nb, const void *apdu = 0, int alen = 0); + static void sendOpenSessionResponse(tSlot *slot,unsigned char session_status, const unsigned char *resource_identifier, unsigned short session_nb); + void recvCreateSessionResponse(const unsigned char *data); + void recvCloseSessionRequest(const unsigned char *data); +protected: + int state; + int status; + int action; + tSlot *slot; + unsigned short session_nb; + virtual int receivedAPDU(const unsigned char *tag, const void *data, int len) = 0; + void sendAPDU(const unsigned char *tag, const void *data=0,int len=0); + virtual int doAction() = 0; + void handleClose(); +public: + virtual ~eDVBCISession(); + + static void deleteSessions(const tSlot *slot); + void sendSPDU(unsigned char tag, const void *data, int len, const void *apdu = 0, int alen = 0); + + int poll() { if (action) { action=doAction(); return 1; } return 0; } + enum { stateInCreation, stateBusy, stateInDeletion, stateStarted, statePrivate}; + + static int parseLengthField(const unsigned char *pkt, int &len); + static int buildLengthField(unsigned char *pkt, int len); + + static void receiveData(tSlot *slot, const unsigned char *ptr, size_t len); + + int getState() { return state; } + int getStatus() { return status; } + + static int pollAll(); +}; + +#endif diff --git a/libspark/Makefile.am b/libspark/Makefile.am index 768de2f..10758b8 100644 --- a/libspark/Makefile.am +++ b/libspark/Makefile.am @@ -7,7 +7,7 @@ AM_CPPFLAGS += \ AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing -AM_LDFLAGS = -lpthread -lasound -lass -lrt\ +AM_LDFLAGS = -lpthread -lasound -lass -lrt \ @AVFORMAT_LIBS@ \ @AVUTIL_LIBS@ \ @AVCODEC_LIBS@ \ @@ -24,4 +24,4 @@ libspark_la_SOURCES = \ pwrmngr.cpp \ record.cpp -#AM_CPPFLAGS = -DF_INTERRUPTS=20000 -DIRMP_EMBED -DLIRC_IRMP +#AM_CPPFLAGS += -DF_INTERRUPTS=20000 -DIRMP_EMBED -DLIRC_IRMP diff --git a/libspark/audio_lib.h b/libspark/audio_lib.h index 7e5cb34..5db8e00 100644 --- a/libspark/audio_lib.h +++ b/libspark/audio_lib.h @@ -6,9 +6,9 @@ typedef enum { - AUDIO_SYNC_WITH_PTS, - AUDIO_NO_SYNC, - AUDIO_SYNC_AUDIO_MASTER + AUDIO_SYNC_WITH_PTS, + AUDIO_NO_SYNC, + AUDIO_SYNC_AUDIO_MASTER } AUDIO_SYNC_MODE; typedef enum { @@ -19,20 +19,20 @@ typedef enum { typedef enum { - AUDIO_FMT_AUTO = 0, - AUDIO_FMT_MPEG, - AUDIO_FMT_MP3, - AUDIO_FMT_DOLBY_DIGITAL, - AUDIO_FMT_BASIC = AUDIO_FMT_DOLBY_DIGITAL, - AUDIO_FMT_AAC, - AUDIO_FMT_AAC_PLUS, - AUDIO_FMT_DD_PLUS, - AUDIO_FMT_DTS, - AUDIO_FMT_AVS, - AUDIO_FMT_MLP, - AUDIO_FMT_WMA, - AUDIO_FMT_MPG1, // TD only. For Movieplayer / cPlayback - AUDIO_FMT_ADVANCED = AUDIO_FMT_MLP + AUDIO_FMT_AUTO = 0, + AUDIO_FMT_MPEG, + AUDIO_FMT_MP3, + AUDIO_FMT_DOLBY_DIGITAL, + AUDIO_FMT_BASIC = AUDIO_FMT_DOLBY_DIGITAL, + AUDIO_FMT_AAC, + AUDIO_FMT_AAC_PLUS, + AUDIO_FMT_DD_PLUS, + AUDIO_FMT_DTS, + AUDIO_FMT_AVS, + AUDIO_FMT_MLP, + AUDIO_FMT_WMA, + AUDIO_FMT_MPG1, // TD only. For Movieplayer / cPlayback + AUDIO_FMT_ADVANCED = AUDIO_FMT_MLP } AUDIO_FORMAT; class cAudio diff --git a/libspark/hardware_caps.c b/libspark/hardware_caps.c index 333c9af..73cbde8 100644 --- a/libspark/hardware_caps.c +++ b/libspark/hardware_caps.c @@ -30,6 +30,7 @@ hw_caps_t *get_hwcaps(void) memset(&caps, 0, sizeof(hw_caps_t)); initialized = 1; + caps.has_CI = 0; caps.can_cec = 1; caps.can_shutdown = 1; caps.display_type = HW_DISPLAY_LED_NUM; diff --git a/libspark/mmi.h b/libspark/mmi.h deleted file mode 100644 index 76ff992..0000000 --- a/libspark/mmi.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __MMI_H_ -#define __MMI_H_ - -#define MAX_MMI_ITEMS 40 -#define MAX_MMI_TEXT_LEN 255 -#define MAX_MMI_CHOICE_TEXT_LEN 255 - -typedef struct { - int choice_nb; - char title[MAX_MMI_TEXT_LEN]; - char subtitle[MAX_MMI_TEXT_LEN]; - char bottom[MAX_MMI_TEXT_LEN]; - char choice_item[MAX_MMI_ITEMS][MAX_MMI_CHOICE_TEXT_LEN]; -} MMI_MENU_LIST_INFO; - -typedef struct { - int blind; - int answerlen; - char enguiryText[MAX_MMI_TEXT_LEN]; -} MMI_ENGUIRY_INFO; - -#endif // __MMI_H_ - diff --git a/libspark/playback.cpp b/libspark/playback.cpp deleted file mode 100644 index adb2e67..0000000 --- a/libspark/playback.cpp +++ /dev/null @@ -1,1466 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - -#include -#include "playback_lib.h" -#include "dmx_lib.h" -#include "audio_lib.h" -#include "video_lib.h" -#include "lt_debug.h" -#define lt_debug(args...) _lt_debug(TRIPLE_DEBUG_PLAYBACK, this, args) -#define lt_info(args...) _lt_info(TRIPLE_DEBUG_PLAYBACK, this, args) -#define lt_info_c(args...) _lt_info(TRIPLE_DEBUG_PLAYBACK, NULL, args) - -#define DVR "/dev/dvb/adapter0/pvr0" - -static int mp_syncPES(uint8_t *, int, bool quiet = false); -static int sync_ts(uint8_t *, int); -static inline uint16_t get_pid(uint8_t *buf); -static void *start_playthread(void *c); -static void playthread_cleanup_handler(void *); - -static pthread_cond_t playback_ready_cond = PTHREAD_COND_INITIALIZER; -static pthread_mutex_t playback_ready_mutex = PTHREAD_MUTEX_INITIALIZER; - -static pthread_mutex_t currpos_mutex = PTHREAD_MUTEX_INITIALIZER; - -static int dvrfd = -1; -static int streamtype; - -extern cDemux *videoDemux; -extern cDemux *audioDemux; -extern cVideo *videoDecoder; -extern cAudio *audioDecoder; - -static const char *FILETYPE[] = { - "FILETYPE_UNKNOWN", - "FILETYPE_TS", - "FILETYPE_MPG", - "FILETYPE_VDR" -}; - -cPlayback::cPlayback(int) -{ - lt_debug("%s\n", __FUNCTION__); - thread_started = false; - inbuf = NULL; - pesbuf = NULL; - filelist.clear(); - curr_fileno = -1; - in_fd = -1; - streamtype = 0; -} - -cPlayback::~cPlayback() -{ - lt_debug("%s\n", __FUNCTION__); - Close(); -} - - -bool cPlayback::Open(playmode_t mode) -{ - static const char *PMODE[] = { - "PLAYMODE_TS", - "PLAYMODE_FILE" - }; - - lt_debug("%s: PlayMode = %s\n", __FUNCTION__, PMODE[mode]); - thread_started = false; - playMode = mode; - filetype = FILETYPE_TS; - playback_speed = 0; - last_size = 0; - _pts_end = 0; - astreams.clear(); - memset(&cc, 0, 256); - return true; -} - -//Used by Fileplay -void cPlayback::Close(void) -{ - lt_info("%s\n", __FUNCTION__); - playstate = STATE_STOP; - if (thread_started) - { - lt_info("%s: before pthread_join\n", __FUNCTION__); - pthread_join(thread, NULL); - } - thread_started = false; - lt_info("%s: after pthread_join\n", __FUNCTION__); - mf_close(); - filelist.clear(); - - if (inbuf) - free(inbuf); - inbuf = NULL; - if (pesbuf) - free(pesbuf); - pesbuf = NULL; - //Stop(); -} - -bool cPlayback::Start(char *filename, unsigned short vp, int vtype, unsigned short ap, int _ac3, unsigned int) -{ - struct stat s; - off_t r; - vpid = vp; - apid = ap; - ac3 = _ac3; - lt_info("%s name = '%s' vpid 0x%04hx vtype %d apid 0x%04hx ac3 %d filelist.size: %u\n", - __FUNCTION__, filename, vpid, vtype, apid, ac3, filelist.size()); - if (!filelist.empty()) - { - lt_info("filelist not empty?\n"); - return false; - } - if (stat(filename, &s)) - { - lt_info("filename does not exist? (%m)\n"); - return false; - } - if (!inbuf) - inbuf = (uint8_t *)malloc(INBUF_SIZE); /* 256 k */ - if (!inbuf) - { - lt_info("allocating input buffer failed (%m)\n"); - return false; - } - if (!pesbuf) - pesbuf = (uint8_t *)malloc(PESBUF_SIZE); /* 128 k */ - if (!pesbuf) - { - lt_info("allocating PES buffer failed (%m)\n"); - return false; - } - filelist_t file; - file.Name = std::string(filename); - file.Size = s.st_size; - if (file.Name.rfind(".ts") == file.Name.length() - 3 || - file.Name.rfind(".TS") == file.Name.length() - 3) - filetype = FILETYPE_TS; - else - { - if (file.Name.rfind(".vdr") == file.Name.length() - 4) - { - filetype = FILETYPE_VDR; - std::string::size_type p = file.Name.rfind("info.vdr"); - if (p == std::string::npos) - p = file.Name.rfind("index.vdr"); - if (p != std::string::npos) - { - file.Name.replace(p, std::string::npos, "001.vdr"); - lt_info("replaced filename with '%s'\n", file.Name.c_str()); - if (stat(file.Name.c_str(), &s)) - { - lt_info("filename does not exist? (%m)\n"); - return false; - } - file.Size = s.st_size; - } - } - else - filetype = FILETYPE_MPG; - vpid = 0x40; - } - - lt_info("detected (ok, guessed) filetype: %s\n", FILETYPE[filetype]); - - filelist.push_back(file); - filelist_auto_add(); - if (mf_open(0) < 0) - return false; - - pts_start = pts_end = pts_curr = -1; - pesbuf_pos = 0; - curr_pos = 0; - inbuf_pos = 0; - inbuf_sync = 0; - r = mf_getsize(); - - if (r > INBUF_SIZE) - { - if (mp_seekSync(r - INBUF_SIZE) < 0) - return false; - while(true) { - if (inbuf_read() <= 0) - break; // EOF - if (curr_pos >= r) //just to make sure... - break; - } - if (filetype == FILETYPE_TS) - for (r = (inbuf_pos / 188) * 188; r > 0; r -= 188) - { - pts_end = get_pts(inbuf + r, false, inbuf_pos - r); - if (pts_end > -1) - break; - } - else - pts_end = pts_curr; - } - else - pts_end = -1; /* unknown */ - - if (mp_seekSync(0) < 0) - return false; - - pesbuf_pos = 0; - inbuf_pos = 0; - inbuf_sync = 0; - while (inbuf_pos < INBUF_SIZE / 2 && inbuf_read() > 0) {}; - for (r = 0; r < inbuf_pos - 188; r += 188) - { - pts_start = get_pts(inbuf + r, false, inbuf_pos - r); - if (pts_start > -1) - break; - } - pts_curr = pts_start; - bytes_per_second = -1; - if (pts_end != -1 && pts_start > pts_end) /* PTS overflow during this file */ - pts_end += 0x200000000ULL; - int duration = (pts_end - pts_start) / 90000; - if (duration > 0) - bytes_per_second = mf_getsize() / duration; - lt_info("start: %lld end %lld duration %d bps %lld\n", pts_start, pts_end, duration, bytes_per_second); - /* yes, we start in pause mode... */ - playback_speed = 0; - if (pts_start == -1) - playstate = STATE_INIT; - else - playstate = STATE_PAUSE; - pthread_mutex_lock(&playback_ready_mutex); - if (pthread_create(&thread, 0, start_playthread, this) != 0) - lt_info("pthread_create failed\n"); - else - pthread_cond_wait(&playback_ready_cond, &playback_ready_mutex); - pthread_mutex_unlock(&playback_ready_mutex); - return true; -} - -static void *start_playthread(void *c) -{ - cPlayback *obj = (cPlayback *)c; - obj->playthread(); - return NULL; -} - -void cPlayback::playthread(void) -{ -#if 0 - thread_started = true; - int ret, towrite; - dvrfd = open(DVR, O_WRONLY); - if (dvrfd < 0) - { - lt_info("%s open tdpvr failed: %m\n", __FUNCTION__); - pthread_exit(NULL); - } - fcntl(dvrfd, F_SETFD, FD_CLOEXEC); - - pthread_cleanup_push(playthread_cleanup_handler, 0); - - ioctl(audioDemux->getFD(), DEMUX_SELECT_SOURCE, INPUT_FROM_PVR); - if (ac3) - audioDecoder->SetStreamType(AUDIO_FMT_DOLBY_DIGITAL); - else - { - if (streamtype == 1) /* mpeg 1 */ - audioDecoder->SetStreamType(AUDIO_FMT_MPG1); - else /* default */ - audioDecoder->SetStreamType(AUDIO_FMT_MPEG); - } - - audioDemux->pesFilter(apid); - videoDemux->pesFilter(vpid); - -// audioDemux->Start(); - videoDemux->Start(); - -// videoDecoder->setBlank(1); -// videoDecoder->Start(); -// audioDecoder->Start(); - /* everything is set up now, signal ::Start() that it can return */ - pthread_mutex_lock(&playback_ready_mutex); - pthread_cond_broadcast(&playback_ready_cond); - pthread_mutex_unlock(&playback_ready_mutex); - - while (playstate != STATE_STOP) - { - if (playstate == STATE_INIT) - { - /* hack for timeshift to determine start PTS */ - if (inbuf_read() < 0) - break; - usleep(100000); - if (pts_start == -1) - continue; - } - - if (playback_speed == 0) - { - playstate = STATE_PAUSE; - usleep(1); - continue; - } - if (inbuf_read() < 0) - break; - - /* autoselect PID for PLAYMODE_FILE */ - if (apid == 0 && astreams.size() > 0) - { - for (std::map::iterator aI = astreams.begin(); aI != astreams.end(); aI++) - { - if (!aI->second.ac3) - { - apid = aI->first; - lt_info("%s setting Audio pid to 0x%04hx\n", __FUNCTION__, apid); - SetAPid(apid, 0); - break; - } - } - } - - towrite = inbuf_pos / 188 * 188; /* TODO: smaller chunks? */ - if (towrite == 0) - continue; - retry: - ret = write(dvrfd, inbuf, towrite); - if (ret < 0) - { - if (errno == EAGAIN && playstate != STATE_STOP) - goto retry; - lt_info("%s write dvr failed: %m\n", __FUNCTION__); - break; - } - memmove(inbuf, inbuf + ret, inbuf_pos - ret); - inbuf_pos -= ret; - } - - pthread_cleanup_pop(1); - pthread_exit(NULL); -#endif -} - -static void playthread_cleanup_handler(void *) -{ - lt_info_c("%s\n", __FUNCTION__); -// ioctl(audioDemux->getFD(), DEMUX_SELECT_SOURCE, INPUT_FROM_CHANNEL0); - audioDemux->Stop(); - videoDemux->Stop(); - audioDecoder->Stop(); - videoDecoder->Stop(); - close(dvrfd); - dvrfd = -1; -} - -bool cPlayback::SetAPid(unsigned short pid, int _ac3) -{ - lt_info("%s pid: 0x%04hx ac3: %d\n", __FUNCTION__, pid, _ac3); - apid = pid; - ac3 = _ac3; - - audioDemux->Stop(); - audioDecoder->Stop(); - videoDemux->Stop(); - videoDecoder->Stop(false); - - if (ac3) - audioDecoder->SetStreamType(AUDIO_FMT_DOLBY_DIGITAL); - else - { - if (streamtype == 1) /* mpeg 1 */ - audioDecoder->SetStreamType(AUDIO_FMT_MPG1); - else /* default */ - audioDecoder->SetStreamType(AUDIO_FMT_MPEG); - } - audioDemux->pesFilter(apid); - - videoDemux->Start(); - audioDemux->Start(); - audioDecoder->Start(); - videoDecoder->Start(); - return true; -} - -bool cPlayback::SetSpeed(int speed) -{ - lt_info("%s speed = %d\n", __FUNCTION__, speed); - if (speed < 0) - speed = 1; /* fast rewind not yet implemented... */ - if (speed == 1 && playback_speed != 1) - { - if (playback_speed == 0) - { - videoDemux->Stop(); - videoDemux->Start(); - audioDemux->Start(); - } - else - { - audioDecoder->Stop(); - videoDecoder->Stop(); - } - audioDecoder->Start(); - videoDecoder->Start(); - playstate = STATE_PLAY; - } - if (playback_speed == 1 && speed > 1) - { - audioDecoder->mute(false); - videoDecoder->FastForwardMode(); - } - playback_speed = speed; - if (playback_speed == 0) - { - audioDecoder->Stop(); - audioDemux->Stop(); - videoDecoder->Stop(false); - } - return true; -} - -bool cPlayback::GetSpeed(int &speed) const -{ - lt_debug("%s\n", __FUNCTION__); - speed = playback_speed; - return true; -} - -// in milliseconds -bool cPlayback::GetPosition(int &position, int &duration) -{ - int64_t tmppts; - lt_debug("%s\n", __FUNCTION__); - off_t currsize = mf_getsize(); - bool update = false; - /* handle a growing file, e.g. for timeshift. - this might be pretty expensive... */ - if (filetype == FILETYPE_TS && filelist.size() == 1) - { - off_t tmppos = currsize - PESBUF_SIZE; - if (currsize > last_size && (currsize - last_size) < 10485760 && - bytes_per_second > 0 && _pts_end > 0) - { - /* guess the current endpts... */ - tmppts = (currsize - last_size) * 90000 / bytes_per_second; - pts_end = _pts_end + tmppts; - } - else if (currsize != last_size && tmppos > 0) - { - pthread_mutex_lock(&currpos_mutex); - off_t oldpos = curr_pos; - ssize_t n, r; - int s; - mf_lseek(tmppos); - n = read(in_fd, pesbuf, PESBUF_SIZE); /* abuse the pesbuf... */ - s = sync_ts(pesbuf, n); - if (s >= 0) - { - n -= s; - for (r = (n / 188) * 188; r > 0; r -= 188) - { - tmppts = get_pts(pesbuf + r + s, false, n - r); - if (tmppts > -1) - { - lt_debug("n: %d s: %d endpts %lld size: %lld\n", n, s, tmppts, currsize); - pts_end = tmppts; - _pts_end = tmppts; - update = true; - /* file size has changed => update endpts */ - last_size = currsize; - break; - } - } - } - mf_lseek(oldpos); - pthread_mutex_unlock(&currpos_mutex); - } - } - if (pts_end != -1 && pts_start > pts_end) /* should trigger only once ;) */ - { - pts_end += 0x200000000ULL; - update = true; - } - - if (pts_curr != -1 && pts_curr < pts_start) - tmppts = pts_curr + 0x200000000ULL - pts_start; - else - tmppts = pts_curr - pts_start; - if (pts_end != -1 && pts_curr != -1) - { - position = tmppts / 90; - duration = (pts_end - pts_start) / 90; - if (update && duration >= 4000) - { - bytes_per_second = currsize / (duration / 1000); - lt_debug("%s: updated bps: %lld size: %lld duration %d\n", - __FUNCTION__, bytes_per_second, currsize, duration); - } - return true; - } - position = 0; - duration = 0; - return false; -} - -bool cPlayback::SetPosition(int position, bool absolute) -{ - lt_info("%s pos = %d abs = %d\n", __FUNCTION__, position, absolute); - int currpos, target, duration, oldspeed; - bool ret; - - if (absolute) - target = position; - else - { - GetPosition(currpos, duration); - target = currpos + position; - lt_info("current position %d target %d\n", currpos, target); - } - - oldspeed = playback_speed; -// if (oldspeed != 0) - SetSpeed(0); /* request pause */ - - while (playstate == STATE_PLAY) /* playthread did not acknowledge pause */ - usleep(1); - if (playstate == STATE_STOP) /* we did get stopped by someone else */ - return false; - - ret = (seek_to_pts(target * 90) > 0); - - if (oldspeed != 0) - { - SetSpeed(oldspeed); - /* avoid ugly artifacts */ - videoDecoder->Stop(); - videoDecoder->Start(); - } - return ret; -} - -void cPlayback::FindAllPids(uint16_t *apids, unsigned short *ac3flags, uint16_t *numpida, std::string *language) -{ - lt_info("%s\n", __FUNCTION__); - int i = 0; - for (std::map::iterator aI = astreams.begin(); aI != astreams.end(); aI++) - { - apids[i] = aI->first; - ac3flags[i] = aI->second.ac3 ? 1 : 0; - language[i] = aI->second.lang; - i++; - if (i > 10) /* REC_MAX_APIDS in vcrcontrol.h */ - break; - } - *numpida = i; -} - -off_t cPlayback::seek_to_pts(int64_t pts) -{ - off_t newpos = curr_pos; - int64_t tmppts, ptsdiff; - int count = 0; - if (pts_start < 0 || pts_end < 0 || bytes_per_second < 0) - { - lt_info("%s pts_start (%lld) or pts_end (%lld) or bytes_per_second (%lld) not initialized\n", - __FUNCTION__, pts_start, pts_end, bytes_per_second); - return -1; - } - /* sanity check: buffer is without locking, so we must only seek while in pause mode */ - if (playstate != STATE_PAUSE) - { - lt_info("%s playstate (%d) != STATE_PAUSE, not seeking\n", __FUNCTION__, playstate); - return -1; - } - - /* tmppts is normalized current pts */ - if (pts_curr < pts_start) - tmppts = pts_curr + 0x200000000ULL - pts_start; - else - tmppts = pts_curr - pts_start; - while (abs(pts - tmppts) > 90000LL && count < 10) - { - count++; - ptsdiff = pts - tmppts; - newpos += ptsdiff * bytes_per_second / 90000; - lt_info("%s try #%d seek from %lldms to %lldms dt %lldms pos %lldk newpos %lldk kB/s %lld\n", - __FUNCTION__, count, tmppts / 90, pts / 90, ptsdiff / 90, curr_pos / 1024, newpos / 1024, bytes_per_second / 1024); - if (newpos < 0) - newpos = 0; - newpos = mp_seekSync(newpos); - if (newpos < 0) - return newpos; - inbuf_pos = 0; - inbuf_sync = 0; - while (inbuf_pos < INBUF_SIZE * 8 / 10) { - if (inbuf_read() <= 0) - break; // EOF - } - if (pts_curr < pts_start) - tmppts = pts_curr + 0x200000000ULL - pts_start; - else - tmppts = pts_curr - pts_start; - } - lt_info("%s end after %d tries, ptsdiff now %lld sec\n", __FUNCTION__, count, (pts - tmppts) / 90000); - return newpos; -} - -bool cPlayback::filelist_auto_add() -{ - if (filelist.size() != 1) - return false; - - const char *filename = filelist[0].Name.c_str(); - const char *ext; - ext = strrchr(filename, '.'); // FOO-xxx-2007-12-31.001.ts <- the dot before "ts" - // 001.vdr <- the dot before "vdr" - // check if there is something to do... - if (! ext) - return false; - if (!((ext - 7 >= filename && !strcmp(ext, ".ts") && *(ext - 4) == '.') || - (ext - 4 >= filename && !strcmp(ext, ".vdr")))) - return false; - - int num = 0; - struct stat s; - size_t numpos = strlen(filename) - strlen(ext) - 3; - sscanf(filename + numpos, "%d", &num); - do { - num++; - char nextfile[strlen(filename) + 1]; /* todo: use fixed buffer? */ - memcpy(nextfile, filename, numpos); - sprintf(nextfile + numpos, "%03d%s", num, ext); - if (stat(nextfile, &s)) - break; // file does not exist - filelist_t file; - file.Name = std::string(nextfile); - file.Size = s.st_size; - lt_info("%s auto-adding '%s' to playlist\n", __FUNCTION__, nextfile); - filelist.push_back(file); - } while (true && num < 999); - - return (filelist.size() > 1); -} - -/* the mf_* functions are wrappers for multiple-file I/O */ -int cPlayback::mf_open(int fileno) -{ - if (filelist.empty()) - return -1; - - if (fileno >= (int)filelist.size()) - return -1; - - mf_close(); - - in_fd = open(filelist[fileno].Name.c_str(), O_RDONLY); - fcntl(in_fd, F_SETFD, FD_CLOEXEC); - if (in_fd != -1) - curr_fileno = fileno; - - return in_fd; -} - -int cPlayback::mf_close(void) -{ - int ret = 0; - lt_info("%s in_fd = %d curr_fileno = %d\n", __FUNCTION__, in_fd, curr_fileno); - if (in_fd != -1) - ret = close(in_fd); - in_fd = curr_fileno = -1; - - return ret; -} - -off_t cPlayback::mf_getsize(void) -{ - off_t ret = 0; - if (filelist.size() == 1 && in_fd != -1) - { - /* for timeshift, we need to deal with a growing file... */ - struct stat st; - if (fstat(in_fd, &st) == 0) - return st.st_size; - /* else, fallback to filelist.size() */ - } - for (unsigned int i = 0; i < filelist.size(); i++) - ret += filelist[i].Size; - return ret; -} - -off_t cPlayback::mf_lseek(off_t pos) -{ - off_t offset = 0, lpos = pos, ret; - unsigned int fileno; - /* this is basically needed for timeshifting - to allow - growing files to be handled... */ - if (filelist.size() == 1 && filetype == FILETYPE_TS) - { - if (lpos > mf_getsize()) - return -2; - fileno = 0; - } - else - { - for (fileno = 0; fileno < filelist.size(); fileno++) - { - if (lpos < filelist[fileno].Size) - break; - offset += filelist[fileno].Size; - lpos -= filelist[fileno].Size; - } - if (fileno == filelist.size()) - return -2; // EOF - } - - if ((int)fileno != curr_fileno) - { - lt_info("%s old fileno: %d new fileno: %d, offset: %lld\n", __FUNCTION__, curr_fileno, fileno, (long long)lpos); - in_fd = mf_open(fileno); - if (in_fd < 0) - { - lt_info("cannot open file %d:%s (%m)\n", fileno, filelist[fileno].Name.c_str()); - return -1; - } - } - - ret = lseek(in_fd, lpos, SEEK_SET); - if (ret < 0) - return ret; - - curr_pos = offset + ret; - return curr_pos; -} - -/* gets the PTS at a specific file position from a PES - ATTENTION! resets buf! */ -int64_t cPlayback::get_PES_PTS(uint8_t *buf, int len, bool last) -{ - int64_t pts = -1; - int off, plen; - uint8_t *p; - - off = mp_syncPES(buf, len); - - if (off < 0) - return off; - - p = buf + off; - while (off < len - 14 && (pts == -1 || last)) - { - plen = ((p[4] << 8) | p[5]) + 6; - - switch(p[3]) - { - int64_t tmppts; - case 0xe0 ... 0xef: // video! - tmppts = get_pts(p, true, len - off); - if (tmppts >= 0) - pts = tmppts; - break; - case 0xbb: - case 0xbe: - case 0xbf: - case 0xf0 ... 0xf3: - case 0xff: - case 0xc0 ... 0xcf: - case 0xd0 ... 0xdf: - break; - case 0xb9: - case 0xba: - case 0xbc: - default: - plen = 1; - break; - } - p += plen; - off += plen; - } - return pts; -} - -ssize_t cPlayback::inbuf_read() -{ - if (filetype == FILETYPE_UNKNOWN) - return -1; - if (filetype == FILETYPE_TS) - return read_ts(); - /* FILETYPE_MPG or FILETYPE_VDR */ - return read_mpeg(); -} - -ssize_t cPlayback::read_ts() -{ - ssize_t toread, ret = 0, sync, off; - toread = INBUF_SIZE - inbuf_pos; - bool retry = true; - uint8_t *buf; - /* fprintf(stderr, "%s:%d curr_pos %lld, inbuf_pos: %ld, toread: %ld\n", - __FUNCTION__, __LINE__, (long long)curr_pos, (long)inbuf_pos, (long)toread); */ - - if (playback_speed > 1) - { - sync = 0; - ssize_t tmpread = PESBUF_SIZE / 188 * 188; - int n, skipped = 0; - bool skip = false; - bool eof = true; - pthread_mutex_lock(&currpos_mutex); - while (toread > 0) - { - ssize_t done = 0; - while (done < tmpread) - { - ret = read(in_fd, pesbuf, tmpread - done); - if (ret == 0 && retry) /* EOF */ - { - mf_lseek(curr_pos); - retry = false; - continue; - } - if (ret < 0) - { - lt_info("%s failed1: %m\n", __FUNCTION__); - pthread_mutex_unlock(&currpos_mutex); - return ret; - } - if (ret == 0 && eof) - goto out; - eof = false; - done += ret; - curr_pos += ret; - } - sync = sync_ts(pesbuf, ret); - if (sync != 0) - { - lt_info("%s out of sync: %d\n", __FUNCTION__, sync); - if (sync < 0) - { - pthread_mutex_unlock(&currpos_mutex); - return -1; - } - memmove(pesbuf, pesbuf + sync, ret - sync); - if (pesbuf[0] != 0x47) - lt_info("%s:%d??????????????????????????????\n", __FUNCTION__, __LINE__); - } - for (n = 0; n < done / 188 * 188; n += 188) - { - buf = pesbuf + n; - if (buf[1] & 0x40) // PUSI - { - /* only video packets... */ - int of = 4; - if (buf[3] & 0x20) // adaptation field - of += buf[4] + 1; - if ((buf[of + 3] & 0xF0) == 0xE0 && // Video stream - buf[of + 2] == 0x01 && buf[of + 1] == 0x00 && buf[of] == 0x00) // PES - { - skip = true; - skipped++; - if (skipped >= playback_speed) - { - skipped = 0; - skip = false; - } - } - } - if (! skip) - { - memcpy(inbuf + inbuf_pos, buf, 188); - inbuf_pos += 188; - toread -= 188; - if (toread <= 0) - { - /* the output buffer is full, discard the input :-( */ - if (done - n > 0) - { - lt_debug("%s not done: %d, resetting filepos\n", - __FUNCTION__, done - n); - mf_lseek(curr_pos - (done - n)); - } - break; - } - } - } - } - out: - pthread_mutex_unlock(&currpos_mutex); - if (eof) - return 0; - } - else - { - pthread_mutex_lock(&currpos_mutex); - while(true) - { - ret = read(in_fd, inbuf + inbuf_pos, toread); - if (ret == 0 && retry) /* EOF */ - { - mf_lseek(curr_pos); - retry = false; - continue; - } - break; - } - if (ret <= 0) - { - pthread_mutex_unlock(&currpos_mutex); - if (ret < 0) - lt_info("%s failed2: %m\n", __FUNCTION__); - return ret; - } - inbuf_pos += ret; - curr_pos += ret; - pthread_mutex_unlock(&currpos_mutex); - - sync = sync_ts(inbuf + inbuf_sync, INBUF_SIZE - inbuf_sync); - if (sync < 0) - { - lt_info("%s cannot sync\n", __FUNCTION__); - return ret; - } - inbuf_sync += sync; - } - /* check for A/V PIDs */ - uint16_t pid; - int i; - int64_t pts; - //fprintf(stderr, "inbuf_pos: %ld - sync: %ld, inbuf_syc: %ld\n", (long)inbuf_pos, (long)sync, (long)inbuf_sync); - int synccnt = 0; - for (i = 0; i < inbuf_pos - inbuf_sync - 13;) { - buf = inbuf + inbuf_sync + i; - if (*buf != 0x47) - { - synccnt++; - i++; - continue; - } - if (synccnt) - lt_info("%s TS went out of sync %d\n", __FUNCTION__, synccnt); - synccnt = 0; - if (!(buf[1] & 0x40)) /* PUSI */ - { - i += 188; - continue; - } - off = 0; - if (buf[3] & 0x20) /* adaptation field? */ - off = buf[4] + 1; - pid = get_pid(buf + 1); - /* PES signature is at buf + 4, streamtype is after 00 00 01 */ - switch (buf[4 + 3 + off]) - { - case 0xe0 ... 0xef: /* video stream */ - if (vpid == 0) - vpid = pid; - pts = get_pts(buf + 4 + off, true, inbuf_pos - inbuf_sync - i - off - 4); - if (pts < 0) - break; - pts_curr = pts; - if (pts_start < 0) - { - lt_info("%s updating pts_start to %lld ", __FUNCTION__, pts); - pts_start = pts; - if (pts_end > -1) - { - if (pts_end < pts_start) - { - pts_end += 0x200000000ULL; - fprintf(stderr, "pts_end to %lld ", pts_end); - } - int duration = (pts_end - pts_start) / 90000; - if (duration > 0) - { - bytes_per_second = (mf_getsize() - curr_pos) / duration; - fprintf(stderr, "bytes_per_second to %lldk duration to %ds at %lldk", - bytes_per_second / 1024, duration, curr_pos / 1024); - } - } - fprintf(stderr, "\n"); - } - break; - case 0xbd: /* private stream 1 - ac3 */ - case 0xc0 ... 0xdf: /* audio stream */ - if (astreams.find(pid) != astreams.end()) - break; - AStream tmp; - if (buf[7 + off] == 0xbd) - { - if (buf[12 + off] == 0x24) /* 0x24 == TTX */ - break; - tmp.ac3 = true; - } - else - tmp.ac3 = false; - tmp.lang = ""; - astreams.insert(std::make_pair(pid, tmp)); - lt_info("%s found apid #%d 0x%04hx ac3:%d\n", __func__, astreams.size(), pid, tmp.ac3); - break; - } - i += 188; - } - - // fprintf(stderr, "%s:%d ret %ld\n", __FUNCTION__, __LINE__, (long long)ret); - return ret; -} - -ssize_t cPlayback::read_mpeg() -{ - ssize_t toread, ret, sync; - //toread = PESBUF_SIZE - pesbuf_pos; - /* experiments found, that 80kB is the best buffer size, otherwise a/v sync seems - to suffer and / or audio stutters */ - toread = 80 * 1024 - pesbuf_pos; - bool retry = true; - - if (INBUF_SIZE - inbuf_pos < toread) - { - lt_info("%s inbuf full, setting toread to %d (old: %zd)\n", __FUNCTION__, INBUF_SIZE - inbuf_pos, toread); - toread = INBUF_SIZE - inbuf_pos; - } - pthread_mutex_lock(&currpos_mutex); - while(true) - { - ret = read(in_fd, pesbuf + pesbuf_pos, toread); - if (ret == 0 && retry) /* EOF */ - { - mf_lseek(curr_pos); - retry = false; - continue; - } - break; - } - if (ret < 0) - { - pthread_mutex_unlock(&currpos_mutex); - lt_info("%s failed: %m, pesbuf_pos: %zd, toread: %zd\n", __FUNCTION__, pesbuf_pos, toread); - return ret; - } - pesbuf_pos += ret; - curr_pos += ret; - pthread_mutex_unlock(&currpos_mutex); - - int count = 0; - uint16_t pid = 0; - bool resync = true; - while (count < pesbuf_pos - 10) - { - if (resync) - { - sync = mp_syncPES(pesbuf + count, pesbuf_pos - count - 10); - if (sync < 0) - { - if (pesbuf_pos - count - 10 > 4) - lt_info("%s cannot sync (count=%d, pesbuf_pos=%zd)\n", - __FUNCTION__, count, pesbuf_pos); - break; - } - if (sync) - lt_info("%s needed sync %zd\n", __FUNCTION__, sync); - count += sync; - } - uint8_t *ppes = pesbuf + count; - int av = 0; // 1 = video, 2 = audio - int64_t pts; - switch(ppes[3]) - { - case 0xba: //pack header; - // fprintf(stderr, "pack start code, 0x%02x\n", ppes[4]); - if ((ppes[4] & 0xf0) == 0x20) /* mpeg 1 */ - { - streamtype = 1; /* for audio setup */ - count += 12; - } - else if ((ppes[4] & 0xc0) == 0x40) /* mpeg 2 */ - { - streamtype = 0; - count += 14; /* correct: 14 + (ppes[13] & 0x07) */ - } - else - { - lt_info("%s weird pack header: 0x%2x\n", __FUNCTION__, ppes[4]); - count++; - } - resync = true; - continue; - break; - case 0xbd: // AC3 - { - int off = ppes[8] + 8 + 1; // ppes[8] is often 0 - if (count + off >= pesbuf_pos) - break; - uint16_t subid = ppes[off]; - // if (offset == 0x24 && subid == 0x10 ) // TTX? - if (subid < 0x80 || subid > 0x87) - break; - lt_debug("AC3: ofs 0x%02x subid 0x%02x\n", off, subid); - //subid -= 0x60; // normalize to 32...39 (hex 0x20..0x27) - - if (astreams.find(subid) == astreams.end()) - { - AStream tmp; - tmp.ac3 = true; - tmp.lang = ""; - astreams.insert(std::make_pair(subid, tmp)); - lt_info("%s found aid: %02x\n", __FUNCTION__, subid); - } - pid = subid; - av = 2; - break; - } - case 0xbb: - case 0xbe: - case 0xbf: - case 0xf0 ... 0xf3: - case 0xff: - //skip = (ppes[4] << 8 | ppes[5]) + 6; - //DBG("0x%02x header, skip = %d\n", ppes[3], skip); - break; - case 0xc0 ... 0xcf: - case 0xd0 ... 0xdf: - { - // fprintf(stderr, "audio stream 0x%02x\n", ppes[3]); - uint16_t id = ppes[3]; - if (astreams.find(id) == astreams.end()) - { - AStream tmp; - tmp.ac3 = false; - tmp.lang = ""; - astreams.insert(std::make_pair(id, tmp)); - lt_info("%s found aid: %02x\n", __FUNCTION__, id); - } - pid = id; - av = 2; - break; - } - case 0xe0 ... 0xef: - // fprintf(stderr, "video stream 0x%02x, %02x %02x \n", ppes[3], ppes[4], ppes[5]); - pid = 0x40; - av = 1; - pts = get_pts(ppes, true, pesbuf_pos - count); - if (pts < 0) - break; - pts_curr = pts; - if (pts_start < 0) - pts_start = pts; - break; - case 0xb9: - case 0xbc: - lt_debug("%s:%d %s\n", __FUNCTION__, __LINE__, - (ppes[3] == 0xb9) ? "program_end_code" : "program_stream_map"); - //resync = true; - // fallthrough. TODO: implement properly. - default: - //if (! resync) - // DBG("Unknown stream id: 0x%X.\n", ppes[3]); - count++; - resync = true; - continue; - break; - } - - int pesPacketLen = ((ppes[4] << 8) | ppes[5]) + 6; - if (count + pesPacketLen >= pesbuf_pos) - { - lt_debug("buffer len: %ld, pesPacketLen: %d :-(\n", pesbuf_pos - count, pesPacketLen); - break; - } - - int tsPacksCount = pesPacketLen / 184; - if ((tsPacksCount + 1) * 188 > INBUF_SIZE - inbuf_pos) - { - lt_info("not enough size in inbuf (needed %d, got %d)\n", (tsPacksCount + 1) * 188, INBUF_SIZE - inbuf_pos); - break; - } - - if (av) - { - int rest = pesPacketLen % 184; - - // divide PES packet into small TS packets - uint8_t pusi = 0x40; - int j; - uint8_t *ts = inbuf + inbuf_pos; - for (j = 0; j < tsPacksCount; j++) - { - ts[0] = 0x47; // SYNC Byte - ts[1] = pusi; // Set PUSI if first packet - ts[2] = pid; // PID (low) - ts[3] = 0x10 | (cc[pid] & 0x0F); // No adaptation field, payload only, continuity counter - cc[pid]++; - memcpy(ts + 4, ppes + j * 184, 184); - pusi = 0x00; // clear PUSI - ts += 188; - inbuf_pos += 188; - } - - if (rest > 0) - { - ts[0] = 0x47; // SYNC Byte - ts[1] = pusi; // Set PUSI or - ts[2] = pid; // PID (low) - ts[3] = 0x30 | (cc[pid] & 0x0F); // adaptation field, payload, continuity counter - cc[pid]++; - ts[4] = 183 - rest; - if (ts[4] > 0) - { - ts[5] = 0x00; - memset(ts + 6, 0xFF, ts[4] - 1); - } - memcpy(ts + 188 - rest, ppes + j * 184, rest); - inbuf_pos += 188; - } - } //if (av) - - count += pesPacketLen; - } - memmove(pesbuf, pesbuf + count, pesbuf_pos - count); - pesbuf_pos -= count; - return ret; -} - -//== seek to pos with sync to next proper TS packet == -//== returns offset to start of TS packet or actual == -//== pos on failure. == -//==================================================== -off_t cPlayback::mp_seekSync(off_t pos) -{ - off_t npos = pos; - off_t ret; - uint8_t pkt[1024]; - - pthread_mutex_lock(&currpos_mutex); - ret = mf_lseek(npos); - if (ret < 0) - lt_info("%s:%d lseek ret < 0 (%m)\n", __FUNCTION__, __LINE__); - - if (filetype != FILETYPE_TS) - { - int offset = 0; - int s; - ssize_t r; - bool retry = false; - while (true) - { - r = read(in_fd, &pkt[offset], 1024 - offset); - if (r < 0) - { - lt_info("%s read failed: %m\n", __FUNCTION__); - break; - } - if (r == 0) // EOF? - { - if (retry) - break; - if (mf_lseek(npos) < 0) /* next file in list? */ - { - lt_info("%s:%d lseek ret < 0 (%m)\n", __FUNCTION__, __LINE__); - break; - } - retry = true; - continue; - } - s = mp_syncPES(pkt, r + offset, true); - if (s < 0) - { - /* if the last 3 bytes of the buffer were 00 00 01, then - mp_sync_PES would not find it. So keep them and check - again in the next iteration */ - memmove(pkt, &pkt[r + offset - 3], 3); - npos += r; - offset = 3; - } - else - { - npos += s; - lt_info("%s sync after %lld\n", __FUNCTION__, npos - pos); - ret = mf_lseek(npos); - pthread_mutex_unlock(&currpos_mutex); - if (ret < 0) - lt_info("%s:%d lseek ret < 0 (%m)\n", __FUNCTION__, __LINE__); - return ret; - } - if (npos > (pos + 0x20000)) /* 128k enough? */ - break; - } - lt_info("%s could not sync to PES offset: %d r: %zd\n", __FUNCTION__, offset, r); - ret = mf_lseek(pos); - pthread_mutex_unlock(&currpos_mutex); - return ret; - } - - /* TODO: use bigger buffer here, too and handle EOF / next splitfile */ - while (read(in_fd, pkt, 1) > 0) - { - //-- check every byte until sync word reached -- - npos++; - if (*pkt == 0x47) - { - //-- if found double check for next sync word -- - if (read(in_fd, pkt, 188) == 188) - { - if(pkt[188-1] == 0x47) - { - ret = mf_lseek(npos - 1); // assume sync ok - pthread_mutex_unlock(&currpos_mutex); - if (ret < 0) - lt_info("%s:%d lseek ret < 0 (%m)\n", __FUNCTION__, __LINE__); - return ret; - } - else - { - ret = mf_lseek(npos); // oops, next pkt doesn't start with sync - if (ret < 0) - lt_info("%s:%d lseek ret < 0 (%m)\n", __FUNCTION__, __LINE__); - } - } - } - - //-- check probe limits -- - if (npos > (pos + 100 * 188)) - break; - } - - //-- on error stay on actual position -- - ret = mf_lseek(pos); - pthread_mutex_unlock(&currpos_mutex); - return ret; -} - -static int sync_ts(uint8_t *p, int len) -{ - int count; - if (len < 189) - return -1; - - count = 0; - while (*p != 0x47 || *(p + 188) != 0x47) - { - count++; - p++; - if (count + 188 > len) - return -1; - } - return count; -} - -/* get the pts value from a TS or PES packet - pes == true selects PES mode. */ -int64_t cPlayback::get_pts(uint8_t *p, bool pes, int bufsize) -{ - const uint8_t *end = p + bufsize; /* check for overflow */ - if (bufsize < 14) - return -1; - if (!pes) - { - if (p[0] != 0x47) - return -1; - if (!(p[1] & 0x40)) - return -1; - if (get_pid(p + 1) != vpid) - return -1; - if (!(p[3] & 0x10)) - return -1; - - if (p[3] & 0x20) - p += p[4] + 4 + 1; - else - p += 4; - - if (p + 13 > end) - return -1; - /* p is now pointing at the PES header. hopefully */ - if (p[0] || p[1] || (p[2] != 1)) - return -1; - } - - if ((p[6] & 0xC0) != 0x80) // MPEG1 - { - p += 6; - while (*p == 0xff) - { - p++; - if (p > end) - return -1; - } - if ((*p & 0xc0) == 0x40) - p += 2; - p -= 9; /* so that the p[9]...p[13] matches the below */ - if (p + 13 > end) - return -1; - } - else - { - /* MPEG2 */ - if ((p[7] & 0x80) == 0) // packets with both pts, don't care for dts - // if ((p[7] & 0xC0) != 0x80) // packets with only pts - // if ((p[7] & 0xC0) != 0xC0) // packets with pts and dts - return -1; - if (p[8] < 5) - return -1; - } - - if (!(p[9] & 0x20)) - return -1; - - int64_t pts = - ((p[ 9] & 0x0EULL) << 29) | - ((p[10] & 0xFFULL) << 22) | - ((p[11] & 0xFEULL) << 14) | - ((p[12] & 0xFFULL) << 7) | - ((p[13] & 0xFEULL) >> 1); - - //int msec = pts / 90; - //INFO("time: %02d:%02d:%02d\n", msec / 3600000, (msec / 60000) % 60, (msec / 1000) % 60); - return pts; -} - -/* returns: 0 == was already synchronous, > 0 == is now synchronous, -1 == could not sync */ -static int mp_syncPES(uint8_t *buf, int len, bool quiet) -{ - int ret = 0; - while (ret < len - 4) - { - if (buf[ret + 2] != 0x01) - { - ret++; - continue; - } - if (buf[ret + 1] != 0x00) - { - ret += 2; - continue; - } - if (buf[ret] != 0x00) - { - ret += 3; - continue; - } - /* all stream IDs are > 0x80 */ - if ((buf[ret + 3] & 0x80) != 0x80) - { - /* we already checked for 00 00 01, if the stream ID - is not valid, we can skip those 3 bytes */ - ret += 3; - continue; - } - return ret; - } - - if (!quiet && len > 5) /* only warn if enough space was available... */ - lt_info_c("%s No valid PES signature found. %d Bytes deleted.\n", __FUNCTION__, ret); - return -1; -} - -static inline uint16_t get_pid(uint8_t *buf) -{ - return (*buf & 0x1f) << 8 | *(buf + 1); -} - diff --git a/libspark/playback_lib.h b/libspark/playback_lib.h deleted file mode 100644 index dcb78e3..0000000 --- a/libspark/playback_lib.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef __PLAYBACK_TD_H -#define __PLAYBACK_TD_H - -#include -#include -#include -#include - -/* almost 256kB */ -#define INBUF_SIZE (1394 * 188) -#define PESBUF_SIZE (128 * 1024) - -typedef enum { - PLAYMODE_TS = 0, - PLAYMODE_FILE, -} playmode_t; - -typedef enum { - FILETYPE_UNKNOWN, - FILETYPE_TS, - FILETYPE_MPG, - FILETYPE_VDR -} filetype_t; - -typedef enum { - STATE_STOP, - STATE_PLAY, - STATE_PAUSE, - STATE_FF, - STATE_REW, - STATE_INIT -} playstate_t; - -typedef struct { - std::string Name; - off_t Size; -} filelist_t; - -class cPlayback -{ - private: - uint8_t *inbuf; - ssize_t inbuf_pos; - ssize_t inbuf_sync; - uint8_t *pesbuf; - ssize_t pesbuf_pos; - ssize_t inbuf_read(void); - ssize_t read_ts(void); - ssize_t read_mpeg(void); - - uint8_t cc[256]; - - int in_fd; - - int video_type; - int playback_speed; - int mSpeed; - playmode_t playMode; - std::vector filelist; /* for multi-file playback */ - - bool filelist_auto_add(void); - int mf_open(int fileno); - int mf_close(void); - off_t mf_lseek(off_t pos); - off_t mf_getsize(void); - int curr_fileno; - off_t curr_pos; - off_t last_size; - off_t bytes_per_second; - - uint16_t vpid; - uint16_t apid; - bool ac3; - struct AStream { - // uint16_t pid; - bool ac3; - std::string lang; /* not yet really used */ - }; - std::map astreams; /* stores AStream sorted by pid */ - - int64_t pts_start; - int64_t pts_end; - int64_t _pts_end; /* last good endpts */ - int64_t pts_curr; - int64_t get_pts(uint8_t *p, bool pes, int bufsize); - - filetype_t filetype; - playstate_t playstate; - - off_t seek_to_pts(int64_t pts); - off_t mp_seekSync(off_t pos); - int64_t get_PES_PTS(uint8_t *buf, int len, bool until_eof); - - pthread_t thread; - bool thread_started; - public: - cPlayback(int num = 0); - ~cPlayback(); - - void playthread(); - - bool Open(playmode_t PlayMode); - void Close(void); - bool Start(char *filename, unsigned short vpid, int vtype, unsigned short apid, - int ac3, unsigned int duration); - bool SetAPid(unsigned short pid, int ac3); - bool SetSpeed(int speed); - bool GetSpeed(int &speed) const; - bool GetPosition(int &position, int &duration); /* pos: current time in ms, dur: file length in ms */ - bool SetPosition(int position, bool absolute = false); /* position: jump in ms */ - void FindAllPids(uint16_t *apids, unsigned short *ac3flags, uint16_t *numpida, std::string *language); -#if 0 - // Functions that are not used by movieplayer.cpp: - bool Stop(void); - bool GetOffset(off64_t &offset); - bool IsPlaying(void) const { return playing; } - bool IsEnabled(void) const { return enabled; } - void * GetHandle(void); - void * GetDmHandle(void); - int GetCurrPlaybackSpeed(void) const { return nPlaybackSpeed; } - void PlaybackNotify (int Event, void *pData, void *pTag); - void DMNotify(int Event, void *pTsBuf, void *Tag); -#endif -}; -#endif diff --git a/libspark/playback_libeplayer3.cpp b/libspark/playback_libeplayer3.cpp index 2dfcbf4..99c3034 100644 --- a/libspark/playback_libeplayer3.cpp +++ b/libspark/playback_libeplayer3.cpp @@ -168,7 +168,7 @@ bool cPlayback::SetSpeed(int speed) bool cPlayback::GetSpeed(int &speed) const { - speed = nPlaybackSpeed; + speed = nPlaybackSpeed; return true; } @@ -307,6 +307,28 @@ int cPlayback::GetFirstTeletextPid(void) return -1; } +/* dummy functions for subtitles */ +void cPlayback::FindAllSubs(uint16_t * /*pids*/, unsigned short * /*supp*/, uint16_t *num, std::string * /*lang*/) +{ + *num = 0; +} + +bool cPlayback::SelectSubtitles(int pid) +{ + return false; +} + +void cPlayback::GetTitles(std::vector &playlists, std::vector &titles, int ¤t) +{ + playlists.clear(); + titles.clear(); + current = 0; +} + +void cPlayback::SetTitle(int /*title*/) +{ +} + void cPlayback::GetChapters(std::vector &positions, std::vector &titles) { player->GetChapters(positions, titles); diff --git a/libspark/playback_libeplayer3.h b/libspark/playback_libeplayer3.h index 0929223..bfbe5fd 100644 --- a/libspark/playback_libeplayer3.h +++ b/libspark/playback_libeplayer3.h @@ -52,10 +52,10 @@ class cPlayback void RequestAbort(void); bool IsPlaying(void); uint64_t GetReadCount(void); -#if 0 void FindAllSubs(uint16_t *pids, unsigned short *supported, uint16_t *numpida, std::string *language); bool SelectSubtitles(int pid); -#endif + void GetTitles(std::vector &playlists, std::vector &titles, int ¤t); + void SetTitle(int title); void GetChapters(std::vector &positions, std::vector &titles); void GetMetadata(std::vector &keys, std::vector &values); #if 0 diff --git a/libspark/pwrmngr.cpp b/libspark/pwrmngr.cpp index d51074b..b5ab30a 100644 --- a/libspark/pwrmngr.cpp +++ b/libspark/pwrmngr.cpp @@ -14,7 +14,7 @@ void cCpuFreqManager::Down(void) { lt_debug("%s\n", __FUNCTION__); } void cCpuFreqManager::Reset(void) { lt_debug("%s\n", __FUNCTION__); } /* those function dummies return true or "harmless" values */ bool cCpuFreqManager::SetDelta(unsigned long) { lt_debug("%s\n", __FUNCTION__); return true; } -#if HAVE_SPARK_HARDWARE +#if HAVE_SPARK_HARDWARE || HAVE_DUCKBOX_HARDWARE unsigned long cCpuFreqManager::GetCpuFreq(void) { int freq = 0; if (FILE *pll0 = fopen("/proc/cpu_frequ/pll0_ndiv_mdiv", "r")) { @@ -48,7 +48,7 @@ bool cPowerManager::SetStandby(bool Active, bool Passive) bool cCpuFreqManager::SetCpuFreq(unsigned long f) { -#if HAVE_SPARK_HARDWARE +#if HAVE_SPARK_HARDWARE || HAVE_DUCKBOX_HARDWARE if (f) { FILE *pll0 = fopen ("/proc/cpu_frequ/pll0_ndiv_mdiv", "w"); if (pll0) { diff --git a/libspark/record.cpp b/libspark/record.cpp index ad8a5cf..09a3ff2 100644 --- a/libspark/record.cpp +++ b/libspark/record.cpp @@ -183,11 +183,13 @@ void cRecord::RecordThread() prctl (PR_SET_NAME, (unsigned long)&threadname); int readsize = bufsize/16; int buf_pos = 0; + int count = 0; int queued = 0; uint8_t *buf; struct aiocb a; buf = (uint8_t *)malloc(bufsize); + lt_info("BUFSIZE=0x%x READSIZE=0x%x\n", bufsize, readsize); if (!buf) { exit_flag = RECORD_FAILED_MEMORY; @@ -237,6 +239,15 @@ void cRecord::RecordThread() { overflow = false; buf_pos += s; + if (count > 100) + { + if (buf_pos < bufsize / 2) + continue; + } + else + { + count += 1; + } } } else diff --git a/libspark/td-compat/td-audio-compat.h b/libspark/td-compat/td-audio-compat.h deleted file mode 100644 index 3e0b4a7..0000000 --- a/libspark/td-compat/td-audio-compat.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * compatibility stuff for Tripledragon audio API - * - * (C) 2009 Stefan Seyfried - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef __td_audio_compat_h__ -#define __td_audio_compat_h__ - -#include -// types -typedef enum { - AUDIO_SOURCE_DEMUX = AUD_SOURCE_DEMUX, - AUDIO_SOURCE_MEMORY = AUD_SOURCE_MEMORY -} audio_stream_source_t; -#define audio_channel_select_t audChannel_t -// ioctls -#define AUDIO_CHANNEL_SELECT MPEG_AUD_SELECT_CHANNEL -#define AUDIO_SELECT_SOURCE MPEG_AUD_SELECT_SOURCE -#define AUDIO_PLAY MPEG_AUD_PLAY -#define AUDIO_STOP MPEG_AUD_STOP -#define AUDIO_SET_MUTE MPEG_AUD_SET_MUTE - -#endif /* __td_audio_compat_h__ */ diff --git a/libspark/td-compat/td-demux-compat.h b/libspark/td-compat/td-demux-compat.h deleted file mode 100644 index 8feacfe..0000000 --- a/libspark/td-compat/td-demux-compat.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * compatibility stuff for Tripledragon demux API - * - * (C) 2009 Stefan Seyfried - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef __td_demux_compat_h__ -#define __td_demux_compat_h__ - -#include -#include -// types -#define dmx_output_t OutDevice -#define dmx_pes_type_t PesType -#define dmx_sct_filter_params demux_filter_para -#define dmx_pes_filter_params demux_pes_para -#define pes_type pesType -// defines -#define DMX_FILTER_SIZE FILTER_LENGTH -#define DMX_ONESHOT XPDF_ONESHOT -#define DMX_CHECK_CRC 0 // TD checks CRC by default -#define DMX_IMMEDIATE_START XPDF_IMMEDIATE_START -#define DMX_OUT_DECODER OUT_DECODER -// ioctls -#define DMX_SET_FILTER DEMUX_FILTER_SET -#define DMX_SET_PES_FILTER DEMUX_FILTER_PES_SET -#define DMX_START DEMUX_START -#define DMX_STOP DEMUX_STOP -#define DMX_SET_BUFFER_SIZE DEMUX_SET_BUFFER_SIZE - -#endif /* __td_demux_compat_h__ */ diff --git a/libspark/td-compat/td-frontend-compat.h b/libspark/td-compat/td-frontend-compat.h deleted file mode 100644 index 46781ce..0000000 --- a/libspark/td-compat/td-frontend-compat.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * compatibility stuff for Tripledragon frontend API - * - * (C) 2009 Stefan Seyfried - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef __td_frontend_compat_h__ -#define __td_frontend_compat_h__ - -#ifdef __cplusplus -extern "C" { -#endif - #include -#ifdef __cplusplus -} -#endif - -/* I know that those are different. But functions that get a - dvb_frontend_parameters struct passed on dbox/dreambox will most likely - get a tunersetup struct on TD, so it keeps the differences in headers - and function prototypes small. Of course, the functions itself will have - #ifdef TRIPLEDRAGON or similar... */ -#define dvb_frontend_parameters tunersetup - -/* compat stuff for settings.cpp */ -enum { - INVERSION_OFF, - INVERSION_ON, - INVERSION_AUTO -}; -typedef enum fe_code_rate { - FEC_NONE = 0, - FEC_1_2, - FEC_2_3, - FEC_3_4, - FEC_4_5, - FEC_5_6, - FEC_6_7, - FEC_7_8, - FEC_8_9, - FEC_AUTO -} fe_code_rate_t; - -enum td_code_rate { - TD_FEC_AUTO = 0, - TD_FEC_1_2, - TD_FEC_2_3, - TD_FEC_3_4, - TD_FEC_5_6, - TD_FEC_7_8 -}; - -typedef enum fe_sec_tone_mode { - SEC_TONE_ON, - SEC_TONE_OFF -} fe_sec_tone_mode_t; - -typedef enum fe_sec_voltage { - SEC_VOLTAGE_13, - SEC_VOLTAGE_18, - SEC_VOLTAGE_OFF -} fe_sec_voltage_t; - -typedef enum fe_sec_mini_cmd { - SEC_MINI_A, - SEC_MINI_B -} fe_sec_mini_cmd_t; - -struct dvb_diseqc_master_cmd { - unsigned char msg [6]; /* { framing, address, command, data [3] } */ - unsigned char msg_len; /* valid values are 3...6 */ -}; - -typedef enum fe_type { - FE_QPSK, - FE_QAM, - FE_OFDM, - FE_ATSC -} fe_type_t; - -struct dvb_frontend_info { -// char name[128]; - fe_type_t type; -#if 0 - __u32 frequency_min; - __u32 frequency_max; - __u32 frequency_stepsize; - __u32 frequency_tolerance; - __u32 symbol_rate_min; - __u32 symbol_rate_max; - __u32 symbol_rate_tolerance; /* ppm */ - __u32 notifier_delay; /* DEPRECATED */ - fe_caps_t caps; -#endif -}; - -struct dvb_frontend_event { - fe_status_t status; - tunersetup parameters; -}; - -#ifdef _DVBFRONTEND_H_ -#error _DVBFRONTEND_H_ included -#endif - -#endif /* __td_frontend_compat_h__ */ diff --git a/libspark/td-compat/td-value-compat.h b/libspark/td-compat/td-value-compat.h deleted file mode 100644 index f7bb952..0000000 --- a/libspark/td-compat/td-value-compat.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * compatibility stuff for conversion of Tripledragon API values to DVB API - * and vice versa - * - * (C) 2009 Stefan Seyfried - * - * Released under the GPL V2. - */ - -#ifndef _td_value_compat_ -#define _td_value_compat_ - -#undef FE_GET_INFO -#undef FE_READ_BER -#undef FE_READ_SIGNAL_STRENGTH -#undef FE_READ_SNR -#undef FE_READ_UNCORRECTED_BLOCKS -#undef FE_GET_EVENT -#undef FE_READ_STATUS -#undef FE_SET_PROPERTY -#undef FE_GET_EVENT -#undef FE_GET_EVENT -#undef FE_SET_PROPERTY -#undef FE_SET_TONE -#undef FE_ENABLE_HIGH_LNB_VOLTAGE -#undef FE_SET_VOLTAGE -#undef FE_DISEQC_SEND_MASTER_CMD -#undef FE_DISEQC_SEND_BURST -/* hack, linux/dvb/frontend.h already defines fe_status */ -#define fe_status td_fe_status -#define fe_status_t td_fe_status_t -#define FE_HAS_SIGNAL TD_FE_HAS_SIGNAL -#define FE_HAS_CARRIER TD_FE_HAS_CARRIER -#define FE_HAS_VITERBI TD_FE_HAS_VITERBI -#define FE_HAS_SYNC TD_FE_HAS_SYNC -#define FE_HAS_LOCK TD_FE_HAS_LOCK -#define FE_TIMEDOUT TD_FE_TIMEDOUT -#define FE_REINIT TD_FE_REINIT -#include -#undef fe_status -#undef fe_status_t -#undef FE_HAS_SIGNAL -#undef FE_HAS_CARRIER -#undef FE_HAS_VITERBI -#undef FE_HAS_SYNC -#undef FE_HAS_LOCK -#undef FE_TIMEDOUT -#undef FE_REINIT -enum td_code_rate { - TD_FEC_AUTO = 0, - TD_FEC_1_2, - TD_FEC_2_3, - TD_FEC_3_4, - TD_FEC_5_6, - TD_FEC_7_8 -}; - -static inline unsigned int dvbfec2tdfec(fe_code_rate_t fec) -{ - switch (fec) { - case FEC_1_2: // FEC_1_2 ... FEC_3_4 are equal to TD_FEC_1_2 ... TD_FEC_3_4 - case FEC_2_3: - case FEC_3_4: - return (unsigned int)fec; - case FEC_5_6: - return TD_FEC_5_6; - case FEC_7_8: - return TD_FEC_7_8; - default: - break; - } - return TD_FEC_AUTO; -} - -static inline fe_code_rate_t tdfec2dvbfec(unsigned int tdfec) -{ - switch (tdfec) - { - case TD_FEC_1_2: - case TD_FEC_2_3: - case TD_FEC_3_4: - return (fe_code_rate_t)tdfec; - case TD_FEC_5_6: - return FEC_5_6; - case TD_FEC_7_8: - return FEC_7_8; - default: - break; - } - return FEC_AUTO; -} - -#endif /* _td_value_compat_ */ diff --git a/libspark/td-compat/td-video-compat.h b/libspark/td-compat/td-video-compat.h deleted file mode 100644 index 137a346..0000000 --- a/libspark/td-compat/td-video-compat.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * compatibility stuff for Tripledragon video API - * - * (C) 2009 Stefan Seyfried - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __td_video_compat_h__ -#define __td_video_compat_h__ - -#include -// types -#define video_format_t vidDispSize_t -#define video_displayformat_t vidDispMode_t -typedef enum { - VIDEO_SOURCE_DEMUX = VID_SOURCE_DEMUX, - VIDEO_SOURCE_MEMORY = VID_SOURCE_MEMORY -} video_stream_source_t; -typedef enum { - VIDEO_STOPPED, /* Video is stopped */ - VIDEO_PLAYING, /* Video is currently playing */ - VIDEO_FREEZED /* Video is freezed */ -} video_play_state_t; -//#define video_play_state_t vidState_t -// ioctls -#define VIDEO_SET_SYSTEM MPEG_VID_SET_DISPFMT -#define VIDEO_SET_FORMAT MPEG_VID_SET_DISPSIZE -#define VIDEO_SET_DISPLAY_FORMAT MPEG_VID_SET_DISPMODE -#define VIDEO_SELECT_SOURCE MPEG_VID_SELECT_SOURCE -#define VIDEO_PLAY MPEG_VID_PLAY -#define VIDEO_STOP MPEG_VID_STOP -#define VIDEO_SET_BLANK MPEG_VID_SET_BLANK - -#endif /* __td_video_compat_h__ */ diff --git a/libspark/video.cpp b/libspark/video.cpp index ea72b70..5ce81e7 100644 --- a/libspark/video.cpp +++ b/libspark/video.cpp @@ -426,6 +426,8 @@ void cVideo::SetVideoMode(analog_mode_t mode) void cVideo::ShowPicture(const char * fname, const char *_destname) { lt_debug("%s(%s)\n", __func__, fname); + static const unsigned char pes_header[] = { 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x80, 0x00, 0x00 }; + static const unsigned char seq_end[] = { 0x00, 0x00, 0x01, 0xB7 }; char destname[512]; char cmd[512]; char *p; @@ -444,7 +446,7 @@ void cVideo::ShowPicture(const char * fname, const char *_destname) if (_destname) strncpy(destname, _destname, sizeof(destname)); else { - strcpy(destname, "/var/cache"); + strcpy(destname, "/tmp/cache"); if (stat(fname, &st2)) { lt_info("%s: could not stat %s (%m)\n", __func__, fname); @@ -456,7 +458,7 @@ void cVideo::ShowPicture(const char * fname, const char *_destname) build that filename first... TODO: this could cause name clashes, use a hashing function instead... */ strcat(destname, fname); - p = &destname[strlen("/var/cache/")]; + p = &destname[strlen("/tmp/cache/")]; while ((p = strchr(p, '/')) != NULL) *p = '.'; strcat(destname, ".m2v"); @@ -468,7 +470,7 @@ void cVideo::ShowPicture(const char * fname, const char *_destname) u.actime = time(NULL); u.modtime = st2.st_mtime; /* it does not exist or has a different date, so call ffmpeg... */ - sprintf(cmd, "ffmpeg -y -f mjpeg -i '%s' -s 1280x720 '%s' > 4) != 0xE) // no pes header + write(fd, pes_header, sizeof(pes_header)); + write(fd, iframe, st.st_size); + if (!seq_end_avail) + write(fd, seq_end, sizeof(seq_end)); + memset(iframe, 0, 8192); + write(fd, iframe, 8192); + ioctl(fd, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX); free(iframe); } out: diff --git a/libspark/video_lib.h b/libspark/video_lib.h index 5b4e1af..8a1a550 100644 --- a/libspark/video_lib.h +++ b/libspark/video_lib.h @@ -63,7 +63,7 @@ typedef enum { DISPLAY_AR_14_9, DISPLAY_AR_16_9, DISPLAY_AR_20_9, - DISPLAY_AR_RAW, + DISPLAY_AR_RAW } DISPLAY_AR; typedef enum { @@ -138,11 +138,11 @@ class cVideo int /*vidOutFmt_t*/ outputformat; int scartvoltage; - VIDEO_FORMAT StreamType; - VIDEO_DEFINITION VideoDefinition; + VIDEO_FORMAT StreamType; + VIDEO_DEFINITION VideoDefinition; DISPLAY_AR DisplayAR; VIDEO_PLAY_MODE SyncMode; - DISPLAY_AR_MODE ARMode; + DISPLAY_AR_MODE ARMode; VIDEO_DB_DR eDbDr; DISPLAY_AR PictureAR; VIDEO_FRAME_RATE FrameRate; diff --git a/libtriple/Makefile.am b/libtriple/Makefile.am index 6df87cb..fa3064e 100644 --- a/libtriple/Makefile.am +++ b/libtriple/Makefile.am @@ -6,6 +6,7 @@ AM_CPPFLAGS = \ AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing AM_LDFLAGS = \ + -lrt \ @DIRECTFB_LIBS@ libtriple_la_SOURCES = \ diff --git a/libtriple/mmi.h b/libtriple/mmi.h deleted file mode 100644 index 76ff992..0000000 --- a/libtriple/mmi.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __MMI_H_ -#define __MMI_H_ - -#define MAX_MMI_ITEMS 40 -#define MAX_MMI_TEXT_LEN 255 -#define MAX_MMI_CHOICE_TEXT_LEN 255 - -typedef struct { - int choice_nb; - char title[MAX_MMI_TEXT_LEN]; - char subtitle[MAX_MMI_TEXT_LEN]; - char bottom[MAX_MMI_TEXT_LEN]; - char choice_item[MAX_MMI_ITEMS][MAX_MMI_CHOICE_TEXT_LEN]; -} MMI_MENU_LIST_INFO; - -typedef struct { - int blind; - int answerlen; - char enguiryText[MAX_MMI_TEXT_LEN]; -} MMI_ENGUIRY_INFO; - -#endif // __MMI_H_ -