Add preliminary support for DVBViewer CI.

This commit is contained in:
Rolf Ahrenberg 2016-08-27 18:54:03 +03:00
parent 9c91e01a87
commit e7c9b04ad2
9 changed files with 365 additions and 16 deletions

View File

@ -469,6 +469,13 @@ int cSatipDevice::GetCISlot(void)
return slot;
}
cString cSatipDevice::GetTnrParameterString(void)
{
if (channelM.Ca())
return GetTnrUrlParameters(&channelM);
return NULL;
}
bool cSatipDevice::IsIdle(void)
{
return !Receiving();

View File

@ -110,6 +110,7 @@ public:
virtual int GetId(void);
virtual int GetPmtPid(void);
virtual int GetCISlot(void);
virtual cString GetTnrParameterString(void);
virtual bool IsIdle(void);
};

View File

@ -16,6 +16,7 @@ public:
virtual int GetId(void) = 0;
virtual int GetPmtPid(void) = 0;
virtual int GetCISlot(void) = 0;
virtual cString GetTnrParameterString(void) = 0;
virtual bool IsIdle(void) = 0;
private:

310
param.c
View File

@ -194,3 +194,313 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
}
return NULL;
}
cString GetTnrUrlParameters(const cChannel *channelP)
{
if (channelP) {
cDvbTransponderParameters dtp(channelP->Parameters());
eTrackType track = cDevice::PrimaryDevice()->GetCurrentAudioTrack();
// TunerType: Byte;
// 0 = cable, 1 = satellite, 2 = terrestrial, 3 = atsc, 4 = iptv, 5 = stream (URL, DVBViewer GE)
int TunerType = 0;
if (channelP->IsCable())
TunerType = 0;
else if (channelP->IsSat())
TunerType = 1;
else if (channelP->IsTerr())
TunerType = 2;
else if (channelP->IsAtsc())
TunerType = 3;
// Frequency: DWord;
// DVB-S: MHz if < 1000000, kHz if >= 1000000
// DVB-T/C, ATSC: kHz
// IPTV: IP address Byte3.Byte2.Byte1.Byte0
int Frequency = channelP->Frequency() / 1000;
// Symbolrate: DWord;
// DVB S/C: in kSym/s
// DVB-T, ATSC: 0
// IPTV: Port
int Symbolrate = (channelP->IsSat() || channelP->IsCable()) ? channelP->Srate() : 0;
// LNB_LOF: Word;
// DVB-S: Local oscillator frequency of the LNB
// DVB-T/C, ATSC: 0
// IPTV: Byte0 and Byte1 of Source IP
int LNB_LOF = channelP->IsSat() ? Setup.LnbSLOF : 0;
// Tone: Byte;
// 0 = off, 1 = 22 khz
int Tone = (channelP->Frequency() < Setup.LnbSLOF) ? 0 : 1;
// Polarity: Byte;
// DVB-S polarity: 0 = horizontal, 1 = vertical, 2 = circular left, 3 = circular right
// DVB-C modulation: 0 = Auto, 1 = 16QAM, 2 = 32QAM, 3 = 64QAM, 4 = 128QAM, 5 = 256 QAM
// DVB-T bandwidth: 0 = 6 MHz, 1 = 7 MHz, 2 = 8 MHz
// IPTV: Byte3 of SourceIP
int Polarity = 0;
if (channelP->IsSat()) {
switch (tolower(dtp.Polarization())) {
case 'h':
Polarity = 0;
break;
case 'v':
Polarity = 1;
break;
case 'l':
Polarity = 2;
break;
case 'r':
Polarity = 3;
break;
default:
break;
}
}
else if (channelP->IsCable()) {
switch (dtp.Modulation()) {
case 999:
Polarity = 0;
break;
case 16:
Polarity = 1;
break;
case 32:
Polarity = 2;
break;
case 64:
Polarity = 3;
break;
case 128:
Polarity = 4;
break;
case 256:
Polarity = 5;
break;
default:
break;
}
}
else if (channelP->IsTerr()) {
switch (dtp.Bandwidth()) {
case 6:
Polarity = 0;
break;
case 7:
Polarity = 1;
break;
case 8:
Polarity = 2;
break;
default:
break;
}
}
// DiSEqC: Byte;
// 0 = None
// 1 = Pos A (mostly translated to PosA/OptA)
// 2 = Pos B (mostly translated to PosB/OptA)
// 3 = PosA/OptA
// 4 = PosB/OptA
// 5 = PosA/OptB
// 6 = PosB/OptB
// 7 = Preset Position (DiSEqC 1.2, see DiSEqCExt)
// 8 = Angular Position (DiSEqC 1.2, see DiSEqCExt)
// 9 = DiSEqC Command Sequence (see DiSEqCExt)
int DiSEqC = 0;
// FEC: Byte;
// 0 = Auto
// 1 = 1/2
// 2 = 2/3
// 3 = 3/4
// 4 = 5/6
// 5 = 7/8
// 6 = 8/9
// 7 = 3/5
// 8 = 4/5
// 9 = 9/10
// IPTV: Byte2 of SourceIP
// DVB C/T, ATSC: 0
int FEC = 0;
if (channelP->IsSat()) {
switch (dtp.CoderateH()) {
case 999:
FEC = 0;
break;
case 12:
FEC = 1;
break;
case 23:
FEC = 2;
break;
case 34:
FEC = 3;
break;
case 56:
FEC = 4;
break;
case 78:
FEC = 5;
break;
case 89:
FEC = 6;
break;
case 35:
FEC = 7;
break;
case 45:
FEC = 8;
break;
case 910:
FEC = 9;
break;
default:
break;
}
}
// Audio_PID: Word;
int Audio_PID = channelP->Apid(0);
if (IS_AUDIO_TRACK(track))
Audio_PID = channelP->Apid(int(track - ttAudioFirst));
else if (IS_DOLBY_TRACK(track))
Audio_PID = channelP->Dpid(int(track - ttDolbyFirst));
// Video_PID: Word;
int Video_PID = channelP->Vpid();
// PMT_PID: Word;
int PMT_PID = channelP->Ppid();
// Service_ID: Word;
int Service_ID = channelP->Sid();
// SatModulation: Byte;
// Bit 0..1: satellite modulation. 0 = Auto, 1 = QPSK, 2 = 8PSK, 3 = 16QAM or APSK for DVB-S2
// Bit 2: modulation system. 0 = DVB-S/T/C, 1 = DVB-S2/T2/C2
// Bit 3..4: DVB-S2: roll-off. 0 = 0.35, 1 = 0.25, 2 = 0.20, 3 = reserved
// Bit 5..6: spectral inversion, 0 = undefined, 1 = auto, 2 = normal, 3 = inverted
// Bit 7: DVB-S2: pilot symbols, 0 = off, 1 = on
// DVB-T2: DVB-T2 Lite, 0 = off, 1 = on
int SatModulation = 0;
if (channelP->IsSat() && dtp.System()) {
switch (dtp.Modulation()) {
case 999:
SatModulation |= (0 & 0x3) << 0;
break;
case 2:
SatModulation |= (1 & 0x3) << 0;
break;
case 5:
SatModulation |= (2 & 0x3) << 0;
break;
case 6:
SatModulation |= (3 & 0x3) << 0;
break;
default:
break;
}
}
SatModulation |= (dtp.System() & 0x1) << 2;
if (channelP->IsSat() && dtp.System()) {
switch (dtp.RollOff()) {
case 35:
SatModulation |= (0 & 0x3) << 3;
break;
case 25:
SatModulation |= (1 & 0x3) << 3;
break;
case 20:
SatModulation |= (2 & 0x3) << 3;
break;
default:
break;
}
}
switch (dtp.Inversion()) {
case 999:
SatModulation |= (1 & 0x3) << 5;
break;
case 0:
SatModulation |= (2 & 0x3) << 5;
break;
case 1:
SatModulation |= (3 & 0x3) << 5;
break;
default:
break;
}
if (channelP->IsSat() && dtp.System()) {
switch (dtp.Pilot()) {
case 0:
SatModulation |= (0 & 0x1) << 7;
break;
case 1:
SatModulation |= (1 & 0x1) << 7;
break;
default:
break;
}
}
// DiSEqCExt: Word;
// DiSEqC Extension, meaning depends on DiSEqC
// DiSEqC = 0..6: 0
// DiSEqC = 7: Preset Position (DiSEqC 1.2)
// DiSEqC = 8: Orbital Position (DiSEqC 1.2, USALS, for calculating motor angle)
// Same format as OrbitalPos above
// DiSEQC = 9: Orbital Position referencing DiSEqC sequence defined in DiSEqC.xml/ini
// Same format as OrbitalPos above
int DiSEqCExt = 0;
// Flags: Byte;
// Bit 0: 1 = encrypted channel
// Bit 1: reserved, set to 0
// Bit 2: 1 = channel broadcasts RDS data
// Bit 3: 1 = channel is a video service (even if the Video PID is temporarily = 0)
// Bit 4: 1 = channel is an audio service (even if the Audio PID is temporarily = 0)
// Bit 5: 1 = audio has a different samplerate than 48 KHz
// Bit 6: 1 = bandstacking, internally polarisation is always set to H
// Bit 7: 1 = channel entry is an additional audio track of the preceding
// channel with bit 7 = 0
int Flags = (channelP->Ca() > 0xFF) ? 1 : 0;
// ChannelGroup: Byte;
// 0 = Group A, 1 = Group B, 2 = Group C etc.
int ChannelGroup = 0;
// TransportStream_ID: Word;
int TransportStream_ID = channelP->Tid();
// OriginalNetwork_ID: Word;
int OriginalNetwork_ID = channelP->Nid();
// Substream: Word;
// DVB-S/C/T, ATSC, IPTV: 0
// DVB-T2: 0 = PLP_ID not set, 1..256: PLP_ID + 1, 257... reserved
int Substream = (channelP->IsTerr() && dtp.System()) ? dtp.StreamId() - 1 : 0;
// OrbitalPos: Word;
// DVB-S: orbital position x 10, 0 = undefined, 1..1800 east, 1801..3599 west (1°W = 3599)
// DVB-C: 4000..4999
// DVB-T: 5000..5999
// ATSC: 6000..6999
// IPTV: 7000..7999
// Stream: 8000..8999
int OrbitalPos = 0;
if (channelP->IsSat()) {
OrbitalPos = cSource::Position(channelP->Source());
if (OrbitalPos != 3600)
OrbitalPos += 1800;
}
return cString::sprintf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
TunerType, Frequency, Symbolrate, LNB_LOF, Tone, Polarity, DiSEqC, FEC, Audio_PID, Video_PID, PMT_PID, Service_ID,
SatModulation, DiSEqCExt, Flags, ChannelGroup, TransportStream_ID, OriginalNetwork_ID, Substream, OrbitalPos);
}
return NULL;
}

View File

@ -11,5 +11,6 @@
#include "common.h"
cString GetTransponderUrlParameters(const cChannel *channelP);
cString GetTnrUrlParameters(const cChannel *channelP);
#endif // __SATIP_PARAM_H

View File

@ -146,11 +146,25 @@ cSatipServer::cSatipServer(const char *addressP, const int portP, const char *mo
quirkM |= eSatipQuirkForceLock;
quirksM = cString::sprintf("%s%sForceLock", *quirksM, isempty(*quirksM) ? "" : ",");
}
// These devices support the X_PMT protocol extension
if (strstr(*descriptionM, "OctopusNet") || // Digital Devices OctopusNet
strstr(*descriptionM, "minisatip") // minisatip server
) {
quirkM |= eSatipQuirkCiXpmt;
quirksM = cString::sprintf("%s%sCiXpmt", *quirksM, isempty(*quirksM) ? "" : ",");
}
// These devices support the TNR protocol extension
if (strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server
) {
quirkM |= eSatipQuirkCiTnr;
quirksM = cString::sprintf("%s%sCiTnr", *quirksM, isempty(*quirksM) ? "" : ",");
}
debug3("%s description=%s quirks=%s", __PRETTY_FUNCTION__, *descriptionM, *quirksM);
}
// These devices support the X_PMT protocol extension
// These devices support external CI
if (strstr(*descriptionM, "OctopusNet") || // Digital Devices OctopusNet
strstr(*descriptionM, "minisatip") // minisatip server
strstr(*descriptionM, "minisatip") || // minisatip server
strstr(*descriptionM, "DVBViewer") // DVBViewer Media Server
) {
hasCiM = true;
}

View File

@ -79,7 +79,9 @@ public:
eSatipQuirkPlayPids = 0x02,
eSatipQuirkForceLock = 0x04,
eSatipQuirkRtpOverTcp = 0x08,
eSatipQuirkMask = 0x0F
eSatipQuirkCiXpmt = 0x10,
eSatipQuirkCiTnr = 0x20,
eSatipQuirkMask = 0xFF
};
cSatipServer(const char *addressP, const int portP, const char *modelP, const char *filtersP, const char *descriptionP);
virtual ~cSatipServer();

38
tuner.c
View File

@ -25,6 +25,7 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
rtcpM(*this),
streamAddrM(""),
streamParamM(""),
tnrParamM(""),
streamPortM(SATIP_DEFAULT_RTSP_PORT),
currentServerM(NULL, deviceP.GetId(), 0),
nextServerM(NULL, deviceP.GetId(), 0),
@ -210,6 +211,7 @@ bool cSatipTuner::Connect(void)
if (!isempty(*streamAddrM)) {
cString connectionUri = GetBaseUrl(*streamAddrM, streamPortM);
tnrParamM = "";
// Just retune
if (streamIdM >= 0) {
cString uri = cString::sprintf("%sstream=%d?%s", *connectionUri, streamIdM, *streamParamM);
@ -445,20 +447,30 @@ bool cSatipTuner::UpdatePids(bool forceP)
uri = cString::sprintf("%s%sdelpids=%s", *uri, addPidsM.Size() ? "&" : "?", *delPidsM.ListPids());
}
if (useci) {
// CI extension parameters:
// - x_pmt : specifies the PMT of the service you want the CI to decode
// - x_ci : specfies which CI slot (1..n) to use
// value 0 releases the CI slot
// CI slot released automatically if the stream is released,
// but not when used retuning to another channel
int pid = deviceM->GetPmtPid();
if ((pid > 0) && (pid != pmtPidM)) {
int slot = deviceM->GetCISlot();
uri = cString::sprintf("%s&x_pmt=%d", *uri, pid);
if (slot > 0)
uri = cString::sprintf("%s&x_ci=%d", *uri, slot);
if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkCiXpmt)) {
// CI extension parameters:
// - x_pmt : specifies the PMT of the service you want the CI to decode
// - x_ci : specfies which CI slot (1..n) to use
// value 0 releases the CI slot
// CI slot released automatically if the stream is released,
// but not when used retuning to another channel
int pid = deviceM->GetPmtPid();
if ((pid > 0) && (pid != pmtPidM)) {
int slot = deviceM->GetCISlot();
uri = cString::sprintf("%s&x_pmt=%d", *uri, pid);
if (slot > 0)
uri = cString::sprintf("%s&x_ci=%d", *uri, slot);
}
pmtPidM = pid;
}
else if (currentServerM.IsQuirk(cSatipServer::eSatipQuirkCiTnr)) {
// CI extension parameters:
// - tnr : specifies a channel config entry
cString param = deviceM->GetTnrParameterString();
if (!isempty(*param) && strcmp(*tnrParamM, *param) != 0)
uri = cString::sprintf("%s&tnr=%s", *uri, *param);
tnrParamM = param;
}
pmtPidM = pid;
}
pidUpdateCacheM.Set(ePidUpdateIntervalMs);
if (!rtspM.Play(*uri))

View File

@ -99,6 +99,7 @@ private:
cSatipRtcp rtcpM;
cString streamAddrM;
cString streamParamM;
cString tnrParamM;
int streamPortM;
cSatipTunerServer currentServerM;
cSatipTunerServer nextServerM;