2014-03-08 12:07:47 +01:00
|
|
|
/*
|
|
|
|
* device.c: SAT>IP plugin for the Video Disk Recorder
|
|
|
|
*
|
|
|
|
* See the README file for copyright information and how to reach the author.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-11-10 22:46:45 +01:00
|
|
|
#include <vdr/menu.h> // cRecordControl
|
|
|
|
|
2014-03-08 12:07:47 +01:00
|
|
|
#include "config.h"
|
|
|
|
#include "discover.h"
|
2014-12-05 22:14:40 +01:00
|
|
|
#include "log.h"
|
2014-03-10 20:21:08 +01:00
|
|
|
#include "param.h"
|
2014-03-08 12:07:47 +01:00
|
|
|
#include "device.h"
|
|
|
|
|
|
|
|
static cSatipDevice * SatipDevicesS[SATIP_MAX_DEVICES] = { NULL };
|
|
|
|
|
2017-11-13 21:12:10 +01:00
|
|
|
cMutex cSatipDevice::mutexS = cMutex();
|
|
|
|
|
2014-03-08 12:07:47 +01:00
|
|
|
cSatipDevice::cSatipDevice(unsigned int indexP)
|
|
|
|
: deviceIndexM(indexP),
|
2017-04-17 21:10:29 +02:00
|
|
|
bytesDeliveredM(0),
|
2014-03-08 12:07:47 +01:00
|
|
|
isOpenDvrM(false),
|
2017-04-17 21:10:29 +02:00
|
|
|
checkTsBufferM(false),
|
2014-03-08 12:07:47 +01:00
|
|
|
deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)),
|
2014-03-28 18:53:22 +01:00
|
|
|
channelM(),
|
|
|
|
createdM(0),
|
2017-11-13 21:12:10 +01:00
|
|
|
tunedM()
|
2014-03-08 12:07:47 +01:00
|
|
|
{
|
|
|
|
unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE;
|
|
|
|
bufsize -= (bufsize % TS_SIZE);
|
2014-12-16 20:58:46 +01:00
|
|
|
info("Creating device CardIndex=%d DeviceNumber=%d [device %u]", CardIndex(), DeviceNumber(), deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
tsBufferM = new cRingBufferLinear(bufsize + 1, TS_SIZE, false,
|
2014-12-14 20:39:13 +01:00
|
|
|
*cString::sprintf("SATIP#%d TS", deviceIndexM));
|
2014-03-08 12:07:47 +01:00
|
|
|
if (tsBufferM) {
|
2014-12-01 17:12:12 +01:00
|
|
|
tsBufferM->SetTimeouts(10, 10);
|
2014-03-08 12:07:47 +01:00
|
|
|
tsBufferM->SetIoThrottle();
|
|
|
|
pTunerM = new cSatipTuner(*this, tsBufferM->Free());
|
|
|
|
}
|
|
|
|
// Start section handler
|
|
|
|
pSectionFilterHandlerM = new cSatipSectionFilterHandler(deviceIndexM, bufsize + 1);
|
|
|
|
StartSectionHandler();
|
|
|
|
}
|
|
|
|
|
|
|
|
cSatipDevice::~cSatipDevice()
|
|
|
|
{
|
2014-12-06 16:02:45 +01:00
|
|
|
debug1("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2017-11-13 21:12:10 +01:00
|
|
|
// Release immediately any pending conditional wait
|
|
|
|
tunedM.Broadcast();
|
2014-03-08 12:07:47 +01:00
|
|
|
// Stop section handler
|
|
|
|
StopSectionHandler();
|
|
|
|
DELETE_POINTER(pSectionFilterHandlerM);
|
|
|
|
DELETE_POINTER(pTunerM);
|
|
|
|
DELETE_POINTER(tsBufferM);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::Initialize(unsigned int deviceCountP)
|
|
|
|
{
|
2014-12-07 16:27:53 +01:00
|
|
|
debug1("%s (%u)", __PRETTY_FUNCTION__, deviceCountP);
|
2014-03-08 12:07:47 +01:00
|
|
|
if (deviceCountP > SATIP_MAX_DEVICES)
|
|
|
|
deviceCountP = SATIP_MAX_DEVICES;
|
|
|
|
for (unsigned int i = 0; i < deviceCountP; ++i)
|
|
|
|
SatipDevicesS[i] = new cSatipDevice(i);
|
|
|
|
for (unsigned int i = deviceCountP; i < SATIP_MAX_DEVICES; ++i)
|
|
|
|
SatipDevicesS[i] = NULL;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cSatipDevice::Shutdown(void)
|
|
|
|
{
|
2014-12-06 16:02:45 +01:00
|
|
|
debug1("%s", __PRETTY_FUNCTION__);
|
2014-03-08 12:07:47 +01:00
|
|
|
for (int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
|
|
|
if (SatipDevicesS[i])
|
|
|
|
SatipDevicesS[i]->CloseDvr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int cSatipDevice::Count(void)
|
|
|
|
{
|
|
|
|
unsigned int count = 0;
|
2014-12-06 16:02:45 +01:00
|
|
|
debug1("%s", __PRETTY_FUNCTION__);
|
2014-03-08 12:07:47 +01:00
|
|
|
for (unsigned int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
|
|
|
if (SatipDevicesS[i] != NULL)
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
cSatipDevice *cSatipDevice::GetSatipDevice(int cardIndexP)
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s (%d)", __PRETTY_FUNCTION__, cardIndexP);
|
2014-03-08 12:07:47 +01:00
|
|
|
for (unsigned int i = 0; i < SATIP_MAX_DEVICES; ++i) {
|
|
|
|
if (SatipDevicesS[i] && (SatipDevicesS[i]->CardIndex() == cardIndexP)) {
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s (%d): Found!", __PRETTY_FUNCTION__, cardIndexP);
|
2014-03-08 12:07:47 +01:00
|
|
|
return SatipDevicesS[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-11-10 22:46:45 +01:00
|
|
|
cString cSatipDevice::GetSatipStatus(void)
|
|
|
|
{
|
|
|
|
cString info = "";
|
|
|
|
for (int i = 0; i < cDevice::NumDevices(); i++) {
|
|
|
|
const cDevice *device = cDevice::GetDevice(i);
|
|
|
|
if (device && strstr(device->DeviceType(), "SAT>IP")) {
|
|
|
|
int timers = 0;
|
|
|
|
bool live = (device == cDevice::ActualDevice());
|
|
|
|
bool lock = device->HasLock();
|
|
|
|
const cChannel *channel = device->GetCurrentlyTunedTransponder();
|
2015-08-20 18:12:21 +02:00
|
|
|
LOCK_TIMERS_READ;
|
|
|
|
for (const cTimer *timer = Timers->First(); timer; timer = Timers->Next(timer)) {
|
2014-11-10 22:46:45 +01:00
|
|
|
if (timer->Recording()) {
|
|
|
|
cRecordControl *control = cRecordControls::GetRecordControl(timer);
|
|
|
|
if (control && control->Device() == device)
|
|
|
|
timers++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
info = cString::sprintf("%sDevice: %s\n", *info, *device->DeviceName());
|
|
|
|
if (lock)
|
|
|
|
info = cString::sprintf("%sCardIndex: %d HasLock: yes Strength: %d Quality: %d%s\n", *info, device->CardIndex(), device->SignalStrength(), device->SignalQuality(), live ? " Live: yes" : "");
|
|
|
|
else
|
|
|
|
info = cString::sprintf("%sCardIndex: %d HasLock: no\n", *info, device->CardIndex());
|
2016-02-28 17:23:31 +01:00
|
|
|
if (channel) {
|
|
|
|
if (channel->Number() > 0 && device->Receiving())
|
|
|
|
info = cString::sprintf("%sTransponder: %d Channel: %s\n", *info, channel->Transponder(), channel->Name());
|
|
|
|
else
|
|
|
|
info = cString::sprintf("%sTransponder: %d\n", *info, channel->Transponder());
|
|
|
|
}
|
2014-11-10 22:46:45 +01:00
|
|
|
if (timers)
|
|
|
|
info = cString::sprintf("%sRecording: %d timer%s\n", *info, timers, (timers > 1) ? "s" : "");
|
|
|
|
info = cString::sprintf("%s\n", *info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return isempty(*info) ? cString(tr("SAT>IP information not available!")) : info;
|
|
|
|
}
|
|
|
|
|
2014-03-08 12:07:47 +01:00
|
|
|
cString cSatipDevice::GetGeneralInformation(void)
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2015-08-20 18:12:21 +02:00
|
|
|
LOCK_CHANNELS_READ;
|
2016-11-10 15:47:30 +01:00
|
|
|
return cString::sprintf("SAT>IP device: %d\nCardIndex: %d\nStream: %s\nSignal: %s\nStream bitrate: %s\n%sChannel: %s\n",
|
2014-03-08 12:07:47 +01:00
|
|
|
deviceIndexM, CardIndex(),
|
|
|
|
pTunerM ? *pTunerM->GetInformation() : "",
|
|
|
|
pTunerM ? *pTunerM->GetSignalStatus() : "",
|
|
|
|
pTunerM ? *pTunerM->GetTunerStatistic() : "",
|
|
|
|
*GetBufferStatistic(),
|
2015-08-20 18:12:21 +02:00
|
|
|
*Channels->GetByNumber(cDevice::CurrentChannel())->ToText());
|
2014-03-08 12:07:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
cString cSatipDevice::GetPidsInformation(void)
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
return GetPidStatistic();
|
|
|
|
}
|
|
|
|
|
|
|
|
cString cSatipDevice::GetFiltersInformation(void)
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
return cString::sprintf("Active section filters:\n%s", pSectionFilterHandlerM ? *pSectionFilterHandlerM->GetInformation() : "");
|
|
|
|
}
|
|
|
|
|
|
|
|
cString cSatipDevice::GetInformation(unsigned int pageP)
|
|
|
|
{
|
|
|
|
// generate information string
|
|
|
|
cString s;
|
|
|
|
switch (pageP) {
|
|
|
|
case SATIP_DEVICE_INFO_GENERAL:
|
|
|
|
s = GetGeneralInformation();
|
|
|
|
break;
|
|
|
|
case SATIP_DEVICE_INFO_PIDS:
|
|
|
|
s = GetPidsInformation();
|
|
|
|
break;
|
|
|
|
case SATIP_DEVICE_INFO_FILTERS:
|
|
|
|
s = GetFiltersInformation();
|
|
|
|
break;
|
|
|
|
case SATIP_DEVICE_INFO_PROTOCOL:
|
|
|
|
s = pTunerM ? *pTunerM->GetInformation() : "";
|
|
|
|
break;
|
|
|
|
case SATIP_DEVICE_INFO_BITRATE:
|
|
|
|
s = pTunerM ? *pTunerM->GetTunerStatistic() : "";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
s = cString::sprintf("%s%s%s",
|
|
|
|
*GetGeneralInformation(),
|
|
|
|
*GetPidsInformation(),
|
|
|
|
*GetFiltersInformation());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2014-03-23 16:59:08 +01:00
|
|
|
bool cSatipDevice::Ready(void)
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2014-03-28 18:53:22 +01:00
|
|
|
return ((cSatipDiscover::GetInstance()->GetServerCount() > 0) || (createdM.Elapsed() > eReadyTimeoutMs));
|
2014-03-23 16:59:08 +01:00
|
|
|
}
|
|
|
|
|
2014-03-08 12:07:47 +01:00
|
|
|
cString cSatipDevice::DeviceType(void) const
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
return "SAT>IP";
|
|
|
|
}
|
|
|
|
|
|
|
|
cString cSatipDevice::DeviceName(void) const
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2016-03-19 19:33:00 +01:00
|
|
|
if (!Receiving())
|
|
|
|
return cString::sprintf("%s %d", *DeviceType(), deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
return deviceNameM;
|
|
|
|
}
|
|
|
|
|
2014-03-10 20:21:08 +01:00
|
|
|
bool cSatipDevice::AvoidRecording(void) const
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2014-03-10 20:21:08 +01:00
|
|
|
return SatipConfig.IsOperatingModeLow();
|
|
|
|
}
|
|
|
|
|
2017-05-24 22:13:21 +02:00
|
|
|
bool cSatipDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
|
|
|
|
{
|
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
|
|
|
Valid = DTV_STAT_VALID_NONE;
|
|
|
|
if (Strength && pTunerM) {
|
|
|
|
*Strength = pTunerM->SignalStrengthDBm();
|
|
|
|
Valid |= DTV_STAT_VALID_STRENGTH;
|
|
|
|
}
|
|
|
|
if (Status) {
|
|
|
|
*Status = HasLock() ? (DTV_STAT_HAS_SIGNAL | DTV_STAT_HAS_CARRIER | DTV_STAT_HAS_VITERBI | DTV_STAT_HAS_SYNC | DTV_STAT_HAS_LOCK) : DTV_STAT_HAS_NONE;
|
|
|
|
Valid |= DTV_STAT_VALID_STATUS;
|
|
|
|
}
|
|
|
|
return Valid != DTV_STAT_VALID_NONE;
|
|
|
|
}
|
|
|
|
|
2014-03-08 12:07:47 +01:00
|
|
|
int cSatipDevice::SignalStrength(void) const
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
return (pTunerM ? pTunerM->SignalStrength() : -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int cSatipDevice::SignalQuality(void) const
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
return (pTunerM ? pTunerM->SignalQuality() : -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::ProvidesSource(int sourceP) const
|
|
|
|
{
|
2015-01-17 00:39:32 +01:00
|
|
|
cSource *s = Sources.Get(sourceP);
|
|
|
|
debug9("%s (%c) desc='%s' [device %u]", __PRETTY_FUNCTION__, cSource::ToChar(sourceP), s ? s->Description() : "", deviceIndexM);
|
2015-03-17 20:25:15 +01:00
|
|
|
if (SatipConfig.GetDetachedMode())
|
|
|
|
return false;
|
2015-01-17 00:39:32 +01:00
|
|
|
// source descriptions starting with '0' are disabled
|
|
|
|
if (s && s->Description() && (*(s->Description()) == '0'))
|
|
|
|
return false;
|
2014-10-31 21:07:33 +01:00
|
|
|
if (!SatipConfig.IsOperatingModeOff() && !!cSatipDiscover::GetInstance()->GetServer(sourceP)) {
|
|
|
|
int numDisabledSourcesM = SatipConfig.GetDisabledSourcesCount();
|
|
|
|
for (int i = 0; i < numDisabledSourcesM; ++i) {
|
|
|
|
if (sourceP == SatipConfig.GetDisabledSources(i))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2014-03-08 12:07:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::ProvidesTransponder(const cChannel *channelP) const
|
|
|
|
{
|
2014-12-14 00:56:21 +01:00
|
|
|
debug9("%s (%d) transponder=%d source=%c [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, channelP ? channelP->Transponder() : -1, channelP ? cSource::ToChar(channelP->Source()) : '?', deviceIndexM);
|
2014-12-09 20:56:32 +01:00
|
|
|
if (!ProvidesSource(channelP->Source()))
|
|
|
|
return false;
|
|
|
|
return DeviceHooksProvidesTransponder(channelP);
|
2014-03-08 12:07:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::ProvidesChannel(const cChannel *channelP, int priorityP, bool *needsDetachReceiversP) const
|
|
|
|
{
|
|
|
|
bool result = false;
|
|
|
|
bool hasPriority = (priorityP == IDLEPRIORITY) || (priorityP > this->Priority());
|
|
|
|
bool needsDetachReceivers = false;
|
|
|
|
|
2014-12-14 00:56:21 +01:00
|
|
|
debug9("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, priorityP, !!needsDetachReceiversP, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
|
|
|
|
if (channelP && ProvidesTransponder(channelP)) {
|
|
|
|
result = hasPriority;
|
|
|
|
if (priorityP > IDLEPRIORITY) {
|
|
|
|
if (Receiving()) {
|
|
|
|
if (IsTunedToTransponder(channelP)) {
|
|
|
|
if (channelP->Vpid() && !HasPid(channelP->Vpid()) || channelP->Apid(0) && !HasPid(channelP->Apid(0)) || channelP->Dpid(0) && !HasPid(channelP->Dpid(0))) {
|
|
|
|
if (CamSlot() && channelP->Ca() >= CA_ENCRYPTED_MIN) {
|
|
|
|
if (CamSlot()->CanDecrypt(channelP))
|
|
|
|
result = true;
|
|
|
|
else
|
|
|
|
needsDetachReceivers = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
else
|
2019-10-27 18:27:09 +01:00
|
|
|
result = !!SatipConfig.GetFrontendReuse();
|
2014-03-08 12:07:47 +01:00
|
|
|
}
|
|
|
|
else
|
2019-10-27 18:27:09 +01:00
|
|
|
needsDetachReceivers = true;
|
2014-03-08 12:07:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (needsDetachReceiversP)
|
|
|
|
*needsDetachReceiversP = needsDetachReceivers;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::ProvidesEIT(void) const
|
|
|
|
{
|
2021-01-31 12:41:04 +01:00
|
|
|
#if defined(APIVERSNUM) && APIVERSNUM < 20403
|
2014-03-16 18:58:09 +01:00
|
|
|
return (SatipConfig.GetEITScan());
|
2021-01-31 12:41:04 +01:00
|
|
|
#else
|
|
|
|
return (SatipConfig.GetEITScan()) && DeviceHooksProvidesEIT();
|
|
|
|
#endif
|
2014-03-08 12:07:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int cSatipDevice::NumProvidedSystems(void) const
|
|
|
|
{
|
2014-03-10 20:21:08 +01:00
|
|
|
int count = cSatipDiscover::GetInstance()->NumProvidedSystems();
|
|
|
|
// Tweak the count according to operation mode
|
|
|
|
if (SatipConfig.IsOperatingModeLow())
|
|
|
|
count = 15;
|
|
|
|
else if (SatipConfig.IsOperatingModeHigh())
|
|
|
|
count = 1;
|
|
|
|
// Clamp the count between 1 and 15
|
|
|
|
if (count > 15)
|
|
|
|
count = 15;
|
|
|
|
else if (count < 1)
|
|
|
|
count = 1;
|
|
|
|
return count;
|
2014-03-08 12:07:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const cChannel *cSatipDevice::GetCurrentlyTunedTransponder(void) const
|
|
|
|
{
|
|
|
|
return &channelM;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::IsTunedToTransponder(const cChannel *channelP) const
|
|
|
|
{
|
|
|
|
if (pTunerM && !pTunerM->IsTuned())
|
|
|
|
return false;
|
|
|
|
if ((channelM.Source() != channelP->Source()) || (channelM.Transponder() != channelP->Transponder()))
|
|
|
|
return false;
|
|
|
|
return (strcmp(channelM.Parameters(), channelP->Parameters()) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::MaySwitchTransponder(const cChannel *channelP) const
|
|
|
|
{
|
|
|
|
return cDevice::MaySwitchTransponder(channelP);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::SetChannelDevice(const cChannel *channelP, bool liveViewP)
|
|
|
|
{
|
2017-11-13 21:12:10 +01:00
|
|
|
cMutexLock MutexLock(&mutexS); // Global lock to prevent any simultaneous zapping
|
2014-12-14 00:56:21 +01:00
|
|
|
debug9("%s (%d, %d) [device %u]", __PRETTY_FUNCTION__, channelP ? channelP->Number() : -1, liveViewP, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
if (channelP) {
|
2014-03-10 20:21:08 +01:00
|
|
|
cDvbTransponderParameters dtp(channelP->Parameters());
|
|
|
|
cString params = GetTransponderUrlParameters(channelP);
|
|
|
|
if (isempty(params)) {
|
2014-12-16 20:58:46 +01:00
|
|
|
error("Unrecognized channel parameters: %s [device %u]", channelP->Parameters(), deviceIndexM);
|
2014-03-10 20:21:08 +01:00
|
|
|
return false;
|
|
|
|
}
|
2014-03-08 12:07:47 +01:00
|
|
|
cString address;
|
2015-02-16 16:21:00 +01:00
|
|
|
cSatipServer *server = cSatipDiscover::GetInstance()->AssignServer(deviceIndexM, channelP->Source(), channelP->Transponder(), dtp.System());
|
2014-03-08 12:07:47 +01:00
|
|
|
if (!server) {
|
2015-01-14 19:34:12 +01:00
|
|
|
debug9("%s No suitable server found [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
return false;
|
|
|
|
}
|
2015-01-15 22:33:51 +01:00
|
|
|
if (pTunerM && pTunerM->SetSource(server, channelP->Transponder(), *params, deviceIndexM)) {
|
2014-03-08 12:07:47 +01:00
|
|
|
channelM = *channelP;
|
2015-01-09 14:42:03 +01:00
|
|
|
deviceNameM = cString::sprintf("%s %d %s", *DeviceType(), deviceIndexM, *cSatipDiscover::GetInstance()->GetServerString(server));
|
2017-11-13 21:12:10 +01:00
|
|
|
// Wait for actual channel tuning to prevent simultaneous frontend allocation failures
|
|
|
|
tunedM.TimedWait(mutexS, eTuningTimeoutMs);
|
2014-03-08 12:07:47 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2014-11-03 20:55:54 +01:00
|
|
|
else if (pTunerM) {
|
2015-01-15 22:33:51 +01:00
|
|
|
pTunerM->SetSource(NULL, 0, NULL, deviceIndexM);
|
2016-01-30 20:41:10 +01:00
|
|
|
deviceNameM = cString::sprintf("%s %d", *DeviceType(), deviceIndexM);
|
2014-11-03 20:55:54 +01:00
|
|
|
return true;
|
|
|
|
}
|
2014-03-08 12:07:47 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-11-13 21:12:10 +01:00
|
|
|
void cSatipDevice::SetChannelTuned(void)
|
|
|
|
{
|
|
|
|
debug9("%s () [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
|
|
|
// Release immediately any pending conditional wait
|
|
|
|
tunedM.Broadcast();
|
|
|
|
}
|
|
|
|
|
2014-03-08 12:07:47 +01:00
|
|
|
bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
|
|
|
|
{
|
2015-08-16 00:38:03 +02:00
|
|
|
debug12("%s (%d, %d, %d) [device %u]", __PRETTY_FUNCTION__, handleP ? handleP->pid : -1, typeP, onP, deviceIndexM);
|
2018-10-21 11:25:15 +02:00
|
|
|
if (pTunerM && handleP && handleP->pid >= 0 && handleP->pid <= 8191) {
|
2014-03-08 12:07:47 +01:00
|
|
|
if (onP)
|
|
|
|
return pTunerM->SetPid(handleP->pid, typeP, true);
|
2016-12-15 23:39:41 +01:00
|
|
|
else if (!handleP->used && pSectionFilterHandlerM && !pSectionFilterHandlerM->Exists(handleP->pid))
|
2014-03-08 12:07:47 +01:00
|
|
|
return pTunerM->SetPid(handleP->pid, typeP, false);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cSatipDevice::OpenFilter(u_short pidP, u_char tidP, u_char maskP)
|
|
|
|
{
|
2015-01-15 19:03:35 +01:00
|
|
|
debug12("%s (%d, %02X, %02X) [device %d]", __PRETTY_FUNCTION__, pidP, tidP, maskP, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
if (pSectionFilterHandlerM) {
|
2014-03-25 20:29:57 +01:00
|
|
|
int handle = pSectionFilterHandlerM->Open(pidP, tidP, maskP);
|
|
|
|
if (pTunerM && (handle >= 0))
|
2014-03-08 12:07:47 +01:00
|
|
|
pTunerM->SetPid(pidP, ptOther, true);
|
2014-03-25 20:29:57 +01:00
|
|
|
return handle;
|
2014-03-08 12:07:47 +01:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cSatipDevice::CloseFilter(int handleP)
|
|
|
|
{
|
|
|
|
if (pSectionFilterHandlerM) {
|
2014-12-14 00:56:21 +01:00
|
|
|
int pid = pSectionFilterHandlerM->GetPid(handleP);
|
2015-01-15 19:03:35 +01:00
|
|
|
debug12("%s (%d) [device %u]", __PRETTY_FUNCTION__, pid, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
if (pTunerM)
|
2014-12-14 00:56:21 +01:00
|
|
|
pTunerM->SetPid(pid, ptOther, false);
|
2014-03-08 12:07:47 +01:00
|
|
|
pSectionFilterHandlerM->Close(handleP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::OpenDvr(void)
|
|
|
|
{
|
2014-12-14 00:56:21 +01:00
|
|
|
debug9("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2017-04-17 21:10:29 +02:00
|
|
|
bytesDeliveredM = 0;
|
2014-03-08 12:07:47 +01:00
|
|
|
tsBufferM->Clear();
|
|
|
|
if (pTunerM)
|
|
|
|
pTunerM->Open();
|
|
|
|
isOpenDvrM = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cSatipDevice::CloseDvr(void)
|
|
|
|
{
|
2014-12-14 00:56:21 +01:00
|
|
|
debug9("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
if (pTunerM)
|
|
|
|
pTunerM->Close();
|
|
|
|
isOpenDvrM = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::HasLock(int timeoutMsP) const
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s (%d) [device %d]", __PRETTY_FUNCTION__, timeoutMsP, deviceIndexM);
|
2021-03-02 20:50:43 +01:00
|
|
|
if (timeoutMsP > 0) {
|
|
|
|
cTimeMs timer(timeoutMsP);
|
|
|
|
while (!timer.TimedOut()) {
|
|
|
|
if (pTunerM && pTunerM->HasLock())
|
|
|
|
return true;
|
|
|
|
cCondWait::SleepMs(100);
|
|
|
|
}
|
|
|
|
}
|
2014-03-08 12:07:47 +01:00
|
|
|
return (pTunerM && pTunerM->HasLock());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::HasInternalCam(void)
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2015-01-05 23:58:35 +01:00
|
|
|
return SatipConfig.GetCIExtension();
|
2014-03-08 12:07:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void cSatipDevice::WriteData(uchar *bufferP, int lengthP)
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
// Fill up TS buffer
|
2014-11-26 21:23:47 +01:00
|
|
|
if (isOpenDvrM && tsBufferM) {
|
2014-03-08 12:07:47 +01:00
|
|
|
int len = tsBufferM->Put(bufferP, lengthP);
|
|
|
|
if (len != lengthP)
|
|
|
|
tsBufferM->ReportOverflow(lengthP - len);
|
|
|
|
}
|
|
|
|
// Filter the sections
|
|
|
|
if (pSectionFilterHandlerM)
|
|
|
|
pSectionFilterHandlerM->Write(bufferP, lengthP);
|
|
|
|
}
|
|
|
|
|
2014-04-06 12:37:45 +02:00
|
|
|
int cSatipDevice::GetId(void)
|
|
|
|
{
|
|
|
|
return deviceIndexM;
|
|
|
|
}
|
|
|
|
|
2015-01-05 23:58:35 +01:00
|
|
|
int cSatipDevice::GetPmtPid(void)
|
|
|
|
{
|
2015-02-08 21:35:35 +01:00
|
|
|
int pid = channelM.Ca() ? ::GetPmtPid(channelM.Source(), channelM.Transponder(), channelM.Sid()) : 0;
|
2015-01-09 01:06:20 +01:00
|
|
|
debug11("%s pmtpid=%d source=%c transponder=%d sid=%d name=%s [device %u]", __PRETTY_FUNCTION__, pid, cSource::ToChar(channelM.Source()), channelM.Transponder(), channelM.Sid(), channelM.Name(), deviceIndexM);
|
2015-01-05 23:58:35 +01:00
|
|
|
return pid;
|
|
|
|
}
|
|
|
|
|
2015-01-09 14:42:03 +01:00
|
|
|
int cSatipDevice::GetCISlot(void)
|
|
|
|
{
|
2015-01-11 00:49:59 +01:00
|
|
|
int slot = 0;
|
|
|
|
int ca = 0;
|
|
|
|
for (const int *id = channelM.Caids(); *id; ++id) {
|
|
|
|
if (checkCASystem(SatipConfig.GetCICAM(0), *id)) {
|
|
|
|
ca = *id;
|
|
|
|
slot = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (checkCASystem(SatipConfig.GetCICAM(1), *id)) {
|
|
|
|
ca = *id;
|
|
|
|
slot = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
debug11("%s slot=%d ca=%X name=%s [device %u]", __PRETTY_FUNCTION__, slot, ca, channelM.Name(), deviceIndexM);
|
2015-01-09 14:42:03 +01:00
|
|
|
return slot;
|
|
|
|
}
|
|
|
|
|
2016-08-27 17:54:03 +02:00
|
|
|
cString cSatipDevice::GetTnrParameterString(void)
|
|
|
|
{
|
|
|
|
if (channelM.Ca())
|
|
|
|
return GetTnrUrlParameters(&channelM);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-05-22 21:42:11 +02:00
|
|
|
bool cSatipDevice::IsIdle(void)
|
|
|
|
{
|
|
|
|
return !Receiving();
|
|
|
|
}
|
|
|
|
|
2017-04-17 21:10:29 +02:00
|
|
|
uchar *cSatipDevice::GetData(int *availableP, bool checkTsBuffer)
|
2014-03-08 12:07:47 +01:00
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2014-03-08 12:07:47 +01:00
|
|
|
if (isOpenDvrM && tsBufferM) {
|
|
|
|
int count = 0;
|
2017-04-17 21:10:29 +02:00
|
|
|
if (bytesDeliveredM) {
|
|
|
|
tsBufferM->Del(bytesDeliveredM);
|
|
|
|
bytesDeliveredM = 0;
|
|
|
|
}
|
|
|
|
if (checkTsBuffer && tsBufferM->Available() < TS_SIZE)
|
|
|
|
return NULL;
|
2014-03-08 12:07:47 +01:00
|
|
|
uchar *p = tsBufferM->Get(count);
|
|
|
|
if (p && count >= TS_SIZE) {
|
|
|
|
if (*p != TS_SYNC_BYTE) {
|
|
|
|
for (int i = 1; i < count; i++) {
|
|
|
|
if (p[i] == TS_SYNC_BYTE) {
|
|
|
|
count = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tsBufferM->Del(count);
|
|
|
|
info("Skipped %d bytes to sync on TS packet", count);
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-04-17 21:10:29 +02:00
|
|
|
bytesDeliveredM = TS_SIZE;
|
2014-03-08 12:07:47 +01:00
|
|
|
if (availableP)
|
|
|
|
*availableP = count;
|
|
|
|
// Update pid statistics
|
|
|
|
AddPidStatistic(ts_pid(p), payload(p));
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cSatipDevice::SkipData(int countP)
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2017-04-17 21:10:29 +02:00
|
|
|
bytesDeliveredM = countP;
|
2014-03-08 12:07:47 +01:00
|
|
|
// Update buffer statistics
|
|
|
|
AddBufferStatistic(countP, tsBufferM->Available());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cSatipDevice::GetTSPacket(uchar *&dataP)
|
|
|
|
{
|
2014-12-14 16:45:55 +01:00
|
|
|
debug16("%s [device %u]", __PRETTY_FUNCTION__, deviceIndexM);
|
2015-03-17 20:25:15 +01:00
|
|
|
if (SatipConfig.GetDetachedMode())
|
|
|
|
return false;
|
2014-03-08 12:07:47 +01:00
|
|
|
if (tsBufferM) {
|
|
|
|
if (cCamSlot *cs = CamSlot()) {
|
|
|
|
if (cs->WantsTsData()) {
|
|
|
|
int available;
|
2017-04-17 21:10:29 +02:00
|
|
|
dataP = GetData(&available, checkTsBufferM);
|
|
|
|
if (!dataP)
|
|
|
|
available = 0;
|
|
|
|
dataP = cs->Decrypt(dataP, available);
|
|
|
|
SkipData(available);
|
|
|
|
checkTsBufferM = dataP != NULL;
|
2014-03-08 12:07:47 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dataP = GetData();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
dataP = NULL;
|
|
|
|
return true;
|
|
|
|
}
|